diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..2db4fa8d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ext/bgfx"] + path = ext/bgfx + url = https://github.com/JoshuaBrookover/bgfx.cmake.git diff --git a/CMakeLists.txt b/CMakeLists.txt index e907ef64..a7cf7608 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,35 +2,57 @@ cmake_minimum_required (VERSION 3.6) project (Imogen) # Add project's cmake modules to path set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/.) - +message(${CMAKE_MODULE_PATH}) SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo" CACHE STRING "Configuration types" FORCE) -SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMake") +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMake") set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) -file(GLOB_RECURSE SRC_FILES +set(BGFX_BUILD_EXAMPLES OFF) + +if(NOT EMSCRIPTEN) +set(BGFX_BUILD_TOOLS ON) +elseif() +set(BGFX_BUILD_TOOLS OFF) +set(BGFX_CUSTOM_TARGETS OFF) +endif() # emscripten + + + +file(GLOB SRC_FILES ${CMAKE_SOURCE_DIR}/src/*.h ${CMAKE_SOURCE_DIR}/src/*.cpp ) file(GLOB EXT_FILES ${CMAKE_SOURCE_DIR}/ext/*.h ${CMAKE_SOURCE_DIR}/ext/*.cpp + ${CMAKE_SOURCE_DIR}/ext/Nvidia-SBVH/*.cpp +) + +file(GLOB NODE_FILES + ${CMAKE_SOURCE_DIR}/src/Nodes/*.h + ${CMAKE_SOURCE_DIR}/src/Nodes/*.cpp +) + +if (NOT EMSCRIPTEN) +file(GLOB EXT_FILES_DESKTOP ${CMAKE_SOURCE_DIR}/ext/gl3w/GL/*.c - ${CMAKE_SOURCE_DIR}/ext/cmft/*.cpp - ${CMAKE_SOURCE_DIR}/ext/cmft/common/*.cpp ${CMAKE_SOURCE_DIR}/ext/enkiTS-C-11/src/*.cpp ${CMAKE_SOURCE_DIR}/ext/NativeFileDialog/src/nfd_common.c - ${CMAKE_SOURCE_DIR}/ext/Nvidia-SBVH/*.cpp - ${CMAKE_SOURCE_DIR}/ext/SOIL/src/*.c - ${CMAKE_SOURCE_DIR}/ext/GLSL_Pathtracer/*.cpp + ${CMAKE_SOURCE_DIR}/ext/ffmpegCodec/*.cpp + ${CMAKE_SOURCE_DIR}/ext/GLSL_Pathtracer/*.cpp ) +set(SDL2_LIBRARIES "SDL2" "SDL2main") +endif() + +source_group("Nodes" FILES ${NODE_FILES}) if(WIN32) set(NFD_FILES ${CMAKE_SOURCE_DIR}/ext/NativeFileDialog/src/nfd_win.cpp) -set(PLATFORM_LIBS "libtcc") +elseif (EMSCRIPTEN) else() set(NFD_FILES ${CMAKE_SOURCE_DIR}/ext/NativeFileDialog/src/nfd_gtk.c ) @@ -38,6 +60,18 @@ set(NFD_FILES ${CMAKE_SOURCE_DIR}/ext/NativeFileDialog/src/nfd_gtk.c FIND_PACKAGE(PkgConfig REQUIRED) PKG_CHECK_MODULES(GTK3 REQUIRED gtk+-3.0) +find_package(SDL2 REQUIRED) +include_directories(${SDL2_INCLUDE_DIRS}) + +#find_package(FFmpeg REQUIRED) + +find_library(AVCODEC_LIBRARY avcodec) +find_library(AVFORMAT_LIBRARY avformat) +find_library(AVUTIL_LIBRARY avutil) +find_library(AVDEVICE_LIBRARY avdevice) +find_library(SWSCALE_LIBRARY swscale) +find_package(PythonLibs REQUIRED) +include_directories(${PYTHON_INCLUDE_DIRS}) # Setup CMake to use GTK+, tell the compiler where to look for headers # and to the linker where to look for libraries INCLUDE_DIRECTORIES(${GTK3_INCLUDE_DIRS}) @@ -45,33 +79,64 @@ LINK_DIRECTORIES(${GTK3_LIBRARY_DIRS}) # Add other flags to the compiler ADD_DEFINITIONS(${GTK3_CFLAGS_OTHER}) -set(PLATFORM_LIBS dl pthread ${GTK3_LIBRARIES} libtcc.a) +ADD_DEFINITIONS(-DBGFX_CONFIG_RENDERER_OPENGLES=31) +set(PLATFORM_LIBS dl pthread ${GTK3_LIBRARIES}) endif() -set(FFMPEG_LIBS avcodec.lib avdevice.lib avfilter.lib avformat.lib avutil.lib swscale.lib swresample.lib postproc.lib) -set(PYTHON37_LIBS python3.lib python37.lib) +set(IMOGEN_BGFX_DIR ${CMAKE_SOURCE_DIR}/ext/bgfx) + +if(WIN32) + +set(FFMPEG_LIBRARIES avcodec.lib avdevice.lib avfilter.lib avformat.lib avutil.lib swscale.lib swresample.lib postproc.lib) +set(FFMPEG_LIBRARY_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ext/ffmpeg/lib) +set(FFMPEG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ext/ffmpeg/include) + +set(PYTHON37_LIBRARIES python3.lib python37.lib) +set(PYTHON37_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ext/python37/include) +set(PYTHON37_LIBRARY_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ext/python37/libs) + + +set(SDL2_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ext/SDL2/include) +set(SDL2_LIBDIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/SDL2/lib/x64) + +elseif (EMSCRIPTEN) +else() + +PKG_CHECK_MODULES(PYTHON37 REQUIRED python3) +PKG_CHECK_MODULES(SDL2_LIBRARIES REQUIRED sdl2) +PKG_CHECK_MODULES(FFMPEG REQUIRED libavcodec libavdevice libavfilter libavformat libavutil libswscale libswresample libpostproc) +#${AVCODEC_LIBRARY} ${AVUTIL_LIBRARY} ${AVDEVICE_LIBRARY} ${AVFORMAT_LIBRARY} ${SWSCALE_LIBRARY} ${PYTHON_LIBRARIES} + +endif() + +set(BGFX_INCLUDE_DIRS "${IMOGEN_BGFX_DIR}/bgfx/include" "${IMOGEN_BGFX_DIR}/bimg/include" "${IMOGEN_BGFX_DIR}/bx/include") +if(WIN32) +set(BGFX_INCLUDE_DIRS "${BGFX_INCLUDE_DIRS}" "${IMOGEN_BGFX_DIR}/bx/include/compat/msvc") +endif() include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/src/Nodes ${CMAKE_CURRENT_SOURCE_DIR}/ext - ${CMAKE_CURRENT_SOURCE_DIR}/ext/SDL2-2.0.8/include + ${SDL2_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/ext/gl3w - ${CMAKE_CURRENT_SOURCE_DIR}/ext/tcc-0.9.27/ ${CMAKE_CURRENT_SOURCE_DIR}/ext/NativeFileDialog/src/include/ ${CMAKE_CURRENT_SOURCE_DIR}/ext/enkiTS-C-11/src/ - ${CMAKE_CURRENT_SOURCE_DIR}/ext/ffmpeg/include - ${CMAKE_CURRENT_SOURCE_DIR}/ext/python37/include + ${FFMPEG_INCLUDE_DIRS} + ${PYTHON37_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/ext/glm/ - ${CMAKE_CURRENT_SOURCE_DIR}/ext/SOIL/include ${CMAKE_CURRENT_SOURCE_DIR}/ext/Nvidia-SBVH ${CMAKE_CURRENT_SOURCE_DIR}/ext/GLSL_Pathtracer/ + ${CMAKE_CURRENT_SOURCE_DIR}/ext/ffmpegCodec/ + ${CMAKE_CURRENT_BINARY_DIR} + ${BGFX_INCLUDE_DIRS} ) link_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/ext/SDL2-2.0.8/lib/x64 - ${CMAKE_CURRENT_SOURCE_DIR}/ext/tcc-0.9.27/libtcc - ${CMAKE_CURRENT_SOURCE_DIR}/ext/ffmpeg/lib - ${CMAKE_CURRENT_SOURCE_DIR}/ext/python37/libs + ${SDL2_LIBDIR} + ${FFMPEG_LIBRARY_DIRS} + ${PYTHON37_LIBRARY_DIRS} + bx bimg bgfx ) find_package(OpenGL) @@ -90,8 +155,6 @@ IF (NOT USE_MSVC_RUNTIME_LIBRARY_DLL) ENDFOREACH(flag_var) ENDIF (NOT USE_MSVC_RUNTIME_LIBRARY_DLL) -set(SDL2_LIBS "SDL2" "SDL2main") - ####################################################################################### foreach(f ${SRC_FILES}) @@ -112,7 +175,8 @@ set(ENABLE_HIDECONSOLE_BUILD TRUE CACHE BOOL "TRUE to hide console for Windows s if(WINDOWS) set(GUI_TYPE WIN32) -elseif(MACOSX) +elseif (EMSCRIPTEN) +elseif(APPLE) set(GUI_TYPE MACOSX_BUNDLE) endif() @@ -124,9 +188,152 @@ endif() SET(LINK_OPTIONS " ") SET(EXE_NAME "Imogen") -ADD_EXECUTABLE(${EXE_NAME} ${SRC_FILES} ${EXT_FILES} ${NFD_FILES}) +ADD_EXECUTABLE(${EXE_NAME} ${SRC_FILES} ${EXT_FILES} ${NFD_FILES} ${EXT_FILES_DESKTOP} ${NODE_FILES}) -TARGET_LINK_LIBRARIES(${EXE_NAME} ${SDL2_LIBS} ${OPENGL_LIBRARIES} ${PLATFORM_LIBS} ${FFMPEG_LIBS} ${PYTHON37_LIBS}) +if (EMSCRIPTEN) +add_definitions(-DEMSCRIPTEN) +add_definitions(-D_X86_) +set(EMS_OPTS "-s USE_SDL=2 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s ASSERTIONS=1 --bind -O2 --no-heap-copy") +add_definitions(${EMS_OPTS}) +set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") +set(EMS_PRELOAD " --preload-file DefaultLibrary.imogen --preload-file imgui.ini --preload-file Nodes --preload-file Stock") +set(EMS_LINK "${EMS_OPTS} ${EMS_PRELOAD}") +set_target_properties(${EXE_NAME} PROPERTIES LINK_FLAGS ${EMS_LINK}) +#set_target_properties(${EXE_NAME} PROPERTIES COMPILE_FLAGS ${EMS_OPTS}) + +add_custom_command(TARGET ${EXE_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/src/index.html ${CMAKE_CURRENT_BINARY_DIR}/index.html +) + +# copy files and directories because packer doesn't know where to place then +add_custom_command(TARGET ${EXE_NAME} PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/bin/DefaultLibrary.imogen ${CMAKE_CURRENT_BINARY_DIR}/ +) +add_custom_command(TARGET ${EXE_NAME} PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/bin/imgui.ini ${CMAKE_CURRENT_BINARY_DIR}/ +) + +add_custom_command(TARGET ${EXE_NAME} PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Nodes ${CMAKE_CURRENT_BINARY_DIR}/Nodes +) + +add_custom_command(TARGET ${EXE_NAME} PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Stock ${CMAKE_CURRENT_BINARY_DIR}/Stock +) + +endif() + +add_subdirectory(${IMOGEN_BGFX_DIR}/) +set_property(TARGET astc PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx/3rdparty) +set_property(TARGET astc-codec PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx/3rdparty) +set_property(TARGET edtaa3 PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx/3rdparty) +set_property(TARGET etc1 PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx/3rdparty) +set_property(TARGET etc2 PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx/3rdparty) +set_property(TARGET iqa PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx/3rdparty) +set_property(TARGET nvtt PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx/3rdparty) +set_property(TARGET pvrtc PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx/3rdparty) +set_property(TARGET squish PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx/3rdparty) +set_property(TARGET bgfx PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx) +set_property(TARGET bimg PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx) +set_property(TARGET bx PROPERTY FOLDER ${IMOGEN_BGFX_DIR}/bgfx) + + +########################################### +if(NOT EMSCRIPTEN) +file(GLOB SHADER_FILES ${CMAKE_SOURCE_DIR}/src/shaders/*.vs + ${CMAKE_SOURCE_DIR}/src/shaders/*.fs + ${CMAKE_SOURCE_DIR}/src/shaders/*.cs + ) + +set(shaders_inc_file "${CMAKE_CURRENT_BINARY_DIR}/EmbeddedShaders.h") +FILE(WRITE ${shaders_inc_file} "// generated by CMake\n") + +set(shaders_cpp_file "${CMAKE_CURRENT_BINARY_DIR}/EmbeddedShaders.cpp") +FILE(WRITE ${shaders_cpp_file} "// generated by CMake\n") +FILE(WRITE ${shaders_cpp_file} "#include \"EmbeddedShaders.h\"\nstatic const bgfx::EmbeddedShader s_embeddedShaders[] =\n{\n") + + +foreach(SHADER ${SHADER_FILES}) + get_filename_component(FILE_NAME ${SHADER} NAME_WE) + get_filename_component(FILE_NAME_EXT ${SHADER} EXT) + + if(${FILE_NAME_EXT} STREQUAL ".vs") + set(SHADER_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_vs_dx11.h") + add_custom_command( + OUTPUT ${SHADER_OUTPUT} + COMMAND "$" -f ${SHADER} -o ${SHADER_OUTPUT} --platform windows -p vs_5_0 -O 3 --type vertex --bin2c ${FILE_NAME}_vs_dx11 + COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_vs_dx9.h" --platform windows -p vs_3_0 -O 3 --type vertex --bin2c ${FILE_NAME}_vs_dx9 + #COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_vs_esl.h" --platform android --type vertex --bin2c ${FILE_NAME}_vs_esl + COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_vs_glsl.h" --platform asm.js -p 120 --type vertex --bin2c ${FILE_NAME}_vs_glsl + COMMAND "$" -f ${SHADER} -o "${CMAKE_SOURCE_DIR}/bin/Nodes/Shaders/${FILE_NAME}_vs.bin" --platform asm.js -p 150 --type vertex + COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_vs_mtl.h" --platform osx -p metal --type vertex --bin2c ${FILE_NAME}_vs_mtl + COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_vs_spv.h" --platform linux -p spirv --type vertex --bin2c ${FILE_NAME}_vs_spv + DEPENDS ${SHADER}) + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_vs_dx11.h\"\n") + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_vs_dx9.h\"\n") + #FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_vs_esl.h\"\n") + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_vs_glsl.h\"\n") + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_vs_mtl.h\"\n") + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_vs_spv.h\"\n") + list(APPEND SHADER_OUTPUT_FILES ${SHADER_OUTPUT}) + FILE(APPEND ${shaders_cpp_file} "BGFX_EMBEDDED_SHADER(${FILE_NAME}_vs),\n") + elseif(${FILE_NAME_EXT} STREQUAL ".fs") + set(SHADER_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_fs_dx11.h") + add_custom_command( + OUTPUT ${SHADER_OUTPUT} + COMMAND "$" -f ${SHADER} -o ${SHADER_OUTPUT} --platform windows -p ps_5_0 -O 3 --type fragment --bin2c ${FILE_NAME}_fs_dx11 + COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_fs_dx9.h" --platform windows -p ps_5_0 -O 3 --type fragment --bin2c ${FILE_NAME}_fs_dx9 + #COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_fs_esl.h" --platform android --type fragment --bin2c ${FILE_NAME}_fs_esl + COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_fs_glsl.h" --platform asm.js -p 120 --type fragment --bin2c ${FILE_NAME}_fs_glsl + COMMAND "$" -f ${SHADER} -o "${CMAKE_SOURCE_DIR}/bin/Nodes/Shaders/${FILE_NAME}_fs.bin" --platform asm.js -p 150 --type fragment + COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_fs_mtl.h" --platform osx -p metal --type fragment --bin2c ${FILE_NAME}_fs_mtl + COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_fs_spv.h" --platform linux -p spirv --type fragment --bin2c ${FILE_NAME}_fs_spv + DEPENDS ${SHADER}) + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_fs_dx11.h\"\n") + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_fs_dx9.h\"\n") + #FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_fs_esl.h\"\n") + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_fs_glsl.h\"\n") + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_fs_mtl.h\"\n") + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_fs_spv.h\"\n") + list(APPEND SHADER_OUTPUT_FILES ${SHADER_OUTPUT}) + FILE(APPEND ${shaders_cpp_file} "BGFX_EMBEDDED_SHADER(${FILE_NAME}_fs),\n") + elseif(${FILE_NAME_EXT} STREQUAL ".cs") + set(SHADER_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_cs_dx11.h") + add_custom_command( + OUTPUT ${SHADER_OUTPUT} + COMMAND "$" -f ${SHADER} -o ${SHADER_OUTPUT} --platform windows -p cs_5_0 -O 1 --type compute --bin2c ${FILE_NAME}_cs_dx11 + #COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_cs_dx9.h" --platform windows -p ps_5_0 -O 3 --type compute --bin2c ${FILE_NAME}_cs_dx9 + #COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_cs_esl.h" --platform android --type compute --bin2c ${FILE_NAME}_cs_esl + COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_cs_glsl.h" --platform linux -p 430 --type compute --bin2c ${FILE_NAME}_cs_glsl + COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_cs_mtl.h" --platform osx -p metal --type compute --bin2c ${FILE_NAME}_cs_mtl + COMMAND "$" -f ${SHADER} -o "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}_cs_spv.h" --platform linux -p spirv --type compute --bin2c ${FILE_NAME}_cs_spv + DEPENDS ${SHADER}) + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_cs_dx11.h\"\n") + FILE(APPEND ${shaders_inc_file} "static const uint8_t ${FILE_NAME}_cs_dx9[1] = {0};\n") + #FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_cs_esl.h\"\n") + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_cs_glsl.h\"\n") + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_cs_mtl.h\"\n") + FILE(APPEND ${shaders_inc_file} "#include \"${FILE_NAME}_cs_spv.h\"\n") + list(APPEND SHADER_OUTPUT_FILES ${SHADER_OUTPUT}) + FILE(APPEND ${shaders_cpp_file} "BGFX_EMBEDDED_SHADER(${FILE_NAME}_cs),\n") + endif() + +endforeach(SHADER) + +FILE(APPEND ${shaders_cpp_file} "BGFX_EMBEDDED_SHADER_END()\n};\n") +add_custom_target(Shaders DEPENDS ${SHADER_OUTPUT_FILES}) +add_dependencies(${EXE_NAME} Shaders) + +endif() # EMSCRIPTEN + +######################################### + +TARGET_LINK_LIBRARIES(${EXE_NAME} ${PYTHON37_LIBRARIES} ${SDL2_LIBRARIES} ${OPENGL_LIBRARIES} ${PLATFORM_LIBS} ${FFMPEG_LIBRARIES} bx bimg bgfx) + +if(APPLE) + find_library(CORE_FOUNDATION CoreFoundation) + target_link_libraries(${EXE_NAME} ${CORE_FOUNDATION}) +endif() #-------------------------------------------------------------------- # preproc @@ -137,6 +344,7 @@ add_definitions(-DBX_CONFIG_ENABLE_MSVC_LEVEL4_WARNINGS=1) add_definitions(-D__STDC_LIMIT_MACROS) add_definitions(-D__STDC_CONSTANT_MACROS) add_definitions(-DIMGUI_DISABLE_OBSOLETE_FUNCTIONS) +add_definitions(-DDUK_USE_CPP_EXCEPTIONS) if(MSVC) add_definitions(-DWIN32) add_definitions(-D_WIN32) @@ -148,12 +356,12 @@ add_definitions(-DUSE_DL_PREFIX) # output dirs #-------------------------------------------------------------------- -set_target_properties("Imogen" PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/bin ) -set_target_properties("Imogen" PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/bin ) -set_target_properties("Imogen" PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_SOURCE_DIR}/bin ) -set_target_properties("Imogen" PROPERTIES DEBUG_POSTFIX "_d") -set_target_properties("Imogen" PROPERTIES RELWITHDEBINFO_POSTFIX "RelWithDebInfo") -set_target_properties("Imogen" PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/bin") +set_target_properties(${EXE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/bin ) +set_target_properties(${EXE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/bin ) +set_target_properties(${EXE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_SOURCE_DIR}/bin ) +set_target_properties(${EXE_NAME} PROPERTIES DEBUG_POSTFIX "_d") +set_target_properties(${EXE_NAME} PROPERTIES RELWITHDEBINFO_POSTFIX "RelWithDebInfo") +set_target_properties(${EXE_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/bin") #-------------------------------------------------------------------- # Hide the console window in visual studio projects @@ -166,8 +374,8 @@ endif() endif() if(WINDOWS) -set_target_properties("Imogen" PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS") -set_target_properties("Imogen" PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") +set_target_properties(${EXE_NAME} PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS") +set_target_properties(${EXE_NAME} PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") endif() if(ENABLE_HIDECONSOLE_BUILD) diff --git a/README.md b/README.md index b48e408b..08cc14f5 100644 --- a/README.md +++ b/README.md @@ -87,4 +87,7 @@ GLSL-PathTracer - knightcrawler25 https://github.com/knightcrawler25/GLSL-PathTr imgui_markdown - Juliette Foucaut https://github.com/juliettef/imgui_markdown +IconFontCppHeaders - Juliette Foucaut https://github.com/juliettef/IconFontCppHeaders + CGLTF - Johannes Kuhlmann https://github.com/jkuhlmann/cgltf + diff --git a/Refs/Concrete__Tutorial3.jpg b/Refs/Concrete__Tutorial3.jpg deleted file mode 100644 index 1d434beb..00000000 Binary files a/Refs/Concrete__Tutorial3.jpg and /dev/null differ diff --git a/Refs/D1lhp6_W0AEfica.jpg b/Refs/D1lhp6_W0AEfica.jpg deleted file mode 100644 index e610790b..00000000 Binary files a/Refs/D1lhp6_W0AEfica.jpg and /dev/null differ diff --git a/Refs/DNkmDcHU8AAZy8t.jpg large.jpg b/Refs/DNkmDcHU8AAZy8t.jpg large.jpg deleted file mode 100644 index a19e4eeb..00000000 Binary files a/Refs/DNkmDcHU8AAZy8t.jpg large.jpg and /dev/null differ diff --git a/Refs/DNt9Vy6X4AAg785.jpg large.jpg b/Refs/DNt9Vy6X4AAg785.jpg large.jpg deleted file mode 100644 index 80df6197..00000000 Binary files a/Refs/DNt9Vy6X4AAg785.jpg large.jpg and /dev/null differ diff --git a/Refs/JapaneseWeave_Breakdown_Martin_de_Graaf_2018.jpg b/Refs/JapaneseWeave_Breakdown_Martin_de_Graaf_2018.jpg deleted file mode 100644 index 7649a598..00000000 Binary files a/Refs/JapaneseWeave_Breakdown_Martin_de_Graaf_2018.jpg and /dev/null differ diff --git a/Refs/Rock_Wall_01_Cube_03_Layout_Comp.jpg b/Refs/Rock_Wall_01_Cube_03_Layout_Comp.jpg deleted file mode 100644 index 4eca7d9f..00000000 Binary files a/Refs/Rock_Wall_01_Cube_03_Layout_Comp.jpg and /dev/null differ diff --git a/Refs/Rock_Wall_01_Cube_Clay_03_Layout_Comp.jpg b/Refs/Rock_Wall_01_Cube_Clay_03_Layout_Comp.jpg deleted file mode 100644 index c7417030..00000000 Binary files a/Refs/Rock_Wall_01_Cube_Clay_03_Layout_Comp.jpg and /dev/null differ diff --git a/Refs/Rock_Wall_01_Flats_Layout_Comp.jpg b/Refs/Rock_Wall_01_Flats_Layout_Comp.jpg deleted file mode 100644 index d1c071c9..00000000 Binary files a/Refs/Rock_Wall_01_Flats_Layout_Comp.jpg and /dev/null differ diff --git a/Refs/Rock_Wall_01_Wall_03_Layout_Comp.jpg b/Refs/Rock_Wall_01_Wall_03_Layout_Comp.jpg deleted file mode 100644 index 2fda1f3a..00000000 Binary files a/Refs/Rock_Wall_01_Wall_03_Layout_Comp.jpg and /dev/null differ diff --git a/Refs/Rock_Wall_01_Wall_Clay_03_Layout_Comp.jpg b/Refs/Rock_Wall_01_Wall_Clay_03_Layout_Comp.jpg deleted file mode 100644 index bb2ccd6f..00000000 Binary files a/Refs/Rock_Wall_01_Wall_Clay_03_Layout_Comp.jpg and /dev/null differ diff --git a/Refs/TileTurnTable_60FPS-HD.mp4 b/Refs/TileTurnTable_60FPS-HD.mp4 deleted file mode 100644 index 46da7572..00000000 Binary files a/Refs/TileTurnTable_60FPS-HD.mp4 and /dev/null differ diff --git a/Refs/aaro-syrjanen-breakdown.jpg b/Refs/aaro-syrjanen-breakdown.jpg deleted file mode 100644 index 43f05de4..00000000 Binary files a/Refs/aaro-syrjanen-breakdown.jpg and /dev/null differ diff --git a/Refs/aaro-syrjanen-grumpy-lion-detail-flower-20180820-a.jpg b/Refs/aaro-syrjanen-grumpy-lion-detail-flower-20180820-a.jpg deleted file mode 100644 index 44e44fc6..00000000 Binary files a/Refs/aaro-syrjanen-grumpy-lion-detail-flower-20180820-a.jpg and /dev/null differ diff --git a/Refs/aaro-syrjanen-grumpy-lion-detail-lion-20180820-a.jpg b/Refs/aaro-syrjanen-grumpy-lion-detail-lion-20180820-a.jpg deleted file mode 100644 index af7ff139..00000000 Binary files a/Refs/aaro-syrjanen-grumpy-lion-detail-lion-20180820-a.jpg and /dev/null differ diff --git a/Refs/aaro-syrjanen-grumpy-lion-detail-ornate-20180820-a.jpg b/Refs/aaro-syrjanen-grumpy-lion-detail-ornate-20180820-a.jpg deleted file mode 100644 index 0b60696a..00000000 Binary files a/Refs/aaro-syrjanen-grumpy-lion-detail-ornate-20180820-a.jpg and /dev/null differ diff --git a/Refs/aaro-syrjanen-grumpy-lion-detail-triquerta-20180820-a.jpg b/Refs/aaro-syrjanen-grumpy-lion-detail-triquerta-20180820-a.jpg deleted file mode 100644 index 885b46b6..00000000 Binary files a/Refs/aaro-syrjanen-grumpy-lion-detail-triquerta-20180820-a.jpg and /dev/null differ diff --git a/Refs/aaro-syrjanen-grumpy-lion-plane-20180820-a.jpg b/Refs/aaro-syrjanen-grumpy-lion-plane-20180820-a.jpg deleted file mode 100644 index b4479a58..00000000 Binary files a/Refs/aaro-syrjanen-grumpy-lion-plane-20180820-a.jpg and /dev/null differ diff --git a/Refs/aaro-syrjanen-grumpy-lion-plane-2x-20180820-a.jpg b/Refs/aaro-syrjanen-grumpy-lion-plane-2x-20180820-a.jpg deleted file mode 100644 index 2a7c173f..00000000 Binary files a/Refs/aaro-syrjanen-grumpy-lion-plane-2x-20180820-a.jpg and /dev/null differ diff --git a/Refs/amy-payne-mw-pool-tile-substance-materials.jpg b/Refs/amy-payne-mw-pool-tile-substance-materials.jpg deleted file mode 100644 index 554f57ed..00000000 Binary files a/Refs/amy-payne-mw-pool-tile-substance-materials.jpg and /dev/null differ diff --git a/Refs/arvin-villapando-toolbag-uplox.jpg b/Refs/arvin-villapando-toolbag-uplox.jpg deleted file mode 100644 index 4a903362..00000000 Binary files a/Refs/arvin-villapando-toolbag-uplox.jpg and /dev/null differ diff --git a/Refs/arvin-villapando-toolbag-uplox2.jpg b/Refs/arvin-villapando-toolbag-uplox2.jpg deleted file mode 100644 index eebcb0c0..00000000 Binary files a/Refs/arvin-villapando-toolbag-uplox2.jpg and /dev/null differ diff --git a/Refs/ben-keeling-marbledrain3.jpg b/Refs/ben-keeling-marbledrain3.jpg deleted file mode 100644 index 27bf4714..00000000 Binary files a/Refs/ben-keeling-marbledrain3.jpg and /dev/null differ diff --git a/Refs/ben-keeling-marbledrain4.jpg b/Refs/ben-keeling-marbledrain4.jpg deleted file mode 100644 index bc528a3d..00000000 Binary files a/Refs/ben-keeling-marbledrain4.jpg and /dev/null differ diff --git a/Refs/ben-keeling-marbledrain5.jpg b/Refs/ben-keeling-marbledrain5.jpg deleted file mode 100644 index cae4d2db..00000000 Binary files a/Refs/ben-keeling-marbledrain5.jpg and /dev/null differ diff --git a/Refs/bram-z-bramzsandplanerenderdesigner.jpg b/Refs/bram-z-bramzsandplanerenderdesigner.jpg deleted file mode 100644 index 99123bc8..00000000 Binary files a/Refs/bram-z-bramzsandplanerenderdesigner.jpg and /dev/null differ diff --git a/Refs/bram-z-groundrocktexturesubstancebramz.jpg b/Refs/bram-z-groundrocktexturesubstancebramz.jpg deleted file mode 100644 index 6be879b2..00000000 Binary files a/Refs/bram-z-groundrocktexturesubstancebramz.jpg and /dev/null differ diff --git a/Refs/bram-z-substancedesignerstonesgroundbramz.jpg b/Refs/bram-z-substancedesignerstonesgroundbramz.jpg deleted file mode 100644 index 0abfed54..00000000 Binary files a/Refs/bram-z-substancedesignerstonesgroundbramz.jpg and /dev/null differ diff --git a/Refs/carreaux-divers.jpg b/Refs/carreaux-divers.jpg deleted file mode 100644 index 2af28576..00000000 Binary files a/Refs/carreaux-divers.jpg and /dev/null differ diff --git a/Refs/cobblestone_graph.jpg b/Refs/cobblestone_graph.jpg deleted file mode 100644 index 9de2e256..00000000 Binary files a/Refs/cobblestone_graph.jpg and /dev/null differ diff --git a/Refs/daniel-thiger-forestscene-a-sphere.jpg b/Refs/daniel-thiger-forestscene-a-sphere.jpg deleted file mode 100644 index 432988e9..00000000 Binary files a/Refs/daniel-thiger-forestscene-a-sphere.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-concrete-panels-maps.jpg b/Refs/eugenio-stanislav-concrete-panels-maps.jpg deleted file mode 100644 index d1d3c443..00000000 Binary files a/Refs/eugenio-stanislav-concrete-panels-maps.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-concrete-wall-stock-render-s.jpg b/Refs/eugenio-stanislav-concrete-wall-stock-render-s.jpg deleted file mode 100644 index cf6e9431..00000000 Binary files a/Refs/eugenio-stanislav-concrete-wall-stock-render-s.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-concrete-wall-stock-render1.jpg b/Refs/eugenio-stanislav-concrete-wall-stock-render1.jpg deleted file mode 100644 index bb3a75d1..00000000 Binary files a/Refs/eugenio-stanislav-concrete-wall-stock-render1.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-desert-cliff-map.jpg b/Refs/eugenio-stanislav-desert-cliff-map.jpg deleted file mode 100644 index acc4fb87..00000000 Binary files a/Refs/eugenio-stanislav-desert-cliff-map.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-desert-cliff-render2.jpg b/Refs/eugenio-stanislav-desert-cliff-render2.jpg deleted file mode 100644 index 4af547e8..00000000 Binary files a/Refs/eugenio-stanislav-desert-cliff-render2.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-forest-rock-maps.jpg b/Refs/eugenio-stanislav-forest-rock-maps.jpg deleted file mode 100644 index 4fd532af..00000000 Binary files a/Refs/eugenio-stanislav-forest-rock-maps.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-forest-rock-render1.jpg b/Refs/eugenio-stanislav-forest-rock-render1.jpg deleted file mode 100644 index a9a6814d..00000000 Binary files a/Refs/eugenio-stanislav-forest-rock-render1.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-hojas-maps.jpg b/Refs/eugenio-stanislav-hojas-maps.jpg deleted file mode 100644 index 6e9a085b..00000000 Binary files a/Refs/eugenio-stanislav-hojas-maps.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-hojas-render-02-s.jpg b/Refs/eugenio-stanislav-hojas-render-02-s.jpg deleted file mode 100644 index 7b4b6705..00000000 Binary files a/Refs/eugenio-stanislav-hojas-render-02-s.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-hojas-render-05-s.jpg b/Refs/eugenio-stanislav-hojas-render-05-s.jpg deleted file mode 100644 index 2afbae11..00000000 Binary files a/Refs/eugenio-stanislav-hojas-render-05-s.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-layered-rock-maps.jpg b/Refs/eugenio-stanislav-layered-rock-maps.jpg deleted file mode 100644 index 47c48782..00000000 Binary files a/Refs/eugenio-stanislav-layered-rock-maps.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-layered-rock-render-s.jpg b/Refs/eugenio-stanislav-layered-rock-render-s.jpg deleted file mode 100644 index 2b519da6..00000000 Binary files a/Refs/eugenio-stanislav-layered-rock-render-s.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-mars-surface-maps.jpg b/Refs/eugenio-stanislav-mars-surface-maps.jpg deleted file mode 100644 index 95ebd577..00000000 Binary files a/Refs/eugenio-stanislav-mars-surface-maps.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-mars-surface-render-p.jpg b/Refs/eugenio-stanislav-mars-surface-render-p.jpg deleted file mode 100644 index a6b38e0f..00000000 Binary files a/Refs/eugenio-stanislav-mars-surface-render-p.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-mars-surface-render1-p.jpg b/Refs/eugenio-stanislav-mars-surface-render1-p.jpg deleted file mode 100644 index 77351790..00000000 Binary files a/Refs/eugenio-stanislav-mars-surface-render1-p.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-old-stone-wall-maps.jpg b/Refs/eugenio-stanislav-old-stone-wall-maps.jpg deleted file mode 100644 index 22e48e35..00000000 Binary files a/Refs/eugenio-stanislav-old-stone-wall-maps.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-old-stone-wall-render-s.jpg b/Refs/eugenio-stanislav-old-stone-wall-render-s.jpg deleted file mode 100644 index c7915e79..00000000 Binary files a/Refs/eugenio-stanislav-old-stone-wall-render-s.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-old-stone-wall-render1.jpg b/Refs/eugenio-stanislav-old-stone-wall-render1.jpg deleted file mode 100644 index 1fd0451c..00000000 Binary files a/Refs/eugenio-stanislav-old-stone-wall-render1.jpg and /dev/null differ diff --git a/Refs/eugenio-stanislav-old-stone-wall-render2.jpg b/Refs/eugenio-stanislav-old-stone-wall-render2.jpg deleted file mode 100644 index 2be26c46..00000000 Binary files a/Refs/eugenio-stanislav-old-stone-wall-render2.jpg and /dev/null differ diff --git a/Refs/eunji-nam-p01.jpg b/Refs/eunji-nam-p01.jpg deleted file mode 100644 index 42757b11..00000000 Binary files a/Refs/eunji-nam-p01.jpg and /dev/null differ diff --git a/Refs/eunji-nam-texture3.jpg b/Refs/eunji-nam-texture3.jpg deleted file mode 100644 index e2b93bed..00000000 Binary files a/Refs/eunji-nam-texture3.jpg and /dev/null differ diff --git a/Refs/george-rushing-cathedral-window-maps1.jpg b/Refs/george-rushing-cathedral-window-maps1.jpg deleted file mode 100644 index c546c668..00000000 Binary files a/Refs/george-rushing-cathedral-window-maps1.jpg and /dev/null differ diff --git a/Refs/george-rushing-cathedral-window-nodes.jpg b/Refs/george-rushing-cathedral-window-nodes.jpg deleted file mode 100644 index e5e6fb35..00000000 Binary files a/Refs/george-rushing-cathedral-window-nodes.jpg and /dev/null differ diff --git a/Refs/george-rushing-cathedral-window.jpg b/Refs/george-rushing-cathedral-window.jpg deleted file mode 100644 index d39ba54a..00000000 Binary files a/Refs/george-rushing-cathedral-window.jpg and /dev/null differ diff --git a/Refs/honey.png b/Refs/honey.png deleted file mode 100644 index 998180d7..00000000 Binary files a/Refs/honey.png and /dev/null differ diff --git a/Refs/honey_pbr.png b/Refs/honey_pbr.png deleted file mode 100644 index 75122f15..00000000 Binary files a/Refs/honey_pbr.png and /dev/null differ diff --git a/Refs/imanol-delgado-as22222222.jpg b/Refs/imanol-delgado-as22222222.jpg deleted file mode 100644 index 3076fbb9..00000000 Binary files a/Refs/imanol-delgado-as22222222.jpg and /dev/null differ diff --git a/Refs/james-lucas-1-2.jpg b/Refs/james-lucas-1-2.jpg deleted file mode 100644 index c249c507..00000000 Binary files a/Refs/james-lucas-1-2.jpg and /dev/null differ diff --git a/Refs/james-lucas-1.jpg b/Refs/james-lucas-1.jpg deleted file mode 100644 index 8ed45404..00000000 Binary files a/Refs/james-lucas-1.jpg and /dev/null differ diff --git a/Refs/james-lucas-2-1.jpg b/Refs/james-lucas-2-1.jpg deleted file mode 100644 index 9eb4fd3e..00000000 Binary files a/Refs/james-lucas-2-1.jpg and /dev/null differ diff --git a/Refs/james-lucas-2-2.jpg b/Refs/james-lucas-2-2.jpg deleted file mode 100644 index b49d1b88..00000000 Binary files a/Refs/james-lucas-2-2.jpg and /dev/null differ diff --git a/Refs/james-lucas-2-3.jpg b/Refs/james-lucas-2-3.jpg deleted file mode 100644 index 5b498593..00000000 Binary files a/Refs/james-lucas-2-3.jpg and /dev/null differ diff --git a/Refs/james-lucas-2.jpg b/Refs/james-lucas-2.jpg deleted file mode 100644 index 9167b6ab..00000000 Binary files a/Refs/james-lucas-2.jpg and /dev/null differ diff --git a/Refs/james-lucas-22.jpg b/Refs/james-lucas-22.jpg deleted file mode 100644 index 4ea382ed..00000000 Binary files a/Refs/james-lucas-22.jpg and /dev/null differ diff --git a/Refs/james-lucas-2combination.jpg b/Refs/james-lucas-2combination.jpg deleted file mode 100644 index bed15372..00000000 Binary files a/Refs/james-lucas-2combination.jpg and /dev/null differ diff --git a/Refs/james-lucas-3.jpg b/Refs/james-lucas-3.jpg deleted file mode 100644 index fd016409..00000000 Binary files a/Refs/james-lucas-3.jpg and /dev/null differ diff --git a/Refs/james-lucas-33.jpg b/Refs/james-lucas-33.jpg deleted file mode 100644 index 37454df1..00000000 Binary files a/Refs/james-lucas-33.jpg and /dev/null differ diff --git a/Refs/james-lucas-3yellowline.jpg b/Refs/james-lucas-3yellowline.jpg deleted file mode 100644 index acdb1cab..00000000 Binary files a/Refs/james-lucas-3yellowline.jpg and /dev/null differ diff --git a/Refs/james-lucas-4.jpg b/Refs/james-lucas-4.jpg deleted file mode 100644 index 18bdffe8..00000000 Binary files a/Refs/james-lucas-4.jpg and /dev/null differ diff --git a/Refs/james-lucas-4surfacewear.jpg b/Refs/james-lucas-4surfacewear.jpg deleted file mode 100644 index 275bf64c..00000000 Binary files a/Refs/james-lucas-4surfacewear.jpg and /dev/null differ diff --git a/Refs/james-lucas-5.jpg b/Refs/james-lucas-5.jpg deleted file mode 100644 index 5ca2f323..00000000 Binary files a/Refs/james-lucas-5.jpg and /dev/null differ diff --git a/Refs/james-lucas-5pothole.jpg b/Refs/james-lucas-5pothole.jpg deleted file mode 100644 index 270e11f7..00000000 Binary files a/Refs/james-lucas-5pothole.jpg and /dev/null differ diff --git a/Refs/james-lucas-6clean.jpg b/Refs/james-lucas-6clean.jpg deleted file mode 100644 index 5186f2f6..00000000 Binary files a/Refs/james-lucas-6clean.jpg and /dev/null differ diff --git a/Refs/james-lucas-7oil.jpg b/Refs/james-lucas-7oil.jpg deleted file mode 100644 index 24839273..00000000 Binary files a/Refs/james-lucas-7oil.jpg and /dev/null differ diff --git a/Refs/james-lucas-chester1.jpg b/Refs/james-lucas-chester1.jpg deleted file mode 100644 index a53f64f7..00000000 Binary files a/Refs/james-lucas-chester1.jpg and /dev/null differ diff --git a/Refs/james-lucas-chester2.jpg b/Refs/james-lucas-chester2.jpg deleted file mode 100644 index a92a20c0..00000000 Binary files a/Refs/james-lucas-chester2.jpg and /dev/null differ diff --git a/Refs/james-lucas-chester3.jpg b/Refs/james-lucas-chester3.jpg deleted file mode 100644 index 8c5bc00d..00000000 Binary files a/Refs/james-lucas-chester3.jpg and /dev/null differ diff --git a/Refs/james-lucas-tilesrender-take1.jpg b/Refs/james-lucas-tilesrender-take1.jpg deleted file mode 100644 index 7fa2ce77..00000000 Binary files a/Refs/james-lucas-tilesrender-take1.jpg and /dev/null differ diff --git a/Refs/jamie-jamieson-render-1.jpg b/Refs/jamie-jamieson-render-1.jpg deleted file mode 100644 index d2ba54e9..00000000 Binary files a/Refs/jamie-jamieson-render-1.jpg and /dev/null differ diff --git a/Refs/jamie-jamieson-render-2.jpg b/Refs/jamie-jamieson-render-2.jpg deleted file mode 100644 index 36122fd4..00000000 Binary files a/Refs/jamie-jamieson-render-2.jpg and /dev/null differ diff --git a/Refs/jamie-jamieson-screenshot013.jpg b/Refs/jamie-jamieson-screenshot013.jpg deleted file mode 100644 index 01f1d3db..00000000 Binary files a/Refs/jamie-jamieson-screenshot013.jpg and /dev/null differ diff --git a/Refs/jamie-jamieson-screenshot014.jpg b/Refs/jamie-jamieson-screenshot014.jpg deleted file mode 100644 index 403e2482..00000000 Binary files a/Refs/jamie-jamieson-screenshot014.jpg and /dev/null differ diff --git a/Refs/jamie-jamieson-screenshot015.jpg b/Refs/jamie-jamieson-screenshot015.jpg deleted file mode 100644 index b4366259..00000000 Binary files a/Refs/jamie-jamieson-screenshot015.jpg and /dev/null differ diff --git a/Refs/jeffrey-hepburn-mandalasculpt02.jpg b/Refs/jeffrey-hepburn-mandalasculpt02.jpg deleted file mode 100644 index 8f75d2d3..00000000 Binary files a/Refs/jeffrey-hepburn-mandalasculpt02.jpg and /dev/null differ diff --git a/Refs/jeffrey-hepburn-mandalasculpt04.jpg b/Refs/jeffrey-hepburn-mandalasculpt04.jpg deleted file mode 100644 index cb205c61..00000000 Binary files a/Refs/jeffrey-hepburn-mandalasculpt04.jpg and /dev/null differ diff --git a/Refs/jeffrey-hepburn-mandalasculpt05.jpg b/Refs/jeffrey-hepburn-mandalasculpt05.jpg deleted file mode 100644 index e6c5c5b4..00000000 Binary files a/Refs/jeffrey-hepburn-mandalasculpt05.jpg and /dev/null differ diff --git a/Refs/jeffrey-hepburn-mandalasculpt06.jpg b/Refs/jeffrey-hepburn-mandalasculpt06.jpg deleted file mode 100644 index a74079fc..00000000 Binary files a/Refs/jeffrey-hepburn-mandalasculpt06.jpg and /dev/null differ diff --git a/Refs/jeffrey-hepburn-mandalasculpt07.jpg b/Refs/jeffrey-hepburn-mandalasculpt07.jpg deleted file mode 100644 index 1008cf04..00000000 Binary files a/Refs/jeffrey-hepburn-mandalasculpt07.jpg and /dev/null differ diff --git a/Refs/lukas-patrus-cylinder-color.jpg b/Refs/lukas-patrus-cylinder-color.jpg deleted file mode 100644 index 949d06a5..00000000 Binary files a/Refs/lukas-patrus-cylinder-color.jpg and /dev/null differ diff --git a/Refs/lukas-patrus-plane-color.jpg b/Refs/lukas-patrus-plane-color.jpg deleted file mode 100644 index fe206b3f..00000000 Binary files a/Refs/lukas-patrus-plane-color.jpg and /dev/null differ diff --git a/Refs/lukas-patrus-plane-light.jpg b/Refs/lukas-patrus-plane-light.jpg deleted file mode 100644 index d3c65ba5..00000000 Binary files a/Refs/lukas-patrus-plane-light.jpg and /dev/null differ diff --git a/Refs/lukas-patrus-preview-basecolor.jpg b/Refs/lukas-patrus-preview-basecolor.jpg deleted file mode 100644 index 17bc07e7..00000000 Binary files a/Refs/lukas-patrus-preview-basecolor.jpg and /dev/null differ diff --git a/Refs/minkyung-kim-01.jpg b/Refs/minkyung-kim-01.jpg deleted file mode 100644 index e6170f06..00000000 Binary files a/Refs/minkyung-kim-01.jpg and /dev/null differ diff --git a/Refs/minkyung-kim-02.jpg b/Refs/minkyung-kim-02.jpg deleted file mode 100644 index babd5621..00000000 Binary files a/Refs/minkyung-kim-02.jpg and /dev/null differ diff --git a/Refs/minkyung-kim-03.jpg b/Refs/minkyung-kim-03.jpg deleted file mode 100644 index 58c9b0da..00000000 Binary files a/Refs/minkyung-kim-03.jpg and /dev/null differ diff --git a/Refs/minkyung-kim-08.jpg b/Refs/minkyung-kim-08.jpg deleted file mode 100644 index c01926bd..00000000 Binary files a/Refs/minkyung-kim-08.jpg and /dev/null differ diff --git a/Refs/minkyung-kim-ss.jpg b/Refs/minkyung-kim-ss.jpg deleted file mode 100644 index 94d4c370..00000000 Binary files a/Refs/minkyung-kim-ss.jpg and /dev/null differ diff --git a/Refs/mira-sin-ceiling01-portfoilo01.jpg b/Refs/mira-sin-ceiling01-portfoilo01.jpg deleted file mode 100644 index 7ca0415e..00000000 Binary files a/Refs/mira-sin-ceiling01-portfoilo01.jpg and /dev/null differ diff --git a/Refs/mira-sin-ceiling01-portfoilo02.jpg b/Refs/mira-sin-ceiling01-portfoilo02.jpg deleted file mode 100644 index a5c06ed6..00000000 Binary files a/Refs/mira-sin-ceiling01-portfoilo02.jpg and /dev/null differ diff --git a/Refs/mira-sin-ceiling01-portfoilo05.jpg b/Refs/mira-sin-ceiling01-portfoilo05.jpg deleted file mode 100644 index 1965d4f6..00000000 Binary files a/Refs/mira-sin-ceiling01-portfoilo05.jpg and /dev/null differ diff --git a/Refs/mira-sin-ceiling01-portfoilo06.jpg b/Refs/mira-sin-ceiling01-portfoilo06.jpg deleted file mode 100644 index 7048cc18..00000000 Binary files a/Refs/mira-sin-ceiling01-portfoilo06.jpg and /dev/null differ diff --git a/Refs/overlappingTiles.png b/Refs/overlappingTiles.png deleted file mode 100644 index 4c6b5d33..00000000 Binary files a/Refs/overlappingTiles.png and /dev/null differ diff --git a/Refs/pauline-boiteux-metal-05.jpg b/Refs/pauline-boiteux-metal-05.jpg deleted file mode 100644 index c5d932e4..00000000 Binary files a/Refs/pauline-boiteux-metal-05.jpg and /dev/null differ diff --git a/Refs/pauline-boiteux-metal-06.jpg b/Refs/pauline-boiteux-metal-06.jpg deleted file mode 100644 index 31f52dff..00000000 Binary files a/Refs/pauline-boiteux-metal-06.jpg and /dev/null differ diff --git a/Refs/pauline-boiteux-metal-07.jpg b/Refs/pauline-boiteux-metal-07.jpg deleted file mode 100644 index 08bc9ad9..00000000 Binary files a/Refs/pauline-boiteux-metal-07.jpg and /dev/null differ diff --git a/Refs/pauline-boiteux-wall-height.jpg b/Refs/pauline-boiteux-wall-height.jpg deleted file mode 100644 index cd7c625d..00000000 Binary files a/Refs/pauline-boiteux-wall-height.jpg and /dev/null differ diff --git a/Refs/pierre-fleau-acu-text-01-1.jpg b/Refs/pierre-fleau-acu-text-01-1.jpg deleted file mode 100644 index 9e820af3..00000000 Binary files a/Refs/pierre-fleau-acu-text-01-1.jpg and /dev/null differ diff --git a/Refs/pierre-fleau-acu-text-010-1.jpg b/Refs/pierre-fleau-acu-text-010-1.jpg deleted file mode 100644 index 094fc11e..00000000 Binary files a/Refs/pierre-fleau-acu-text-010-1.jpg and /dev/null differ diff --git a/Refs/pierre-fleau-acu-text-011-1.jpg b/Refs/pierre-fleau-acu-text-011-1.jpg deleted file mode 100644 index 258a539c..00000000 Binary files a/Refs/pierre-fleau-acu-text-011-1.jpg and /dev/null differ diff --git a/Refs/pierre-fleau-acu-text-02-1.jpg b/Refs/pierre-fleau-acu-text-02-1.jpg deleted file mode 100644 index 8799ba1e..00000000 Binary files a/Refs/pierre-fleau-acu-text-02-1.jpg and /dev/null differ diff --git a/Refs/pierre-fleau-blacknwhitemarble-tiles.jpg b/Refs/pierre-fleau-blacknwhitemarble-tiles.jpg deleted file mode 100644 index 91eb4661..00000000 Binary files a/Refs/pierre-fleau-blacknwhitemarble-tiles.jpg and /dev/null differ diff --git a/Refs/pierre-fleau-marble-011.jpg b/Refs/pierre-fleau-marble-011.jpg deleted file mode 100644 index 249888ae..00000000 Binary files a/Refs/pierre-fleau-marble-011.jpg and /dev/null differ diff --git a/Refs/pierre-fleau-redmarbletiles.jpg b/Refs/pierre-fleau-redmarbletiles.jpg deleted file mode 100644 index 6a60dd8e..00000000 Binary files a/Refs/pierre-fleau-redmarbletiles.jpg and /dev/null differ diff --git a/Refs/pierre-fleau-stone-wal02l-pfleau.jpg b/Refs/pierre-fleau-stone-wal02l-pfleau.jpg deleted file mode 100644 index 41707379..00000000 Binary files a/Refs/pierre-fleau-stone-wal02l-pfleau.jpg and /dev/null differ diff --git a/Refs/pierre-fleau-wall-brick-pfleau02.jpg b/Refs/pierre-fleau-wall-brick-pfleau02.jpg deleted file mode 100644 index a6ca9f13..00000000 Binary files a/Refs/pierre-fleau-wall-brick-pfleau02.jpg and /dev/null differ diff --git a/Refs/pim-hendriks-pg3.jpg b/Refs/pim-hendriks-pg3.jpg deleted file mode 100644 index d7757f83..00000000 Binary files a/Refs/pim-hendriks-pg3.jpg and /dev/null differ diff --git a/Refs/pim-hendriks-pg4.jpg b/Refs/pim-hendriks-pg4.jpg deleted file mode 100644 index 8d9ad67f..00000000 Binary files a/Refs/pim-hendriks-pg4.jpg and /dev/null differ diff --git a/Refs/pim-hendriks-pg5.jpg b/Refs/pim-hendriks-pg5.jpg deleted file mode 100644 index a3a25d41..00000000 Binary files a/Refs/pim-hendriks-pg5.jpg and /dev/null differ diff --git a/Refs/pim-hendriks-pg6.jpg b/Refs/pim-hendriks-pg6.jpg deleted file mode 100644 index ab278707..00000000 Binary files a/Refs/pim-hendriks-pg6.jpg and /dev/null differ diff --git a/Refs/pim-hendriks-pg7.jpg b/Refs/pim-hendriks-pg7.jpg deleted file mode 100644 index e6aa253b..00000000 Binary files a/Refs/pim-hendriks-pg7.jpg and /dev/null differ diff --git a/Refs/pim-hendriks-pg8.jpg b/Refs/pim-hendriks-pg8.jpg deleted file mode 100644 index 1faf4274..00000000 Binary files a/Refs/pim-hendriks-pg8.jpg and /dev/null differ diff --git a/Refs/pim-hendriks-pg9.jpg b/Refs/pim-hendriks-pg9.jpg deleted file mode 100644 index c3825985..00000000 Binary files a/Refs/pim-hendriks-pg9.jpg and /dev/null differ diff --git a/Refs/rogelio-olguin-bronze-trims.jpg b/Refs/rogelio-olguin-bronze-trims.jpg deleted file mode 100644 index 786ccf0b..00000000 Binary files a/Refs/rogelio-olguin-bronze-trims.jpg and /dev/null differ diff --git a/Refs/rogelio-olguin-metal-floor-03.jpg b/Refs/rogelio-olguin-metal-floor-03.jpg deleted file mode 100644 index 4ce56989..00000000 Binary files a/Refs/rogelio-olguin-metal-floor-03.jpg and /dev/null differ diff --git a/Refs/rogelio-olguin-tile-floor-01.jpg b/Refs/rogelio-olguin-tile-floor-01.jpg deleted file mode 100644 index fc8b5c50..00000000 Binary files a/Refs/rogelio-olguin-tile-floor-01.jpg and /dev/null differ diff --git a/Refs/sbs_directionalWarp.JPG b/Refs/sbs_directionalWarp.JPG deleted file mode 100644 index bb5d6b96..00000000 Binary files a/Refs/sbs_directionalWarp.JPG and /dev/null differ diff --git a/Refs/scifi.jpg b/Refs/scifi.jpg deleted file mode 100644 index 0379ab1a..00000000 Binary files a/Refs/scifi.jpg and /dev/null differ diff --git a/Refs/simmou-rida-screenshot008.jpg b/Refs/simmou-rida-screenshot008.jpg deleted file mode 100644 index a16ad71a..00000000 Binary files a/Refs/simmou-rida-screenshot008.jpg and /dev/null differ diff --git a/Refs/simmou-rida-sub-graph.jpg b/Refs/simmou-rida-sub-graph.jpg deleted file mode 100644 index f1b239cc..00000000 Binary files a/Refs/simmou-rida-sub-graph.jpg and /dev/null differ diff --git a/Refs/substance-Kuzyakin-ceramic-tiles-1.png b/Refs/substance-Kuzyakin-ceramic-tiles-1.png deleted file mode 100644 index 3010c17c..00000000 Binary files a/Refs/substance-Kuzyakin-ceramic-tiles-1.png and /dev/null differ diff --git a/Refs/substance-Kuzyakin-ceramic-tiles-2.png b/Refs/substance-Kuzyakin-ceramic-tiles-2.png deleted file mode 100644 index 5aa3b5fd..00000000 Binary files a/Refs/substance-Kuzyakin-ceramic-tiles-2.png and /dev/null differ diff --git a/Refs/substance-hugobeyer-victorian-1.png b/Refs/substance-hugobeyer-victorian-1.png deleted file mode 100644 index 170f6be3..00000000 Binary files a/Refs/substance-hugobeyer-victorian-1.png and /dev/null differ diff --git a/Refs/substance-hugobeyer-victorian-2.png b/Refs/substance-hugobeyer-victorian-2.png deleted file mode 100644 index 2a709bc1..00000000 Binary files a/Refs/substance-hugobeyer-victorian-2.png and /dev/null differ diff --git a/Refs/substance-karthik-j-pattern-tile-001.jpg b/Refs/substance-karthik-j-pattern-tile-001.jpg deleted file mode 100644 index efea804e..00000000 Binary files a/Refs/substance-karthik-j-pattern-tile-001.jpg and /dev/null differ diff --git a/Refs/substance-karthik-j-pattern-tile-002.jpg b/Refs/substance-karthik-j-pattern-tile-002.jpg deleted file mode 100644 index e96c33b8..00000000 Binary files a/Refs/substance-karthik-j-pattern-tile-002.jpg and /dev/null differ diff --git a/Refs/substance-karthik-j-pattern-tile-003.jpg b/Refs/substance-karthik-j-pattern-tile-003.jpg deleted file mode 100644 index 9a5e4c6e..00000000 Binary files a/Refs/substance-karthik-j-pattern-tile-003.jpg and /dev/null differ diff --git a/Refs/substance-karthik-j-pattern-tile-004.jpg b/Refs/substance-karthik-j-pattern-tile-004.jpg deleted file mode 100644 index 71b80361..00000000 Binary files a/Refs/substance-karthik-j-pattern-tile-004.jpg and /dev/null differ diff --git a/Refs/substance-karthik-j-pattern-tile-graph.jpg b/Refs/substance-karthik-j-pattern-tile-graph.jpg deleted file mode 100644 index a6b7365e..00000000 Binary files a/Refs/substance-karthik-j-pattern-tile-graph.jpg and /dev/null differ diff --git a/Refs/substance-kyle-horwood-floortilesfinallarge.jpg b/Refs/substance-kyle-horwood-floortilesfinallarge.jpg deleted file mode 100644 index 6e9afe17..00000000 Binary files a/Refs/substance-kyle-horwood-floortilesfinallarge.jpg and /dev/null differ diff --git a/Refs/substance-unknown-marble.jpg b/Refs/substance-unknown-marble.jpg deleted file mode 100644 index dce88cc8..00000000 Binary files a/Refs/substance-unknown-marble.jpg and /dev/null differ diff --git a/Refs/substance-unknown-morocco.jpg b/Refs/substance-unknown-morocco.jpg deleted file mode 100644 index 179a0616..00000000 Binary files a/Refs/substance-unknown-morocco.jpg and /dev/null differ diff --git a/Refs/tristan-meere-concrete-01.jpg b/Refs/tristan-meere-concrete-01.jpg deleted file mode 100644 index 94286aa7..00000000 Binary files a/Refs/tristan-meere-concrete-01.jpg and /dev/null differ diff --git a/Refs/tristan-meere-concrete-02.jpg b/Refs/tristan-meere-concrete-02.jpg deleted file mode 100644 index 48fce3c0..00000000 Binary files a/Refs/tristan-meere-concrete-02.jpg and /dev/null differ diff --git a/Refs/tristan-meere-concrete-03.jpg b/Refs/tristan-meere-concrete-03.jpg deleted file mode 100644 index c6013f26..00000000 Binary files a/Refs/tristan-meere-concrete-03.jpg and /dev/null differ diff --git a/Refs/tristan-meere-concrete-04.jpg b/Refs/tristan-meere-concrete-04.jpg deleted file mode 100644 index 576d7265..00000000 Binary files a/Refs/tristan-meere-concrete-04.jpg and /dev/null differ diff --git a/Refs/tristan-meere-concrete-05.jpg b/Refs/tristan-meere-concrete-05.jpg deleted file mode 100644 index 78b5b445..00000000 Binary files a/Refs/tristan-meere-concrete-05.jpg and /dev/null differ diff --git a/Refs/tristan-meere-concrete-breakdown-01.jpg b/Refs/tristan-meere-concrete-breakdown-01.jpg deleted file mode 100644 index 18222915..00000000 Binary files a/Refs/tristan-meere-concrete-breakdown-01.jpg and /dev/null differ diff --git a/Refs/tristan-meere-concrete-breakdown-02.jpg b/Refs/tristan-meere-concrete-breakdown-02.jpg deleted file mode 100644 index 9c54ce43..00000000 Binary files a/Refs/tristan-meere-concrete-breakdown-02.jpg and /dev/null differ diff --git a/Refs/tristan-meere-cracksbreakdown.jpg b/Refs/tristan-meere-cracksbreakdown.jpg deleted file mode 100644 index 98c01f71..00000000 Binary files a/Refs/tristan-meere-cracksbreakdown.jpg and /dev/null differ diff --git a/Refs/tristan-meere-material-04.jpg b/Refs/tristan-meere-material-04.jpg deleted file mode 100644 index 1ce5c269..00000000 Binary files a/Refs/tristan-meere-material-04.jpg and /dev/null differ diff --git a/Refs/tristan-meere-tilesbreakdown.jpg b/Refs/tristan-meere-tilesbreakdown.jpg deleted file mode 100644 index ec304b6b..00000000 Binary files a/Refs/tristan-meere-tilesbreakdown.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-basic-final-06.jpg b/Refs/vinicius-ribeiro-basic-final-06.jpg deleted file mode 100644 index db4a7627..00000000 Binary files a/Refs/vinicius-ribeiro-basic-final-06.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-01.jpg b/Refs/vinicius-ribeiro-render-01.jpg deleted file mode 100644 index 10203b62..00000000 Binary files a/Refs/vinicius-ribeiro-render-01.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-02.jpg b/Refs/vinicius-ribeiro-render-02.jpg deleted file mode 100644 index b3a1450c..00000000 Binary files a/Refs/vinicius-ribeiro-render-02.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-03.jpg b/Refs/vinicius-ribeiro-render-03.jpg deleted file mode 100644 index 0e37ad0a..00000000 Binary files a/Refs/vinicius-ribeiro-render-03.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-04.jpg b/Refs/vinicius-ribeiro-render-04.jpg deleted file mode 100644 index 6d2f80e3..00000000 Binary files a/Refs/vinicius-ribeiro-render-04.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-05.jpg b/Refs/vinicius-ribeiro-render-05.jpg deleted file mode 100644 index 03cd9f9c..00000000 Binary files a/Refs/vinicius-ribeiro-render-05.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-06.jpg b/Refs/vinicius-ribeiro-render-06.jpg deleted file mode 100644 index c0d668e1..00000000 Binary files a/Refs/vinicius-ribeiro-render-06.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-07.jpg b/Refs/vinicius-ribeiro-render-07.jpg deleted file mode 100644 index 54c74438..00000000 Binary files a/Refs/vinicius-ribeiro-render-07.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-08.jpg b/Refs/vinicius-ribeiro-render-08.jpg deleted file mode 100644 index 15ec0eb6..00000000 Binary files a/Refs/vinicius-ribeiro-render-08.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-09.jpg b/Refs/vinicius-ribeiro-render-09.jpg deleted file mode 100644 index 1bb0dbff..00000000 Binary files a/Refs/vinicius-ribeiro-render-09.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-10.jpg b/Refs/vinicius-ribeiro-render-10.jpg deleted file mode 100644 index d791671d..00000000 Binary files a/Refs/vinicius-ribeiro-render-10.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-11.jpg b/Refs/vinicius-ribeiro-render-11.jpg deleted file mode 100644 index fbb56907..00000000 Binary files a/Refs/vinicius-ribeiro-render-11.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-12.jpg b/Refs/vinicius-ribeiro-render-12.jpg deleted file mode 100644 index 531d79bb..00000000 Binary files a/Refs/vinicius-ribeiro-render-12.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-13.jpg b/Refs/vinicius-ribeiro-render-13.jpg deleted file mode 100644 index c99cc3f1..00000000 Binary files a/Refs/vinicius-ribeiro-render-13.jpg and /dev/null differ diff --git a/Refs/vinicius-ribeiro-render-14.jpg b/Refs/vinicius-ribeiro-render-14.jpg deleted file mode 100644 index 2f3e036e..00000000 Binary files a/Refs/vinicius-ribeiro-render-14.jpg and /dev/null differ diff --git a/Refs/yannick-castaing-de6-004.jpg b/Refs/yannick-castaing-de6-004.jpg deleted file mode 100644 index af815b51..00000000 Binary files a/Refs/yannick-castaing-de6-004.jpg and /dev/null differ diff --git a/Refs/yannick-castaing-de6-005.jpg b/Refs/yannick-castaing-de6-005.jpg deleted file mode 100644 index 4455f081..00000000 Binary files a/Refs/yannick-castaing-de6-005.jpg and /dev/null differ diff --git a/Refs/yannick-castaing-de6-006.jpg b/Refs/yannick-castaing-de6-006.jpg deleted file mode 100644 index 0de968f0..00000000 Binary files a/Refs/yannick-castaing-de6-006.jpg and /dev/null differ diff --git a/Refs/yannick-castaing-designer.jpg b/Refs/yannick-castaing-designer.jpg deleted file mode 100644 index c12a67fb..00000000 Binary files a/Refs/yannick-castaing-designer.jpg and /dev/null differ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 90d59714..7815a9ce 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,7 +10,7 @@ pool: vmImage: 'Ubuntu-16.04' steps: -- script: sudo apt-get install -y build-essential cmake libffi-dev libgtk-3-dev git clang +- script: sudo apt-get install -y build-essential cmake libffi-dev libgtk-3-dev git clang libsdl2-dev libavcodec-dev libavdevice-dev libavfilter-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev libpostproc-dev displayName: 'Install Build Deps' - script: | diff --git a/bin/Autotests/Assets/CartoonHead.gltf/scene.bin b/bin/Autotests/Assets/CartoonHead.gltf/scene.bin new file mode 100644 index 00000000..1f089066 Binary files /dev/null and b/bin/Autotests/Assets/CartoonHead.gltf/scene.bin differ diff --git a/bin/Autotests/Assets/CartoonHead.gltf/scene.gltf b/bin/Autotests/Assets/CartoonHead.gltf/scene.gltf new file mode 100644 index 00000000..753a172a --- /dev/null +++ b/bin/Autotests/Assets/CartoonHead.gltf/scene.gltf @@ -0,0 +1,270 @@ +{ + "accessors": [ + { + "bufferView": 1, + "componentType": 5126, + "count": 65532, + "max": [ + 1.569299578666687, + 1.4159302711486816, + 0.87469422817230225 + ], + "min": [ + -1.569299578666687, + -1.621997594833374, + -4.0125851631164551 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 786384, + "componentType": 5126, + "count": 65532, + "max": [ + 0.99999606609344482, + 0.9999886155128479, + 0.99999231100082397 + ], + "min": [ + -0.9999961256980896, + -1, + -0.99999266862869263 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "componentType": 5126, + "count": 65532, + "max": [ + 1, + 1, + 1, + 1 + ], + "min": [ + 1, + 1, + 1, + 1 + ], + "type": "VEC4" + }, + { + "bufferView": 0, + "componentType": 5125, + "count": 335421, + "max": [ + 65531 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 1572768, + "componentType": 5126, + "count": 37450, + "max": [ + 1.5645266771316528, + 1.4146754741668701, + 0.87469422817230225 + ], + "min": [ + -1.569299578666687, + -1.6220142841339111, + -4.0125851631164551 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 2022168, + "componentType": 5126, + "count": 37450, + "max": [ + 0.99999558925628662, + 0.99993050098419189, + 0.99991405010223389 + ], + "min": [ + -0.99999552965164185, + -0.99990594387054443, + -0.99985039234161377 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 1048512, + "componentType": 5126, + "count": 37450, + "max": [ + 1, + 1, + 1, + 1 + ], + "min": [ + 1, + 1, + 1, + 1 + ], + "type": "VEC4" + }, + { + "bufferView": 0, + "byteOffset": 1341684, + "componentType": 5125, + "count": 137967, + "max": [ + 37449 + ], + "min": [ + 0 + ], + "type": "SCALAR" + } + ], + "asset": { + "extras": { + "author": "DeMoon (https://sketchfab.com/demoon)", + "license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)", + "source": "https://sketchfab.com/models/4769e1ab43824dfb98a5da736988b718", + "title": "Cartoon Head002" + }, + "generator": "Sketchfab-3.20.7", + "version": "2.0" + }, + "bufferViews": [ + { + "buffer": 0, + "byteLength": 1893552, + "byteOffset": 0, + "name": "floatBufferViews", + "target": 34963 + }, + { + "buffer": 0, + "byteLength": 2471568, + "byteOffset": 1893552, + "byteStride": 12, + "name": "floatBufferViews", + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 1647712, + "byteOffset": 4365120, + "byteStride": 16, + "name": "floatBufferViews", + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 6012832, + "uri": "scene.bin" + } + ], + "materials": [ + { + "doubleSided": true, + "emissiveFactor": [ + 0, + 0, + 0 + ], + "name": "material_0", + "pbrMetallicRoughness": { + "baseColorFactor": [ + 1, + 1, + 1, + 1 + ], + "metallicFactor": 0, + "roughnessFactor": 0.59999999999999998 + } + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "COLOR_0": 2, + "NORMAL": 1, + "POSITION": 0 + }, + "indices": 3, + "material": 0, + "mode": 4 + } + ] + }, + { + "primitives": [ + { + "attributes": { + "COLOR_0": 6, + "NORMAL": 5, + "POSITION": 4 + }, + "indices": 7, + "material": 0, + "mode": 4 + } + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "name": "RootNode (gltf orientation matrix)", + "rotation": [ + -0.70710678118654746, + -0, + -0, + 0.70710678118654757 + ] + }, + { + "children": [ + 2 + ], + "name": "RootNode (model correction matrix)" + }, + { + "children": [ + 3, + 4 + ], + "name": "Cartoon Head002.OBJ.cleaner.materialmerger.gles" + }, + { + "mesh": 0, + "name": "" + }, + { + "mesh": 1, + "name": "" + } + ], + "scene": 0, + "scenes": [ + { + "name": "OSG_Scene", + "nodes": [ + 0 + ] + } + ] +} + diff --git a/bin/Autotests/Assets/Lycksele/negx.jpg b/bin/Autotests/Assets/Lycksele/negx.jpg new file mode 100644 index 00000000..aa7df6a6 Binary files /dev/null and b/bin/Autotests/Assets/Lycksele/negx.jpg differ diff --git a/bin/Autotests/Assets/Lycksele/negy.jpg b/bin/Autotests/Assets/Lycksele/negy.jpg new file mode 100644 index 00000000..1f370963 Binary files /dev/null and b/bin/Autotests/Assets/Lycksele/negy.jpg differ diff --git a/bin/Autotests/Assets/Lycksele/negz.jpg b/bin/Autotests/Assets/Lycksele/negz.jpg new file mode 100644 index 00000000..f5f29820 Binary files /dev/null and b/bin/Autotests/Assets/Lycksele/negz.jpg differ diff --git a/bin/Autotests/Assets/Lycksele/posx.jpg b/bin/Autotests/Assets/Lycksele/posx.jpg new file mode 100644 index 00000000..e7949e88 Binary files /dev/null and b/bin/Autotests/Assets/Lycksele/posx.jpg differ diff --git a/bin/Autotests/Assets/Lycksele/posy.jpg b/bin/Autotests/Assets/Lycksele/posy.jpg new file mode 100644 index 00000000..92d04c46 Binary files /dev/null and b/bin/Autotests/Assets/Lycksele/posy.jpg differ diff --git a/bin/Autotests/Assets/Lycksele/posz.jpg b/bin/Autotests/Assets/Lycksele/posz.jpg new file mode 100644 index 00000000..ddc17cf3 Binary files /dev/null and b/bin/Autotests/Assets/Lycksele/posz.jpg differ diff --git a/bin/Autotests/Assets/Lycksele/readme.txt b/bin/Autotests/Assets/Lycksele/readme.txt new file mode 100644 index 00000000..8b404c27 --- /dev/null +++ b/bin/Autotests/Assets/Lycksele/readme.txt @@ -0,0 +1,13 @@ +Author +====== + +This is the work of Emil Persson, aka Humus. +http://www.humus.name + + + +License +======= + +This work is licensed under a Creative Commons Attribution 3.0 Unported License. +http://creativecommons.org/licenses/by/3.0/ diff --git a/bin/Autotests/Assets/PartyCat.jpg b/bin/Autotests/Assets/PartyCat.jpg new file mode 100644 index 00000000..63395471 Binary files /dev/null and b/bin/Autotests/Assets/PartyCat.jpg differ diff --git a/bin/Autotests/Assets/Vancouver.jpg b/bin/Autotests/Assets/Vancouver.jpg new file mode 100644 index 00000000..770b82a6 Binary files /dev/null and b/bin/Autotests/Assets/Vancouver.jpg differ diff --git a/bin/Autotests/Assets/studio022.hdr b/bin/Autotests/Assets/studio022.hdr new file mode 100644 index 00000000..b803fda2 --- /dev/null +++ b/bin/Autotests/Assets/studio022.hdr @@ -0,0 +1,1330 @@ +#?RADIANCE +EXPOSURE=1 +FORMAT=32-bit_rle_rgbe + +-Y 1000 +X 2000 +œʿƂƍƒƶƶǜǏƉ„£„㿎ƂƈňƒƂńƄƼƲDŽƓńƨŖƄК¤Š‡ƒ‚­̿ſÿžԽƈLjƌDŽƚǂƇżōƆƟœƂŊƈłśňƂŏƈńƗŎƌƑŻŲņĭčăąŊijłŐƄŝ–ֿ޿οȾ̾ѾƆńƊŤƒŠƴłƆŊżŋƊłłƚŧňĆŎĈćźĆńĈňżċĥÂĩąłŃŐƣŜοſĿͿツԾξž쾌ѾȾŐŬƋʼnƢŔƋŅƆńłĊŎĉňăņijąſĹŔėņćłĸƃŇƴńņĂīĂÿĄŌŅăĄŮĘŘĄńĆĊŇňĹЇ޿ſĿ˿쾯Ǿ¾꾈ҾؾξĞŏĊœĊŌōńŃĜŚĄŭĄĆĠŝăňĂŘĄĴůƂŤƄōƓņƤĂęŅĉņĊĐũØėÎĥôĹŋĊĄŜĂŐĘŐĜįą࿇ȿ㿔澅þ轂߾Ѿ̼ċÆćäĄøĚÄĄÑĉīĂīăŏċłđřČʼnĆŇĂŊĢłĄžĄĝĘíɖ¨é±ëĒÏĈĕńćŶĄÏĉÄăËĉÉăÅčĆŰ𥌥ō޿澐ֿ꿆辂ĿֽʽܽÂÄėÇġßĆâĆĭĒŊĂſĂõĊÄăÌäċĜ¥Ê‚„æĂÂĄþűĐŠăŎЫ澤޾ٿ较޽Ͻݾȿʽļ̾⼄ļĊÄIJÂ„â‚æ‚Øñ«Â­şĆŃĹŗĔłĆłĄňĄņČŒĈŖĄÅ†ɂ‚‡ÄÅ̂…ކ‚Ñ‚É—ÅĄÂĈ͙Éׅ‰ÈƼУ޾ӿĿξeܽʾ½żξо⻂Ż뼟Ă· „Ä‚ÐǬŒĄŇĄńČŅăŎĄņĆśąŖĈżĂÄĻÈ΂Ȅ҆لŽ‚ÑÊ–ÆĄÂĈʋ‚‚‘…„°Š›ÂćëЍž濌޽콂ؼϽϼ򼓻ռλ…εÂď΂‰‚ˆ‹„ÙƒÒ‘‚ĆĹõłĐłħŐĝċŊĄņĂŨÊĝÃēÂĈÌĄÈČÂČ”ˆž…„ˆÂšÄăËĂéČϛ„°ƒÄæµЧ־轞ο׼ü𾃽ɾ߽Լ뼃ջšÏ¥Šˆ‚ȈĺæćńĘńŅğřĚĆġÅĂÎĂäĄÄħÜ„„ö¶Æ‹‡žÇăćЊŠ‚«‚ŠμнʿϾξܾž濤ػͽ  亃㒆ˆË‚„ŨĄêĵĔĺìďÌĞ¸È¦Æ–ÂĄÆČøĆÐĆŞĂŘĠӂźąØĈÈĂèĂÑģ΂ÑЊҽȿݾ̿ػ캂༅ͽýý…„␂ˆˆ®úĒłĎŸĨüĂÆĐĖƂÌìďÆģìĄłĒłćœĠōďřęȞÂĊÊĔÆĂØĊÂĆüĄÆę͆μ̾뿓ԻȺ罄ؾѿ꺂‘‡ˆƒÅ‰ú‚Æ…łƞƼËÏĸÂĄÂËćÃČĹljÍéĆÄīŋûĊņĄńĠłƅŇƐŎƂŻƮŏĄŔĆÌĄÊăšĆÒĎÊĄÆ÷ĆÌĘ֌Ąå’󻃼̾Ѿ™лǺ轃ʺ¡‡‚ƒÄŠÓ‰Î…˂ŔÂĊÂĄÆÖÄij‡˜ŊÌÅĄÞąÅĸÛąŏĸƅţƂŬƈDŽƈǘƜłƍŊĘţĐŘÑēÇăÇĄôČÆĘ׍ˆà’Ͼƒ™†ς·ýܽ⽈ν⺎¢¢Ô†ÛˆÄ±Ú³ÛăúĪÂďÈÐĄūØČÎĞÇÖēŃơŎƈDžƠǚƐLjƱȎDŽƌǶƗŇĖńĄńċŅĄŊąÅĎÉĉîĻʅĄî•Б㻆ľ濂Ǿ ɾʿ…ç„ϤƒȅÞ…›ƿ¾ +ʻܽѹ纋¢¦Ì‡ÛˆÄ±Ú§ĄÃĥÈĒÂʇÓÐªÙąÜĆÂĄÞĐŐƈʼnƇŏƦDžȨǃȏǓǐȆǒȈDžȞLJƈǢƉƊłƜłƌŊĂÆĈÓĂðĝĠĎî”Ŀᾖʾ ‚•ĴņĈŔĄÂČÂđ”Ö†ŒҹǼʼֽ½†„‡Æ”NjȩĆÊĪ䉘ʺˆ°Ä âŠÆŒÂŒÌ„Œħáđãĵ×ĂÆì©‡Ò‘ÄšÂþĔńƆŔƇljƌǃƢǕɵɈʌɂʇɌȂɅȂɊǔȖdžƒNjőĔ̂˭ᄔݾʾ쾨侦†‡È”ÇćłęĨņƄƇņƂŔƄƣŤÎĎàչҼ½¼—ÃĜÂĐæĉŝĂÌĎŽІʔ…„±Ä ä‡ÇŒÂŒÊèĊç ÄĚŠØĂÐÕ¨ä†È˜ÄĂáŖĎŞƴLJȈǔȆɉɜʂɨʆˆʜ˄ʂˇ˖ʤȏɎȤǎŏě‡Dz‡ݔБɾǾ„ÈÇ…ƂƄÛČůƦǐƜǂƆdž DŽƉƆLjƎŊƏʼnĒĆ݇Һ廐йĽȽ”ÎĎńĘŐƂŅƨŅƴńśĄÄĈЂœ „†Â¾ÆŽô¨ÎĂÄĈØĂźĊłĈłďŒġÂĄÄĈÄÉĚÉě̄׃Ж‚˜Â…ÔÔĄņĎŎƚDŽȐDŽȆǂȆDŽȚɌʎ˃̝˨̊ˣˊ̂ˎ̂ˑ̈ˍʊˑʇɒȄdžȜLjƈŌƘłĒłĈņăŧĔҨʔБƾɾ‰Ç°ÆĆŃĒŏƨǧȉǢȂdžȗǐȇǐƃLjƃńƈŎĆĕʂϬȺ車йü⽈Ӽ‡…›ÌčŅƉŖƚǠƅǃƄǵƋňĊŎć҅¤†Ã…´È†ô›õĔŞĄńĆŃĬőĠÂĄÄĈÄĂÈĒÄăÑĆÃċù‚‘‚Ç „ÞÏĄņċōƋLjȈǯȆɆʃɑʎ˨̪̬̈́̈́̆͂̒͆̐˄̏ˈʍɆȂɔțǝƂŌưłĐŔĘʰѝտХݿ۽žÕĊŊƈLjƌDžȌʇɚʗ˅̅ˈ̆˘̄˅̊˕ʈˌʊɎȐnjƈŒĠÃđԂ˅„ӻ󹘺Ż鼔¿Ƽ’ÈĜʼnƌǜȒɮˆʄ˔ʆɊȖɆȌǔƊʼnďڐȽºʿ„Ë•Ê‹Ö‹îŒøńƠőĉÂČæąïĞ᫇‰†‚ÔºÆĂńĆőƇǞȕɊʊˉ̇ˌ̄͌ΆςΚϗльАώЄϋΎ͈̈́̃̌ˈʒɠȃɑȡdžDŽƂnjƙƒŠĆÆĆÂĒÂČÂȆɚۻֿڽ‚”ØĐŊƗNjȄɕʙ˖̑̓Έ͖Ᾰ͉ː̈ˊʌɍȇNJƉŒğÆĎÓԐӻʹͿ”ÍĉŘƈǎșɏʑ˂̆ˌ̂ˢ̌˒ʄˎʊɈȉDždžƋʼnčڐº¢‚ΑɈԗĊ֌òłƤŢĂöċŝĝÞ¨‰„…Œ‚‚„ИÈÉďÅČŎƊǔȘɐʉˉ̂͌̌̈́ΌφЂϔБї҉Ҙӄ҄Ӎҡ Љϋ΍͆̋ˈʒɟȆɎȓȉǂƉǐƔłƆłƌŸĄÂĆě†ƞЧ۽ýŽÍďŊƍNjȐɈʇ˚͎̏ΒϊНэҕτЏϋΊ̈ͅˆʅɅȅdžƉōć鈅šҺƼ⽈»“ÅđŎƎnjȈɃʋˆʒˋ̗͊ΈφЄτЅϔЇψЄϊ΂̈́Ί͈̊ˆʈɄȇDžƄŊċτîķŌƪŕăŋăŵċŊČńƒœĂōĤϕ……ž„‚ŸÄĄÑĥŒƐǎȍɏʉˑ͎̌ΉχЄцҏяҊӗԉՈֆׄք׆֒׈ֈׄ֊ՂԄՊԇӊ҅шІυ΅̅ͅˊʌɇȩLjƆdžƜǚƌńƈŊƕŗĉŏĊ†ÐŠУؽ½ŠÎĎŌƌǍȋɎʉˇ̄͊Ά͌ΈϋГшҌӂԎӊԂӄԏԆӇҋщЇω΅͈̄˄ʅɅȄLJƉŊĈ㋈œʼ⽈⾇‹ÑąŏƐnjȌɇʃ˚͈̍ΌύЉъч҂є҇ы҂ъЇωΉ͆̅ˇʄɅȄDŽƆʼnĊ΄ĺùˆÎ‚Ä•ÂëďłƩŋƪŗĂŋĂŪįŅƄńƌŌĉŏĢÒƒŸ†‚™ÖđƒŏƒljȎɍʍˈ̍͌ΊόЈтҚӎԈՌ֍׉بل؎ق؊ׇֆՇԉӅ҇хЃφ΄̈́̈ˈʊɇȕǂƍnjƃLjƒƆǚƌńƈŌƄņƋŃĆŌĊŏđϋХ߼ϽȾþ‚‡ÆĆŊƊǏȉɊʌˌ̈͊ΈτЈѐ҉ӃԆՅև׃؋ل؊نډمڄڇَ؂ُ؉ׄևՆ҈фЇ̈́̄˄ʆɄȆNJƄŇĎɉ–„ÈĊŐƌLjȊɌʈː̅ͅΈψЂчЃш҆ӄԅՄ֕ב؂א؄׌ք׆ք׊ֈՃԉӅ҂чЂψ΄͂̅˄ʂɅȆǃƇŊĄÐ†˿ƺƒ„Ý‘ÉīÈ¢ÂęÕĆÔĥłĺłąʼnĆÛńĚŌƊŋơʼnĚłղÆ̒„†…ŸÎĖŇƅŔƒdžȆɆʊˉ̏͊ΈϊЍҍӆԄՈֈׂ؇׃؈مڅۄ܇݇ރߋޗ߃߄ފ݇ނ݈ވ݉܃ۈڅق؇ׂևՅ҅тЄχ΃͇̉˄ʇɍȆNjƄǖƈńƄŊƊŊƂŋƗŌƆńƌłĒŇēˉȾŽÈĄņƊLjȎɊʉˉ̌͆ΐυЅш҂ӐԂՈք׆؄نڄۊ܄ۊ܅݋܄݌ۄڊۄڄۉم؄׈քԇӂ҄ц΄˅ʅɃȇLjƄņĎÅ«†ÅċňƋǎȇɉʉˊ͉̊·φЅч҄ӇԃՆֆ׆؂ٔڌۂڄۂڏۄډقڎو؇׃ֈՄԄӂ҇тІῡ˃ʄɆȄDŽƆňĆΆ“‚„Ҍ֌ÏĨÆ¢ĕïąďłĎńʼnăäĒńƂŎƈŌƠʼnÄĦȊÂĸΎ„ކ‚ŸÍĕŞƏǎȈɃʇˉ͍̉΋ψЈщҊӉԋՅֆׅ؇هڇۃ܅݆߄߉ނ݈܄ه؂׆օӄ҄тІτ΃͇̈˄ʆɎȄǫƢŅƈŌƂŏƅłƌŌƆŅƌłĒňĔɍГͽ‚„ňÌĆńƋDžȈɈʈˎ͈̄ΆφІю҄ӉԆՃֆنڃۅ܆݈ބ߆߄ނ݄܄ۄڇق؅ׂօ фЄτ˅ʅɂȈDŽƄŇĂɈǿ㽍ŒÃćŌƆdžȆɊʎˆ̄͆ΉύЅч҆ӆԄՄւׄ؆نڄۊ܂݇ޅ߆߇܄ۃڄم؆ׂքՃԅфЃτ̄˂ʄɆdžƈƄ‚…’„‚È“¤ÐĢçÌŃėőũčŖƅņƝŭĿÒďłÈ„‚ƒÆžÂĄÌĊʼnƝDŽȅLjȌɅʄˋ͇̆ΆЉю҇ӆԄՈ֍ׅ؆هڅۄ܅߅߄ނ݄܄ۄ؄׃քӄЅτ΂͈̄˄ʇɂȈljƭōĒŮƂňƆŌƗŇĆàĄÂĈЈЉ ĜÈĊńƈNjɇʆˈ̄͂Άͅ·φЄчҋӄԅՇօׅ؄ل܆݅ރ߅ ݄܃ۆڃلք +х΄˅ʅɂȈDŽƄńĄÈ†©Խȿཏ„ˆÈĄŌƆLJȉʆˎ̆̈́΅ψЅы҅ӆԆՄք׆ڄۄ܆݄އ߄ۄڄن؂ׄւՅ Єτ΂̈́̄ʅɅȂDžƈĄÇƒ ΅±òęçĒÂijËĎńłęŎŦČŖƆņƚŲĺÑđ„̂‚‰ÂšÖČņƗǛȇɊʅ˅̍͂ΉψЇфҎӆԄՅֈׄ،لچۆ܅݂އ ߂ބ݂܅ ׄքӄфЄτ΂͈̄˄ʄɄȈdžƔňĒŅÌēŵƆŊƐŐĈçĉǃƇХӾÏćńƈNJȆɇʊˋ̇΄ϐ҆ӄԇՃֆׄ؃لچ܄އ߅߆ۄׄф ̄˄ʂɅȄdžƄńĆŃŒ +‘ÃćŇƉdžȇɐʇ͇΋σЅф҄ӇԂՇփׄ؅܇݅ ޅۄ؄ՆԄ υ΄ʆɂȅǂƇńĄÅ†ܾĖ•òĒŕĕÍĂÕĠáČłƆŊƍŌůƟŇĖŝďśƋŇƝœąŜČÂĸÄŒߋЂĂĊÒĚōƏǐȏɇʄˇ͈̉ΆωЌч҂ӄԆՋփׅ؄كڇۂ܇݃ބ߅ ܆ۄօԄх ̅ͅ˄ʄɆȄDŽƌŋēÃėÄĄÍĆśǍƏńćĂŋćÂĊȜ‚ƒХ–ÆčłƇdžȋɅʈˏ̅͆τЋӆԄՂև؆ل܅߄  + ܄ׅքф ̄ɄȄDŽƄńĄÇ ޼־ϾƼŠÊĄŇƋdžȇɉʌˆ̂̈́ΆϊЃхԈ׆څۄ߅  ߄քՂԄ τ̈́ʄDŽƄńĄÄ† 辕å‚ÈŒç•æĄņ +ėŗďäĕÞđńƄŔƎŇńƄŘƈǕƜŊđŘĐśƌʼnƜŒĄšćÂIJΌÄې̃ʉÏĜŒƌǏȆɊ˅̆͌΅χЌх҇ԄՆ֊׃؅قڄۆ܄݂ޅ ݄քԄф΄̓̄˄ʄɄȇņĈΊÆ”ÉĈŦƎŎĂĂŖĊԖ̅Л¡‰ÂćŇƋDžȅɊʊ˅̃͊΄υЄц҇ ׅچ |}~~}}~~~}|}ƾ‚ÈĊňƆNjȈɅʄˈ̈͂ΆτЅч҂ӄԂՆ؆&{{{|}~}|}|||{ބbºÇČĉԇÒÔĘÂĎÏğłĎłĤŅŏăÔĂņĆŝŠĊŭƜŞƈńƊŎƤǠƒŅĄŅĐŖĘŘƋōƊŅƓŰĪĂΒèˆÔȋÈĒłƄŅƂśƌljȂɇʇˇ̈ͅ΋ψЅф҈ӇԂՆքׄ؈قڄۂ܅߅ eɨŽÆċňƍŃƏŜĄĕŗĘÙĒÕ¦ƒÄ¡ŀЛ±¥‹ÃćńƉljȅɌʈ˃̅ͅ·τЄц҅ӆքׂ؄ل܅6}~~}|~} ‚ÆĈŋƅLjȊɆʅ˃͇̇΂φЄх҅Ӄԅׅڄ|||}}}~~}|{{􁋊~}|Ď΍æąÐÓńĄŤĂņĊřĉŚćžƍťƅŜƥǥưŎĜŖƎŜƍŲĄĝۉò‡Ç„È’ÆĈņƄłƄŢƌNj ʄˊ̈͆ΊψЄц҃ӇԆՂֆׄ؄نڃۄޅ7ÄĉņƠŚĜŔĜÜĕϦ›©Â݀ɀЎȽ‚ĈÃćŇƅnjȆɈʇˇ̃̈́΅ςЉф҃ӄԄՅم<|}~~}|~~|̼˾Ⱦ…ÅćŋƇLJȊɆʃ˄̅̈́΅φЄу҄Մ؅݄{|}~~}|{}~}|ĉÂĄÂĖȊîĂśĂŗŘĉÙĂŭĒŕƂƠǃƄǒƎłʼnČřƙŨĆÃĐñ„¡ËĎŊƌŔƒLjȃɆʇˆ̌ͅΈχЇт҅ӅԃՆօׄ؃لڂۆބ߄, + ’ÊĩśĈŚčÂĝÂĄÞčͦ…šÅĪĈÃЎš’ÅĆŇƇljȇɅʈˇ̅φЂч҅ӄԂՄւ׆ۄ܄8|}}~~~~~}¿}߾¾„‚ÉćņƊDžȉɆʆ˂̄͆΃υІф҂ӄԄՄւׄلڄ9|||}}}~~~~}􃂁~}|~|ýĈÂą믇åċąŇąŌĄœřąÚĂœąņĂňēŘƃƠǓŅłƪŎĊŘƚŪĄÄČó†›ÏďŊƊōƈǒȅɆʆˆ̋͆΄ψЇц҂ӄԅՄք׆؄قڄۃ܅ ?”ÄĩńŎĈņĂÊėÂģÞč͐”ƒšÆĨÂĉÂʀЇ¤„–潗ˆÍċŌƆdžȆɃʅ˃̇͆΂τ҅ӄԇՄւׄۄ)|}}~ ⁄~}|+~~ѾɿŽÈčňƆDŽȅʈˆ΄τЄф҃ӈ لC{||}}}~~~ဃ~}|{+}}ܽػÈĤÕćłĬŌĤłğƝʼnĐłĆŒňƂŔƂǤƂljƃǟƇŠƌǕƓŋńƦŕĒņƈłĄŎčţċ”ÊĈƍŔƊLjȍɋʇ̄ˉ̆͆΃φч҇ӂԄՃքׄ؄قڈ +߄8 酈*ľŽÊİłĊʼnĢÍĂÎĐÊĕÍœ‰ƒ’ˆÇ‘ÆĘÂďǀЉ¤„œ•˽ ˆÈĎňƎLJȅɅʃ˄̆̈́ΆςЄт҄ӄԄՄօׄل݄?}}~~~󂑑~}5~ɿ‹ÍČŇƅDžȄɆˇ̆ ЅӄԆՄ ۄ?||}}~~~񁐏~}|5~}ĄÃĢÕđŃƢŇŌƖłĠ ļŇňƂŔƂǤDŽƆǜƌŢƈǖƔłŌńƒłĐŜĞŔĎŢċ–ÉĈŃƊŎƐLjȈɊʅˏ̆͆΄σЅт҆ӆ ׅڄۆT 6ý„ŽÊĊįŊĢÜĮă’„ǒÅċÃĈÄď́ŀБˆ +„ŠđÇąŌƊljȉɅʃˆ̅̈́΅τІфԅׄۄ߄K||}}}~悂}|A}|þ†ÈČŅƍdžȄɄʇ˄̆̓΄χ҅քڄC{{||}}~~~䁁~|{A||¼нýÄěÏĝłœŅƜňƂƃljƈōƣŌĎʼnƝŊƄłƗŃĄŖĄŎČłČŋĒŝĒêƒÝ‚ʦÉĆōƄNJɑȇɅʋˊ͉̉΅ш҄ӅԃՄևلڄ݄ 솅C¿ýŠúĖŚĕÏİ͉̚‚†ˆ…Å’ÂĊØđ߁‡‰ÅÏąňƋdžȋɈʄ˃̇̈́ΆςЄч҃ӄԂՅ ܄.}}~~戊~}|M~}ľʽ +‡ÄċŊƈljȅˈ̄͆΃χЄӆׄ5||}}~䇉~}|{J}|¼нÇĒÖŃƕŔƐłŇƛňƃƄLjƉƅńƪŅăńĎŌƜŎƝŕĊŎČłČņĚŚēé„Ê‚Î¦ÃąÊĂÈĆňƈljȅȏɅʈˊ̆͌·τ҇ӄԆՃևׄڅބ5쌎K¼‹áÇËĕŌĄŋĖÄÆĨ„Ʀö‚„ˆ“ÂĊâć€еƒ†‘„”ÌĂŇƊLJȈɈʈ˃̇͂΄σЅч҃ӆU}}~~~苑Y~}¿~žĿп¼„…Ä„ÄćŋƈDžȉɆʆ˄̂̈́΄φЅхՄ5|}~ 抐X}|~}ýƓłƈŢƂŌƂőƒʼnƂńƄŊƦŒƌŚƃſƄDŽƓNJƋƐǐƍŃŔƚŠƌŒĐĿŕĂÈēã„©åčŇƆDŽȂǔȌɂʆˊ͈̈·ψЃц҄Մֆׅ؅ۄAWÇŒÆĄÎĄÄĄÂćßĐÜĖÂĄĵÚď˄׃ƒ–ðа‰„„”ÌăņƉljȇɅʈˆ̅ͅЄц҆ӃԄD}}~~𑗤}~~~}}|_}|}ƿ пÂĉŋƇDŽȈɈʃˇτЇх҄Մa||}}~|}}}||{c~|{¿~|ľ +ģŃƧŃƎņƈŢƂŌƄŏƕŅƅŌƣœƊŏƄŇƄŞƂŞƄDŽƗǃƠǏƇƅŃŕƘŪƚŔĕá¦âċƄŋƇDŽȂǓȌɃʅˇ̌͆΄ωІф҆ԄՂք׆؅م܄ObļŒÄĆÎĄÄĄÂĈÜēĆÔÒŏĘüŒ–õ뀊Г„Š™‚‘‘ÆĄÃċŊƇNjʆ˅̅̈́΅х҃ӅֆY|}}~~~~~~}}||~}N~}пʿ‰ÈĉʼnƈǃȅɄʆ˄̅̈́τЄцԅՂքU{||}}}~~}~~}}||{{~}|O¿}|ƿģņƣŏƏŃƗŐƄ +ŌƂŊƉƄŕƗŅƙŖƊņƊŐƄʼnƇŖƇŒdžƈDŽƂNJƴǚƝōƤŔņƆƒǂƄǑƣňƉŅĄŒĐքĚæĕʼnƌǐȆɄȂɌʉˇ̋̓΄υЅх҃ӆքׄ؅ ܄`RŽ‹ÔĂŊĄÇĕÆĂÄėáēɊÓÞōĘĄðƒ–õꀇЈ„„‘‚Ô—‚АÎĉŌƇNjȃɄʅ˅̄̈́΄υ҅ӃԄׅلL}}~􃅉~~}}p~|¿~¿ĿLJËĈŊƇǃȄɄʇ˄̃ͅх҅ӂԄՄւׄL||}~~~􃟨򂄈~~}}||q~}|~}ēłƇŏƟœƈłƄŃƚŌƅƉŌƂŊƎŔƘńƈƌŏƂńƊʼnƇńƂŊƄŦŲƄǂƛȔǘƜŒƤō ņƆŤƌNjƜǐƢňƉŃćŇŊĒЗÂċêęŅƋǐȎɈʌˇ̉͆΄τЃч҄Ӄԅ؅ل܄[pƾŒÎĂŋăÇĕÄĄÄĂÄĖâĒ΄ƐâĈŐĪë‹ÂĊõ倇큽Дšƒˆº‚Ö…–…ãƒÌ–ƒÕĈŌƋLjȄɆʂˆ̆̓΅τԄׄ؅Q}}}~~~ 򈥯~~~}||a~}|¿~ŠտڿŒÆČňƆDžȅɄʆ˄̆΅фӄԂՄևQ|||}}}~}~~}}||{c}|{~}ńƈŒƂǚƊŚƂŅƂńƠƆńƊŨƈńƞłƄŐƤŔƏŋDžNJƊǼƜǂȖdžǖƊŘƠłĈňĐŇƃʼnƓDžȣǃȋDŽƂǖƲłĊŎčÅœÐĄáğňƇǃȔɉʋˋ̉̓ΆσЅц҃ӆԂՄڄ݇M +b¿Ǿ™ÐďÕėâĘЃ‰ëŔħÔ Ïăâċ䀆聼Ћ’ˆ‡°ƒ‚˜…ãƒÍ—„ÓĈŌƊdžȆɅʅˆ̆͂ΆςЄ؆لބF}~~ +ׁ~~}}~||Èƾ˿ƿǿŠÆčʼnƈDžȆɃʇ˄̆Άӄք׆Q|}}~~Հ~~}}||f~}{¿~{¸ňƇœƊǒƈőƃňņƨŅƈũƈŃƜƄŒƞŇƂŊƂňƈŌƇƆLjƍǺƳDžǘƈŘƞŔĐŒƔDžȣǂȌDŽƂǘƼŏī÷ĠňƆǃȔɈʌˉ̇͆΄φЃч҄ӅՆڄ݄ކR +݅hȾ£ÊĎØĖàĘ҄‚ŽÄĂÐĂäĆÂĞ¢ÄĂÕăâċހ‚灼Ѕž–†‰ž†‚‡…ª‰ÌąŌƇdžȃɉʄˊ̅ͅӄ[}}~~~~}}|q~}~}Ĺƿ„†ÄďņƄDžȈɇʇ˅̅υb||}}~~ 􆑖~~}}||{r}|}|¸łƊŝƛǘƔłƢŔƂŨƬńƆłƄŤƜƅdžƂǭƃǐƈNjƅLjƂǖƺłĄŌĕʼnǪƎōƉňƎŜĎüĠņƊLjȌɄʈˌ̅̓ΈφІц҅ӅԄՅ ۄU  pɾ–ÂĄÂĄÆďŽÙĖÓĚ̆„‡„‰ÂĐÌĤüĄÆĊłěހЂၼЄ˜˜„„Œ…Š„‚¬ˆÌĄňƋDžȄɄʄˆ̈ͅ΅хa|}~ކ󆐚~~}||u~|~Ĺѿǿ„†ÄČŇƅDŽȈɄʋ˅̅τ ՄR{|}~~  ܅񅏘~}}|{{g~}{~}øńƈŜƜǘƔłƢſńƎłƖńƆłƅʼnƆǘƐłĆƆdžƇƄǠƺłĄňęʼnƾdžƊǫƊşƏōĂŌĉ÷ĠŅƋLjȌɄʄˎ̅̈́΅φЅы҄ӆքلބN 䊞tɾ„ÂĒČÃĐÆ”ÖĜÉė҈ˆœÊĢéĉŒĩـڂ‹ˆ‚¤“ŠÆĈņƈdžȈɆʅ˅̃͋ ҄b}~~ + ӂ䀎~~}}l}|Źƿ̿‡ÅĈňƅLjȆɄʅ˅̉τЂф`|}}~~ с~~}}||p~|~{÷ŋƎőƠNjŗƑŘƄńƎłƒňƂũƕŌƂƈljƠŊƈłƉŭŐƝǃƒƇǃƑǂƌǤƄŖƆǐƐŌĂńʼnĂÜĂʼnŎĬŅƉNJȆɈʆˇ͇̇ΆυЄф҆ӈԄՂքׂ؄N +مꄑtʽ•ÂćÈ˜ÂŒÆÅąÒ„Ē߃„œ›ÈĦËŊIJʼnċńƂŅƆł؀݁Џ‹‡°•…ÇćŇƈDžȈɇʄ˄̄ͅΉф҄c|}~~ }~~~}}[~¿}Ő׿ƿ„ÆĊŇƃNJȆɄʅ˃̊Єf{|}}~  +|}~~}}||d~}|÷ŋƎŒƠNJŐƄłƒŜƈńƅƌŇŧƕƅdžƨńƖūƱƐŃƓŏƻǂƣǣŎDŽƇǏƌŌĂńĂŰĄŇıńƊDŽȇɆʈˆ͈̆ΆφЃх҃Ӊׄe + +Ȁ灑rʽÈ†Æ‡È†ÌŽÂĄÕƒÕ†Ó‚¬‚ĆËņėƜňċŋƆłՀ܁Ѕ’ƒÉ…«£„ÊćʼnƋǂȊɈʄ˄̄͂΄υЂф ՄY}}}~ τ~}}|o}|¿~}οпŠÊąņƄljȇɄʅ͆Ѕт҄Ԅm|||}~~ ΃~}||{p~|{}|;ńƄłƜŌƝǓƩŅƆńƂŌƟſƂňƒŃƍōƄŃĒŊşƴŒĨńƆřƅƗłĢłƎŔƜǃȉDžǬƂǣƌŘăŗąōĴńƉDŽȉɈʈˌ̂ͅΉφЄцԆׅh +Շp¿ď„ƃņֈ†Ë„‚æ“„‘Å©ÄĆÓņƉրځ”ƒÉˆš¡ˆÄĄłćŊƋǂȉɅʇ˄̅φ҅քg}}~~ Є|~~}|q~}~ϿпؾŠÉĈŋƃljȇɄʅ̈́΄фd||}}~~ ΃{~}}|{i}|~}νńƦňƝǔƧŞƞżƒłƎŎƄěƅņŕƳŔħŅƆřƯńƎŃƌŐơǃȉǐǨƂǠƐŖĆŖĄŎĴńƅLJȄɄʂɆʊˌ̂ͅΉφЄхԄ؄قڄ`ՈրoÍ‚ΆՉ„ɉ䘄•ȧÄĊÖŅƊӀفЍš‡ÚšÏ‚‚†ž…ÃĒŌƈDŽȈɄʇ˅̅τԅՄb}}~~Ʉ}~}|W~}ÿ}ѿп“…ÄĆÊĉŇƆȄɈʆτ҆ӂԄX||}}~ +ȃ|~~}|{i~}||ϾĽŅăņĒŇƖǛƠŜƢŶƤʼnƅłƄŎƢŌƄłƆŐćŅ ņĐŐĤŌƄŖƌńƂʼnƅŞƂŗƌdžȚǚȏǂƌǂƪǔƉǝƘŏĎňăŋĄňĂňĤŊƄDžȃɒʊˆ͈̈΄τІцքمS ψրlĽ‚–̉ƒ„›†®ÊąÃĘÇăÌĜńĊńćńĘЀׁЍ‚¡†ÒƚЂ‚‚ÒŠ‚„ÅĒŊƇLJȈɄʄˇ̅хԆ݄R|}~~񍞪~}||q}~}Ͽ’…ĆÊĉŇƉǃȄɆʇυ҄ӃԄ +ۄS{|}}~~~~}|{{c~|}|пŅĄŅĂńĒňƊǂƄǞƟśƤŶƤŊƄłƄŏƝŕƉŎďŃĆńĖŋĥōƄŗƃƌDžȚǚȐǂƌǂƘǂȑǓƎǜƚņĂńĒŇŌąŇăŇĢŌƃDŽȅɒʉˇ͈̈Јцօلk cō…›ÉŽœ‚­ÓęÃąÍĘŃĊńĆņė΀Ձ𮖐…Ј‘ˆ…ÐĊńƎDŽȆɅʂˉ̃ͅЅԄF}}~ ƃ܆ ~}|_~}~†ÂˆÈĉŋƃdžȃɇʅ˅΅τӄJ||}~łۅ~~}|{d}|¿~}ѿĠńƄǚƈņƄłƒŗƩŪƂŌƢŌƆŎơŗƇňňąŌėłƄŢƂǮLjƃǗƑƎljȂDžDŽȐljƎǓƂLjƘņğőĕŃěŏƅDžȏɊʄˋ̈͆΄ςЈф҆ՅքلZ ̇㊜¿cƏœÈ”­‰†Ž•ÅąĊÖęÚġŐėˀԁ¼”ƒĂĈԄ‘ˆ„ÒĊńƌdžȆɄʂˈ̄͆Ѕm|}~~Ɔ茝~}}a}~…¿࿆ˆÈĈŋƃLJȃɆʆ˅΅τj||}}~ Ą拜~}||_~|}ƚłĐĉŘƐņƄłƐńƂŖƪŢƍŅƠŎƆŌƠŚƅņĥƎńƗŌėłƄŦƄǼƄǖƑƒǃȄǂȄLjȓdžƌǔƃLjƙĠŐIJŏƅDŽȒɊʄˊ̈͆΄ςЇх҅Յքل 8 +ˉ_ǎœÉ¬Œ„’ÇăÄć×ęßĜŐėɀԁЃ +žƒ­ÊŠ„†Ž…ÖĊŇƆDžȆɆʃ˅̉ЄфԄ؄c}}~Ą拞~}}a~}}…뿇ˆ›‡ÄŽÇćŅƆLJȃɅʆˇ҄X||}~ƒ䊝~}||_}|| +ńƑŕĎŇƃňƗŃƆŮƘŦƟŇƞōƃŎƝōńƮņƆŗƤŋƂńƂŘƃǛƋŇƠņƆǂƬǃƅDŽưǬȊNjǎƆǎƶłĊŇıōƊDŽȗɊʆˆ̅ͅ·σЄш҅ބ:# Ɉ쏢[lj’ÔˆœąÏĄÌěÑĆÊĆłĄņįǀҁИ›ƒÓ†…®Ìކ‰ØćŇƅDžȅɇʃ˄̉̈́Єn}~ ㉜~~}}b}~û࿂“ˆÄÇĆŅƅLjȂɆʆˆ̄ ҄ׄ:|}~~ማ~}}||[~|¿}¾ŖĎņƆņƖńƇņŌƂŚƖŦƚŌƞńƄńƄŏƝŌƸņƆřƅńƘŭƂǛƶŇƞǂȓnjƮǮȋǐƃdžƆǎƳŅĊđƑƎŌƅljȘɊʇ˅̅ͅ·σЄш҅ބ0ꍠ[ȇˆË”Ó‰œÉĆÄĥÏĆÊĄŒĕłĔÀсА‘…“ë‹ËŒÚĘʅ†¤ŠÖĈŇƄDžȅɆʆˆ̂̈́΅σЄB}}~~& Ԃ~~}|Y~}}Ñ„’”ŠÇąņƃdžȄɆʇ˂̅̈́G||}}~~' ҁ~}}|{W}|¿|‘ŤĞłƋŌƛŊƂǐƐŧƎŪƃŌƇłƄœƔłƖŔĜŸƖűƂŋƎŌąŅĉōdžƅǓȫNJȌNjțɘȊdžƇLJƄǣƑŊĂņĂńĄŋđōƇňƌNJȕɈʇ˅̅̓·σІц҃ӅJ%چ]ȑ‚ÆŽÅďÆ‚†‚Ē•ɎÅăÊĄÜĄňĄŋą€ρЇœˆ†„†®ƒ”ê¡åĐׅ”ŽŠÉćÌĈņƇǃȅɅʆˆ̂̈́΄τЄB}~~~Bɋ~}|¿\}Đ’’‚ä‹ŒÈąŅƄdžȅɅʆ˂̅̈́΂τA|}}}~~:NJ󎟤~~}|{W~|¿~ÑąŅăŦīŋƛŊƂǖƄũƉŽƇŌƃLJƓłƕŕĈņƎšƃdžƄǎƈŐƂDŽƃǡƂŐƍōņċňƂDŽƆǔȪǡȥɐȖdžƄǔƂǎƐŊăŅĂńĄńăŋĐŎƆňƌNJȊɆȌɈʆ˅̅̈́ΆφЅӅԄՂքADΏYɑŽÃćąNJŠÔ„Ð‚ÅÊĄÆĄâĂŗρЗ³ œ‚ࢌċ„ʂȈȘÄéĖՑ•šÅĆņƇDžȆɅ̅̈́ф ؄*}}~~~4םυ$~}}W}}Œ¶†Ò‚Ù“†ÆĈńƆLjʄ˄τ4||}}~%՜΄~}||¿Z~||úҼĂŠĆņĂŔĔłƈʼnćŜƂŠƄǮƂńƂŐƄNjŎƇǛƈŇĄʼnĂńČŔƄŔƴǂȝǣƔŏăŌƚNJȂɊȂDŽȊǂȈLjȈǘȮɖȖǑƃǔƌłėŃąńĚŃƋőƅǚȄɆʆˇ͈̄΄τЂх ք31ݡՉ X¿ʘ‚‚Ҋχƒã„ΈÈĂÇĈëĈḈЗ ›‘Ȇʦ‡ÆŒÆČƝŘÎĂşăÆĒԑ•ŽÇĆŇƇdžȇ̅̈́ф ؄$}}~~,.߈~~}|W~~}Ə ´ˆÑ…Ú”‡ÅĈņƈDŽȄɂʄ˄΄8||}}~݇}}|{Y~}}|ėμŢĂŞĔłƈŊĆŽƆǭƂńƂŐƄǐŏƇǛƈŇąņĆĊŗƄŐƵǐȉdžȇǥƏņĄłĄńƓLJȆnjȆɌȆǜȇljɌȏɂʟɃȆɒȔǒƃǕƢŇĜłƌŇƂňƘǎȇɆʆˈ͈̄х҄Մւׄ1%匞 +X¿ˈ„†êˆ„΍ ÅċäĎÇẤܿˆ“Ë’ÉċÃēʂ„†š¡ÍÄąÒĠÓĂńĄŨĔ̖’‹ˆÊĄŊƆLjȄ̄ ҄ӂԄM|}~~~;~劗~}|L~|¿~Ǿ»“‹ŠêŠ…ÚƎԆ„ÇĉņƆЄф҂ӄK||}}~~~C}㉖~~}|{V~}{}Ƽ +ֺĂÓăØĜŌĐńƄŐƃǑƊŒƂNJƄǐƉŅĆłđŮƋǓȌǑȉɋȅɑȊǂƄDŽƆdžƄǚƆǠȎȄɅȒɞȑɅʃɄʨɔȌǖƊǎƓŜĭŊnjƌLjȊɄʊ˅̇ͅЄׄ؄0"뎜(Q¾̅ÂĆԄčℌã“Ê«ÇĂÉɂˁŽА¡Ã’ÑăÊČ勈›ÐĆŪĔÏċłĄŨĚʒˆÊĄŋƇdžȄ̄ ҄ӂԄN|}~~~5鋕~}}S~}Ⱦ›…Þ‰Š‹Î‚ƈ҂¢ÆŽÔ††ÈćŇƅDŽЅӄ@{|}}}~~9芔 ~}||Y}|~ǽ׺ăßăÐĈÕĜŌęŏƅǏƄşƄǏƋŃĘůƈǡȃǒȑɃȊɌȤnjƂLjƇǛȐɆʪɔȎɌʂɅʧɚȊǕƍǐƒŋăÎĮŔƊLjȊɄʊˇ̇Єт҄ׄ؄قڄQDLÄĉƄÛ҄‡ãÎ®É͂ˁЗ™‚ÖĂæŔĜąÚʼnÖĚŇĕŌĆØĔŧċˆÌąŋƇDŽȄɄ̄ЄфԄ-}}}~ +G㇐~~}|V}}ɿ „ë—Ò‚¸¥ÃčÔ–ĚٞÇĉņƅ +˅τ6|||}~ + +ᆏC}}|{¿I~||LJѺĆÔĄÊČÄĂØĊŊĄłĘƅƍŐƈŝƂǕƆƆŸƐǂȖɂȥʔɜȄDžȃǚȅljȖɚʇɕʌȔɛʤɋȂǐȎǂƞǓƓŐĘłĆņėōƆLjȌɈʊˈ̄̈́ +҄քVS銔Q΄ŊĘÆčӌ‰‚ñ…à‚Æ„—ÉԂȁЕƒÈĂŮďąŏČÅİ‹ÔĤńėũĔŦČ’ó‘‰ÊċŋƇDžȂɄ̅І6|}}}N֚ق~~|S}}ɿλŒÄ‚΂Ą¡ã…„‡•ĊÂĔÐĐ̱צÈĊŅƅ +˅΄҄.{|||~[ԙׁ~}|{L~|¿}ȎĆÆčÓăÇČÅĂìĞƕōƐ +ƎǃȈɂʮɖʎɋȆɮȂNjȔɤʃəʨɔʦɌȂǒȭǑƐŎĞŅćċōƅljȉɋʌˆ̅̓΄҄Մ8 +Fܞ߆V¿ŋċÄăËĂÄćÕ‡‚‰‚‚鉗Ä؂ȁЈÃĎŚĭůĂÐĊÈĂńēłƅŌƈŖƘőĄ÷Ĉň”ϊ݉†ÉċŊƈDŽȂɄʄ˂̆D}}~~~l~}L~}ʿԻÿ†ÂĘ’ÜĐˆú•ìĂőĝÆÉŒÆ‘Ï›£‹ÎĄňƄ ʄG||}}}~~d󅈈~~}|F~}~|ȽÄĂÌĂÌČÈĆÄĂßĔŃĆƛƐƃŏƂDŽƉnjȃɎʚɒʂ˙ʯɂȐɊȈɂʄɒʄ˃ʏˆʝ˗ʐɄȷɇȆDžȄǓȏNJȝljƐĠłĎłĈŊƐdžȉɉʊˈ̄͂΄ф@dÍM¾ϵĐʂĄƕŠŠ„ϚÈċ݂ƁЙœŠÅďŘČŊƛʼnŹÌĘřƂŠƖŐćôćʼn—ÌŠÞˆ‹ÊĊŊƈDŽȂɄʃ˄̄C}}}~~i〄~}}C~¿~ʇֿ„ÆģãĂÄĤDގˉĄÜĄŐČŏąÂąČڄȄʛ  +ŠÎĄʼnƃDŽȄɂʆC|||}}~^~}||D~}~}ȽÆĂÊąËČÈĊÄĆÛďŃČŠƆŮƶƆŊ +ƈNJȅɏʓɌʋ˚ʉɂɗʛ˂ʎ˂̐˖ʐɇȴɇȅljǗȌNJȝljƐłĠƝŊƐNjȉɊʊˈ̄͂΄τЂцBp郈Cϱ +ĉɎĖ–„ΘÊċŁЕ†ˆ’ŠÅĮōƃLJƐƝłƈŔďšƆDŽƐdžƋȊNjƑŇđÂĆäĂņđǜÔٍ…’ÊĊŅƇdžȃɄʃˆ̂̈́D}}}~~~l“~~|E~ʾ콞ŠËčÊĄÆĎŐĂËăÌăÍϐÎĂŇĉłČğʼnƌʼnčт—dž”¤„ÌĆńƅDŽȃɆʄH|||}}}~j~~~}}{D~}¿~Ȇ ÄÉčÆğČÔĂŅēŃĊšƄŤƢłƮŚƂǢƄňƐNJȄɐ˟ʎ˄̆ˏʃˌˏʄˆʓɏʢˆ̄ː̆ˊ͇̋ˑʇɑȂɆȢɄʆɑȇǜȮnjƜŐńƊņƈŒƈǑȋɊʄˈ̅̓΄τЅԄ@rȗ􂃃E¿æĊņĈƔʅŽƒ††Â™ĘÂĉÁЕ‡‡†›‰ÅĐłƏŃƄƇōƅLJƍńƉņƉŋƆņďňƄDŽƚǂƒǂƌdžȌdžƍňďÃĆÙňĄňďǜꑈÅĊŇƄDžȄɄʆ˃̄E}}}~m}}~~~}D}ÿʾ潚ٿ‰ÍĆÚēůĂŇĔÏĢƅŎƋőƋŊĊò—ʘ§‡ÈćńƅDŽȄɆʂ˄D|||}~~u||}}~~~~}|¿=~|~ȅÄĄÇďÅįÐĂŅēńĊŚƄłƄŞƂńƢłƋŃĢřǐƂǑŊƐljȄɑʂˎʊ˅ʍˆ̌ˈʄˈʋ˅ʌˆʄɄʂɐʆˌ̂ˮ̂ˋ͍̇̅ˌʈɏȃɆȘɃʇɄʈɏȇDžǖȩǓƘŒŅōƂœƇLjȂǏȄɋʆ˄̆̈́΃τЅRlEàĄčńĈƔÌŽ„„†Â˜ĠÁЉ•ŒÉĒşƗǕƂőƇdžƆňƆǂƄƅǎȆɄȊɘȎǏȅǃȈLJƊŲąńŘčǂ҄Ąâ½‡ÄˆÈĈńƄLJȃɆ̄G}}}~~~|}}~~}|A}˿†ÛćŌĊʼnƉńĆŐĎŎĐņƖDŽȋƋDžƄŤƇʼnĊ”ɝаˆÆĄŇƃDžȅʅ +Є:|||}}}~t{||}~~ +~}|{¿<~|ɡ  ‚ÄŽÆąÆĒĮØģŋƂŊƒńňĂŋĔšƏǕƌnjȉɅʂˊʟ˙̔˂ʐˉ̅ˆʈˏ͙̋΋΅͈͌̆̚ˊʲɆʄɂʒɌȉȅLJȂDŽȅǃȡǽƊʼnƍňƃŌƉDžȄLjȈɇʅ˄̆̓·ф +ׄ.~AЇĊńĒŊƂŎćÃČʂȄ‚ć–¥Äđ‰Љ +ƒÆˆ‹ŒÍąłƊŠƚǢƎNJƄǃȉDžȏɅʅɉʕɅȄǠȅLjƊńĐœđŗĎΆ„Æ䦕‡ÈĈLjȃɆˆ +ф.|||}}~|}~~~}¿7}}˪†ÚĉŅĈŐƔņĐńƋĈŐƌǜDžȐǢƃLJƆŊĠĨЬˆÆĄņƃLJʅτ/{{{||}~~~{|}}~~~}|9~|¿|ʇ ›ÃØĢņƅʼnƒńłĄňĂŌěřƇǃȆǔƌnjȍɅʃˉʟˏ̂͊̄˄̖ˎ̊ˆ̆͆̆͌ΈτΊϗ΄̤̓͆̈ˌʂɒʑɓʒɎȎdžȂDŽȆȇǂƚǨǕƈńƏŃƆŎƙLJȈɇʃ˄̈͂ΆςЄE™;¿ĪŊƆŎĎǂȄŒœ„¸ƈ݂ЄŠ…ÐĊţƓNJȔƋǒȂɇȏɄʂˆʈ̅̈˅̒ˈʜɂȈɈȂǎƆōńƐŌƐĆŎƹɉɊ£™…ÊćŃƄDŽȄɆʄ˄݄̄|}̛|}}~~}|¿3}ÿ~̕о‘ÏĂōąĐŅƆńƃLjƕŊƅdžƍǂȄljȍɎʂɈʒɎȗǃȆDžƇŗĂŭĖҏˆ†ÄĄńƄdžȅɄʀ{|ʙ{||}~~W~}|{8~|}ʄǧÄĺÇōČʼnċŃĐŦĜņƄŊƘǂƄNJƋDžȐɊʢ˄̂ˈ͉̃̊̈͠Ή̈́΄͐΄όІтЄцІђЊϥ·̓̎˅ʒˎʒˏɆʎɅȂɅȉljȈǂƄNJƒǾƃŅƔńĒŇƜDžȊɇ̅̓ΆυЀџX:ĖňƃŅƈņƍőċˌ—†È¾ÃŽ܂ЅЇÏĊţƔNJȜNJȅɅʈɆɈʌˡ̂ˉ̇ˌʄʒɃʅɆȆǣƂŞƕŕąÇŠÈ‚£š†ˆÈĆŃƄDžȃɇʄׄ؀ܞ|}}~;~}3}}̕ “ÍĂŏčŇƅŅƅLJƇƆŊƒdžȂDŽȂɉȅɌʆ˄ʂˆʆ˔ʈɚȂLjȈǂƎņČńĂŔĈŋÆĎҎ†‡ÅĂŅƄDžȆɄʄЄрڝ{||}~~G~}|¿1~|~|˄ǦÃĖÄžÚĈŖĈłƈńĵĎũĚņƄŊƘǂƄNJƊLJȎɋʢˎ͈̃̄Έ͖̊͌΄υΏτЂцЄхґғчБϏ΅φ΅͇˕ʕɅȇNJȇDŽƃǏƑǾƄńƐńēœƂdžƈLjȈɆ̅̓ΆυЃфׄ؀H5ÿѕœƇŃƓŔċNj—†È®Å‹ÃŽւЇ™ŒÎčŞƏǎȒǏȆɍʌ˖̆͆Ί͂Έͅ·͈΂͈ʈˈʂˆʆɆȄDŽȧǓƂŋƉŒĔƂ‚»ˆÅĈŃƄDžȆɄτӄԀ蛹|}~~E~}|5~|~ˑŽÜĂńċōƃǣƅǍȈɐ˅ʊ˥ˌ̄ˆʢɈȆǘƈŃƛŕčÍ„ †ÇĄńƅLJʄ̈́҄ 暷{|}}~~!~}|{¿7}{¾}ɾÐ‚Ä¯Ø’ÂąËĉŖĐŐĆłƎłƴńăŚĞŋƑǙƈnjȎɌʞː̏͏̐̈́ΌψМхҔҌӂҌӄ҆ѠЈυΆ̠̓̅ͧˈʒɔȆƆǍƍǻƚʼnĐłƍŅƆņƆLjȅɈʃ˄̄ͅ΅τхلڀB…4БŘƅŃƔńƆŔĊƎ“‚ȪɆŌÅՂЈš†Â…ÍďŇŔƏǎȈǖȄɈʊˌ̖͆΅ϋ΂ϖ΂φΈ̠͂ˈʇɕȜǒƂŌƈŒĔÆ„Ž»†ÆĈńƄDžȆ˄̃̈́ ҄'|}}~ ~}1~¾~ƑÝĂŅĊŌƄǗƐDŽȊɈʐ˂̊˄̇͂̎̓̇͂̌̈́̆ˆʂɈʂɆʆʆɉȅǃƄǐƃŏƓŌŇď܃‡ÆĄŅƆDŽ ˄̄Єрߛ{||}~~G~}|2}}ž ׄåڙÉĉśďŒĕńƴłĄŚĜŌƏǗƈdžȂDžȍɍʞˏ̗̐̈́ͅ·χЈѝ҇ӆӅԇӆԆӈԃӇ҂шЄєЊφΖ͉̃͏̃ˇ̕ˈʒɔȆLjƆǏƊǻƗŊĢłƆņƈdžȆɈʄ˄̄͆΄ςЄӄԀ样R‹Çƒ¿-ˑŌƂŊƄŅƏŅƎœąÈ’Ž’ǫʂȄĄÅςЂŽ†ÆĉʼnƄŚƖǔȈɂʆɆʅ ͅ΃φΊσІϋІЊїЌσΊ͔̎˄ʈɚȔǓƊőććϞ”ˆÉćŅƆɄʂ˅̄τ֓|}~~+~~|/}’ˆâċńƅʼnƇǂƊdžȄLJȅˆ͖̐ΛψΆχ΍˄̓˄ʏɄȒnjƃdžƐőčهŠÆĆń ʅ̈́Մ Ԓ{|}}~&}}{.~|¿~Êì”â˜ňĄŒČłƏœƃLjƃńƐłƐdžȆɈʌ˂ʚ˔̈ͅ΅͉΅φΆτЄт҆ӊӉԓ՚։Մ֊Սԃӈ҂ь҆юЅϓΒ͔̔ˊʐɇɇȏǞǕƎŐƄłƔŐĈĘŎƅLjȉɇʅˆ̂̈́ х)ܗ-…ÑĄÄ€.¾ņĈŐƂŊƂLjʼnƘņĂʼnĄɄ‡†ŒÆ«à‚Ä͂ˆ†ÆćōƂŚƖdžȆɃȈɇʄɆʄ˄·ϓГљҗэЂωΒ͇̎ˆʎɒȔǓƋŐĆÂĆкƒˆÌćŇɄʃ˅̄͂΄πˋ|}~N}}¿/}¿’ý‡ÇĂœĎłƍŇƐLjȂɆȆɄ͍̇ΙχюхІϊЇύ΂͈̄ˈ̇ˏʆɇȘdžƂńƏőĉƂЇŠÅć Ʌʄ˃̄!߄ʊ{|}~~&~||.~|~Êì”â˜ňĒńĐłƎŞƅŃƐłƐdžȆɇʩ˖̆͆΂͈Ή΅Ѕӆԍՙև؉؅׆֊׆֎ԉӒҐфЈύΑ͖̒ˊʐɆȂɆȏǻƎŐƚŐĈČłƇŐƃDŽƄLjȌɅʈЅу҄#я-„ÄĎńĄÀ+ʉćŜƃǒƜňĄÄ„Έ„‹‚ĬæƁȂЈ†Ã…ÄąŜƇNJDŽƐǃȉɇʎ˄̂̈́Єх҄ӕԂՉԕՂքՎԂՇԇӆ҄цЋτΎ͍̇ˆʇɉȖǐƎŒČʈˆ†ÊČDžȃɄʆˀၿ|}~X~}¾+~}ŋ‘н„ÎĄńĩňƃNjȉɂʄɄʂ˄̄υЃэ҂ӈҌӄԈӈԂӄҍӇ҄хЅφΐ̈́̈ˇʅɊȉǎƘʼnĒωҿ‹ÅăńƄǃȅɄ؄قۄ܀߀{|}~~2~}|)}ÿ|Çß“͂ܔêĈÅÈÉōįŢŇƌńƄǂƆdžȃDžȄɄʜˈ̈˄̂ˏ͈̅ΆϏЄт҄օ׃؍قڇٍڄۂڄڈَڇل؅ׅֆՐԄӎ҄т҆цІϊ΋͕̋ˎʒɌȊLjƄłƆńƂńƄńƂœƆłƎņƖŐĂńĜŔƄnjƄdžȊɋʃ˄̄̈́΃φЀĆ[ĄŒƄŀ,¾ńĄņƎǓƃNJƂŊƐŅąÎ„„†…«é́ƂЈĄÄĆśƇǎƐDŽȅɈʉˈ̄͂΄ф҄ӄԊՌւ׉֙גֈՇԅӅ҅ъЄϏ΋̄ͅˈʆɈȖǂƄNJƏőČʈŽˆÍĉńƅǃȄɆ؄قۄ܀舍}}~6…~}|'~¾}ʼnš…ÉĴʼnƃljȇɋʄ̄Іу҄ӔԄՄ֐ՓԌӂ҆фІϐ΄͎̄˂̆ˆʄɈȈǎƘʼnĒω쿜ÄĄŅƃDŽȅ τڅۀ燋||}~2~}|{¿)}|ćâ‘Ï‚áêĈÄ ĄÈĮłĒŎĮŦŇƌŋƆȄǃȅɅʛˉ̇˕̅̓ΉϊЈф ׄ؅كڕۈ܄݂܄܇݃܊܇ۇڂن؄׆֊ԅՃԍӌ҅хЈφΌ͚̊ːʐɌȊLjƅłƅńƏƄŔƄńƎňƖŖĜŔƄǎƂLjȌɊʄ˄̄̓ΆքڄۀCŅƎDŽƀ)ʊŋƒǐƄǙƍńąÏ„„¬éӁ‚Ѕ„ÆĈŎƂǔƌdžȆdžȂɈʄˇ̅͆ +ӄԂՄքׂ؄ق؆ڌۂ܄݆܄݈܂ۈڄقڅى؄׈քՄԂӐ҅ьЇσ΄̄ͅ˄ʆɊțLjƑʼnÈĊʘ…ŠÒĄŃƄǃȅ ̈́Є ׄ؀~|}~9Å€}}¿&}~ƇˆÐ‚‹󼎽‰ÅĒŃĒŕƄǃȈɆʄˊ ҅ӃԄՃ֋ׂؑقڐۇٌ؄ׄօՆԅӄ҂ыЂфЅϐ̄˅ʆɃȇǘńƄƉņĄÂĎЊ…Ã‰ÃĄńƄDŽ̅υЀ}{|}~~C‡~~||%~|¾}ćæ†Þ‚ӂɏ×ĂËăÆĄÈĐÌĊłĞńĊŒėŌƋŤƆņƎʼnƊDŽȆɇʇ˂̄ˆ̒ˈ̊̆̓ͅ·τЇтҊ مڂۄ܃݉ބ߈݆ނ݄܇ۅ؋ׂ؄ׅ֍ӄ҄фЅυΏ͛̈ːʒɊȊǘƒŔƅŌƅņƔŗĐŇČŇƅŏDžƈNJȒɄʂ˅̂ͅ Ӆօڄۀف:ńƃdžȄɇȄǀ%ˇŌƃLjȏDŽƂnjƂŔƇŅĆΆ“ĄЦÍæƒفЅ…ÆĈŌƆǎƈnjȂLJȃɆʅˆ͈̃ ԄՂքوڄۂ܏݂ޑ߆݅ۄ܅ۉڂى؃ׄԏӆ҄тЄш΄̈́̄ˆʅɑȗLjƑŒċÊ”ŒÆĂËĂŅƂDž +̅τЀ܂}~|}~H„ÊąÀ~~|(~|¾ ŠÄƒÍŒպ򼏽ˆÆĒłĒœƅDŽȈɅʄ˄̇ ӅԂՄփ׈؅ڇۊ܂݄ގ݅܅یڄل؅ׇփՅ +҄т҄цЊφ΃̈́̃˅ʅɄȈǚƎŇĎЎ„ÃĄŅ ˆ̈́ ӄԀځ|}~{|}~;„}}{ÿ}{!~ćŒ‚ӃȎÎăÅĈÆĄÆĂÊđËĊěńąŗĒōƈŢƊŇƇłƈŌƅDžȆɈʆ˂̄ˇ̍ˋ̍͂̅ͅ΂ψІф҄ӆ +چ܄ߋ߅߅ކ݄܄ۂڈل؆׊ֆӄ҅цЂφΐ̈͘ːʒɊȊǕƒŔƅŌƅńƕŗĐʼnĖŖƈnjȆɂȊɃʅ˂̄̈́ ҅ԅՀᆼJDŽȎɄȄǀ$ÿŇDŽNJȄǃȉNJƄŔƆłĉυÎ£ÊŠæƒځЅýˆÈąňƠǒȆɄʈ˂̆̈́υЅք ۄބ߂߆ކڄن؂ׅօՈӈ҆уЄ͊̄˂ʆɑȎǏƍőčÅ̎†ÄĄńȄɂʅ˂̅̀|~|}~I„Äďŀ~|¿$~LJ–È¢纇񼊽‡ÇėœƏDžȅɆʅ˄̂̈́ЄԄՄلڅۄ܄ބ߇ރ݅܄ل؅ׄփՅԅӆ҇уЇτ΃̈́ˉʄɃȉƆLJňƈŒčłɒ„ ƅǂȄ˄̂̈́΂τЀ{}~{|}~>…ÈąÄ€~}{}þ~ŎŒՂ„„‰ÏćÂčĆÄăÑČÌČłĆńĉČŔĜŤƈŊƄňƂŅƍňƃLjȇɆʈ˞̉͋΄υф҅Ԅׄۄ܄ ߆܆ۄڄه؃ׇ +҉фЃω΄̓·͆̂͆̎ˎʐɍȅȌǎƓʼn +ƉŏƐōĄÅĂÎĆňĔŜƙDžȄɄ̈́΂υЃф +ք׀>ȄɄʊ˅ʀ"̇ƋǕȈǞƅńćáŽ⿇‚ƇǜÆÕɅ‚؁ЅŽ†ÇćņƚǒȊɄʆ̄҅ׄͅ܄݄ ߅܅ۆ؄ׄֈԇӃ҇ф͉̃˄ʈɄȃɇȆȅǐƋœĎĂ̍…ÅDžȂɅʃ˅̂̈́΄π׆}~}~~DĄōƄŀ}}} ¾LJ—LJ溈ѼˆÈČłƅŔƎdžȅɇʃ˄̄քۆބ߄ބڄنքՅԆӂ҇уІυ̉˅ʂɄȎǐƆŔčłɓƒÄăńƃDŽȄɄʃ˄̀Յ|}~|}}~KÈňĀ~||~"|Ƌ‹ܹÖˆ‰ÎĈÂĔÄăÓĆÍċłĆŃěŐĠŢƑńƃňƂŅƍŇƄdžȇɇʆ˙̍͏΅υІу҅ ؄܄݄  ބ݄܄ۄن؃׆քӄ҈ψ΂͆Ά͆̂̏ͅˍʑɎȄǂȌnjƟŃƇŃƌŌƏōčÎĉňęŧƑDŽȄɄ̄͂ΆςІӅԀ݉BɄʆ˅̆ˀ"ÿ̇ƊǖȇLJƂŖņĆäŽ࿐‚Æ„ +¢ç†ՁЅ佒ŅÉĉŃƌdžȆǐȈɆʄˉ̄̈́Єׄ ߅ڄق؈Ԇӆ҆΄ˊʇɌȊDŽƔŖĎƂȌ…ÆLjȈɂʄˀꗳ}~|}~KƅLjȅǀ}}~Dž‚“ƇŠĊœDŽƊdžȄɊʂ˄̄Մ +߄݅؅ׂևӅ҃цЇ̈́ʅɅȉǏƅŐČȂÌ’„ÃĄņƆǀ薱|}~{|P}~ÄĄŌƄŀ~||¾}¾Ƌá„……ˆÉĝëĆŒĈńƉŃƌłĕŅʼnťƍňƇłƋņƋDžȈɉʃˍ͇̆̑ͅΆυЈу҄ӃԄ ݅ + +߄ބ݅څك؆׆Ԅӂ҄тЊχ΋͈̄˕ʕɎȆǂȈNjƩƌŊƌŎĒÊĂņĮŒƇŏƍDžȅɃʄ˂͈̈΀Ȑ̀!ƄǂƊǒȇdžƃőƌňĄäˆ†¤ã‡ҁЅν˜ŅËćńƈdžȆǐȈɆʄˈ̅؅ +ۄڂمՅԃӇ҅τ̄˅ʊɉȉDŽƔŖĎƂȌ‡ÄĄłƌDžȄɀԁ}~|}~NdžȅɆȀ~~}‚„ˆΚ ŽÂċŗƊdžȄɆ˄̄օ +܄ ބׅӆ҆цʊɆȆNjƆŐČȂВ„ÃĈʼnƀҀ|}~{|N}~ĄńƊDžƀ}}~|Ƌㅄ‰„ÊÅĝÕĂŎĂńĆŒĈņƆŅƙūƄǗƌŊƆŃƊňƌDžȉɉʃˌ͈̆̑ͅ΅τЉт҄ӄ݅ ߄ޅچن؆ԄшІψΊ͈̄˖ʔɎȆǂȈNjƭłƍʼnƈŏĒÊŇįŏƋŏƍLJȄˊ̆ͅ΀ڄO͎΀ ¾ƄǂƊDŽȂLjȎdžƂŒƊŊąà‡ˆÂ¨ä…ρЏ§ˆÇďʼnƔǒȇʅˆم &ׅւՅԄЅυ΃͆̄ˈʈɃȇǎƐœďЌŠÍĈŀ܇}~}S~ɏʀ~}ÿ~ÿlj†Ä‚ÐŽȺ ÆČńƂŐƌdžȄˆօ ބ + ՆԄӃ҄τ΄̈́̄ˆʆɈȅdžƉŔĈʂ͓ +…†ÄĀۆ|}U|}~~DžȈɄȄǀ}|}ſ†Ú„„Š™Ä„“ÎĂńĄŃĉŎĘłƄőƆŃƄŘƤǦƄńƊŊƊLJȇɍʋˎ̊Έ͆΂τІт҆߅ ܅ۄڄքՄԄӄ҅хЉυΆ͇̋ːʔɎȐnjņƈŒĎÔęŃěņƑłƅŌƉNJȌɉʀ⊚Q΄όЀ¿̊ƇdžȄǂȐǍƃņƈŎē΋̿†œÂ”‚Ǻ°ˆÈđʼnƓǑȇʆ˅̂ͅڄ" ڄق؄ׂքՄфЄτ΄͆̅ˈʅɃȇǎƐŒĐЍ’ÄĀナ}U}~Ʉʌ˄ʀ~}¿~‚̓ȺÆčŏƌdžȄˆ؅߄ֆՂԄφ΄̓̅ˆʅɈȅDžƉŔĈʂ͑ƒ€₉|~U|}~ȆɄʆɀ~}|}ÿŇ„×ˆ˜™Ä‹ÃĄÎĂńĄłċʼnĘŔƄńƂŒƨǰƆŌƉLJȈɑʈ˓̒͆΂υЅт҆ބ ݅ڄֆՄԂӅ҆хЈτΆ̈́̎ˈˇʒɐȐnjłƈőĐÓčĊńĜłƠʼnƉLjɉȄɀ重VτЊфЀ¿ŊȌDŽƆǏƅńƇŋĂÄĘɉ̿†·ʁНƒÙ‰ ŽÅćŃĈŋƅƌljȊɂʆ˄̂̈́2 }~~~~~}|/҆τ·̈́̄˅ʈɂȅljƕōēӐ…„Œ}~}Y}~˄̉̈́̀~|¿}¾‹ÆĆłďʼnƅLJȅ˄% + |}~~}|!҄уЅ͇̅˅ʄɆȅǃƋŒĈЄˆ|}~|~_|}~ʍ˄ʀ~}{~|Ňм„”ÏĂńĂŊđŇĉĐńƂŭƅǃƌǂșǐƄNJƂǠƆǎȄɈʃɇʋ˕͈̊΄φ҄2 ߄ׄԆӅ҅уІφ΃̈ͅ˅ːʌɓȓǐňĝÑĊłĎłČŅĉŖćŋƅNjƄnjƀZх҆ӅҀ¿þōƉNJƉŃƈłƊŇĉÉĔˈ„ÆĬȁЕ‚ڍ† ŽÅĈĈŘƊljȉɃʅ̈́ф|}~ +~~~~~} |+Ԅӄφ΅̃ͅ˅ʇɃȅLjƕŌĔӐ}}\|}~̅͆΅̀}}¿~ĿDžŠÆĆłĖŊƇDžȅ˄4 {|}~ +~}}~~}}}| {"҅х͇̅˄ʅɅȆǂƋŋĄÂĉÏŽ|~|~[{|}ʄˊ̄ˀ~||}¾ŋ©‘ÏĂńĂŊĒņĊŃČŅƂŨƆǂƄƍțǎƆLJƃǠƆǎȅɑʋ˃̉ˊ͉̉΃φ҄% +  ,ل؅Ԇӆ҄фЄφ΃̉ͅ˕ʋɔȓǐŋę×ĉłĎłČŌĂœăÅĈśƋŀ]ҎӀ̆Ň LJƢňĊÈČÅȉ„ÊĴĀŁ‰‚„ŽÄČōƃǕƉdžȆ҄:|}}}~~ ~D|Ѕτ΄̈́̅˃ʆɄȅLJƇĄąņĖ˜~|~b|}Ύπ}|}Ɖ†ÎĎʼnďņƅǃȄɂʄ +Єք0{|||}}~ ~}{4҄Ά̓̆˃ʄɆȃDžƊňĐȗ}~{}~_{|~͇̅΄̀~|{~|Ŀ҉ĊÐĈňĚłĕʼnƃŎƑNJưǂƚDŽƈƅƎǎȄɌʌ˄̑ˊ̆ׄͅ?@Յԃӆ҃хЄτ΄͊̇ˑʆɖȄǓƜłĶňĕÜćŖĄŤćÍĐņĄĆŀaӄԋՀˊŒƄņƓŃćÃĘȈƌƒÇžÆăÐĔÃĄÖ„äҀāЂŠ‚„ÆŒÄČŎǙƈdžȄ҄@}}}~~~~~}<хΆ̓̅˃ʅɄȊLJƉńăŇĆҕ~~Y}~΄ϋЄπ~}~Ƌ†ÎĎŊďŇƄʄN|||}}}~~I~~~}}}|||ῠ˂ʅɅȃDžƌņĐȗ}~}~a|}~͏΀}|¿}ŇŠ‚ÄŒÃĉÐĈňčłƋłĖňƄŌƖNJƆǂƨǂƧƈDŽȆnjȄɌʌ˄̖ˉ̆ͅL6ڄօӆ҂фЅσ΅͉̈ˈʄɄʆɆȒǔƟńĵňĕÝąŘĂţĎÍĄŅŕĀ`ԄՉքՀþńĆŔƂņƑŅĈĘɉŌ„ĝαŊĈÄĂÅąÔ„ÆÍƒڀЄƒƒÂĄÌėśƈDžG} ~~ +2~}|ׄ҄ῡɈȆNJƇŎČÚ~|~\}~ъҀ}}}Ŀ +¿„ˆÈăÌńęʼnH| }}~~~4~~}|{Մ +τ΄̈́ɄȄNJƆŇČÆ}~{}~X|}~όЀ~||¿~|¾Ŋˆ–ÃČÒĄňĉŋƚłƎłƄňƖǃƆDŽǐȂɄȌɆˏʘː̅X6܄ +քՃԅфЂτΈ͆̊ˇʍɌȄǂƌLJŒƖňąłĨŇėÆčőĄèĎÊ¢ÃđÄŀZք׆؄׀˅ďŕƌŒĔΆÌ†žÌĈŦĆʄ†̂‡Ѕ”ÔĆłƒŝƈa}}}}}~~~~}*؄ фЄʄɈȅNjƇōČăš}|~R|~х҆ӅҀ~~~ƅ¿‚ŒÇąÑĒņƄZ|||||}}}~~~}|6ф΅ ɄȅLJƆňĊnj}{}V{}~ЉфЀ}}}Ŀŋ„’ÆċÔʼnĈŎƘłƎłƄŎƠǔȔɆʂ˒ʜˈ̆VĽ +,݄؄ՅфЃτ·͇̉ˇʍɌȄDŽƊLJƂőƐōĄĢňĘÅđŎĄâĐʈ’¹͆ÀYׅ؄م؀˅ČœƍŒĄŠÎ‚Ô†ÈČńĂŢĂʄ…͂ˆДŒ”ÌČŃƩŅƍe|}ɶB~~}|ф΄͂̄˄ʅɅȄNjƋŋČɘ}}N}~ӌԀ~}}½ƅ’ÈĉÉĄÆĈÈĆŊc{~|ȵC~~~}}|{τ̄˃ʅɃȄDŽƉʼnČȎ|~|~L|}~ф҆ӅҀ}|~| ŏ‰ÉĂâĐŐƄƆńƅŊƍňƋnjǔȌɏʅ˧ʆˌWϻ\хЃυ΄̉ͅˊʋɌȉǗƅŇƏŔćŃĖŎĎÑėņãĔʼnދdžMٌڀ¿ˍċʼnƔňÆĆ„Č֐Ä†ÈĬŔĈʂ҃‰В‘”ÈĔŃƝňĆńƈ`|~DZׯB~}}}|΄̓̄˄ʅɄȈLjƊŋčȘ}~|~|K~ԊՄԀ~¿~Ŀ Ƅ’ÈĊÆĖÆČń^{}ư~ծ\~~~}|||{ʆɃȄǃƊňČɎ|}{}{}I~ҍӀ~}}½ ŏ‚ˆìďŒŇƅŋƋňƌǑǔȈɓʅ˜ʈɆʄˌj퀃Ͷܴ +Vӄ҃фЄτ΄͈̈ˊʈɍȈǗƅŇƏŔĆńĒŒĎÑėţĄÃĔƅ݄ͅJڊۄڀĿ ˍČŇƕňć„ČԒ‘ÆÉĬŚă݃‰ЏœÊĂńĐŢĈņl||}~ͳ|}Ӷ~;}}υ +ʆɄȊLjƌŇđȔ}~}~DՄևׄր~}| +|Ǘ‡”ÇđʍÈăńh|{~|}̲{|ѵ ~~}=||̈́ʄɃȆNJƄŊĉ̍|}|}EԊՄԀ}|¿~{Ŀ +{ƿŠÈąÄąőĆŢƄŔƂńƖǐǜȆɅɐʢɈʆm퀄ӸػdԅфЃφ΄͉̈ˌʇɑȈNJƂňƄňƄłĆŗăńĐŖĈÃąÐħŋʇǂÅɓˆCۄ܇̗݀łƖōąÂĈͅژҾ†ÈưŔĆÌ…‹׀ЇʻðÔĐŦĆńƅp}}}~޺޿T~~}}τ˅ʆɅȈLjƌŇĎȊ}|~}~Cօ׃؅׀~~½ +}Ǘˆ“ÄĒϒÆr|||}ݹܽR~~~}}||΄̈́ʄɄȄNJƅŅĊ̈„ʾ|~{}|}~@ԄՇքՀ~}¿} |ƿ޸„ŠÈąÄąŐćŔƃŋƄŚƖǐȰdžƛǝȔɐʢɆʄ˄nķ$:ՄфЄφΆ̈́̇ˌʇɎȈljƃŔƅĆŗăńĐŗąÆĄÐĨŊĘˆÆÏ£A܄݄ޅ݀ÿ½ +͗łƗŌĐÎܗҾ†ÇĄƎłơœĆȇ˜̀Ї +’鍠ÊËĄŚćŋĆŅv}|}ƽ˾f~}|ЄˆʈɊȆdžƈŇđȊ}~|~>ׄ؊ـ~}Ŀ }džƹ„’Ê¡Åy|~||~Ļʼ_~~~}|{τ ɈȌdžƄŊĄÌŒ |~}~{}~B֌׀}|~½ |ſŽ‹ÖĊłĈŎƌʼnƃŋƂǍƔǒȨǎƘǠȊȋɄʚɈʉɇʅv­æ^фІχ·͆̅ˈʇɑȈljƅŔƔņŅĎşąÈăÅĝŎ攋ʎA݄ފ߀¿¿Ŀ ̛łĈņƈʼnđØ‚Š‚†ÈċŋƌƖŋĉÄ–ŀЇ»Œ˜èŽ¢ÆĄÊĄŚćōĆŀ~}}~}î|`~~}}Є ˆʇɋȅdžƈņĒȊ}|~}:؄وڀ~¿} ÇŽ„’Ë£ÅĀ}||}|{Ʒb~}}||ɉȋdžƅʼnąË…†|{}|~;׊؄׀~}|Ŀ‹ÖĔŎƌŖƄnjƒǘȨǒƔǡȇɄȊɄʚɈʋɇʀȳ^фІϊΉ̈́̆ˇʆɒȈljƉŐƖłĄńĎŠĄ ÅĜŎĈà͏<߉ țłĈņƈŊĐØ„‹‚‚‡ÊĈŋƈŋƖŋĈÌŽЋˆŠÃ‰Û‚Ê‘“ùĆŐćŀ~~|}ʼг^~~}|̄˄ʇɆȉNJƈńĕō}|~}~Bڌۀ~}~¼ƹϺ†„ †Õ™Â‹À}}{|~ɺϱT~~}}||΄˅ʃɆȅljƊŇćȂ†|{}|}9هڀ}|}놿†ÍĂÆĄłĖŗƝLjƕNJȃljțǂȉǒƗǓȹɆʐɇʀַLՄхЅφΈ͇̉ˈʄɕȅnjƊŊƞŊĘŝčÌĖŋĉËƐǤ6ćŊĎŌĉЄ‹‚ŽÈĆňƆŎƖňĎґЏ…ƒÎˆÄŠêŒ’ÂĄøĆŐćŀ~}~Ǧ^~}}|̄˄ʆɆȈnjƇŅĖĎ~}}~5ڄۊ܀~}þƹҺ†‚ǃ֚‹y}~|}ƥܿT~}||{΄ˆʂɅȅLjƈņĈȃ‡}|~|}6ٌڀ~}¾~|¼놿 +‡ÎĂÇĖŖƤdžƆǂȎLjȄNJȦǍƛǒȂɄȸɆʐɇ}ÄͫƧ^хЄφ΅͈̌ˈʄɖȄǎƈňƠŊĘŝčÎĔŋĖǏȣ7¿þłąŏĆœĊ͇Œ‚ÉćŅƅŏƖŅĎ„ƂĐƂȆً҃܃̄¬ÂĈØŏĉ{~}|}ɯ۶6~~}}߄̄˂ʆɆƄǎƄňć…э}}}~4݈ބ݀~}¿}Ŀ…Œ„¤|}|{|~ǭٴJ~}}||΄˄ʃɅȆDŽƉōĆǖ|||}2ۊ܀}||þ싿 ŒÐĂÌĒřƉȈdžȒǃșNjȜǃȌDŽƄǂƞǬȂɈȘɅʏɉyĄŊŽϴỜKՄфЃυ·͇̎˄ʈɆȂDžȑnjƆłƩōċŢĊÏĖŏĔÏɇ„3ĿĆŏćÂĄÅēȋŽÂˆÆĒœƃńƎŌĄÃđͅς‚ƌˉֆ݄Ƀ—“ĆØćōċx~}~†u录ǣ~~}ʄɆȄnjƈňĆғ}}~/݅ރ߅ހ~”…¤Äy~}|}~㻔~ŢM~}}|΄ +ɄȆdžƈŎąÇ—~|~|}~.ۄ܆݄܀~}ÿ~Ŀ쌿ŒÞĒřƍǂȆnjȋljȖdžȝȉDŽƦǖȂǒɆȘɇʌɌz邆ńƆDŽü™̨JՄфЃτΆ̓̓˅ʈɆȒǎƬōĊʼnĂØĊÏėŎĎÂĖɇ‚…/łĆŌĬȤ ŽÂ‡ÇĒŘƂńƎŌĄÂĖ̅ւЋÈĞĄԄÏå˜ÇĈÂĄÜĞz}}„Ät辛}á~~}|ʄɃȇLjƐʼnĉԔ~~}~-ߊ}|}‚‹‡‡‹ÇĔw~||~潚| R~~}}|{ɄȃLJƄŊĔĊ}}|}+݋ހ|{|„ÐÙĐŔƗǍȈɞȄǃȕdžƕȏȦǒDŽȇɇȃɄȜɞy肇ƄljȄàȦV΄̉ˏʉɉȔǔƬņĂńĎŨąÏęŇĊÌėȃ‰*¾¼ņĄÄĜĄę‹•ÇĎŋőƈņƌŅĒŽȅ݂ЋÎĂÆċ…Õ„ƒÅ‚Þ–ÊÈÈŏğx}|~ŠÄr߷𽝊~}}ʄɂȇLjƋńʼnĊԔ}}}~+~}¾~þɸ…ٝ†šØĈx~|{}„r~޵~~}||ɄȂLjƃʼnĐ„ĉ||~|})މ߄~}|}„Â’ØĐœƖǍȎɂȆɋȂDŽȕLjƢǃȅǂȞǖȓȈɂʎɠz郇džȄɄt漚¡τ΂͈̇ˋʄɂʈɊȅƊǔƬņĂńĊŶęĉÍĘLj)ýņĄÃĕ܋”ÈĎŅńƄŏƇŇƍŅđŽƄ䂃ЍŠÂˆâĒ܂ƒÇÇ‚ІŒíĊřƈt䀅~~„Ìr˩Х~}˄ʂɄȅLJƊŎĉ͇‰„}~}~(|}Ŀƺ +†Ú‚šˆÂ•év}}~‡{ʧΤ~~}|džƆňċψ|}|}-|~|¿~þ•ÑĘņƐNJȂLjȢɏȜǂƖǃȇljȈǂȐdžȂnjȭɉʛˇvꄈȄɈzѭժ΄͆̇ˉʎɉȍLjƈNJDžƘłēʼnĂňĄŶĠńĊÔđއ)¿ľńĄŏĕɝˆÒĈłƗŇƃŌƎňĈƂƃ還ЎŠÂ†äĆÂčуɂ„ÅŠÆ‚ΔÒĆŌĆłĊŠy偅||ÄćńrӬԦ~}}˄ʂɄȄLjƉōċ͈‡„~~}~%|~}¿}…†ۙ†Ä¢ÊĄņČŊw〄{~{~‹rѫҥ~}}|ʄdžƆņČψ}}|}+|}||ĿÄĆÐĘņƐNJȂdžȤɍȑǃȉǂƖDŽȅNJȆǂȎǔȒɆʌɎʤw넉ɋzٱګ΄̇ͅˉʍɋȍLjƊLjƂDŽƖńēʼnĂğŅĊÕąÂŠÜ†+|ŃąŌĔȅ…ÎĈńƝłƄŌƎňĚÆ‚ƃЏˆ‡Ä†èăËąÈƒÆ„ä‰ÃÌ‘ÕĈłĎŒƄǘt悆}}~ĄŅƅtЫԥ~}}˄ȅDžƊŇē̎‹}}}$}|~¼ˆÂˆÂ‰Ù›š‚ĂąÄčÒĦv䁅||}ÊjΪҤ~~}}|΄ʄdžƃŅĊՋ||~|~!|~{ÿ} ÙĜŇƃljƄLJȄdžȨɃȋɅȈǃȆDŽȤljȃǐȌǐȖɈʂɎʑ˅̔u셊ʋvְکЄτ΃̈́̆ˉʇɓȊǐƈnjƅŅĈņēŋăŹÅĞŅĊÔĄæ‰ +!xÿłĄŐăNJˆÂĄÆĊńƩŃƆłƎŃėЃЎ†Â…êĂÌĈĄŅ΂ʂȉÐ̐ÕėŒƎǔu烇~~Ŋv~¡}˅ȅDŽƉʼnĔʏŠ~}}z}|ýŠˆÃ‹Î‚Æœ†‹ÆĈÌĂńĪt傆}}~Ìz}|ȄdžƃŅĉ֋}||~ z|~{¼𿇾 £ÓĉłƅŃƊŔƆDŽȃDžȞɂʊɂȌɇȅDŽȅDžȏȊǂȈljȃǐȌǐȕɔʐˑ̓w톋˅̅uȥƙЄτ΂̅ͅˈʉɔȉǐƊNJƅŅĈņĔŊăŸăÄĞŅĊÍ࿉!x¿½łĄŐăNJŽÆČƓńĆłĔłƎŃč†҃׼…áĈŐĔÈň—ÖčÓĉņƊŕƏǓp脈||}ńƊf̮歋҄ʆdžƇņąÇďˆ„…}~v~¾}ſ”Ñº‡’ÜĔńƚr惇{~{|ąŃƅf~ʭ嬊τ˄ȅǃƅŅĆۋ~|~}~y~}|ý񈿢×ĈńƃŌƄŕƇDŽȢɈʐɔȄLJȅLjȂLjȂǍȃǕȅnjȔɈʈˈʕ˓̒q˅̆̈́eѳքυ΃̈́̄ˇʆɅȇɎȋLJƆDŽƆdžƊņąŅČńĎĞʼnğêŠx¿ĿşĆƊƒÆěŕĐņƌłć˂ׄÒĆňĊőđĈ̦Ñćšƙ +Ƅr鄉}}~ƆDŽȄh~|ϵ~Є̈́ʄɄȂdžƇŇĆÆĄÂĈ̂„†}}|~v¿|~©Ï¸‡„ŒÉĂŒĕŅƚp烈||}ĄňƄd}{ʹ}Є˄ȅǃƅŅĆÆ‰||{}!v~{¾}ľ򈿋ØşƃřƆDŽȒɆʈɊʑɑȄLjȄljǘȂǦȐɈʤ˨t̋gպׄ҄ῠˇʇɆȆɄȂɈȊLJƇDžƅdžƌńĆńČńčĞŋĜëŠ xşĆNJƒÅĚŗăńĊŃƉņć˂ÄÒД”ˆÆĝʼnĂÉĄÂĈ̂ę„ĨÆĎņƂǎƈDŽƲoꅉ~~DŽȇj~}ɳ~Єτ̄ɅȄdžƆņĜÉ„‹‹}}~w¿~|¾†ÇćÂĐȂΚ”„„…„ŽÆĊŃĥňƂŔp脈}}ƊDŽh}|Dz}΄ ȅǃƄņĆވ~|~|}v}{~򈿊„І‹‰× ąŖƂǔƈŌƄLjȆɞʈȊɈȌǂȄǙ ɨȅɏʆ˄̋ˉ̄˲p͌sθơфЂτ΃̈́̆ˆʆɉɒȉDŽƂNjƃǎƉŋĞŠĉŚċłąċőď…íŠuƈŞĄÈ‰†ÒĂŐĄÚĈŎĈʊŠ+Ž‘‹ÅĠňĂÈĂÄĈ̂ĞÆěČÄĎŇƈLJƴDŽȄDŽp놊|ȊɄh}ɿヤτ̄ɆƆŇĞÊ„~}}t~}½…ÓĎȂϙŒ†„ƒÆĔņƌņƈŞn酉~{~ƄdžȄl~|ǽ̈́ʄɂȅǃƄņćÊ…þ}||~y¿~}¿|†‹ˆØĈŅƄǏƂǐƇōƄNjȅɡʇɂȎɈȌǂȄǞȆɚȂɌȄɎʆˊ̆˰̈͂̆q񉎓ΈuIJØфΆ̈́̂ˇʆɞȉDŽƂǢƊʼněņŗČŚĆłąċőĎăÒ‡‰v¾¼ƇśĄÅ‰ƒ†ÒĂŎĆðĈʌ‰ÂЈ‹‡ÈġŅćËĐÆ“ĊÄėÄÆČņƔnjȖDŽȂǖn쇋}}~ɋa~|¿渑Ԅ˄ȅǃƅŅĘή}|~t}¾~ľ‡ÖĎيš„‚‘Åĉ ţƂŞpꆊ||}ȇo}{䷐̈́˂ʄDžƄłĆʄƒ†~|{}t~|}½̇łÎŒ†…ÐĒŅƊLJƋNjƆŊƍLJȈɤʅɇȋɅNJȆǒȂɊȄɗȄȅɌʅ˕̝̌͋ͅo򊏕ωh콕քӄ҂ф΄̈́̄˄ʅȄɘȎǮƫŞćśĄÆėŃĄÌĐ҈…rýƅńăÏąË… +ˆŒÐĔÄÅÇĂÙă̅ÇďЊ‚‹‰ÉĥŅÐčɐÂĊÄĕÇÊđńƕǍ +Ȅǂȅǝo툌~}~ʇ˄f}¾|ȣЄ˄ȄDžƄŅĞί~}~t~}ſˆÚĊÍˉ„‚‘ÅĊn뇋}|}Ȋ|~|{ǢDŽƆłąË„ˆ†}~|}t}|¿~þĕÇŒ…ŠÉěŅƌǂƏNJƆʼnƌljȈɦʅȐɍȉǐȂɊȄɔȈȊɑʄ˒̖̞͂̄̅͂m󋐕υЂхtΨЄ̈́̅˄ʅɞȋǯƭŞąŝąÆĒŃĄÌĐ҈‚†r¾ľƄŖąÉ‡ŒÌěÂĄÙă̄ÉĎА„È‚ŽŠÊĪŜĉъÂĊÆĂÉąÓĒńƓdžȂLjȂǰj|ʄˆ̄l~ÿ}ڶͅdžƄʼnęЇŒ|~}u~¾|ˆ•ÇĄÇďÆ +˃†ÄŠÎĒŝƆǔƄdžl쇌~{~Ɋp~}|ص˄ +ƊńĆѕ{}|~r¿}|ĿŸÆ ŽÄĎŇƋńƃDŽȇǃƍLjƈņƇljȊɪʜɉȑNJȂɉȇɂȊɄȓɑʄ˔̰̐͂o􌑖хn߻ӄ҄τ΂͆̆˄ʉəȐNJǎǎƎĜŝĂůĐŏĎĆ͊„ˆuƿljƈŇĂÊĆĖ +ŒÆĈʝōăȊÍĊЏ†ÎƒÅ–ˆÐīřąÐŠÂĈÄËĄÓđŅƓLJǖȅɟk}}˅̂̈́l~|ÿٻ̈́̄ NjƄʼnđ…Ñ„Œ“Ŀ}}|~u}}ˆ•ÇĄÆđłƂÌ„̆ĊÎĒŘƖǎƄdžj툍||Ʉʆl}{׺̄˅ ƉŅĆΚ||{}r~|¿|ÈĊȄ–„ÂŽÄČŋƉńƂdžȎǃȅǖƆLjȐɮʚɄȑljȂɈȄȋɄȆɂʊɒʄ˔̞͆Ξlщn҄τ΂̈́̆˄ʉɑȂDžȑdžƈnjƄǒƥĄńďŎďĊÍ‡Ž rljƋńĂÌĄÅ”„‡ÃĉÌ—ōăÆÌĊД”†ÅÒ„„ÖIJŊĂÆĆÄĆ͇ÅĆÄĆÒćŎĄłĆŎƉǍȒɄʋɕj~}~̄̓΄m}~Ϲ˄ʄɃȅNjƅŊČó‰ }} p~|¾~¼†ˆÚĊÂč„Ö„†È¢ÅČœƋǒȋLjƈh퉎}|}ʄˇm~|¾}ͷʄɅȂDžƆĈÊ ~||~ p}{}’ÌĆ̃ݐÇĂÅąŇǕƄdžȅǍȒDŽƈDŽȖɲʊɂȆɆȄɆȍLJȆɄȅɆȑɈʎɅɆʍˉ̎͐·ϋΔjҊo¾վЄσ΄̈́̌˄ʊɌȳljƈǏƆłċłĖŽăÈĄŖĐƊЂŒ q¿ÿƍœĄËŽ“Ø‚ćÑėÉČЗƒŒ‡ÄˆÄĂ݅ÓĵŊčÆąÍ‡ÆąÅąÑČņČōƈǏȐɈʋɓj~͉p~|}Ž˅ɂȆnjƃōČôˆ”|||~q~ý|‹“ŒÚĊÂĒØƒ†È ÆČŊƐǘȊLjƈi~}~ˋp}{¾|ĻȆǃƅņŅĆÌ {{~{}p~}¾~»{’ÌĆÆŽØŽÐăŇƅǃƄnjƃLJȄLjȄɂȓǂƈDžȓɋ˅ʂˣʉɍȆɅȍdžȈɄȅɅȑɔɌʍˆ̑͋΄ςΊόΐkӇq¾±Ѕ΃̌ͅ˃ʍɌȴLjƈǐƆċłĖżąÇĄŔĒČá‹ n¿¼ƌŔĄÊŽ’Þ‡ÑĖÊċЇ‚™Ã„ˆÎĊňƠČŅĉÇČȊÄĆÉăÌęőƊLJȏ +Ɋʐɐi񋐖}}Ήu}~ĿȅDŽƊŒč÷‚Œ~}} n}¾}ž}‰Œ¢ÛċÇĒƓ‚ÇƒÚąĎňƎǦȈǂƈh||~̄͂΄t~|}½~ȄƄńċӖ}|~|~o||ü|Ċ†ÉĞ„Ë‹ÊĄłąŊƒǃƄǙ LjȂNjȎɋʉ˅ʃˤʅɉȇɌȈNJȄɆȊɂȌɘʑˉ͎̈ΠχΏjԇvĿ̄ͅˊʒɌȘǂƞǂƍǏƑņĕŐØąÎĊÍćÆĒ҄„‰o¿ÿýLjƆńƊŌąÉ†„Ƃ܋ÑÅĉÚЈ™ÃˆÂ•ÇČŋƄŃƖłČŅĈÈĎÆŠÅąÊăËċŃƆŊƂljƈljȎɖ ʈɏj񋑗~}υz~|¿}ýDžƄńĂŎčÄŠ}~~ +o~|Ŀ~ƿ}Š +‡˜ÊĂŐĊÈĆÂĊÈŽƒØēʼnƇǝɑȒi}|͇|}{|ńċӘ|}}p}{¾}Ľ|đÈęďˉÊČŋƙǙȃLjȂǕȇɌʌ˄ʄˣʅɈȉɍȆNJȅɅȊɃȋɊʄʊ̄ˈ͎̈ΣωΈlԄՂքx½̄˄ʎɍȸƏljƑŇēŐăÖĈËċÌĈÆģӄ„Šo¿ľNJƅŅƊňĆÈŠÄĂÊĂÊĂËăőЏƎÆċČÌÎďňǍƢŒĂŎĐÈĄÒĉŗƆƄNjȈɤʜh򌒘}І}~½~ōĂÅč +؃łæ +„|}m¿}~‚˜†ÍċŋĆÈ̍̄‚ȈÆńÏČƆņƊǚȈɒȐh|~·|~|¿}}Ƈԛ~{~|~l~|~ƿ}ČÈĈÊĄÆĐȆÆčʼnƉȆNjȆɋɌȄNjȎɏʇ˄̋ˢʒɃʍɐȈɄȒɈʘˊ̌͆ΨϖfՄփׄ|¾½ʍɂȅɍ +ȘǂȆǂȦDŽDžƇƆňĐŐąÉčÃĔÉĐÂĠȂšk¿þſnjƇńƏłĆǃƒˆ…†ÅćÄĄńĈłĔʼnА•ÈćÈĚÏČŋƃNjƣŅĆņĄŎĊÍăÒĊŖƊnjȈɤʄɂʖf󍒘}Љ|~|}½}ǍąĎàŠÂ…ã‚…}|~j}ÿ~‚Ó…†Ã‡ÌĎŋăÊĄÆĤȂ‚ȉ˄ÎĒńƍǛȊɐȆDŽr񌑗|~Є{}{¿||Ņڝ|~{}j~|¾}ĂÈĊÈĆØĐÆ„ÇČŏƈǕȈɇȈɎNjȎɋʇˆ̊˦ɇʆɅʍɊȍɃȒɆʚˊ͇̋άϖgև}¿¿½̍ɄȂɎȠLJȂDžȣǂƄDžƆƆňĐŐąÉčÃēĆÃĴÈœk¿ƉŃƒłĆƄ’††ÆĆÂćĤʼnЏ‚…ÔĄʼnăńěÄĔńƆDŽƄNJƆņƝłƊŅĉʼnĂéąńƃőƇǍȂɄȖɭʅd􎓙~~хӄҀ}¿~¼ĚЈ”؂ˇ¾}}h~}ý~‡ +„ƊĈȐÈēŚĄÈĆÉė̂Å΄DŽÑčŊƓǖȒɖg򍒘}}І~~|}Տ +|~|~h}|} +ĊÇĆßđÄĎňƄƈDžȔɅʈɅʃɚȄɔʄˇ̃˅̉ˆʇ˛ʅˉʄɉʉɂȩɅʄ˂ʒˆ̉͠΋σТh׉؀ɚȐLjǔȘǂȊǂƆLJƅłƠŎĈÔČÄ“’ȏكi¾»LJƋłƐѹĈ†ÂŠÆĄ ƇŘƆŇ􂣁Џ‡ÔĈņĆńĘÄĔńƆDŽƅljƄʼnƚŇƈńĊňĂéąńƂŒƇǍȂɄȖɒʄ˚g}҇Ӏ~|ÿ~¼ĝш˜ֈLj||~i}ÿ~ľ~†Ž¦Ê††ŽÈĖŚĄÙĕƅЄƄÓĈňDŽƔǐȖȉɇd󍓙~|~Љ{}{½}~˚~{~{}i~|}¼}ĉÇĆäĊÄċŊƈǂƅLJȔɈʅɇʄɘȄɔʄˇ̃ˆ̈˃ʋˌʂˊʈˈʃɋʳɅʄ˂ʒˆ͈̉͗΋τЂϊЖh؆ـɝȑLjȂǘȖLjȆǂƆLjƄłƞŐĄËŎĉË„‘‘ɏقjüdžƒňĂńĆĈ +‘ÅĊśƂǎƄņ􂢁Б‡ÃďŃĔʼnđÇďņƃLjƂǚƈŖƙŕĄÍņąʼnňƈǘȊɒʒ˔c}|~ӈ|¿}~ċÕØȎ֋„†~}~g~ſ +†Ò…•ÅĄÆćЃÇĖŊĆņĂáĢ×‹ÕąʼnƂnjƎǎȌɈʙc􎔚|{}хӄy~|Ŀ~}Œ‡‚~}|}g}ÿ~ľ~ĄÛĂŊŎćÄĆńƂŊƒLJȃɐʂɔʊɐȆɏʅ˄̇ˆ̘ˇʖ˚ʇʈɄȍʆɄʘ˅̙͇ΑϊЄюЎdه|ÿɋȮȉǎȖNjȃDŽƄDŽLJƟůĆÖ ˆÂšÉ‚×…hĽƇŋÆĄÆŒÄĄŅƗdžȒDžƂń󂢁Ѕ +‡ÃĐłĕŌčÇďŊƂLjƃǚƇŐƂńƝŃĊńĄÌĄńĆňƂŌƅǘȇɑʊ˄̎ˊh~~ԅ|}¿~}ąö†ÈŒØ‹Ã„‚†~}}h}¾|†Ɛͅ ĉÑĈՐÈėŅĊņĂÄăńĄŔġՍÅăŌąʼnƃNJƌNJȑɌʗd}}҇y~|}|ąŒ‚}}||~j¿~|{ſ~ +ŒĂÜĂńŎĆÃćńƂŊƓdžȃɐʂɕʌɍȇɎʊ˃̇ˆ̙ˆʖ˞ʂɊʄɄȌɅʃɅʗ˄̛͇ΒψЉїfڅ|ĿɅȶdžȈnjȘNjȂDžƄdžƚŮćڈĘ߅zhþžƋņČÂĈōÇăŅƆdžȆǐȌdžƄ򂡁Ѓ ƇłĈŊƌŎĄÃĕŋLJƅǮƴŐĂÄĐőƅǕȉɓʇ˒̃ˆ̌c}Շ|~¼}ل†„ĂӃ†Å{}|~h~|Ŀ}º „ÕăŌĆ̅ÆČÒč͐ÉĪŌăŧčÈ͏ÆĂņĊʼnƉǂƈnjȆɃȇɎʂ˔ʆb~|~ӈx~|ÿ~|†||~{}f¿}{¾|~†ÈŊƄşăňăʼnĈŏčňƚ +ˆʂɈʊˍʍɃȄɕʊ˃̅ˆ̯ˊˇˠʐȅɏʑ˅̋͂Έ͊ΉЅχТцcۇ|¾șDŽƊLjƎDŽȄǂȓǃƔdžȄDŽƂDŽƄǍƗŬć͖̇̌ɂŽ|hǿƈŇđˊŽÄĄłƇǃȕɃʌɆȌDž񂡁ЅĊłćŋƐŐĖŋƂLJƄǨƂńƮłƄŘĈąŐƆNJȂɈȈɊʂˈʈˠ̈`|~Մւׄw¿}¾|¼|ȅ„ˆ„҄‚Ȑx}~|g}~» +†ćňĎņćËÆċÓĎʒÈĜłċʼnĂŖĂÖ ÉĊʐÆĂņĈŋƏnjȔɍʃ˘d{}Ԇw~|{|‡ +|~}{{{e¿|}~ ‡ÂČÄČŌƇřĄňăŊćŏčʼnƙɓʋːʐɖʊ˄̅˅̨ʅ˘ʂ˔ʂ˄ʖɐʐ˄̋̈́Ά͇ΌφЄφЎтҔц`ۄ܂݄wÿ¼ȇLJƏDŽƊljƍDŽȒDžƕǂȇDžƄǐƗśăōĈʈ̇ѓȂŽ{f½ƈņĉ…̉ƄdžȂɋʇɐʄɇȋ񂡁Ћ†ÆĈŎƄłƎŎĒŎƂLJƃǔƆńƻʼnƊřąōƇLjȍɏʖ˚̆ˆb}}}ׄv~~ý–„Ć̆…‡Ë…‹†z}}}|||}h||||þü‡ +ÆąšƃŅćÈŠÎĄōĞÉėńţđÍĄÍģÄčʼnƌnjȊɂʄɈʄ˄ʄˆʆˇʅa|||Նz¿}þ}z|||~{{{|f{{{~{~º ‚ÆąņĆŋăŋƂņĄÔĂŠĂÅċōƕdžȆɈʐˎʍɒʋ˅̆˄̔ˆʄ˄ʄˈ˜ˍʊˉʒɂʄɅʍˈ̈͋΋ϒЂшДу҄Іfр݄v½¼ƆǖƩDŽȄdžȋDŽƂdžƆDŽȂdžȊǔƄdžƖŪėǂäŽ̎…we¿ĿdžƇņĕɇ†Â„ƄȆɅʖ̋˂ʅɇȈЋ†ÆĆőƃńƏŊēŎƂLjƂǓƇŃƭłƌŌƉřĄņƂDŽƈLjȌɐʖ˕̈́̂ˆ̄`~}׈q}~ľŇ–…È҃…„͓„z}}|||}g||¿}އ ƒÅăŅƙNJƃńĈƋŠÍąŔěËėŇĄŦĐÎĄÒđƋÄčʼnƊǎȊɂʄɌʆʅ˃ʉˆʆˀ}~|~\~|}¼v||{~{{|e{{|ÿû…ÆĕłƉńĄÅ‹ƂņĄÄĂŎăşĂÆĉŎƕdžȆɆʙˎʉɔʊ̇˃̔ˆʄ˧˄ʅˉʌˉʘɅʆˊ̈͊ΌϏІчЋт҇х҈х`݈qþýʇƂǖƨDžȃLjȊǃƅDŽƅDžȂDŽȌǔƄdžƖŪĘĈâ‹Ñ’td¿»LjƆŅÄĆˆɇ ƄǃȅɃʄ˝̇˃ʄɈȆņ„ÄĈŎƂnjƂŇƆńčƉŎƂǙƋŅƣŐƂŔƊŐĈņƏDžȆɂȎɉʍˊ͇͈̄͂̇̂^~|~؈s~|ſˆÆ„ÐŠÂŠðŒŠ‡u}~|}`|¿|½}ƾˆɅƄLjȄɂȇɄȇǃƄņĈ„ÄąÆĎŖċ×ĘŅąŠ +ĄÐĂŌĂŇŊĈˉÅďńƎǒȋɒʡˀ}{}X}{¿~ľr|}}{|a{~{|ļ„ńƝLJƄńăÆ‡ȅdžƄʼnćŇĈńĄŎąÇƆŋƉƍDŽȄɈʏ˂̍ʈ˅ʄɍʂ˄ʎ˂̇̒ˊʅˣʐ˂ʔˊʐɈʅˏ͓̃΄ςΈόАє҂ъ^ބw¿ľƇłƄŏƅLjȆDŽȐNJȂNJȯǍƂǒƕţĂÎěل‚‚ωtd¾ýljƇÄĆ…Ɖƒ‰΅˄̆͆΂͈΄͆̄˃ʆɈƇ‚‚ÅČŏƂǖƆłĊňũƋŅƝŨƊŐĉŅƎdžȎɊʌ˄˅̏͆̆̈́`}}مs~½}|ˆÄ‡ĂȊs}|~|}~}_|}Ŀ}ǿ† +#DŽȊɂʓɇȃDŽƄŅćÃ„ÆĄÆĔőćÚėņąŠÅăÐĂŌĂņĄňĄÌˆÆąƈńƔnjȌɑʡ^~||~׈q¿}|ſ{ž¨p|{~}{|}|_{|½|Ž"ƅƄǕȄdžƃńąÄ„ȆLJƅņĈņČńĄłĄňĄÈĊňƊǃƍǂȅɌʌ̗˅ʂɊʌ˂ʎ˂̚ˊʅ˅ʂˎʂˆʭˉʐɈʆˍ͇̆΂͊ΈόАџ`т߆s¿ƎŊƊLjȄdžȄǂȄnjȂNJȮǎƃǓƐŇřĈÎďċ؏…r`ĽLJƇÄĆ̊‡˄͇̄΅ςΆόΆ̈́̃˅ʄɇ킠ЄÇˆ‹ÆĂşǎƊńƈūŐƄŇƅłƎŃƅśƃŎƄŃƄŊăÄĈŇƉDŽȅǐȂɍʖˈ̙a~~چo}¼}ń–ÆĦƆĂڎ“s~~}|}}}~}\|~„)}~}ʅˏ̇ˎʂɄȆʼnㄆÑĕšąŋčŢĂŪĆŒĈŊĆ̆ÈĈœƋNJȈɔʌ˂̌˂̆^~}}؆p~|ÿ~|ˆ†ŒŸn}}|~{|}|\¿~{Ŀ}ƾ)|}|ȆɊʂ˄ʉȆɅȃDžƅłąÄ„ȇLJĪņĆÈćňƍNjȆɂʞ˄̌ˉʅˈʽ˃ʇ˅ʂˎʄ˃ʝ˂ʎ˄ʃ˅ʉɃȄɈʆˉ̅͂̒͂ΎψЄфЊѠ^o½ȅDŽƄŎƄǖȇɥȆdžȄǂșǏƅǓƄłƆŤĆÈĈÒĊәˆp_ſƅDŽƆŊĄÉ‹ƒÏ†3φАшЌ͇ʈ삟LJ‹ÆăŒƃljƄnjƈŇƇŪƄŏƃňƄłƄňťƂŏƂńƅňĄÄĉņƊǃȆǏȃɌʖˈ̜\}ڈm}¾}ľ~ǔ–ÑĨăَ”v~}|}}}~_}}||}½„1}~ˆ̏̍˅ʂɆȄǂƅńĄ‡ ˆÆĂňėŠąŌČŖĂŊĂŢĄńĆőĉŊĆ͇ÇćŒƆNjȇɉɉʍ˂̅ˊ̅^~~|لr~||ý}…†‚‹ªo}~|~{|||}^||{{|~ǿ5|}~ɇʋ˂̄ˇʍLJćȇLJƮņĆÈĆňƒNjȅɄʒ˄̈˄̌˄ʇˇʪ˄ʐ˂ʈ˄ʮ˂ʖ˄ʈɄȄɈʆˊ̄̏̓ͅ΍ψЄфЈф҂є҂ӆҀ¾QĿýȇǔƅǖȑɨȄǃȘǐƃǔƄłƆŞĂÄĖÒĊʃ›ˆm^¿þƿƄǃƇŊĄÈ„ƒÐ…6Їѐ҆ьЄσΆ˅ʄ삟ńĄÄ†‰ÇĈņƂdžƖǛƆŅŅƂŜƉŏƂLJƃŗƃǠƆLjƈņćÅĈłƅƊdžȈɆȇɅʓˍ̐͋^̀|܄m~|½~ɈƋŒÂĎãěÈ“l}~|}}~_~~~}}}|¿|Ŀ| +6}~͆΃τЋς·͇̆˄ʄɃȄŅ„ˆÅďłƈńƈ +ŐÐăňčńÊĂňćōĎćņĉńčŊĆdžÅƈʼnƒLjȋɂʄɈʑˋ̂͆\{}چm}{}ſ~Ї†Ü‚–ȸl~|}{||}~}\|||{}{½{9|~˅̅͌΄̈́̋˄ʅɇȄńʄɄȄdžƮҹ¥ ƕljȇɈʆ˂̆ː̛ͅˆʋʓ˂̈ˈʐ˃̇˂ʎ˂̆˅̞ˈ̈˅ʆɇȄɈʃˏ̇͊΂͈ΆϒЈфыҒ\l¾ƿΈȆnjƇNjȂɎȣɛȈDŽƈǔƇŎƈćŜěÈĎȚˆn]ĿƅŅĂÄĈĆυ;҄ӄԌՄԃӋ҄фЅτ΂̈́삞ЅĄÃ‡ŠÆĊņƂDŽƑǃȄǜƆłƄńœƂLJƊŏƃǗƂdžƆLjƂǓƇLjƅŅċÃćłƎLjȊɂȉɅʓˍ̌͐[}}܇k¿~Ŀ|ýċȆŽÂĎæęÈ„” l~|}}~~Z}}}}¼=}τІъЂτΊ̈́̆˅ʅDŽĄÃ„‰ÄČŒƓŚăňčńÊČŊĚłĦňƆ†ÆƈŇƖdžȑɇʑˌ̂͆Z~||ډj}þ|‡†Â‰Ø–ȸj~}{||}~}[|||Ŀ|C|~ͅΎτ΄͉̃ˆʅ DŽąɄȃLJƇłƤņąÃĄÂĄłƔNJȆɉʇˌ͈̂̄͆̚˅ʙ˃̆ˊʏ˃̐̄ˈ̂ˆ̈˄̐ˊ̇˄ʅɋȂɇʃˎ͔̈ΆϒЇхъҋӂԆ[kÿ¼ɋȅdžƆǎȂɎȧɘȈDŽƇǕƊŌƒŘěÇďȘl\ƆņĈ‡…?ԅՍքՄԇӅ҅хІτ̄ꂟЃƄĈˆÈĊňƈǒȈDŽƆǍƂōƂňƈDŽƈʼnƂǏƦDŽƄDŽƉnjƅ‰ÅĄņƆNJȔɒʊˆ̊͑[~~|݉n~ÿ~ƿ}ŠÐ–ÇèěЖk}~}}~~~\~~~}}~½~ýA~҄ӄԊӇ҃фЄςΈ̓̅˄ ń†ÊĊŒƄDžńƔŔăŅĎŐĬŌƨŊĄÂ‰†ÆĄŅƉDžȂǐȑɈʐ˅̆͆̀}}{~K}}ľ|‰ †…ŇÑ•m|}||}}}~~[}}}||¿}}»C}Ѕцҍцφ΃̆ͅ˄ʂɅŃ˄ȄLJƅňƎłƉŋĄÈƔLjȇɋʈˇ̗͍̂ˇ̝ʆˊ̄ˇʍ˂̄˂̈˚̂͏̃˒̌ʄ˄ljȅɃʇˆ̈͆΂ψΎςІϋЇю҆ӂԋӀ҂QžNJȐǖȃLJȨɛȐǍŇƍŋƗōĉÅĜÄĄć΂Œƾo`ÿ½ºƇŇĆɃŒ‰Dƪׅ؇ٌ؆ֆӆ҂фЄτꂞƄˆˆÆċňƇǙȓǙƂņƉDŽƇŎƂDŽƂLjƖDŽȌDŽƄDŽƄǑƄŠÄĄƆNJȎɘʊˆ̌͐\~ކi}½}¼~ēĆ׈éěϕ +l|}}}~~~^~~}}|}Ŀ~ĽM}~ГׅԆՌԇ҄фЂφ΄̈́̂˄ʄǂŅˆÈČņƅDžƆLjƈńƈŒĂņĎŐĞłƌœƟō‰†ÇăňƊǓȒɉʐˇ̉ͅZ~}܇j¿||}ŠŸ†„Ç…Ö†i{~|||}}}~~Z}}||{~|½}üK|}ϒҊӍ҅Ѕ̃ͅ˄ʂɄ˄LjƄʼnƇłƄłƈŌĄÈĂńƔLjȆɊʈˈ̒΋͔̘˂ʆˊ̄ˆʎ˄̆˖̊͌̃ː̎ʄ˄NJȄɄˆ̈͆΂φΎτЂόЉя҆ӃԊZi¾ɓȄ ǗȂLjȩɛȎǎŇƎňƚŌĉÇĚÄČԌjb¾ĿúŋąÉ„…ˆK֗مڍمׅԈӃ҄тЄ邞ЂDžȐ†ÃĈňƍNjȒɄȈǂȊǏƉņƈǒƪDžȃLjȆnjƄǍƃņƆŅĊÇąŃƌLJȇɌʅʆˌ̘͌Z|߈j}ſĖÄŸÏÇĄÑđҖj}}}|}~~~[~~}}|¿~žO~|քׇ؋ׄքՂԄхЅɄņ†ÇĉʼnƐdžȆŌƍőċŊąłČņƂňƂŠƔłĆձǂƒÆăōƈLJȑɍʗˆ̅̀ͅ{~G|Ŀ~Ľ悖…фҖj|||~{|}}}~~~[~~~}}||{}Ŀ~ýT}{ՊւՄֆՄ҄тЅτ΄ Ȅǃƃ̄ȈDŽŋƋŃƅŌčÂąňDŽƄDžȄɈʈˈ͍̊χ΃͈̆͆̐ˈʆˈ̒ˎ͖͇̂̐̊˅̎˂ʆˇʄɊȇɄʄˌ͇̆·όЄтЌі҈ӂԅ[l¾½ĽɖȄǟȏȇɄȑɑȒǖƆƅłģřĝÆďҍh\ûňே†Tր܄݃މ݆܄ل؂ׅփՅ ΄邝DžʏŠÆĈŅƋǎȋɆʅ ljȈNjƉŇƄǕƎǂȖljȃLjȆNJƆnjƄņƆňćÇąŃƌLJȆɇʐ˒̘͌Z}~g}}»}ɇĐÂĠÂćÏÈăÑčÓ–j}|}}~~Z~~}}|}¼ƿZ}}}~|؊ن҄фɅ„ÈĈŌƐnjȄǓƌŇÊĉŊĔŲƔłĆŎĈƂ„ÅăŎƇDžȌɂʄɊʠˈ̂͆X|}އi|¿||וŒÐ„Ò–h~~|~{||}}~~~a~~~}}||{ÿ~|Ľ_|~||}{ׅ؈׆քӄ҂фЄτ Ȅǂ̅ȉǐƋłƄŌčÃĆŌƂDžDŽȆɈʄˈ̈͐Ήτ͈̋̊ˉʆˇ̓ˍ͖̃̔͊̄ˈ̈̄˃ʆˆʈɇȇɄʄˌ̆͆ΆϐЎт҄іҐXfχɍɈǗȂɇȏȈɃȕɍȒǖƆƅłĊŃĖřĜÇď҈f[ÿ½Ļņć҇Zވ߈ބ݄ڄق؄ׄ΄肝ȄǂƄǑ‰ÆĆʼnƅNJȍɉʂˉʄɑȆLjƍŅǓƘǂȅǖȤLjŎĄÊĄńƊdžȆɄʋˎ̙͇͋΄X~|h}ĿſňĎÈċŊúĈÎǜh~||}~~[~~}|~þ^}}~~ۉۄڄ؄Ն̈́ʅƄ…‡ÈĆŅƒdžȄȉɄȄDŽNJƈńĈÆąŌďłƄŘƆǓƄŌƏŌČ΄ÄņƆdžȆɎʖˈ̂˒\}{~g¿|þĽ~lj׆ŽÇ†Â„Ä‚Ì–m}{~{|}}~~~X~~~}}|{¾}¼ž[|~|}~~}وۅچق؄ӆɅ̈́̂˄ȇǐƏÅĄÆĄŎƃljȆɆʇˆΆ͌ΊφІτΔ͂̈ˌʆ˂̑˓̤̂̈́̌͢˂ʎɄȊɃʄˋ̄ͅΆφВѠґӄWhĽʈɎȈɋȅNJȐɂʄʣɈȎȇǜƉĎŊĂňĄōħÇĐӈkX¾ÿżňąÉ„…ƒ…]څ҄τ肜ȏ‡ÇĆʼnƄDŽȄɃȌɋʈ˄ʄɔȂLjƎňƂōƙǢȥLJŎĄÊăŅƊdžȅɅʇˑ̆͊̐̓·ͅ΅V}iÿ}¾~¼ŇąÂĆÈċňÑăńŝĂÄĈ֔ i~~|}~~V~~}|¿|ſ}d}~ޅ݅܂ۄل؃և̈́̃˅„ˆÆĈńƋdžȒɄȏLjƆŅĈÆĄōďƅŖƉLJƂLjƄŏƍŌŠÎ„ÄƄŅƆdžȅɎʖ˜Z~|c|}ƋÔ…ŽƒÅŽÆ‡„Ă̊g}}{|}}~~~V~~}}|{~{þ|ƿh~|}~ۈۅڂلԆɅȈǏƍÅËąŊƇLJȇɆʇˆ̄͒΅ϑΔ͂̈ˎʈ˂ʌ˙̥͊̈͑̋˂ʈɂʄɄȊɃʄˊ̅̈́·υГі ҒӀÿEĿͅʈɄȂɆȈɋȅLjȐɄʄʋɂʑȄɈȖǔƄłƋĎŋňĂŎĨÄĒЉdXƽŇĆʄ„ƒ‡e +ۆЄ炜ЄƄŅąÄŒ„Âĉňƈǃȅɏʋ˅̄˃ʏɆȂdžƒŏƛNJȂɘȎDŽȌǂƄljƃňăŅĂÊĂņƄLjȅɅʊˎ͍̅̎ͅ·͂ΆV|e}þ}ƿ~ƇŏĂÊĄÂÍĂņĄŠĄÂĆLj‘g~~}}~~T~}|}}~ c}}~߅ ؄ׄ΅ʂȄĄÄ…†ÊĈńƆǒȈɌʃɉȄǂȆǂƆņĂÄÓćņƈņƕǃƈǞƉʼnĐÌ„ÂąƆŃƅLjȆɔʖ˄̂˘V{~d||ž}Ŏ֐šÅŠÔ†d}}||}}~~T~~}|{ÿ|ſ|}h||}~އ߇ރ݅ ׄ̄˂ʄτ˄ʅɅȄnjƌŚĄŊƉDŽȂɉʈˈ̂͆ΐχЊуІόΆ͂̆˒ʎ˛̇ +Ε͌̆͑̊˂ʈɃʅɂȊɂʅˉ̇ͅΆτДш҄ьӄҔXdÿžˇʏɂȊɄȂǏȌ ɄʠɄȂɆȆDŽƆLjǑƎƄĄŊĆńĄŒĬėȝbYÿ¼ƾĆʃƒÉˆg ބӅ炜ʄƆńĄÄ‰ˆÂĆŌƇǃȆɒʈˌ̃ˈʉɆȂdžƒōƛ əȍDŽȒljƃňĄŐĂŅƉLjȅɆʉˏ͎̃̎͆Ά͂ΆV|}d}ýƈŐĂÊĔÌĈłĄŠĄÂĆÆ„Šf}}~}}~~V~~}|~¾~¹򋿇k}}~ +ل؂ׄʃȄąÄ„‚ÍĈŃƄljɄȎɏʃɈȄǂȆǃƅņĂÅÓņƇŅƘƉǞƊňąŠÅ…ÂĄłƅŃƆljȅɔʖ˄̂˘V{|d|ſ~»őɂ˅‡žÆ„Ó‡c||}||}}~~X~~}}|{¾}}𾽆h||}߄ބ ̈́ υ˅ʄɄȄLjƌŔŅĄňƆLjȂɆʋˇ̄ͅ΋ψЍфЈυ΅̓̅˒ʎˇ͒̄͋΋͂Ή͊̈͐̉˃ʈɄʏˋ̇ΆυЏш҈шӅҖUc½»ˉʏȋɔȌɏʟɄȂɆȆDžƃNJƂnjƒƄŊĈłĆŎīęɞa򀆋TýǾćLJŠÌˆh ߄Ԅ 悛ЂʄDžƅłĄÄ…‰ŅdžƇǃȄɂʏ̅ˉ͇̂̃̈́̆˂ʉɅȄdžƒŏƕDžȎɄȄɄȂɌȄDŽȌLJƅŊĂňĂńąŃƊDŽȉɇʈˠ̑͑T}|b}~}ȉŝĆÄąÍĐřčō†a~|}~~T~~|¾|Ŀº򉿉s}}(ф ȄǂƆń„‚ÆċŅƄǃȇɊʂˆʏ˃ʅɅȆƄŊÎĈňƂŐƣǟƄłƄňăNJ‰ÄĄʼnƇNJȆɍ˄ʆ˂ʅ˃ʈ˂̄˖T|{~b¾|}ƿ|ğބ…ÅĒDŽ…̄a~~}{|}}~~T~~}}{~|þ~ p||~ʌ7Ƀτ̄˅ʂɄȄLjƌňĂŊĉŅƉljʄ˂̆ˆ̄χцАу҅ц҃хЃω΄̈́̆˒ʎˈ͎̂͆̂̈́̈΃͆Ρ͌̇˄ʊɂʈɂʄɄʄ͉̇·ωАуҋш҂ӆҔUcÿƿ͊ʜɆȄɅȍɐʘɍȅǍDŽƆdžƚŏĐŔĊ’ĐϐbZſȿÄĉąˆ„Â…ÅĊÈ…pф5傛ЃʄɂȅǃƄłą†…ÈĄńƄǂƆDŽȄ˄˅ˋ̆͂̐˄ʇɆȃdžƏŎƐNJȎɄȄɄȂɒDž ȋLJƅŊĂňĂńą LJȊɇʈ˟̑͒T}}}`¿}}ž̌ňĆŎĄËÐĘŕČŌ‚…b~~|~~W~~}|~ú󈿉r}5 +ƅŅ…„ÄċņƃDŽȂɎʐ˂̈˃̄˅ʂɄȆdžƄŊÎĈŚƧǡƅŇăÇ“ÅĄňƇNjȆɍˆʄ˂ʅ˂ʈ˃̄ː̂̈́T|||a|ľ|Ľġ̃͌ÆĒƄ„Å„_}}{}}~~W~}}|{ÿ}Ŀ~¹񋽈r~|~1˄τ΂̃ͅ˄ʂɅȃljƋŇćłČńƉDžȈɃʅˋ̅Ељ҅тЅφ΅̓̇ˎʌˊ̂͆̈͐΃͇΢͋̇˄ʊɂʈɂʄɄʄ˂̊͊·ωАтҌш҂ӆҔӀ¾;üˋʈɆʏɃȋȏəʕɌȅǍƇDžƚōĐŔĈˉÈĔʒ`X¾ȿÄĆÆ…ˆ‰„ÊĆȆrğ5傛 ȅǃƄņ +†ˆÆĆńƇLjȅɂʄ˂͍̌΃ώ΄̓̄ɇȆNJƆŒƊǒȆɋȂɆȄɥȃLjƄŚĄńƃLJȌɇʉ˂̆ˆ̂ˌ͕̑΀}~~9~ü}ǡʼnÅŒĠŒĄ…Ç„…a~}~}~T~~|ÿ¼Ļ󆿄v~}܇߄ ƄņĂŃ„ÇĆŅƋʄˌ̂̈́̌͂̄͂̅̓̄˂ʄLJƇŎĄŃĆňDŽưǛƄňĆÄ„ÂŒÆĄņƇNjȄɞʈ˚Z|}}a}ÿ|ŋĆÅčȄˆ‹ÆĄÂĄÂČˊ `}|}|}~~T~~}}{~ú񈽄y}|~ڈ/ ͆̃˄ʅ LJƖŃąņƆLjȆɆʄˆ̈͆ф҅ӂҊӊԅ Ԅӄ҂фЂτΆ͆̊ˆʒˊ̒͌΄̈́΄͌Π̓̇˄ʐʉɂʆ˂͍̇΄φЄМч҆ӂғԄS`̡ʏʒɠʒɄȂDŽȇljƊǂƅDŽƃńƏőĐŒĆχ +ĉՉaT½Äăĉ†‡ÅćÒĂŋy;䂚 ȆņĄ‡†ÈĄņƈǃȇɅ˄̄͋Ις΅σ΄͂̄˂ʄɆȆnjƄŒƊǒȆɋȂɆȄɥȃLjƄŚŇƄDžȍɅʕ˂̄ˌ͖̐R~}_~ĿƣōĂŒġőĄÉ † +_~}}T~}|}þ}ż󆿄|}}԰; ƅŅĂÆƒ†ÆćŅƆdžȂɄʂ˄̂̈́̏̓Ύͅ džƈŎĈńąŋƸǏƃLjƅŇĈÂ„ÂŒÆĄņƆNjȅɞʋ˓̂̈́̆T}~|^}ý~ƿȝčǘÄĄÂĄÄĆ̉_􀆌}||}~T~}}|{|¼|û򈽄||~үބ +̄ͅ˃ʅɄȂNJƖņƆdžȈɄʆˇ͈̃΄ςЄтҌӎԂՒԄхΆ͇̌˃ʒˊ̊͂΅͍Έͅ΃͎Ξ̓̈˄ʏɂʇɂʇ˃͈̅΅όДш҆ӂҒӄUӁ`žˤʌɃʇɂʈɡʑɄȈDŽƂDŽƊǂƄDžƃňƏőĐŒĆχČӊ`]ÿþĉ‡‰ÆĆÊĂņĂŋ{ڵ:䂚ǁ +ȅDŽƂňĄÂ‰ƒÅĄňƆDžȄɃʄ˂̅ͅ΃ϠЅςЄͅʄȌǝƇLjȚɅȇɃȇɡȊdžƄŖĂŊȉɍʜˆ͈̊΂͐ΆR~~_ÿ~~ž~ƇňƎłƆŊĊńĠńĄʼnă΄]~~~|}~T~~|ÿ~ſ}ƽ~}چ9 DŽƄłąÆƒ‰ÊĄŅƅDŽʄˆ̄ͅΙόΆ˄ +ƌōĄńĆŌƔǃȥǂƄLjƄdžƈňĆďÆćłƅNjȘɌʊ˕̏R}}_}¾}ļ}ŘĂÄÅĈÄ ÅćÄĎʈ]}}}{|}~~R~~}}{¾}þ|Ļ򆽈}|~؄5 ͅʈɄȂljƋŃƆƉɅʉ˅̅̈́΄҇ӃԆՈՅւՄֆԆՆ҅ ͍̜ˆ̈͜΃͉΂͊Ἠ΅͉̆˅ʕɂʉ͈ΊϝЇъҔӎQ^¾ſûˆʌˎʂˆʊɄʂɋʃɠʂɆʉɃȎDŽƒǒƓŕĄńĂŎď͖Ë‹^򂈎RĿºÆ†‚‡ÉĄÅĊńąÄŠ5゚́ ȄňĄÂ‰…ÃĊʼnƅDŽȆ ͆΅ςМэЅͅ ȉǝƇLJȜɃȉɂȊɘɅȊdžƆŔĂŊȈɐʇ˂ʑ˅͈̋΂͋΋P}|`¾~ľ}ûljōƌłƆŊĄłČłĠńĄņĆÆ‚‘h}~|}~~T~}|¾|~ƽ􉾆~~ +ɦ9 DžƄąÇƒŠÆĄŅƆ ˄̇̓΅φЕυ΂τ̅ +DžƄŐĂņĆŋƃnjȄdžȤǂƄLJƅdžƄŇĈÅĈłƆNJȜɈʆ˙̎̀~|{~5}½|ƌăŐĂÅĬÉăÄĎʇ\􁇍|}{|}}~T~}}|{~{ſ}ż򆽈}}~Ǥ +ۄ ΄ ʇɄȂLjƌńƊDžȃɉʊ˄̅ͅ +҅ӆԄՄֆוօՂքՅ҄ ̜͊ˆ̈ϴΒ̈́΄͊̆ˆʓɃʉ͈ΎϙІъҕӍRՂ]Ŀ̈ʎˌʂˆʊɄʂɌʂɠʃɅʆɆȆǂƆǃƑǔƔŔĄœđ̕ˌŽ]Rÿûdž‚†ÒČѱĊΪ5゚ӁDŽƄņĄÂ†‡ÅĆņƆdžȆɄʄΆτІфҊӊ҆х҄хȆLJƄłƋŅƈDŽȄɌʅʌɂʘɒȌLjƈńńăŊƃdžȄɌʃɏʊˇ̄͛ΊR}}]ľ|ƊńdžƑŊĆłĤŒĊބ’]|~|}~R~}|}½Ǿ􇾉~}8ńĂDŽ +…ÆĆňƄDžȅͅΈσОфЄτDŽƆŗĉńƅDŽȈdžȄLjȟDžƆDŽƇƈńĖÄĈńƆǔȑɈʇ˘̌̈́P~||a~½{ǿ~ÉĎņĂÆĖÃąÄĈÌ篂‚`~{}{|}~~R~~}|{¾|~ƽ򎼆}|~ ߄̅˃ʆɄȂdžƎłƇLJȈɅʆ̇ͅ΃υԇՆփמ؄ׄք͆̇˄ʂˋˇ̅̓΍τ΅ω΂Ϝ΍͌̈ˉʇ˅͇̃΍ςΆτІφЈцҙӋԄՀ3Ŀƾˉʄˊ̅ˈˈʉɇɛʂˈʒɊȞDŽƂǒƂŇƊŕăŅĄŋČӇʌ‚„^򃉏Q¼ü…É…‚ÎďńąÄˆ7ₚفDžƃńĆÅ ÍĄņƄLjȄɅʃ˄υЄ҇ӆԇӉ҄ӄ툏~ɄLjƑńƈDŽȅɌʅʋɃʜɎȌLjƊĄĄŇƆdžȄɋʅɎʊˇ̃͜Ίπ~3|ľƿ|njŅƇǃƑʼnĆłěƈŒĊރ\~}~Q~~}¾~þȿ􇾊}|~|}}}~A٬ʄƄńĂÆ„†ÄĆņƆdžȄɄ ΅φЄќ҈фЄ뇍}ƅŏăÆĉŃƅDžȈɄȂdžȃljȏǃȐǂƆDŽƆłƈŅĔÄĉńƆǖȐɇʇˎ͉̋ͅQ~}~_ÿ~{½Ž{ĄÈĎŎĖÃĄÅĉËđDŽ‚`~}|}~~N~}}|}½~ƽ򏼅|{}{|||}ת3͆˂ʅɅȃDžƎłƆȍɅʆ˄̈̈́΄τЄԆՄֆׄ؜ل؄ׄ󌒑΄̈ˑʂˉ̄ͅ΍τ΅χ΅ϝΊ̈́΂͍̇ˋɈʈ˅̆̈́΍ςΐχЇцҘӌԄP[ÿļ̋ʅˍ̃˅ʄˈʈɆɛʄˆʒɊȞDŽƃǑƂņƌŌĂŎĄŐďфЌŒ…^RýļʄƒÍčŅąÅˆ ߰ₘԁDŽĆƆ„ÊĆņƄǃȇɄʄ˄ +ц҅ӅԇՌփ׆օՄԂӅ쑢}DŽƌłĆńƈȋɊʐɄʠɄȈɆȊdžƈƄŃąŇƊdžȋʆɔʉ˃͙̄ΌRЀ}[¾|ľŽƎŌƆNjƋŅďłƟʼnčî†^쀇~}}O~}|ɿ􍾅 +}|}}}~~D}ƄĆŒÆĄŃƆDŽȅɄ +τЈф҈ӄԄՂԈՇԆӃ҆ꐡ|ŅĐÄĄņƊDŽȆɄȂdžȂǒȆDŽȄDŽȓljƈńĄÅĉÆĆʼnƅǛȍɃʅ͋̅͂̌͆O~|Z~{½~ûʅĆÌĎŇėÆčÇĒÆ¦Z~}||}~S~~}|ÿ~{þǾ򼽽~|~{|||}}}~~%|̄ɆȆdžƎłĄDŽȉɆʆ˄͈̃΂τЅ҄ք׈؄مڅی܈ۅڃن򕦧̄ˌʂɆʄˇ̂͊ΌύΈϪΆ͊̆ˈɅʇˊ͉̆ΝψЄфҒӌԆP\ÿºˌʎˆ̌ˊʄɐʂˠʈɍȫdžƔŌĂŤĎ⌔ˆɊ[󃊐P¾ſ﯃ŽÎĂŊĆȈBₘˁDŽąÇ†„ÆĈņƄDŽȇɂʅ˄ ҉ӂԆՆ֋ׅ؈ׅքՂԄ擳ƋŃąŅƇȌɊʍɉʪɇȉdžƇ ĄňƋDžȜɎʆ˃̄͗΋υP~Z}Ŀû~ȄƐŊƄǎƉńİʼnĈĄÓׅY}~~|}~N~~|ÿ}􍾅~}|}}~ƄˆŠÇĄŃƄdžȄɄ̄ш҆ӆԄՎֈՆԂӆ 咱~ĐÄĄņƊDŽȆɄȂǤȄdžȈǂȈLjƈńăÇĈÅćŊƊǚȌɄʄˎ͇̓O}Z¿|½~º}džĄÑďŊĖÆċÆđƧ[|}}{|}~R~}}{|ĿȾ򼽽}|~{||}~~9̄ɅȇdžƓƄDŽȆɈʆ˄̃ͅ΄τЅ؈لڇۃ܌݇܆ۂچ엷ˌʂɅʅˆ̂͌΄ςЅυ΂τΑϣΈ͈̆ˇʄɄʇˋ̆͊ΘωЃфґӌԆՀ¿.Ŀͅˉʏ˅̎ˊʂɐʂˡʇɈȄDŽȓȖdžƔŖĂÛčߋ”…ƒÈŠ\〈PŽÅƒŽÎĂŊĆlj%႘ŁDŽƄʅ„ÄćʼnƄɈ̄τԈևׄ؇وڂنچ(ލĿ}ƆņĄńƄDžȍɑʃɎʃɋʒɂʉɇȊǃƅņƊņƍNjȖɌʇ˄͇̊ΌψM|X}ľ~͆ǎƈʼnƃNjƓģŊć˂ΈЂ„W}~|~~P}}~¼}}}}~@ńĄÂ…„ÊńƂdž҄ӇՅօח/܌¾|čÄăņƄǃȄȆɎȄɒȄǓȆljƄŋĄÇąńƆŃƏǂȋljȉɅʅˋ̐͌M{~YĿ|ý}ƉŗđŃĞÃČÃčË…W퀇|}{}}~Q~~||ÿ}ȿ󼈽||||}~~@̄˄ȉdžƈŊDŽȄɄʉ˄Έڈ܈݄މ)ˆʆɄʄ˄͎̄΄σЩϑ΅ψ·͉̆˂ʆˊʅˍ̄̈́΄͕΍τІш҉ӍԌNXĿǿ҇̍ˈʈ˄̌˺ʊɇȋǂȎLjȐDžĄłćřĂÐăÍĊ܌ƒ„‚Ë…ÈŠXN¾ŽÆ…ŠÐņĉˆ:႘DŽƄƈ†ÄĄŌƃDŽȂɈӄՇׇ؄هڈۂڇ3ۃÿ~ņĄńƄDŽȏɯʋɈʈɈȈǏƉņƎnjȔɍʇ˄̊͆ΏωN|}X~Ŀ~ʊNjƌŅ džƏŅĄłěņČ˂ĂȈЊU}~O~}ÿ|ý|||}~䠄9ńĄÂ„„ÇĉńȇӄԆՆք׆؛,ق}ċÂąŅƄDžDŽȇɋȌɩȉNJƃŊÇąŃƇńƆǂƔljȈɇʈˈ̊͌N{|X¿}ý}ƾȏŔĐńĞÂčÂčˆV~~|}~M~}|~{¼{ɿ󼇽~|~{|}~⟄9̄˄ȆLjƆʼnƃdžȄɄʌ˂̄͂Άτۇ݉ރ߉.ĿʆɃʄ˅̄͊ΗςИωΎχΈ̈́̏ˈʅˎ͕̌ΌυІщ҇ӍԌNY¿ĿŽϋ̋ˇʄ˄̂˅̅˒ʂɈʂɜʆɈȋǂȎLjȐNJĄłćńÕÐăÍĊ܌‚ˆÉ…ÈŒW肉M½ƾņ‰ÐĆņĉ†꤄9ƆńĂĎ…ÄĄňƆDŽȄɄʄք׃؄نۄ܊݄ބ݂ކ;񄂀}½ƇǃȉɆʄɕʄ˯ʐɄȅNJƉńƎLjȂnjȊɌʈˆ̊͆ΆЄϋL}~W¾~ſ}ƾȒNJƇʼnƅLJƆłĄňĂňĖňČтߍW|}}J~}|}ſ}º~|}~9ć„…ÇĆńƄDŽȄɄԄՂֆ׆؅مڊۄ܂ۈ2|~ĈńƄǒȊɇȒɃȄɄȂɄȈɏȍǂƍōĎŎƒNJȋɅʈˇ̅͏΅π|}}*ý|Ž~njłƉŏĈƄʼnĪÂĈ΄Z󃉐{~||~~O~}|{Ŀ|ý|}{|}~9ˆʄɂȄǍƃŊƃDžȄɄʈˆ̃̈́΃τЄ݅ޅ߆;½ˇ̃ͅΊσΆσЌφЄτИσЏό΄͆̊ʆˎ̌̈́΂͍΋ϊЅщ҆ӄԆՂԈՄLWĿû͒̋˅ʆ˅̇ˆʂɅ ʇɗʈɌȑǂȞLjƈłĈŸĈ؂‰‚Êʂȇˆ^N¾ĿǿLJ„ÖĄņĉÀ +9߂Ɔń™„ÅĄňƆɅʃ˄ׄ؄مڇۂ܅݉ބ߂ވ5퐑~ĿƅŃƇǃȉɆʄɕʅ˃ʅ˔ʄˏʏɂȇDŽƂŊƎDŽȇNJȊɍʈˆ̊͆΅όL~|Vſ}Ž͖NJƅʼnƄLjƇĄœċłćʼnČÑ߈ Vꁉ||}L}}ÿ~~º}}}}~?ć„ÅĆńƃDžȄքׄ؆مڅۉܐ݄=뎐}½ńƄǓɌȆDŽƊŌďōƒLjȌɆʈˇ̅͐΄L}{~V¾~þ|ļ˄ƊłƌŌĎʼnĕ›Î†V耈~{~{|~~N~~||½}ž}||~||}~> ΄͂ˆʄǎŊƄDŽȄɅʇˆ΅τ܄݂ކ߅3Ŀ˅ʂˈ̂͆Ίς·χЈϒЄωЏϏ͇̐ˎ̄͌ΌϊЅщ҆ӄԐՄLW¾ſº͗̈˄ʈˇ̈ˆɅʇɂʉɌɇʉɌȑȟLJƄłƓŲĉ؂‰Տ^NȿȆ„ÖĄŅČ5߂ ɄƆŅĂč†ŅƉɄʄهڄۂ܅݃މ߆5߃˓}ʆƅDŽȊɂʄɌʌ˄ʝ̔˒ʂɆȊljƛǂȎɊʇˈ͇̉΅ϏЀЀ~*|}ļɇȕǑƄǎƊœĉŊĒìŒ T~}|~K~~|~û}}|}~ +4ĈĂÅĉńƄǂȅׅ؅كچۂ܄݈މ߇8ނʒ~|ąņƃǏȃɄȌɂʉɅʄɆʄɍʓɎȄNJƆłĊƅłƄłƆŃƇǎȎɆʊ˅͕̆΀~}~{'ľ|ûȓƊōđņďń•Έ +U}~|{}~L}}{Ŀ~}º||{|}~?ˆʅɂȄǍƄńƈdžʅˉ̄φ҄ބ߆6їυˆ͈̄΅ІώЄφЂфЂьЈђАσ΅͋̅˝͎̃ΈόЈщ҅ӆԔՀÿ'ſϋ͎̐˄̄˂̈ˊʒɊʋɑȬDžņƈņƊŪÉĉÈ¡“׊UりL¾Å„‡ÎĂʼnÆĀ3߂Ȃ ȄƅņĂč†ńƉDŽʅ΄لچۄ܃݄ރ߈:}þ|ƅDžȊɂʄɌʌ˄ʌ˄̉ˉ̒ːʄɆȊǂƠǃȍɉʇˈ͈̉΅ύЄKU}|ûɌȎǐƃǏƊœĉŊĒìŒW􅌓~}|~~J~}ÿ}ýļ~~|}~4 ƄĆń‚ÅćņȆׄ؆ۅ܃݄އ߇@쭏~|½{ƄņƄǎȄɂȍɃʈɢʆʊɆȆNjƎłƄłƌŃƆǏȎɅʋ˅͓̈K~T¾|ľ{º΅ǐƏŊąłĊņČÆ‚ÄŽÔˆT򄋒}|{}}N~}|½|~û}}{|}~3 ΄˅ʆɂȄǍƄńƈdžʄˊφބ߄7þч͉̆ ІώЃυЄфІфЍѓЎτΉ͇̂ˠ͎̂ΈόЈъ҄ӇԓKUſ΍̄͌̐˄̄˂̉ˉʓɉʊɒȭDžņƈŇƊťÈĉȜ„‚Ǐ։TKüĄ‡ÄĂÈĂňĀ +3ނςŅąÃŠ‚ÆƇDŽȂɆʄքۄކ@}}̋ȍɆʂ˄ʂˆʐˈ̂˕̊ˎʅɑȡDŽȎɍʈˉ̊͆·ύЀ}||}%º}ɓȌǦƇŋÇĆňĈÄČê Vꃋ~}}~L~}~ĿŽ~}~5 DŽDž…ňƄDŽȅ΄ ׄ؃ل݆ނ߄?󰽺|þ|ˇƇNJȘɊɓʆ˔ʊɉȅǕƅňƈʼnƅǃȅLjȍɇʊˇ͉̇φ΀|{{|$Ŀ|ʏDžƎŊĄłĊňĉ̏؆S肉}||}~I~}|Ŀ}ýĻ}~|}~7ʅɅȃNJƆńƇǂȆˇ̅͂Ά +Մ ބ @ъ͋ΉψЅϋЂфДуҏтЄфЋτΔ͍̄͞ΈЄψІь҆ӆԐՀÿ(ȿ̈́΍͋̍̈˂̊ˇʒɇʄɈȄɌȪǎƠŠĈÄċɐ‚Å…ŠÄ…Ö‰SJ½Ľ¸…ˆÂČÅÇĀ7Ղ DŽćĊ‚ÇƆDžȂɆʄЄ مڂۅބ߅C|}͊Ȋɇʄˆʊ˂̄˔̂͐̂˄̄ˍʅɔȞdžȆɂȈɌʆˈ̋ͅΈόJ|~|Xÿ~ȄɍȋǣƇňĄÆĆňĈÄČʂގW܀}~}}H~~ÿƾ~~}~φ6ńĂ҆ňƄDŽȄׄ ܄݅A칦¿~{ſ|DŽƇDŽȗɋɋʄ˃ʋ˒ʈɉȉǓƅņƈŊƌLjȉɆʌˇ͎̇J|}{S}ſȕDŽƎŊĄłĊʼnćˏ؆T|}||~H}}½~ľļ }}|}~ͅ5ɇȄNJƅŅƇǂȇˆ̅̓΅τބC҉͋ωЅχІфВчғшЊυΕ͎̄͜ΌωІь҇ӆԎJ􀅋SǾϏΉ͉̕˂̌ˆʈɄȆɆʈɈȄɌȊǂȝǏơşĈÄċɐ‚Ć…ŠĆ֐QჍIĿžù† —ÄăÄĀBՊۂ DŽƄĄÊ‚ÈĂńƄdž"ڄ  J|ɈȊɂʈ˂ʌ˂̈ˌ̒͒̈ˈʇɕȄDŽƒǎȏɊʅ˅͈̊ΉτH}|}Q|~ГɋȅLJƂŚƈŅąÈćńąÆċƄ̂Ώ W}}~}~J}|||Ǿ}}~2ل Ƅń…†ÂĆŃƅɄ؄ۄބ߄ G~~|ĿȆƊǃȓɘʐ˂̆˂ʉ˅ʇɆȈǂƈdžƆŃƆłƄņƒNJȊɄʏ˅̊͆J΀|~{|Q{ÿ}ȿΆȕDžƊŊăņĈʼnąËÕŠS||}|}~J~~|{Ŀ{{Ž}|~|}~F +̈́̃˄ɄȊƆňƄǂȈ˅̅̓΄  JÿΈ͉΃ψЂϋЖѕ҆т҉чЉωΔ͂̄˒͍̎·ωЅю҄ӆԆIՄP¾ƽ՚΅̈́̂˄̆ʏ˂̋ˇʅɅȈɇʄɅȇɊȆDŽȌǂȎǏƄōƔŞĄĊɋ‡ˆšÓ…P׀Kù…›À􀅉IƅƃÈĂńƄDžȃɄڄ J~·ȉɂʈ˂ʌˆ̂ˎ͓̒̇ˈʊɔȂDŽƒǎȄȋɊʄˊ͈̊ΈτG~}|}R||ÿ¼ʔɅȄǂƄǣƈńĄÉćńąÆĊăņʂΏV}|~F~}þ}¼}ǿ}} 5 Ƅń„†ÂĆŃƄ#لK}ſDŽƉDŽȎɒʒˆ̔˃ʆȄɆȖDžƕŎƌljȉɅʏ˄͈̊G}|{|P{{~ǾˈȔdžƊŊĂņĈŌĆʌխR|~{}~F~}|||ƽ||}5 +̈́̃˄ȄǂƄƆŇȈɂʄ˄̄̈́ Jӆ͉΃ψЂωЗѐ҂ӄ҆ц҆цЋχΈ͂Ί͂̄˒͎̎·φЄю҅ӇԇINż҆ϖ΄̈́̂˄̤ˇʄɄȉɇʄɅȆɊȄǃȅdžȊǂȎǏƃŎƐŞĄĊË„ ¤Ô“†OJÿŅ˜ÀLŅ“†ÄąŃƄɅڄ +N쉀ÿ~ɅȆɈʊˑ̄̈́̅̓Έ͒̄ˋʏɊȇLJƋǓȊɆʅˊ̈͆ΊNρ~|}}}~Q}}}||¼ȿ}ʚɉȐdžƆŋƈŐĆŇđDŽĉ̨Oヌ|}~H~|~Ľ~ȿ}|~5 ƄņƒÄąDžȄ̈́لQ}~ƈDŽȌɊʅ˅ʒˋ̓˄ʄɂȄɆȇǃȎLjƍőƌNjȆɇʊˆ̈͌H~}{|||}Q|||{ÿ~{ƽ|ɇȃDžȐdžƎŕąňĄÆ„ŠԔ”S₋{~|}H~}{ÿ}¼}ƾ~|{}~5 +̈́ʅǏŊƂdžȈɅʂ˅΄τЄ N¾΄͇΄ύЉф҇ёҊӆ҄т҄т҄фЄςЇϑ΂̈́΅͇̆ˈ̖͉·χЉш҇ӇԊFP¾¼Ļ΄φ΂Ϗ·͐̆˂ʄʌˇʏɇʇɑȇDŽȄLjȄǂȌDžƃŠƌĆŋĄņĄňÉć÷¦Ç‡ÎŠІT醏K½ź…Æ€5ń“†ÂĄÂąŃƄɄʄ˄ބP~~}~~ʄȅɈʊˈ̄͆̉̄ͅΈ͒̄ˌʒɅȇLjƋǒȊɇʅˊ͈̆ΊςЄF|}}~O}}|¾}ýǾʌɂʍɊȏdžƂńƇŋƈŏąňĒÆ„ÄŽÌ„O׀||}~G}¾|ž~}}~!5ą„ÃĄDŽȅ'߄ +P멳}}|}}ȉDŽȌɈʞˌ̒˅ʉɆȆDŽȎLjĈŒƌnjȅɇʊ˅̉͋G̀~~{||}N||{|żщȂNJȌǐƆŔĄňąÃ’Ô”O{{|}~H~~|~{ý}Ǿ +z|~|}~5ʅǓƂŊƂdžɅʂ˅΅"S󮹁¾͆΄όЊш҂ђҊӈ҂ф҅фЇϗ΅͆̇ˆ̘͈ΈχЉч҆ӇԊJԅS¼úΆτ΄ύΉ͎̆˂ʄˆʌˈʎɇʇɒȆDŽȄǎȌDŽƄŜƊńĆŊĄŅćÈĈƂî¨ÄˆÎŠˆP݄Kþľź„Å򀅊!5ƄŃĄŠÆĂńȄʄ΄#o削}~̅Ȅɇʇ˄̌Ύ͍Ύ͉̄ˏʇɂʈɇȇljƇnjȉɉʅ˅͈̉ΆτЈG􀅌|}}~~~S~~~}}~ľƽʄɈʌɄȂɋȋDžƈƒŅŌĬË®N}}}G~}}~|~` ƄłĄÅ‚ÄƄ#ڄT䈉}|¿}ĿʇDŽȇɈʅ˒̊˃͉̄̐ˇʆɗȆdžƃŅĄŏƌǍȆɄʉ˅̈͏H̀{||}}}~O}}}||ÿ}¼ż͗ȑNjƄşĕ֒ŠN|||~~F}|þ|ž~ǿ +~}{}~[̈́̂˄ʃɄŅƆŅƂňƂLJȆ +̈́ +ӄ$T쌎¿΄̈́΅υЈхҐӋ҄ӂԈӐ҈уБψΈ͆̈˄͈̍΍φЅщ҃ӉԎFԅPýº΄Ύϒ΋͋̇ˇʃ˘ʌɫȋDŽƃťƆņČŌċŃąÅĎ„ՄРÂċƈNJŽÂŠOҀJſ݇ƒÄƀ_ DŽƅłąŠÆĂńȅ ΄<\򛢅~}ſ~ȄɈʅ˅̆͊Ό͎Ύ͉̄ˑ ʅɈȆLjƈǐȈɎʆ˄̊ΆτЈF}|}}~~P~~}}¾~ľƽɄʂɌʌɃȅɊȌljƟŌĪË­M򈏗~|~I~~½~ ~}gĄÆÄƄ ̈́ۄ%W}|~ľ}ȄDžȆɇʅ˕̅˅͈̉̐˅ʇɕȆdžƄńĄŎƌnjȉɅʆˇ̉͏G̀􀅋|{||}}~M}}||}ýż˚ȎǓƄŞĐڄ’ŠL}{}~F}}}ƿ~ȿ}}|~TՄ +̄˄ʃɄńƆŐƂNJȆ +̈́ Ԅ}~}~D~}~ד̌˄ʊɢȈDŽƄDžȇLJƈŋƊńĂńăŇŅĈȂ؆† +…ŠEه}}?~|~ǻ}f|}}ۄ܄݄t~~}ڨՄ φ ʄńĄÅ‰DŽX嫷d}{}ü}ʅ˅͎̒Θ͒̐ˈʆɑȍɄʈˈ̜͖>|}|}~D}|ĿžȾ}Յ˂ʊ˅ʋɉȇǑƅNjƏłƄDŽƊņĆÄĆŅĞÇ¢F؅~||~A~}{þ}~ƺ|h{||~ڈj~}}|ئ~ ӅΆ˄ʂɅŃ˅ʃɅȇǎƂŐƆɄPńƅDŽdĿûц҄ӉԂӇԎՑӅԋӂ҅Ӑ҉фІχ΃ύЄч҈ӚԓAԇ󀆍E¼žŻ܉҅эЄτΣ͉̂ˇ̇͆̄ˇʌˉʄɂʄɃʇɂʄɈȈǂȘǍƅƖLjƅŇĊêĄÆĆŌƌŇƇNJƉŅĊÇċňƂŎƃńƏŅđƎJߊ@ſhkଂބڅՅ τ̂ЂƄłĉȎĄDŽE|Ì`}ƿ~̈΄τΊτМϒΌ͍̃˘ʌ˂̈͐ΒώІDτ~}~F~}ľ}}ӄ͎͂̆̉˅ʋɃȇǐȑDžȉnjƄŎƗŃćńć΄ŃɈ†̅‚EЄ~~>}|¼~üȼ}c~|~ߊn}}Ͼӄ΅ ɅȅƄăĊ„ńF{…Ä]~|¾~Ž}х˅̒͘Β͗̍˄ʊɈȊɇʃˊ̖͐΂ψͅ@}|}~F~}|¼|ɿ|ѐˍʈɅȊǐƅNJńƉŎƆŐćŌĚĤGσ}}~A~|{}ƺ|d}{}݅߄z~~||ͽц̅˄DŽƄĂ˄ʂɉȈǎƄňƆ̄aӀȄɆʄ]ļ؆҅ӔԉՂԆՕԖӉ҄т҄хЎόЄ҈ӐԚՂԄA􁇎GÿƿƼ؍ҍшЅϋΜ͒̆̈́̍˃ʇ˂̅˘ɈʅɆȎDŽȅǃȈNJƚdžȋdžƄŖĈÄĄŖĆŜƊǂƈǂƈņĈÅčŊƂœƑōć҆Fև?ºdpij܄؆ӆ ΅̈́ЂЅłĉɒĄDžb؊Ąńƅ]~þ}҈΄σΕςДϒ·͎̂ˆʂːʋ +͐ΏϓЅBτ~|~~D~}~ü}Ӆ̇͏̉˄ʌɃȆǐȕDŽȊǟơńĊĆŇƄ‚ĎŃą‚‚ˆD̈́}~>~}ľĽȼ}e|t}|Մ҄͆̂˄ʂɄȄDžƃĄÃ‹„ńb~׉„Éb}½ƾ|˅͚̐Ε̅͏̍˃ʐɅȋɆʄˊ̎̓΅͐΂ώ?}{}}E~}|}|щ˂̆ˆʂˇʇɄȋǏƆǎƈŏƈńĄćŌĂÆĊćĤF̃~|}A}|¼~¼ǻ|i􅌓~{~߈q~~|{¾ӄІ˄ʄɂȄDžƅ˅ɉȉǏƄňƆ̅aގɄʊ^Ž؄҅ӑԍԊՒԕӆ҅т҄цЊϊЅуҋӉՆԐՂֈԅ@EǼ؎ҏшЅϋΜ͉̖͒̅˃̆ˡʄɉȆdžȅLJȅDžƑȄǎȅdžƅņĄłĎŇćŒąńƊLjƕǂƇņĈÃĎŋƂœƓňĂńĄÒ‰DӇ?þû hq׆҅ф̄ͅԂņĆʔÄĄDŽȄd~DŽȆ^}|τ͆ΎψЂψЎςЈϐ΋͍̄˄ʃ˄ʂˇʌ˂̄͐ΐϠ=}|}C}|þĽ}ø~ӄ͍̓̆̂˄̇˄ʈȄɠȊLJȅƏǏ +ŇƌŅĈÌĈĂ„Â¨Å„‚ÄՊ‰Â„„ŽC̈́||}=~}ſɽ}a}y~}}҆ +̈́̅ʃɅȅdžƃłÅŠńƄA"}Ɗ^~|þ|ƿ˅̏͛΂͊Ώ͇̆˃ʄ˄ʞɆʂˌ͈̊΃͑΄ό=~|{|~C~|{½~ü|}ғːʆɇȌLjƊǎƂŎƌņƐŢĆÆ‰Œ„Œƒ ˆD̃{{|~?~}ľ|ýǻ|f|v~}||ц΄ +ɅȃDŽƈńʆɆȊǓƅŊȄ̄̈́e͋^Ž҆ӏԙՄԅՈԍӋҊхЂϛЄуҍӉԇՄԐՃ֍>Dľ»ȽِҒцЄώΌ͂Β͈̈̈́ː̏ʉˌʅɇȄnjȄLjȄǂƈDŽȂǨȅǃƆłěŇėŇƆǂȄȕNJljȂDŽƂňĄÅčŅƄǎƞņĔƅE҈?ļ·hv؆Մ Ѕς΅̆ͅ˃؂ЇĆɔÄĄDž˄`탆ɉ_}ÿ}ͅΏψЂψЋЊώ΍͋̄˄ʄ˄ʂ˅ʋ˄̄͐ΐϠ<򀆍~}~E}|}ƿ}Ĺ~ԅ͍̓̆̂˄̇˅ʇȆɍɒȆNJȄƅȊDžƃǜƍŅĈ†ĆÃ‰ËŒÈĄÂĖÆ†ˆÄ‚Ε…„ŽH̄}}>~}ƿɽ}c냌|}w~}̈́ʅɂȆLjƄƈńƄ ˄[낄DŽȃɄ\~||ǿ͆̍ͫΐ͆̂˄̅˃ʄ˅ʜɆʃˍ̆͋΃͑΄χ<}|}~E~~|{ſ|Ľ|¸}̒ˏʆɇȎdžƋǝƌŊƎŌĄŐĈDžŠ„…… + B˃||~C~}|ľȼ|c邋{|~y~}|̈́̃˄ɄȄDŽƆņăÇɆȉLjŋƅŊȄ̄̈́҄?󇉖χ_Ŀƾ҅ӎԩՎԇӌҋѠЅтҏӆԉՃԑՂքՂֈ=DĽɾӐґчЄϐΊ͇΍̋̈́̂ͅˈ͈̄̄˄̝ˌʅɈȂdžɆȃljȋnjȈɄȂɖȆDžƑłƇƅņėňƆLjȄǂȎǕDžƆŋĎŊƄǍơŇĒdžC҈@¼Žøa񇐗yԄӂ҄τ΂̈ͅ˄܂ЋÉŠ„ÅDž˄ӄN숢̊_~Ŀ~ΎϤЊ΅τΏ̂̈́̊ͅˊʆ˃̇͐ΔϔЄф>󁇎|~C~|ľ~~źԍ͑̈ˊʏɇȌɛȋDŽȄDŽȍLJƂǎƂŇƉňĉÅďÆÆĂŋĄÈć’Â“È„B̄|~~<}þ~|ʾ}d䂋}~~}ӆ΃̄ͅ˂ʄɂȆDŽƈńLjŅɄ҄Kꇠʄ˄]}¾}͎̈́΂φ΂Ϛ΍͇̄˂̆˂ʆ˄ʄɄȋɇʇˏ͇̅΅͕Ό>񀆍~{}~@~}{¼}ƿ}ù~҈̑ˉʊɈșȅƊǒƂœƆŃƗŏć҈—ŒÔȃ†ƒB˃{}}~@~|½}ƿ{ȼ|]⁊|}~}|¿ч̃˄ʆȅDŽƄňăċȉNJńńƉńƂDŽȅ̅p򌦗҇[ſƾۅӈԲՌԅӏ҅хЅωЃшҎӊԂՈԒՌ>DþƿʿهӍҌыІϑ΃͍Ά͂Ε͎̈́̇̓̄ ̄̒ˈʈɉȅɏȆǏȆɂʌȊɆȂǑƓŅĎŎƇǍȂǓȈDŽƐŊƄŞƊńĆņƊņĂÄĐÇC҈􀆌FĽƾø_酏}؆ӄ҄хυ΂͆̃ˈʄ߂ЊÉÆƄDŽʄ̈́`ꇠ΄τY}~҄΋ϪЌτΏ̂̈́̊ͅˊʇ˂̊͏ΓϔЄ@І􁇏}}B~|»ƻԍ͔̆ˊʒɃȍɖLJȂDžȈǂȍǗƊňĆÆĐÃ橡đÂď΄ŽG̅}~@}|º}ʾ}a}}~}͆̄˅ʂɅȄDŽƈņLjńȄфQ腟̇f|}͎΂φ΂υΆό΋͈̆˂ʆ˅ɄȊɈʈˎ̊͂Έ͒Ό=򀆎||~~B~}{~ĺ~҉̔ˆʊɉȗǂȖǖƂDžDžňƖŔĆÒ˜Œ΄ȃ …ăA˄|~}~<|{ľ~|ɼ|^~||~}|ˆʅɃȄǂƇńćŊȉNjńƏńȆʄ˃̄τЄ؄PӄՄ]½ƾӄԖՂֆՅ֋ՋԆӎ҃ф҅фІωЄшҎӊԂՈԒՌ>CىӋҎъЉϞ΂͉Γ͇͎͂̒̃̒ˊʈɆȆɐȂǐȃɇʠɄȄǐƒłĎŔƈǏȂɏȎƅƊŌƂŏǎƊńņƄƆŌĐÇ B҈<ſǿø`₎¿҄фІ΅̈́̅ˇʆ゚ć͌„ ƆǂȄɂʆфX蛫ф҄Z~½~ΈϜЄтЄэЉυ΍͈̅ˇʋˎ͉̄ΈςΎϊЌ;~}~@~þ}ĽǼԎ͕̆ˑʥɋȂLJȅǂȄɂȄɖȄǝƆœąÂ‘ÃČŔĄŇćlj‡ÇĂÒŅĂńĄÃ“‰‘D̅~||~;~}¼û}˿}]}~~}ˉʃɅȆDŽƌłĄąˆƒÄĂŅƄǂȅЄV暪χY}~ȿ}Ѕ͈΂ό΄ςΐϋΉ̈́̂ˆ̆˂ʆ˄ʂɄʌɌʋˊ̖͏Ύ;󁇎}|}@~}|üŻ~҄̎˅ʋ˃ʇɐȆǂȒǂȑDžƂNJƗNjƑŃĆňĊƄɌ„…čNJƊ‹Â†Å‚A˄}{{|;}||ɽ|\|}~}|ɊȄdžƄņĈÇɇȍnjƄŃĊʄ˅̃̈́΂υׄUքׂ؄W¾ƾׅԛՏ֋ՉԅӅ҃ӄ҄ц҄фόЉу҄фҊӖԊՎ|ƿ}Ž~˿}^₎}}~}} ܾ݅ȌŐċ˂ġņƄǂȄɂʄ ЄX┷ӈY}þ~Ǿ͙ΊЍό΄͊̐˄ʂ˄ʌɓʈˇ̌͊΋φЅ<~|~~>}|¼~{ȽҔˊʄˉʅɗȋȅǎȔɑȃdžȄǃƎłƌʼnđØ„ÆĄÈĆÌĄÅ…‡ÉņÄăÆ„ ?˅~}~:~{ľ|û}ʽ|[||}|~| ڽۇƇŃąÅ‚ÌƒȎǎƈņĉLJʅ˅̄τЂфӄׄY꙽ۆ[żԘ՗֌ՅԉӏҏэДх҉ӌԊՋֆׅ=BýƿĹِҖфЈτ΅ό΃͖υ΄͍·τΈϐ΂͈̃˒̄ˋʄɆʊɂȄɆȂɞɇʃˇʂɋȃLjĎŊƆƅǒȄɆʄ˄ʋˇʅɃȍǍƈŒƂńƄŔƐňĈ„@҉:ſ»Ĺ\膑 ͋ʐɋ킙ώ†ÄăńƆDŽȄɂʄ˄̂ͅфZᑯֈV}ǿ҄ψЈχЏђЄϊΐ͎̄ ʉˎ͉̅ΐϊА;||}B}|}ü}̅̋͜ˉʔɄȖɂʄɄȌɈʄɈʐɃȈƔLjƆńĆŖÄđńƌŌƄłČÇŽÄĆʼndžŅĄÌ”’>Ԋ|~B}~ƾ̿}Z~}~}¿~| ƾ~NjƃŅąÂχ‚ÄĆŅȅɂʄ̄҄Vߐ~քX|ſ~ƽ͗ΆЌό΅͇̏ʄ˄ʌɒʄˊ͍̉ΊχЅ;{{|~@~|{|º|ʿґ˗ʅɔȋǂȄǏȊȆDŽȄɜȄDŽƋŃƎňđÉ„ÊƒÇĄÒĂÏĂł„†ńĊňĄÄ†>҉􀆍{}~=~|ƿ}ļ~ʾ|\}|~}|}{ ż}ń؃ȏǎƈņĉdžȄɃʄˆ̄υӄ +؄V畴܈XĻԘՆ׆Յ֍ՄԊӎҊ҄щцЌт҄ф҈ӋԋՊևׅ<󀇎Aƻً҄тҚфЈτΆϋ΃͓΅υ͎ΉσΊς΄ω΃̈͜ˆʃɇʛɑʄˌʌ˄ʂɌȃLJƖŊƆƆǎȅɆʈˆ̆ʅɄȌLjƆ ʼnńņƃŘƑŇćÄ?َ:üĹ]ہ¿ Á̇˃ʅɄȃɎ񂘁ކÅĂŅƅDŽ ̄ׄLޑ}~نU~½ƽڇςІψЊт҄єЋχ΍͈̄ˆʈː̈͆ΉψЖ:}}}~>}þ~ž·ل̂̌͜ˌʔɂȔɆʎɌʄɑʉɆȚLjƓʼnĂńĒńƂņƈŎƅŅĂĥĈƒÐĆƍLJƃńĄÂ…ƃ‡•Aڊ~}~8~}ýǿ̿}X||¿}~LjƆņĎȆÂĈńƂDŽȂɄʃ˅τЄZݐ|}׆X¿}~ż͐·ωЊώ΋͍̆ʅɉȅɍʄ˂ʇˇ͈̆Ώϊ<φ|||}?~|¼}ļ~،ˌʃːʉɓȍǂȆNJȌDŽɉȈɈȆDžƅŇƂňƅŊĢáċņĂ̄ŠÄĈňƆŇăČAى}|}<}|~Ž~ʾ|W퇐{{~~|¿~}¿ƌćɌƇǎƍňćDžȆɂʄˇ̄ ф҄ք^䕫߆[¼ºԇԆՉև׉֐ՊԎӆ҆фІφЍ҄чҊӆԈՎ։=֊AýûǼшҏҊфЂцЊτ΂ώ΂͍Έώ΍ςΊυЄτυ΅͙̈˓ʈɄʂɋʂˆʌˇʄ̋˄ʅɂȄɄȄDŽƄńƈŐƍǃȐɅ ͈̇˃ʄɄȂDžȄƈłƆňƄŒƈǖƋŅąÄƒ?9üĽĹX¿̈ˇʅɎȉ󂘁Ѕ’†ÅĂňƄDŽ˄̅τЄ +ՄQܡ}~ڇU|ý~ĻԅςІφБѕЌϋΈ͇̄͂̄˅ʅɃʇˑ͈̇ΆόЖ9}}~=|Ĺم̂̍͜ˋʔɂȓɆʎɍʄɈʆ˄ʅɅȘLjƔłĔńƆōƃņƂNjƄŋąÃˆ„ÎĈŅƈLJȆdžƄŃċŃƒ”@ۋ}}8~}Ŀȿ̿}}s}}¿ΌŇċˆ†ÂĈńƂDŽȂɄʄ˄΄τ +ԄNڠ|}؈Y~{}ú͍·χЊϏΆ͂Ά͋̅ʆɆȅɌʄ˂ʈˆ͈̈Ύό;φ||}~=~{ƿƾ÷؍ˌʃˉʂɄʋɓȉȆLjȄɂȌǃȉɈȎɊȄLjƂőƅŊĖÂĄÛăňČņąË‚†ÂÅĈŌƆńĄÄ„Cي|~|8}|ý~ƾ~˾|ނ|t~|¿~|ÆĆʎƂǑƌŊĄdžȆɂʄˇ̄ цՄ +ڄ +߄E⥴U½څԌՊևׄ֕Սԋӆ҆хІτ΂χБц҇ӅԇՎ֋=֋>žɾ߄чҏ҉хшЋϔψΈύДχЉφ΄̈͘˩ʉʏ˂ʅ˅̊˄ʊɅȃLjƃŅƇőƌDŽȎɈʅˇ̈͆̇ɋȅǃƐŊŅƃńDžƋǕƌńĄÄ„>9ľžĹW冒¿ӌʇɋȊLJ򂗁Б ‡ÄăņƅDŽȂɄʅ˄̄φЄт҄Xٛ|~܈S|þ~ºЄϋЈтЈъЄφЕχ΂͌̄ʈɃʉ̄ˊ̆̓·ύЋц҇<Ї~~}<~Ľ}»ƻڢ̒˔ʎɂʌʄɋʅ˄ʂˎʈˊʆɄȖLjƙ ǒƊDŽƊLjƃŌĆŌ†ÅčŇƊǎȆDžƂʼnĄÂ„‡Âˆ A܍:~|}X|}|~|}؆ĉю…ÃĈńȄɆʅͅ΄фXؚ{}ۄV~{¼}͌ΔϘ΂̈́Ό͆̆ˆʇɌȆɐʆ˃̅͊ΌόЈ8}}|~<~}¼|Ź؎˄ʄːʐɕȃLJȄDŽȄLJȆɂʉɆȖɄȅLJƆňƇōĄÐĈňċłƋŃƇņĆʄŽÈąňƇLjƆńăȅ=ۋ~~;~}ſ{ǿ˾|Z{|{¿}{¿~|”ƂńƊņĄńƂdžȄɄʆ˄̅τЄфԅՄւׄۄSߟUýȿԊՔ֋ԌՄԂՌԆӃҊх҄тІς΄ψЎц҄ӅԉՌ֌׈8?ýыҗхюБϋ΅ϊτΊώЋωЋυ΄͖̉˗ʌ˂̎˘̈˄ʋɆȅnjƂŒƎDžȅɍʇˊ̏̆ͅʉɄȂDŽƒőńƆǂƊdžȂLjƂDžʼnƇńăÆ…=␝8ƿŹZԀކȂɈȐǏ񂗁ÂЏ‡ÄăņƆDŽȂɄʆ˄ΆτЃфՅNו|~݈R~ľ}ׄωЄъЂτЄφЕχ΂͌̄̈́ʅʊˊ̅̓ΆϏЋц҇;Ї~|}<~~Ž}Ƚ̎͠˂ʄ˕ʋɄʌʄɉʈʆˌʈˌʄɆȔljƓŏNjƜljƅʼnćȈ†ÃďņƅLjȇɈ ҡ„ˆÃ‡ ?돛􀆍~~>|¼}}X熒~||}|}¿~}‡Ö‡…ÄćńȇɄʄ͇΃τӄԅM{}܄T¿}¼|ȿ֋ΕϞ΍̆ͅʉɌȈɎʄ˄̆͆ΐόЈ7}~{|;~}}û|ǻ˄ʄˏʒɐȂLjȄDžȄdžȆɃʧɄȆDŽƆʼnƉŌĄÌĂņĘňƄŅƈńĆ̆ŒÆĆŊƐdžƄĆ„<鎙}}~;~{|̿|X慐~}{{|{¿~|}~|ŅƔŅąLJȄɃʆ˅̄φЄфӄԆ ؄XܙTýƽ݌Ք֋ԌՌԆӃҊчІς΄ψЄЉц҃ӅԇՍ֌׈8<º·҆тҐєВϊ΅ω΄τ·φъЈώЅυ΅͔̊˒ʏ˄̊˝̈ˆʈɇȈLjƂŒƌdžȂɏʇ˄͎̈·ʇɄȂDŽƒŖƑLJȂLjƂDžņƆńăÆ…=񓟩8ǿƺV튕džȕLjƄŅˆÄĄńƈDŽȄɄʆ˂͈̄ ф҂ӆQՏ|~Q~ľǾфϜ +τЈςЎψΈ͆̆ʆɈʈˇ͇̃΅ϓЗ8|}>~}ľƿ~˿΅̊͜ˮʇɊʃɈʨˌʅɂȓDžƉŌƄDŽƖǒȍDŽƄŋ௄ƒÇĆŌƅDžȈɐ +ȄǂƄĄ‚ˆÃ“>}~6}ľ~û|Qց~~|}~}|~|}¿|‹„††ƒÅĆŅƄDŽȄɆʃˇ̃ͅцRӎ{}ވU}¼ƽΉ΋ϔ΂͌·̕ͅɉȈɉʅ˅̅͋΃υΊυЂϊ9~{|~;}|¼ž}ɽ̇˄ʌˎʞɚɎȊɂʆɅʍɃʍɈȃǐƉŋĂÇđƇőƂLjƍŃĆʇ…ÉĊňdžȄą;퐛􀇍~|}<~|ü}̿|QՀ}}{|}|{}{¾~|~{ŅąÆŅƃLjȄɄʄˇ̄̈́΃φЄф҆ӄԄ؆RړRýúԄՇփՄ֚ՂԅՌԆӈ҄щЌЋу҅ӅԓՊքׂ։7֋?üŽĹӆ҉ҍщφТΖϐЂіЂτЊυ΃͉͈̆ˈʉ˅̂ˆ͎̂͐̓̃˅ʊɅȆDžƂōƋǃȆɆʍ˄͈̆΄ςЊ˄ȄDŽƆłƈņƄDŽƔLjȃǎńƂŅƅńĆÅ<9ýƺS܄¿ǘdžƏРŠÃąńƇDžȅɂʈ˃̇̈́΄ ҄UҊ}S|ýŻϝώЄτЍωΈ̈́̈̈́Ɍʇˇ̃ͅΆϔВх9ш}~=~}~ºΆ̅͜˯ɊʂɊʐ˂̖ˍʄɄȇȌdžƈňƐǂȏǗȎDŽƆňĆʄƒÅĆŇƊLJȂɊʌĄ‚ʼnÛ:|}9}|ƿü}T}|||}}}~}}¿}ÿ~¡ƒÄćŅƅǃȇɂʅˇ̅ ЇS|~߈O~{¼úքΉ΄ϧΊ͆̍̆˂ʄɉȇɈʆ˃̇͊΅σ΋υЂϊ8~|}~?}|ƿ}̆˄ʆːʞɇɊɋɉȌɂʅɊʊɅʎɈȂǐƋʼnńĆłƈňƅŋƐDžƍńĆȈ‡ÆČŅƅLjȅʉˆ:{|8|{Ľ~»Ϳ|T퉓|{~{{|||}|¾~||¾}ŅĆÆŅƂljȄɄʄˈ̄̈́΄χЂц҅ӅքׇROÿý݅ՆքՂքՂ֚ՂԆՏԆӕЏσЈх҄ӆԌՂօՊօׂ֊9>ǿƻԈ҉ҍъЪΖϏЇђЂυЉσ΅͉̆ͅˈʈː͎̙͍̂̄ˆʈɆȉDžƂŌƋǃȅɄʈˋ̇ΊύDŽƆłƈņƄǂƎǂȅljȃǓƂŅƅńĆÅ?=Ŀ¹ƺR􍘡ɇśƏ킕Ѕ‰ÆăŇƇǃȊɄʆ˄͇̄·]т}~Oý¹ԷЈτ΂φΎ͂Ά̈́̂ˏʂˇ̄͆΄ώЄуЎэ7􀈏~}<}Ľļĸω͊̆ˇ̍˂ʄ˧ʄɏɊʌˇ̌̇ˌʆɃȅDŽȌǑƋDžǔȈ ɎȄljƄńĄÉ‰ÅĄŇƆLJȇɄʇˈ̃̈́!ꃂ~|†ˆÂŠÄ›=}~|8~}Ž}N܄}}~~}}|¿}~¾~…Ãćņƈdžȃɇʄˈ̄͆Zρ|}N~~҉΄ψ΂φΎϊΏ̈́̇ˋ̄˄ʅɅɄʇ˃̆̈́ΖϊЉ8Ї}|~?~|ü~û·̈˜ʍɕȍɖȍɅʂɜʐɄȅǗƄňćōƄǂƄdžƄNjȉǍƅńąÄŠˆ„ÇĄňƈdžȄɇʉ"肁~}{„‡@|}{~9}|ƿü| Nڃ~||}~}||{~|ÿ}}…ńēŅĈÅŅƂljȅɃʇˇ̃͊΄σЇу҈ӄԆZօM¼ǾًՂ֘ՊֈՐԄӌ҆ӄ҄уЍςІц҃ӆ՗։׉9׌=ý¹ɽԊҘѓЙτЄςΔςЄφЃхГшЄσЅτ΄̓̇̈́̂̈́̐ˊ̛͆΅̈́Ύ̈́̉˅ʃɄȉǎƂǏȄɅʆ˄͉̇΄ψЄф$džƊŅƏLjȂdžǛĈŇ>Ń6úƺPᇕ¾ÿÿÈĐōƉŇ낖Ћ‰ÆăŇƈǃȋɂʈ˄͈̈^͇}M}½~ɿ۩ЄщІχφΌͅ΅̈́̄ˌʃ˅̆ͅ΅ϊАшӄ6􀈏};|»|ǿ|ƺЊ͊̈˃̏˩ʂɇʂɑʄ̆˒̆˂̇ˋʆɄȂLJȅȅLjƊǐȂɈȄɊʊɌȆLjƄńĄÈˆŽÄąņƃLjȇɇʄˆ̌(ԉ~}ˆÂ†Ą–@~8~½ƾ}S􌗟|}}~~~~~}}|}} +Ä…ÄćņƋDŽȆɄʈˆ̇̀̆|~/~|}ǽى΃ωφΆ΋ϊΎ̆ͅˌ̇˂ʆ +Ʉʆ˄̆̈́ΖόЌ6~|?~{{Ž{Ź̉˗ʏɖȍɇɇȍɦʍɆȄǖƊłĊňƂDŽƄǂƌLjȂɄȌǂƄDŽƊńĄÄŠ„ÆĆņƆLJȅɆʄ˄)ӈ}|„ˆ<~~}8~}Ľ|S򋕞~|~||}}}~}}}||{|ÿ~|~ĈĊŅĈÄĂńƂljȇɃʇˇ̃͊΄χЄш҅cӋN¼ĻՂ֐ՊֈՉӆԄӈҊӅ҄хЊςЄц҄ӆԄՒ֌׌7<ļ˿֌҉хЈєИϊЄςΓσЄφЄуМшЃτЄυ΄̈̓̇̈́̈ˈ̍̈́΅ͅ΋ωΌ͆̄˄ʄɄȈLjƈǎȄɅʅ˄͇̇·τІч҂ӄ(ڍƄąņƐLjȂdžȅǙƄŃ㯉;Ć6»ĻǻT¿¿¾ȄňÆēŃƌŇꂕЋ†ÄĂÆĆŅƇLJȇɈʉˌ`|}Lÿ|¼|żҎϖІхЈώΌ͇·̄ͅˉ͈̇ΆφДхҏ5}~:~ľ~¹~ɽӍ͆̚˼ʂ˅ʄ˃ʊˣ̇˄ʆɉȃNjȓDŽȃɅȒɂʋˎʄɋȈŅĆĈŽÄĆńƃLjȂɇʈ˂̇̓Ί-뤪}ŒÆ†Ä„Š@ɇ􀇎|}~8Ŀ|ǿ¶} Oޅ~|}~~~~~}|¿~|¾ +‡ÆĆńƋǃȏɄʊ_ߴ{~|L~{{ĺњ΄τΊω·͐̂ˎ̇˄ʌɃʄˈ̈̈́ΊϒІт҈6􀈏|}=~}ý}}ǻˇ̇ˈʜɑȄɃȍɅȆɃȕɎʌ˅ˆʊɉȆNjƄǂƈńƅńƌȇǃȄɂʆɆȄɄȉLJƄĄÅ‡ƒÇăņƄdžȆɆʅ˄̉/꣨~|=dž{|}8~ý{ž|Q܄}~{|}}~~~~~~}}}|{}~{~ þćʼnĉądžȄɂȆɅʅˇ͇̇΅όЅц`N¾ؚՂևՉֆՉԍӇҋӈ҄ф фҊӆԄՊ֒׆؂و6;ļǿ·م҂ӈ҆јЦЈσЅϔАщҏъЈχΉ͂̌͒̄̈́΂͔΂όІςІφΈ͈ʅɆȄLjƆǎȄɅʅ˃̇͂ΈφЄц҃Ӌ-񩮭ƈŃƔLjȊǂȄnjƂņƅłĉŋ9Ί9ĽżǻO㈖þ†‡†ÅĄňĔŇ邕Џ†ÄĂÆĆňƄnjȃɏʄjۤ}K¿}¸}ٌЂϖЅфЉϏ΍͆Ή̈́̄ ͈̇ΆυДхҐ5~9~ļ˿Ԏ͆̋˄˄ʅ˵ʂˆʎˑ̈͏̆˅ʈɈȂLjȊȇDŽȌʊɄʅ˄̅˅ʄ˄ʆɊȇŅąÅ‡ÅĄņƂdžȄɇʄˆ̅̈́΂υ8Ќ…ŒÆ†Ä„Š<΋|~8|}÷}Q􎘠||}~~~~}}|}Ŀ}ľ +‡ÆćŇƈLjȆȄɊc٣~|~M||י΄τΊω·͐̂ˎ̈˄ʊɄʂˊ̇ͅΉϓІт҈5}~9~}ûʾӆ˄̈ˈʙɓȅȇɆȆɂȓɏʐ˂ʇ˅ʊɊȆNJƄDŽƆŅƄŃƊǒȂɊʎɄȌLJĆƃÆăńƇDŽȇɆʂˆ̄͊6~<͊~{}8~{Ŀ|ƿ|P򍗟{~{|}}~~~~~}}||{~|¾~½|ýĆŌĈÂĈdžȄɂȆɆʆˆ̈ΐτЉbLǽߚՃօՉքՉԏҌӉ҄щфҊӆԄՉ֓׆؂و5:Źڑ҅јЦІφЃϕЎь҄҅щЈψΈ͉͂̈̃͆̄͊΄τ΄τЇэЅχΈ̈́ʅɅȄLjƆǍȅɄʅ˂̅͆ΆτІт҇ӃԊ8ƕNjȆdžȄDŽƅDŽņƅłĉŇ9ԏ8žżȼP¾Ŀ‰…ÒĊŇ肔І„ÂąÃċŇƌDžȌɍf֔}K|~ȾҝЄчЋϊχ΍̓Ό̓̍˄̆͆΅υВш҈ԉ7}|;~}ž}ǿ·ۍ͊̅ʈ̍ˑ̘͆̄˄˅ʋɏȄɄȆLJȈɏʂˋ̆̈́̅ˆʋɆŅĄˆÃĆȅɊʆΆτЉ:ٲ}ɆȊˆ̋;ڍ}}9}»~÷}Mل|}~~}}¿}ÿ~¾†ÊčńƈnjȆfԓ~|~P~{ſ}ƽϓΌυΆ͂΄͉͆̆ˎ̄˂̄ɄʄɄʂˊ̆̈́΋ϏІц҈4|{~8}|ļ|Žٕ˄ʆɋȆɟȅɄȅɂʅɃʇɉʊ˂ʈˆ̄̇˄ʊɋȉDŽƋŐƄdžȆɈʍˈʅɌȆDŽĆĄ‚ÄƄLjȈɂʄ̈́΅@ذ|…8،||~7|}¶|M؃~{|}~~~~~}||~|}~ĆÖĈÄăŅƆDŽ ɋʆˍ̅͌΍hۘOſù֕ՊֆՋԇӄԊӈ҄ӈфЂц҉ӆԅՊ֎׆؇و49ýļǻ҅хόЂьЊт҆чӎ҅τЄψΊͅ΃͈͆̈ЈςЊщ҄ЄфІτ΂υ΅ʅɄLjƅǍȃɆ͆Άω ԄՅ@߷ȉdžȈljȃLjȋNjƅŅĆȋ=ߑ􀇎4ǽȼK߈~½…ÊĂÛ炔Ј…ĎʼnƈLjȌm΄}J¾ſ|ĺؙЇхЍω΃ψ΋̓΍̓̄˂̆˄̆ͅ΅φАшҔ6|}}:~»¹|Źބ̈́̆͋̅ˊʂɚʂɚʌ˂̋ˆ̄͆̊͂΍͆̃˄ʂ˄ʈɋȅɃȆLjȈɂʅ ˄͇̏̅ˆɅʄɅƅłĆ‰ŒÄąȅɆʉ˂̄χЄш?}¿~ĆȔ̋ +:瑝}6~|ü~¹÷}K~|}~x~~}||~½†ÌČňƊǍȀ̓~|~9~ľ|¸ևχ΄τΌφΌ̓̍͑̅ˊʂɄʂˊ̆̓΋ώЈц҈7{||~7}~{øݖ˄ʆɐȄɣȄɆʃɈʂɈʖˇ̂ˇ̆˅ʋɊȈDŽƌLjƃdžƅDžȍɂʌˇ̃ˈʆɌȅǃƄąÄ„ƒÄƄDŽȊɆ͆΃υф?|}Œ•;吜~|~7}{»}¶|O}~{|}~~z~~}}|{~{¾}Ŀ~ĆÏÆćÅăņƅDŽȄɍʊˈ͎̆΅iԇJľɿ݄֋ևՋֆՌԆӆԈӈ҄ӈ҂ӄ҄хЄҊӆԄՊ֎ׇ؇و48ǿʾ҄хυЂхЃшЈъ҂ш҆ӄ҆ӄ҆ъІόΊ͇͆̌ͅ΅ύЂыӄ҈цЊφ˅ʂɄljƄnjȄɅ̈́΅χІт҄ӂԆՃօ؄?ȄdžȈNJljȌNJƅŅĆȌ;핡4¼ȾɼP¿½ŠÂĄÛ傕Ї…ÈĕňƇǒm䉐}}I¾ľɿ߇тЈфЈцЌςΐψΈ͂΄̓̇̇ͅ˄̆͆΅χЄђҖ2}~|~:}ſ|ż~ȼ΅͗̃ˉʅɍʑʇɄʆ˘̆̓Έ͆΃͈Έ̋˃ʌɍȅɈȃɆȅ ˅̄͆Ήσ·̆ͅ˄ʂɄƅń‰ÅDŽȄɄ̉͂΄ςІт҄ӆHӟ~~}}¿Ç–Ò‡:􀇎~6}žú|ĸ}LЁ~}~w~~|¿}Ŀ~¾“ÆĎŌƊm⇏||~J~üȾРϊΐ͂Έ͐̏ˋʄˈ̆̈́ΈωМ6|}{}:|ý{û}ƺ͔ʅ˄ɴȊɖʈˇ̃˚̂ˊʊɅȜdžƅǃƄȄʅˇ̇͂Ά͆̆˄ʌƄńĂą„ƆDŽȄʊ˂̄͂΅τOҞ~}}||ÆŒ:򓞩~}~6~|Ľ~¹{¶|Lπ}|}~~{~~}}{~|¾~þ}ĄÆĂŚĂňƄDŽȈɖʅ˅̂ˈ̍s錓Jüĺנօ՘ԑӄщҎф҈ӅԄՈֈל6񀇐;Ľӈ҄҅т҄уКψ΄τΆςΈυЗш҄ӆҘӂ҈ьЃϋΌ͆Έ̈́΄͆х҇ӎԆӅ҄хЂυ˅ȅƆljȅ +̈́΄τЂъӄԂՅքR٣ȇǕȒDžƅņĂÄȉ;7þɿɼOօyĿÃĉÍ䂔Ї…ÈąŃĄłąŏƅnjn}}I¼~źՏуЈшЈΑψ΍̈́̆̄ͅˇ̆͆΄ψЄђҖ5}}9|¼~ȿ˿І̃͘ˉʃɎʝʅ˗̇ͅ΅͕Ά˄̌˃ʋɍȅɈȄɄȅ ̅͆ΉτЅχ΄̈́̌˂ʄDŽĄÄ„‡ÄĄDŽȄɄʄ ΄ςЅфԆJ͐~}ŇÂčӆ9||~:~Ļ}ĸ}J劘~}~r~}}|}Ŀ˜ÃćłĈŒn||~Iÿ~}ùӖЈϊΐ̓Ή͎̐ˉʅˈ̅ͅ·ωР5|~|~;~{}ƾɽ̉˂ʈ˂ʄ˄ʆɗȇǖȆ˄ʆː͇̂͌̃ˉʄɄʄɄȄȓDŽƌDŽ˄̈͌΄̅ˆʄʄɃȄńĂą„ÂĄłƄDŽȄˉ̂̈́΂υЃф҆J̏~}|„9{{}6~}žú|¶|J䉗~}|}~~o~}||ÿ~{|ýĿĄâĂňƄDžȇɊʂɄɆʏ˄̒nI¾ʿ۟ֆ՚ԏӄ҂ыҋх҇ӅԅՇ։נ2򁈑:żĸՉҖЖω΃ττΆυЖчҥӂ҉ыЄϋ΄͇·̈́΃̈́Ԅ҅ӆԋՅԆӆшЂτ΂̈́̄ɄȄDŽƇLJȄɄͅ΄ф҈օ׃؄UӔ¿ǕȓdžƅņÊ… :„7ſɽ M뎜tÿ¿Ŀ‰ÂčÊゔЇ„ÊĄŌĈńƂŇƓr}H~݌цЍхЄςΕψΎ͉͑̄ͅ·φЈѐ҈Ӆ4~8~ƾº¶ъ͎̄˄̆ˑʕɄʆɆʄˆ͇͔̇̃Άώ΅͋̂˄̄˅ʉȄȇɄȋЅψЋц +Έ ˄ʅƄ ˆ†ÂĄDŽʄ˃̄̈́΅ςЄфԅՅS~}}ËćłÇƄ9‡}}}5}ż}ĸ} H}}}}~n~}|~¾~ĿŠÂŠÐĉƆt~|Hÿ}ƿɾ܆ςКσΑ͂Ί̄ͅ˂̑ˇʈˈ̄͆ΆόЄуЗ4}~:~}Ľ̊˖ʇɐȈljdžȄɇʕ˄͇̔̈́̄̃˓ʂɅȐdžȌͅΌσЄϊ ̉Ɇ„ƒÄ +ȅ˄̅̈́Єф҃ӇQ~}||Œ9|||6~|ú|ö|H||||}~r~~}|{¾}}ýžąÓĄŊĂņƈDŽȊɄʌɈʄ˂ʆ˓̀?¾ƿźփՑփ՜ԈӘҌ҈ӄԆՆ֌ׅט4򁈑;ĽȿǻӊҖщЍϔΆτΆτІщш҄ӂԄӎԄӄԆӄґуІϛ΂͋ԆՋ֋ӎІ˄ LjƇdžȂɄ̄υЂф҄ӄԄׅڄWۃȊɇȆǂȎǃƇńĈ΃6NJ􁈏6ɽI΀p¾þľ”ÇₓƒËŎĊłƄņƔDŽm񀆌}}H¿~ſźӊфАфЄςΒϊΏ͉̂͐̄ͅ΄ωЈђ҆ӈ4~|8}ü~Ž}ŹΊ͎̄˅̋ˊʖɄʆɆʄˆ̖̈́΂υΎόΆ͑̃ˆʛȉ|҄Љш҄ъЄχ·ˇ ńĂć†ÂĄDŽʅ˃̄̈́΃τЂф҅ӂԄՄքS~}NJĈńÄ„ 9ˋ|5|ý}ƽ}ĸ} +J؇􀆋}|}~p~}¾}½‰È‰ËĔňm||H}Ľ~ùфσЍЇσΑ͂Έ͉̗ˈʄˇ̅ͅ·όЄцД4}{~:~|º}Ļ|ĸ̎˖ʊɉȄǕȅɇʇ̈˄̜͇͂̅̆ˊʂ˄ʂɊȎdžȄLj{чϐІ +͉ Ɇ„Ʌʃ˄̄̈́΂τЄӆԄY~}|˕6ʊ~{~3~{|Ļ|ö|J׆|{|}~o~~}||¿~ľ~ĊÑąʼnĂŇƉǃȊɃʍɊʆ˕̄̀:Ľʿ،Փւ՜Ԉӎ҂шҏт҇ӄԆՆ֌ׄ؅ו4󂉒;¹˾ӊҙчЋϕΆτ΅τЇц҂ӌ҄ӛԃӄԈӂғтЅϘό؇֐׆ +ԈӆІ ʄɂȄLjƆdžȂɄ̄Ѕт҅ӃԄՂքׄڅۅS̊ɈȅDŽȄǂȆǃƇńĈ΃:ю:»ºʽKފmſ•Æ႓Ѓ‰ÆċÊĆŐƋn}~|~F¿}üʿ׎ҋчЈψ·σΖ͊̂͊̄̈́΄φЈц҂ќ2}}7~|ɼΌ͎̆ +ˆʐɑʄˊ̃͋΄͈ΒЅό·͊̃ˉʘɄ҆ԅӄԂӋ҄фІφ΄͂̅ ƄłĄÄ†„ˆ̃̈́ ҄ӆԂՄքׄ\涷}}ČÂ†9ڏ}~4}ſ~Ǿ~ĸ}G뎛}}~m}}¾}ý‚‹ÇęŅƄi|}{}E|»ȾՍψЊφΕ͊̊ˆʅˏ˄̅̈́ΏϙЈ7щ~||6}{ľ~Ǿǻۆ̄̍˖ʆɊȂǗȆɅʇˆ͇͉̃͌̊Ή͈̍ˈʃɍȄdžȄDŽ􀆋ю҄щІυ΅ͅʅń„ʆ˄ х҃ӄԄՆZ䴵~|¾|Ąˆ‰9؎󀇎|}~5|ý}ż}÷|Fꍙ|~|}~j~~||~Ŀ|ċÊĄŅăňĆʼnƃljȇɊȊɊʊ˄̂ˍ̄m􀈏FĿĺ܍ֈ׉ք՗Ԇӏ҉тҊтЄт҄ӄԄՏ֙׈7؎􂉓:ŽżӓҎЉцЃω΂τΒφЄшҕӉԆՆԈՈԈӋҊуЈϘ΄ƽ؏ل؉ׅֆՄԆх ˄ʂɄȄdžƈDŽц҄ ؄لڄۄ܄b컼LJȃǎƆņčȅ72ĽûʽD񑟩kÿ½ˆ†ÂŽ႒‹ÂČÎćŏƌDŽȅe}||F|Ĺ݌ф҉чЉω΄τΓ̈́̂˄͈̂̆̈́΄χАчє2~|~5~ý|ú̿͋̆ˇ̃ˆʋʄɒʆ˅̄͘ΆφІψЄό΋͋̂ˈʘ~ԂՆԉ҆цЄῡĄÆ„„˄̄̈́ ӅԄՄքׅ]~|ÿǑĉÆ8씡}4}|~Ⱦ~Ÿ}Fʀ􀆌~|}~e~}|~|þǿˆ‹ÄĘņƈe|{~{F¾{ƿ~ø܊ϊЊφΔ͊̄˂̊ˇʄˎʂ˄̅ͅΏϘЈ6щ~}{}5}{˾̎˔ʆɢȅɇʆ˄͈̊̈͘Έ̈́̌ˈʄɌȂnj~}Ҏӄ҉цЄυ΅̈́̂˄…ʆ˂̄ф҆ӂԄՄb}{„†…8꒟~|~8|{ž}ƽ}÷|F}{|}~f~}|{¾}{¾~¼ŽÉĄņĂňĆʼnƄNJȃɌȎɆʐˌ͇̃eFƿɾ։ׇֆՕԃӖ҉тҊтЄ҅ӄԆՎׇ֙6؎􃊓8ºȿŸӗҋтЉхЄωΖψЄч҃ӊԈӉԖՉԇӍ҈тЈϏ΅τُ͂ڄو؆׃ֆՅԄɄȆDŽƈDŽц؄نڂۄ܃݄]̛ȂDŽƆŅĎȆ9򗥰2žļʽGσgýčЍŠÇŽÆĆŒƊǍc~||}C|ÿžɾӊфҊцЏϋ΋̂̈́̅ͅˇ̄˂̆͆ΌφЋћ1}5|ǿƽ}öΙ͆̐ˍʇɄʃɍʊˆΆψΈϒЄцЇτ΍͊ʄ˄ʌɄ&}ۂֆׂք׆քՇԉӂ҄фĄÅ‡Æʄ΄ +ԄՅփׅgٚ~~njÅĄÂ‰:~~4~}ºɿ~Ÿ|F؈}}|~f~}ÿ}~ýŒ„ÏĉňƂLjf􃊑}{{|C{¾~ĽǽфόІϊΌ͉̈́̆˂̊ˈʃˌʃˈ̊̈́ΎϓЈ5Љ~~|~8~{ƾ~ż|̈ˈ̊ˌʈɢȆɄʄ˄̜΅σΊψ΄͇̑˃ʇɊȂLj&􂈎|فԎՅԅӊ҆тЄς΄̈́‡„ +DŽӄԄՆփׄa}}Ɔƒ:~}}4}|~Ǿ}÷{Hׇ||{}~c~}||Ŀ}ľ»ÊąŃĄŃĊŊƈNjȇǎȆɃʑˎ̍dDüø؈ևׅօՐԎӒҋ҉҈ӋԄՍׇ֓؄29žúȻӊ҆ӈҎчУω ӊԂӐԆՄքՉօՈԄӎ҈шЅχ΅#ᅍ܅ۄڊن؂ׄւՄɄȅLJȆ +̈́Ԅ +ڄۄ܃݅ޅa¾̍ȃɅȂljƂńąÌ†55ŽʽKތg½ſ‘†ŠАˆÈÅĊŎƊǍa~~||}}~}A~»ø׉ф҉цАϏ΋̆ͅͅˆ̄˂͉̉ΆϊЈњ1~4ļ|ƺњ͆̎ː Ɏʊ˅̂̈́·τΐψЂфЉцЇτΏ͇̈ˆʊ*}~׆؂ׄ؅ׅօՈԅӂ҄τńĄÄ‡Æʄք׃؅مe~ÿLjÅĄÂ‰:󀇏~}4}üŸ|E돜􀆌|}~~c~}~}ý¼ƒÐĈřa󃋓}}{{||}|Hÿ}~όІϐ΅͐̍ˉʃˌʃˉ̋̓ΎϑІ7щ~}~5~û{ȿ~Ÿτ̉ˇ̊ˌʈɢȆɂʄɄʄ˄̔͂΅̓Θφ΅͇̃˅̈˄ʈɈDž(|}քՅԈӅ҂фЄ‡„ +DŽӄԅՂֆj}Ɛ7}|4~|ºȾ~÷{Fꎛ{|}}c~}|}ÿ|ÈĄŃĄŃĊŋƉLjȈǏȅɈʌˋ̑`JȽևׅֆՊԏӍ҅фА҇ӋԃՎ֐׆؅3؎5»ƽ̿քӋ҃Ӌ҈щФωЄф҄ӜՓֈՄԅӒ҅цІφ,󁉐݂ކ݅܄ۉڅق؄ׄɄȄLJȆ +̈́ Ԅ +ڄۄ܂݅ބhĿ̉ȃɄȂNJƂńą…̆4Ƌ4ŽʽF򓠫dþ¼†ƁВŽÏąŇƢ`~~}}~~~F~~}}}ȼ҆у҇ъЌϒ΅͉̈˅̃ː̅ͅΆώЈш҄ӊ04~}Ļʽ׋͋̅͆̍ːʈɆ +ʅ˅̃ͅΊςЈςЇυЌЅфЄψ΂͊΃͇̆ˇ0}ڂۆڅم؄׆ԄӅ҄τćÅ Ʉʂ˄τلڄj}þDŽĈÄ„ 7͍3~ŽŸ|CȀ}~`~~|}¼¼ŒÆďłƅņƉ]}}||}~B}}||¾|žƻڐЄϏ΅͎̈̉ˉɋʆ˂ʈˇ̅̈́ΏψЈфЄ0~6~}ƿ|ºȼ˄̙ˊʒɚȊɄʄ˂̊͒΂͆ΐςЈτ΄͓̅ˆʈɆ.~|~؈ن؄׆ֆՄхDŽ„„ƄЄՄ؆j|ƌ6̌~~3}üɿ~ķ{D~|}~c}}{~|ſÅĆłĄńĉńƂňƗǎȎɆʆ˘͊_AŽׇ֏ՅԄӄԏӅ҉чЊу҅ц҅ӅԅՎև׈؄ׄ04ƾµܞ҅ѐАσΏϊЄф҃ӊԐՄԅ՚քՄԒӅ҅шІ/󂋒߃ޅ݆܄ل؄!ȄLJȅ ΄ׄ܄݂ބ߄lþ̄ɈȄdžƃŅēȋ8ӑ4ýƾʽF̓aþ½ƿ́В‚ÒĄŇƎǂƎLJ\~~|}}~~B~~}}ļ~ӄ҄ф҆ьЇϖ΃͉̊˄̂˄̂͌̆̈́ΆϏЈч҄ӊ0}3}ľǾ|ވ͈͐̂̌˄ʂːʈɆ +ʄ˄̄̈́΋ύЈτЌЊфЄϓ΄͆̈˄8}~܆ۄڅل؆ԄӅ!ņƒÄ Ʉ τ؄قڅ܊Ȅh~ƈÄ +6ⓠ}}}2ƿºŸ|FՇ}|~`~}}½ž‡ÈĔņƍ\}}~{||}}~B}}||ÿ~»}˿эЇϐ΅͎̈̅ˍʂɈʇʆ˅̅ͅ·ΊυЊф4Њ|3~|üƽ{̿ݐˆʊˊʒɚȊɃʄ˃͚̊Κυ΃͔̆˄ʊ2|}ڄن؄ׄֆӄ҆DŽ ˄ЄՄւׄ؄ډDžg}Ą…7|||~3~Ž~ķ{Fӆ~|{|~~]~}|þ|~ýŒÂ„ÄĆŅĉŃƄňƐǂƄǍȑɄʇ˟̇]@ºƻ؍ׇ֏ՅԂӇԎӅ҈шЊф҉х҆ӄԇՃքՉֆ׉؄4׎4ûĻƹҋш҆ёЎτ΋ϊЄф҂ӊԒՂԆ՚քՄԓӅ҅щ4񁊓߅ކ ن"ȄLjȄ"ׄ +݄ނ߄΄hˈȄ ŇĂÄČȍ7藥󁈐4ľǿ˽Cڋ^½ýҁЃ†ÎČŊƂǖƂŇ[񂍗~~}}~~H~}|Ŀ~ź҆ѓЃφ·ό΅̈́̒˂͎͉̄̅΄όЈѐ5ҋ񁈒|~3~|}¹ķΈ̆˄̅ˋ̈ˆʃˊʏ ʅˆΌϊЂъІфІфЃчЄϒΆ̈́̇7}~݅܆ۄڃم؄Յ'‰„DŽ ̈́ +ӄۄd~~~}}}|¿|ĿĆˆ 6񀇎|~2}}úƹ|C䎜|~^~}|Ŀü}ûˆÌĚŊ^}}||}}~~A~~~}|{¾}ƿøԋ΄υ΃χΏ͆̂̅ͅˆʆʆɃʆˊʆ˄͍̈΄ϊЍ0Њ{}3}{ǿ|~ö̪ʐɄɈLjȈɅ˄̂͆΂͊ΆϐΚ̈́̋̆ͅ˃ʆ6|}܃ۅڄق؄ӅȄǞ +҄քم쁇h~~~}}}|||{~{½~6󖢮~{}2|ƿ|ķ{C⍛􀇍{}~_~}|{þ~½~|ŽÄĈŋčśƋDžȏɌʉ˃̇̎˂ʇYBſƾʿۋׂքՂֆՂֆՐԌӄ҄юЂхҌх҆ӆԎՃ֊׍1׎4ƿǾʼӨшЂφЋϋ·ψЇӋԉՅ֑՚ւՄԊӂԆӇ҃ч7쀊¸߆ +څ&ljƄDŽ̄фل݄ bĿɆLJƃŌďÌ +73ƿ˾D꒠[ľІ†ÌďŇǗƂŋW}~||~~E~~}|Ŀ}Ľ}ɾ҆ђЅσΊϊΆ̓̓˂͎͉̄̆΅ϊЈѐ҄1ҋ񁉒}|~9}ƽƼȻ̘˂̎ˆʂˊʐ ʅˆΌϊЂыІфІф +ЄϓΆ@}κ݆Յ&‰„DŽ̄ӄۅj~~}|~ˆ +5}}5}»}ûƹB}~}~[~|þ}ſƻˆÌĄņĂňō\|}{~{}}~~G~~}}|{þ|û|ȼщφ΂φΓ̈́̅ʍɃʅˋʆˆ͍̇΃ώЍ/|{}3|ļ~ĻǺΩʒɌȈdžȈɄʄ͍ΏωΛ̎̆ͅ˄:󄍕|͸ۅ؆ Ӆ$Ä̅ +҄քڎe~}}|{}ſ6􁈐||2||ºķ?󒞨|}|}~~[~}{~|ý~ĺ‡ÅąŎċŘƌdžȌɎʈ˂̖˂ʋXꀌ@º÷ׂքՂֆՂֆՐԌӄ҄ђЂфҌцҊӃԍՃ֎׍/3ü¸ՈщЂцЏщЂφЋύ΅χЇ҄ӂԐՊ֏ՙքՂԆԈӆ@Կ ߅ۄڄ$NjƃDŽ̄ӄބhLjƂŒĊË +33˽C[ĿǿЈˆÄčŅĄŅƓłƆŇZ~|}~~A~}|ÿ¶ҊщИυ·̓̉ʄʅ˗̋ͅΈφЊђ.򂉓~}2|º|ͿՄ̖ˆʄˍˊʄɂʄɂȆɆʆˆ΅ϊІуІфЄτЂцЅфЂхЄφ΂τ΂τΆ>|ว ܄ۂڄ ք#Ą‡ Ą ʄԄČh~~}|}½Š5Ȍ}~|1~ý~ļƹ Aʂ󀆍}|~X}}ÿ|¼}ʽ•ÄĂŞĈX킎~}{|}}~?~}|{~ǿхЌϋ΄͎΄͆̆˄ʐ˄ʂˈʈˊ͈̆΄τЂώІ.}|~2~{{ȿ˾ӌʞɄȊɑȈDŽȈɅʂ˄̄̈́ΎΏψΐ΅τΓ̈́̄>쀋{~޷ +ۄ؅ׂքՂԄӄ"„ Ʉӄ ڄ‹o~}}|{|5Nj|}{~2}»}úķAȁ|{}~Y~~||½~{~ƿ|ɼ„ØăŇƌŖƊLjȄɎʄɃʆˑʅʄˆX?Ŀƾǻ׌֊ՊԄՂԄՃԅӆ҄ђЄҏщ҉ӈԆՄքׂ֎׆.2ǿżķچіЂϋІωЉό΅χЄӄԄՎւՎֈՐՄքՆԂӋԅӄB􄏙潫݄܂ۅ!ɄLJ Ʉ Єڄ݄ ɐh¼ljƊŐăĈ4͏򀈐2»˽AφYƾ‡Љ‰ÄĉňĄńƔńƄńƊV}}~B~}þ~ĽƺҍхЌςІτ·̈́̉ +ˆ̂ˆ̄ˇ̋͆·υЌѐ.󂊓~~6~ƿĻ~ö̌˓ɔʄɂʄɂȆɆʆ˄΅ωЈтЎфЃτЃфІтЄфЄφ΂τ΂χE~﶑݄ڄ ք"ĄÂ† Ą ʄτ +Ԅݢ􄒅d~}|¼}Ċ 5ܒ~1~|žŽƹ@Պ|~V~}½}þú Â„ÎĄÏĈ[||}~~D~}|}ûĹЍϋ΂͐΄̆ͅ˅ʐɊʂˈʊˉ͇̇΅ϏЄ.񁉒}}1}Ľ~¹}µ܍ʐɂȋɅȊɑȈǃȈɄʄ˃̅̓ΠψΏςЊτΒ̈́C}ڄق؄ׂքՂԅƄ„ Ʉӄ څ򑑅i~}|{~| 2ڑ~}2}{ý~ûķ@ԉ~{}~[~}||ƿ„ÎĄÆăŇƍŐƊljȃɊʈɄʄ˓ʆ˃ʄˊTAþº˿׍֊ՆԎՃԄӇ҄ђЕю҅ӇԆՅ֏ׄ.1ĻɻєЖφЊτ΂ό΅χЄӅԃՏՏ։Տւ׉օՄԂӌԄZ߂ބۅ%LJ Ʉ ЄلڄdɊƊŅăňˆ6▥2ļ¸˾ AۍXþþžȿŽЉŃÔĒłĈŊƏS||}~?~}½~ʾѐЂϒЈςΆ͈̈˅ʉ˄̇ˆ̄̊͆·ϋЊш-􃊔|1}»|ȾǺ͔˒ɋʞɅʅ˂̄ͅ΅фМшЈЌхЄτ΅_쀎|}~}ڄքՄԃӄˆ‚Ä ʄ΄&ꎖg~}|}‰5~}0}ƾƹ>㏞~}|~T~}þ|̽ˆÈˆĈÎĎV{{|}~>~}|ƿ}ȼЅςΆϞ΂͆̈ˆʊɆˉʒ˄̊͆ΊϊЄ-򂉓~{~1~|{ƽƸˍʎɒȂɊȄNJȆdžȂɆʄ˃̆̓ΖτЇυΎφІφΑi~{|}~|ՄԄӄ҄ăɄ̄'荕c~}|{¾|ſ8󁈐}|~1~|ž~ļŸ@᎝}|{}~T~}|{Ŀƾ~ʻƒÌĆÄĆŌƂņƉŋƋȅǃȔɛʋˏUA½Ž÷ևՃ֞ՃԄӅ҉ъЄхЇуЄѐ҅ӉԆՆևׄ.1ĺͿ҇ЄюОώψ΅τЄф҄ӆԂՖք׆ևՍֆׅևՆӊa򄑜߄܄ۄڃلLjƄǂȄӄ𒇛a¿˅ljƊňĄÂ…22Žù̾?铢TÿžŠ‘Њ„ÍĂÄĐńćŋƅƈDžS򇕠~~}@~}|~ļ}ѐЂϒЇσ΅͉̈ˇʈ˄̇ˇ̋ͅΈόЈш0}0}ȿ~¹̾ϊ̊ˑʆɊʞɅʃ˄̄̈́ΆфМшЎу҅фЄτΆ^񅓝}~܄ل؂ׄւՅԄć‚Ä ʄӄݤd~}¾}Ȅ‰4}~0~ǾƹA􀇎|~V}|½~ý}|ł˗ÎĎņT}}|~~C~}|{ſ}º}τ΅ϐΆφ΄͆̈ˇʉɆʂɈʂɄʐˆ̈͌Ήυ1Њ󂊓|0~|ƽ}ʽ͎ʎɒȂɈȊdžȆDžȃɄʅ˂̈̓ΌЉψЄυ΄ЇωЄχ΍d~|}~؄ՅԄӂ҄̅لڄe~}||žnj5|}1~}ŽŸ@򒠪~{}~X~|{}|ƿ{÷„ËĆÄĆōņƈōƐDŽȍɂȄɑʂɆʌˏ̅Q>ƺֈՂ֞ՄԄӄҊъЅωЅхЄђ҅ӇԌՉօ1׏1ĽȾõчЄьЎςΎϜΆσЄх҂ӇԃՖֈׄֆՌևׅևՅӇn܄ۄڂلLjƄǂȄӄ 㩝cſ΄LjƊňĄÄ‘2‰񀈐.ǿĹ̾>V¾½ƾɽ’ł†ŠċĊńĆŋƃLjƇLJP텔~}}>~|ǿ|ĸٛЃцЂω΃͌̄ˍʕˌ͈̊·όЇ0ы~/~Ļƽµք̍ːʆɌʉ ȉɄʄ˃̄̈́ΆφЎы҇цЋш҅фЋa}~݄ل+ć„DŽ̄̈́ +҅ۅ➞g~}}Ľ~†6̎}}0ûȿǹ=ǀ}}U~~|ý~~ֿ„—ÆĕʼnR넓~}||~~;~}{þƾ{÷׌΄Ίς·͆̅ˌȆɄʅɃʆɄʏˇ̇͌΋φ,󃊔}/|¹Ż~ՆʅɄʌɄɕșɄʄ˄͇̅ΊϘЄςΊόЄψ·_~|}~܄؄҄ƄτЄڄj~}|¾|¼}5ˍ~||0~ƾŸ?||~V}}{}ľ}Ծ†ÆĈÅąŠƂLJƋljȆɋɊʄɅʋˈ̃ˇ̈Q󈘦<ſżʽߋ։ՈփՆԆӃҍтЌϕЅю҇ԍՊֆ,0¸Ⱥ܅цЃыЎσΎϜЄф҃ӆԆՊ֘ׄփՉ֌ׄևՈmބ,LjƄDŽ̄ф +քׄ裣i¾¼džƋŋĂĒ 2ђ1ź̾<̃WþſƿĻ •˂Ђœ†ŠÂĎÇŌąŋƄLjƇljQ}|}@}}ľ~ú~ǻіЅхЂϊ΂͋̅ˎʔˌ͇̋ΈωЉ/}|~.}ǹ̌ˑʇɋʊɆȉ˅̅͂·φЏф҂э҇фЋщ҄фЈr}}|؄*ˆ„DŽ +̈́΄ф҄ۅ +d}Å +7蔣|0ļ}ǹ?φ~}S~}¼|ýºϼˆ–ÅĖʼnƅP셔|{|~=~~||¼}}ƺߋΐςΆ͇̅ˋʃɆȇɃʏɄʏˇ͎Ί0ϊ􃋕|{}0|ƿ~ɿƸˈʂɄʌɌȂǑșɄʄ˃͈̅ΊύЃыΉϐωo|~|~{؄ׄ*˄̂̈́Є!۹h~|¿~ƿ4瓡󁉑{~0~û|ǾŸ?ͅ}~|~~T~}|~{~ͻ‡ÄĈÅĄǜƂLJƋNJȂɎȆɅʅɄʌˇ̄ˇ̉S􉙦;þȿօՎփՆԆӃҌуЍϕЄѐҊӆԋՉ0֏/ƽƼ̾чЃцЍυΎό͈΄ςЄф҄ӄԈՊ֌׃؊Չ֏ֈՄ|瀏ڄ LjƄDŽ̄ф҄ +ׄe½ƿȅƎňăŒ 11Ż̾@ԉQ½¼҂Ѓ”ƒ‚‰ÃĈÓąŋƄDŽƈNjP郔~||~;~}¼ƾ˾҅ьЋуЄω΃͈̈ˈʂ˄ʄ˄ ͇̔΍ϐ.}}2|ĽŻ|̾͆̐ˊʖɂʎɆȈˇ̂̈́΃ϊЌт҄ј҄ЊэЄo怏~}ڄ Մ!‹̄ фۄj}~ľ  +3}}~0}ƾ}ǹ?Ԍ󀇎}}P}½|ļꆂĈÄĘňƆN肓}{{}~;~}|ļɽЇςΊςЈσΉ̇ͅˆʛȊɃʓˆ̊͌Ά/􃋕||~2~{»ù{˼̐ʌɆȋǒȋLjʆ˄͇̃ΆϑЄшЌϐЄτp}|~؅3 ΄ςЄ(ۆf~|¿}ü2||}~0|ļ|ȿƸ>Ӌ||~S~~|~ſ{º͹ˆÐĄńƄǔƄǃƄǃƎljȃɈȒɆʊˊ̂ˆ̎P;¼ú÷׆փՔփՈԅӆ҆шІϊЄυЃђ҆ӎԌ2֎/¹õӊфщЉϑΈςΆτ͇Іт҄ӄԇՉ֐ׄ؈׌֐ׄu섒߅ނ݄܂ۄڂلnjф҂ӄԂՄւׄjüƆŃƋń㥠+1񀉑0üƼ;>ڐPþӿ‰ׂЃŠˆ„‚‰ÃĈ…ÂĄÊĆŊƅƆǏR酘|~=~}~҄шІфЄϊ΃͇̊ˆʂˈʄˉ˄͇̒Αό.~~1~~ɿõ҈̏ˊʜɆʄȆɄʂˇ̈́΄ϊЌт҄јҏэx~}}~ȇڄ Մ҄Œ +Ƅʄ˂̄τۄi~}¾}3Ŋ}0}ǿ~Ǻ=ᐠ}~M~|½}ľ~ƾ醇ÄĘňƈK焖~{}~=~}|Ŀ}ǿцςΊςЈσΉ͆̆ˆʚɄȉɃʒˆ̎͒+}}1}ȿ}ǽ~БʌɆȐǒȉLjʇ˂͇̄·ωЂωЄщЊό|}||}dž؄ׄ0ʄ"لf}||ƿ +6É~|~0|Ž}Ƹ=ߎ~|}~O~}{|ý}Ž̸ˆÐăŅƄNJljƃDŽƅǂƎLjȄɈDžȂɄȉɆʋˊ̂ˆ̎̈́M;ƽǺ؅փՔւՊԄӇ҅шЅωЂτЄφЂђ҆ӎԒ+.ƾĺȺ׋фщЈϖΆόΈц҃ӄԇՆօ׃ֈׄ؈׌֋}聒Ί߅ނ݄܂ۄڂلnjфAὨjÿžŅƌĄ +0ʎ0ĽǼͿ=瓤P¾ýûӾŠ݂Ѕš„„…ÆĖÆĆŋƅLjƄǘL񈚨~}~=~}ľĻ}ķхЋшЊψ͇̄˄ʆ˔ʄˆ̈́̉̈́΍ϒ-0}ƽùǹ܊̊ˊʈɂʔɄʆɈʂ˄̆͂΄ϊКіҊя|}؅ԄĄÃŠƄ ˅̄͂΄фل ۀ룤f~»„ + 3ٓ}/~¸Ⱥ:듢}||~L}|þ}¼ι‡ˆ‡ÆĕŇ +ƄdžL}~|}~:~}|½º|¶ӗωΉ̈́̉ˈʏɊȈɂʐˆ͖̈,Ί~~3~|ϏƸːʋɛȄǔȄɄ͉̅ΆψϑЈшЃϋІ{~~|~ׅӄ„ɄʄCꢣd~}~3ؒ􂊒|/}ǿ~Ƹ;钡|{{}~M~|{|ǿ̸ÑăņƄǚƊNJƃDžȆɖȆɆʊˈ̅˅̐͂ΆL;ýɼڕ֊ՈԆӈ҈эВχІэ҅ӈԖ0Վ.ºɾ;щτЊφ΃ϐΌυ·σЄх҂ӅԈՇֆׄ֐׈؆׆֊׆|ꂒޅڄɄȃNJƄЅф߄"򨩩g¿ƅņƃŅĂÆŠ„1ߗ0ƿȽͿ;񗧲󀇏OþƽӾŽႡІšŠ…ÃĒÄÆĆŊƆLJƅǙK򊞬~|~:~}¼}Ǿƺ~чЊчЈχ͉̄˂ʅ˕ʂ˄ʂˊ̊̓Όϓ-}/|¹~Ǿ};̊ˊʂɄʆɃʓɕʃ˄̅̓΄ϊКэ҂ӄҊъҀ|}~؅ׂքՂԄӂ҄ĄÃ‰˅̄̈́Bڹg~|¾}ûȊ2~}1~|»ùǹ:~~L~}þ}}Ļθ’‡ĔņƉǃƄDžƄI}{}~:}||ż~Ÿ}ӕϋΊ̓̊ˇʌɐȈɆʌˆ͖̈/ϊ~|~3~{}Ƽ|˽ːʋɛȄǔȆɆʂ˄̄ͅΌχЈϐЊєЅY||}~لׅӄЄ…Ʉʆ +τׅ#c}{|ƌ 3󘥲}~|~/}{~Ƹ>~}}~M}|¼|ſ|ºͷ‡ÐĄŇƃǚƉNjƃDžȃɑȄDŽȆɅʋˇ̅ˆ̘M:û̿ڔ֊ՈԆӈ҈ьГτЅю҄ӈԖ,֎-ȾùõшτЌςΈώΒЅӅԅՇև׈֐׊ׅؔ}怒ބڄׄɄȂNJƄІф҂ӄք4ྏhÿņƃŅĂÆ‰ƒ4򁉒0Ⱦ;>KþſӽŽ肟Ї›„ƒŠÒ‡ÃćňƈDŽƆǔDžȆJ}~~|~9~|ƿɼىЈьЈτ΄͍̇ˌʈɈʂˉ̋̈́΍ϑ,~0~ƾ¸õЍ̈ˑɌʏɑʄˆ̃̈́΃χЇцҎы҄Ӊ҄ыX~}مքӄ҄ĄÂ‰˅̆Є?ل†d~|~ļ~Ņ 2򁉑~.}üĹǹ9󀇏}J~}Ŀ|ľǾ}ּ˜ƒÅęŅƄnjƈJ|}}{}~:~}{ľ~ȿȻׅςΎωΊ̓̄ˋʇɖɄʎ˄̈͌Έ,}5}޳ˌʒɈȄɎȂNJȍɂʇ͇΋ωЈϋАёЄZ󌜪}|~ׅւՄԂӄЅ„Ʉʆ˄τ@؃b}{ÿ}»}ĉ2}/~|¸Ƹ9~|~M}|½{ýŽ|Ի…ÄĆÉćŘńƂDžƄǃƆNJȒLJȃɆʉˈ̄ˆ͆̚K‒7žƽބփՊ։ՉԃӄҍшЊτΉςЈы҃ӌԌՄ-2ĺǽȺҊщЖύΊχІт҄ӂԈՋև׉֋אؒ[ބ݃܄ ׅɄȂNJƄ΄ςЅх҄քۄ܂݄0߈ȅDŽbʄƆŅĄØ//¹ɾ;=ʂJĿĽû™삞Їˆƒ‰Ô†ÃćňƈDŽƆǒȂdžȄɅG႕|}}~8~|ý|Ļ̿وЈьЈτ΄͋̉ˊʊɉʃˈ͇̋΋ώ-ы~/}û}ƼȺڎ̈˞ʐɇʅˆ̃̈́΂χЌцҋэҊӉ҂ъY퉛}ڈ܄ل؂ׄք҅ĄÂŠ Ȅɂʄˆ̄̈́Մւׄ0ٰĊe}ļ 2ґ~}.~Ľĺȹ<ƅ}|~J~|Ŀý~¹ݽƒÆĘŅƄnjƋG߁{||}~9~}{{¹ʽ؄ςΎϊΉ̓̄ːʅɉȂnjɆʍ˄͉̌Ί,􀅋}2~||ŻǸˌʓɆȅəȋɄʈ˂̄΋ωЈϋЕчb숚|~؇ׅւՄ +Єτ„ DŽȂɅʇ΄ Մ0ׯ…ÂąÄ_~|¾~û† /ѐ}|~.~}üøƸ<ń􁈏|{}H~}{þ~}ۻ…ÅĆÈĈŎƂňńƂLjƄǃƆljȔdžȃɆʄ̄ˈ̄ˆ̙͆΄H煙@¼ĶՊ։ՉԃӄҍчЋψΈςЈь҆ӊԉՉ-2οҊъτАωΉύԈՋֈ׉֊ו؈_􍟯ބ݂܄ +ׄքɄȂNJƅτЄц܄0޵Ʌʄ˄ʄ_ɇŅćÕ 3ؕ/ûʿ;9ˉIĿ¼ǾˆЅ„„Ø„ÄĆńƂDŽƐǚȄɆGꈝ}}~6}~ƽ|ЈюЊσ΅͈̉ˇʆɄȄɄʂɈʆˎ͇̈·ф.ъ||~/ȿο͌̎˄ʇ˅˅ʇɄʃɄʂɆʊˈ̆щЋтҋщҎԆӈ^烗|ڄ Յ҄фĄÂŒĄDŽȄɃʅ˄̄N}ۘʄ˅d}¾ļ 2򙦳|~0ƿŻȹ8·}I}»Ǿó†ÄĖŊƄLjƒF臜||}7~|ſ}ż{ͿޗφΊ̓̉ˉʅɉȉnjȅɍʊ˄̈͆Ί,{{}+~ǽɿ~̾ˌʛəȇɈʆˆΐψЅϋЊц҆хЅW傖{~ل ӄ҄тІ„ńƃDžȂɇʂ˄Ԅ4|ٖȄɃʄɄ^~|~û2𗥲~􀅋{}.~ĽĹƸ:͆~|~G~}|þ~ż +ŒÆĉÅĈŏńƂňōƄDŽƈDŽȘDŽȃɆʄ˃̄ː̊͂Ό͆΅I7ƿúƸ։ՊԂӆ҉чЇυ΂͆΄ΉυЌщ҅ӈԅՊ,/ļƼĵҍщЃϋЅΖψЅц҅Րֈ׆֊׊؆ن؅ׅ[톛߄ۆׅɄȂnjɄ̅ Їۄ7᜝Єцeÿʼnć‹Ä 1􂋓/ļ; :ԊIùȷ􂜁Ї„„„ÅąŌƎǚȃɇȄD~}}~9}Ľ~õъЊσΆ͇̈ˈʆɅȄɉʅː͇̇ΆЄ+}}/~Ż}ŻŶ͌̎˄ʈ˄ʂ˄ʆɌʂɇʆ˅̈ щЏ҈щҌӄԆӇX~}}لՅ҄фŒĄȆɂʄ˄̄̈́фՄ:~͋a~Ļſ +1󂊓~}0ƻ|Ⱥ +:э}}K}¹ε†ÄĖŊƄLjƒF􏤳}||}6~~|¼Ǿ}߆ЏϊΆ̈́̈ˉʅɈȊnjȆɌʊ˅̇͆Ί,||~/}ú|ĹõΆˍʜɗȈɈʆ˅΍υЂψϊЋч҆фX}||؄ Ӆ҂фЄτŅƃDŽȄɅ̄ӄ9}˅̅͂̄Z}ÿºČ1򁉑}|.~ſĺ{Ƹ9Ќ||~~H~|Ŀ~ſ~̴ ŒÆĉÅĈŔƂňƂŌƄDŽƔDŽƄǂƆDŽȄɅʅ˂̄ː̊΋͈΄͆D6¼żȺ։ՊԂӇ҇шІφ΄̈́΄ςΈφЌщ҅ӆԆՊ,/ʻԅҌъЃϏМψЈц҆Տֈ։ׅم؇ن؄T䁔„Œ ۄڄق؄ׄքnjɄͅ΃τЄф҂ӄ څ8҄Ӊ^ʍēÅ2/Ž; 8א󁈐EƿȾӺ ƂЅ††ÆőƋǕȂɊȉEㄚ|}~7}}¹ķъЇτΉ̈́̊˄ʆɉȇɊʅˍ͈̄ΆχЉ+}}~.|ʿ}ʼ؎̌ˇʅˈʄ˄ʂɖʄˆ̆͆ΆτЂфІ҇х҆ч҆ӊԃӄR}|Ą4ӄ҄уЄČÄĂņƂDŽȅ˅̂̈́ЄӅFᆎՅ\~|½¹ 1ґ}0||Ǽ|ȹ:ҍ}~K~|}ȿٻƒÅċŅƆLJƙF⃙{|}~7~|ƿ|~öЅχΆ̓̉ˈʆɆƉLJȄɌʇˈ͇̆Ή-Љ||}.}{ǿ~Ⱦ|ɺֈˈʤɊȃɌȄɅʄˉ̂͆΋ϊЂϐЇщ҂ӈY퇝|{~4҄уЄτÅƅDŽȂɅʃ˄τ҄B߅҄Ӆ[}{~Ϳ 3А|~.~{{Ż|Ƹ =Ќ~|}E}{~ľ|ƽ׺ęÆąšŌƂdžƒǐƂdžȅɂʐˋ͈̓΃͋F釞􀅋7ƿȾʼ׆քՂֈՅԃӉ҄цІτΈ͈ΉυЌф҉ӅԈՈ.׎񀋓+Ƽź݆҉эЃϔЛτЄч҇ӂԅՋ֊ׂ֐ׇ؉قڈYDŽȅ$߄ۄڂل؃ׄքȄńȄɂʆͅ΄ςЅ քلE犒ۅ\¾ǾƌĐć + +/ו.Ǿ;8בFžĺ˂†…ÆĂŐƌǕɋȋB񎥵}}:~|Ľ~Ļǹф҈эЅσΉ̈́̊˄ʅɋȇɉʆˋ̃͊΅ωЈ*}}~0~Ž}ĺ͌̌˔ʅ˄ɖʄ˅̇͆ΆτЈт҆ш҂ш҆ӄԂӊԄTၗ}}ʼn2ׅՄԂӄ҃фЄ̄ ĆņƃDŽȅɂʄ˄̃̈́ ӄGׅ`}ÿǿ 3񙦴~~.|ú}Ƚ}Ⱥ 6ޏ򀈏}E}ýſúű‚ÎĊńƆdžƎǂƊDŽB||}7}{»}úŸыЌφΆ̓̉ˇʇɆƄǂƈLJȅɊʇˈ͈̆Ή-Љ||}.}ļ|¸ο̈ˈʥɇȆɋȃɄʅˉ͇̂΋ϊЂϐЇщ҂ӈR߀||~ÈĂń2Մӄ҂фЄτ ÅĄłƆɅʃ˄΄цFՇ[~|½ȿƉ +3𗥳}}.{|ƻ|Ǹ8ݎ~|~B~|~Ľ¸İ„ÈēÆąŮƂdžƍƄǐƃDžȆɂʐˋ̑̈́Ά͌E7»̾؋ׅևՅԃӉ҇цІτΉ͇ΉυЊц҈ӆԇՉ*׍񁋔/¹ɿƶӆ҉эЄψЂϊКσЅф҉ӂԇՊ֊ׂ֐ׇ؉قڈX焛˅?݉ׄքȄʆͅІт҄Մ؆F݆\¿Ŀƽ̋ďÈ +..ȿ¹;8䓧K½ĽɿʶςЄž†‚Ž…ÆĆŋƌǢȋC}~5~ƽɻӇҍшЅσΊ̈́̄ˆʈɐȂɉʇ˄͇̉ΆόІ*~~|-}ɾƷЇ͈̎ˏʊ˗ʄ˄̆̈́ΈωЖь҆ӐԀ~ ؄ՄԂӄ҄ф† +ŇɅʄ˂̆̈́΂τЂфҀ局0}Ŀƽ +1}-}Ļ}ɾ}Ⱥ8ⓣ􁉑|~A~~ľľԶ ‚ÇńĎŌƐdžƋEނ~|}~;~}ƿżǹщЇϊ΂̈́̊˄ʈɆdžDŽƃdžȊɂʆˊ͈̆΋+Ј}}{~-|ɿǽŶτ̉˃ʑɂȄɂȎɆɈȄɃʇˆ͈̆ΊϒЄтЇђV}Ʉ/քՂԄӄ҂фЂυÆĄłƄDŽȄɄʄ˅ͅ΂τNۄ\|þ~ż-􂋔|~.|º|Ǽ|Ǹ6򀈐{}E}}½~üɿӵÌČËĂōǞƄdžƄǂƋǏƄDžȅɇʉˎ̌͂ΊΉ͊D懟<ƿú؈׈ֈՄԃӊ҄чЃχΐ͂ΈψЃц҉ӆԈՋ,׍򁋔1ƾù̼ӈ҄ѐЌόЖц҆ӇԈՍ֊ׂֆׄ؂ׇ؋قڅVЅ4ۄڄق؄ׂօDžƇńƄʆΆτЂф҅ӂԄՂքN분_¹ňÇĊ +10úο7藧BľüƼڻӂЃ˜‚Ž‡ÅąŊƎDžȂǚȊɅ?}~}@}ü|ʼ҉шЄσΊ̈́̈˃ʇɑȄɇʇ˃͇̈·ϋЇ*~~},|ǽ}ø̽لΆ͆̏ˍʊ˘ʃ˄̅͆ΈωЗц҂ӄ҆ӏQ}̄̈́#Ƅ ؄ׂքӄЅ†ŇȄɆ̇͂΄ςЅNҐ|}~ߊW|~ûƌ0ђ~~~-}Ž~ɾ}Ⱥ:㔤}}C~|ſĽ~Ⱦò +…ÄńĎŌƆƅdžƋdž?򏧷|}|~5~|»{ǾȻ҅ъЉχ΂͇̇˅ʇɇȂǏƂLJȉɂʆˉ͇̇΍*}}|-~{Ƽ|~ʻ׆̈˄ʐɂȕɅɈȄɂʆ˄͈̊ΊϐЎёSހ|ˈ5ԄфЃτÆdžȄɂʆ˄̄τM{|}~݄]~{ľ}¹Ő 2ϐ}}}0|Ļ}Ƚ|Ǹ 5ᓣ||~D}{ľ~»}Ƽ°ÍĊÌăŌƇǙƄǂƕǎƅLJȄɆʈˏ̌͂Δ͊΅@5»żم؊׆։ՃԄӉ҅ч Α͂·ψЂцҊӆԈՌ+򁌕-ºȾ³߅ӈ҃ѐІЄύЕσЄцӇԈՉ֊ׂօ׍،V慝Ҋ?؄׃քdžƆńƄʇΆч҂ӄքMYˍŅĈ 6֕󂊓.»úο6阩Dſ»ùȶ؂Ѕ„ÎŽŠÎކÄĂŋƂDŽƈǂȅǚȏEᅞ|~|~6~ƿ~¹|̾ԄӈҊхЃτ΅͋̅ˇʃɒȄɄʄˈ͉̃ΈψІ.щ~~+~ùȽ³Ά̢ͅ˘ʃ˅̄̈́΂φΈτДыҎӌR}҅FхЃυ҃ĥDŽȆɄʄˆ̄͂΄Xз|~\}| 0񙧵󁊓}-~ƾʿ}ȹ :㕥~|~E}ý}ĺ׷‚ÆďŐNJƎLjC{}{}3}ž}{ʼӈшЊς΄͇̊ˇʅɆDŽƆLJƃDŽȄɆʆ˄̈͊Ύ*}~},}~Ƽ̅ˈʆɃʗɂȕɆʄ˃̆͊ΈϗЄц҂юS슢~|ЅDޓЄτ΂͆„ƒÄăńƇǃȄɅʅ̈́Uϵ{}~W~|Ŀ{ȿο 0񀉒|,}ż~Ƚ|Ǹ:┤}{}B~|ſ~»|ùֶßćʼnƅDŽȎǎƄNJȎǎƉDžȅɂʉ˄̃˅̟͑΄?爢􀆌3ŽǾõڈ؆׋ԇӆҋхІςΒφІф҆ӇԆՎ*󁌕)Ⱦ¸ȸӆ҇ѠЌυІςІф҂ӆԂӆԈՇֈ֎ׄ؆ق؍T􏧻؅DׄքՂԆȅLJƆŃƄǃȄɄ̄͆΃τІ ԅSWżƆĆņą 1.üĻξ6陪C»ʿݼ˂ÉۂЄ…ÏŒÈކÄĂŋƅȆǖȒɆ?}~}5}»ú}Ϳֆӆҋτ΅͌̅ˆʂɎȄɄʄˈ͈̃ΉψІ.ц~~+}ȿ|·}ɹ҉Ά͇̟ːˇʂˆ̄͂΅υΈτДыҌӌO~}|Ԉ4؄ ҄уЄφ΂̈́ƆƒÄăńƆDžȃɅʅ˄̃̈́΄V}~V~ƽĊ /|}|0~|ȿ˿}ȹ9얦}}A~|½ý¸DZ‚ÆĎŞƏNj<|}|~8~|~¹|̾҅щЉς΄͉̉ˈʄɆƆLjƂDŽȄɆʆ˄̇͋Ύ*}~},|ƾ{|ǸЌ̃ˉʄɅʖɂȕɆ̌͋ΆϘЄцюO~|{~҉CЄυ΃ͅ„ņƄdžȃɅʄ˃̆V|}~U¿}ĿĻÄ 0{|{~-}{ƽ~ɾ}Ǹ8딥|~|~A}{~»ŰÉăŒĈŇƆDžȎǎƄǐȈǎƉdžȄʊ˄̂ˆ̗͓̆̈́Ά@ۀ4Ķن؈׉ԇӆ҄҇хІΒ̈́΃τЇф҅ӇԊՎ*󂌕)ĺǼξ׋ӄ҈ѠЄτЂφЅσІӇԂӆԈՇ֗ׄؕO備ڈ+ׄօՂԆ҄ȅLJƇŃƄɄʄ˅̅̓΅τІт҄Ӆ[W¶ćň-.ĽŻξ 4򚫸򀈐B¼»Ǽ̶†Æ„Ä…ŒȉŠÃĄŊƉDŽȐǎȅɇȋAꌦ|~4~|žż~ׇӉ҅фЅψΊ͆̄ˇʂɅȂɋȄɃʄˈ̆̈́΄ύЈ,}~~+ûǼϿۋ΅͌̈˄ʚˊʄ˄ΒχЉщ҇цԆӅT懠|ن5؄ׂք фЄσΆ͂̄ ĄÅ‡…ÄĈńƃdžȄɃʉ˄]ӆ|~S~~ˈ3ԓ~-}~ȹ 5~|~A}ľüữ ƒ‚ÈĊŌƂōƇǂƐnj?若~{}6}{ļĻ}Ϳ~҈шЄτΆ͈̌˄ʈƇLJƄɇʈ˄͈̄Β)|}}1~¹~Żͽ͊̉ˉʯɄ̄̈́΅͉΄ϊЂѐЂђO䆟{~ׇ5քτ΅ͅ…ÇăńƆDŽȆɆ_҅{}~U¿}ľ}ʾ .Ғ}~-~|ǿʿ}Ǹ􆬃 6}{}B~|ý»Ⱦߺ ÄĄńĎŇĄňƞljƊnjȇNJƉljȃɄʉˈ͓̈͊̉΅?6üŷو؈ׄքՅԉӉ҆ф΅̓Ή̈́Јч҃ӅԈՏ*󂌖,ĵӆҌѱЄ ՈԈՄ֋ׂؐؒO슥߆/քՅԄф ɄȅLJƉŅƂDžȄɆʆ˃̄ͅ΃χЅ^يUÿſƼĆʼn -ٗ*ƾżξ3􁉑>ýºŹƒÊ‰ЃŒÂĄÇ‰‰ÃąňƟǍȄɈȎ?݅􀆍}3~|Ǿׇӈ҄фІωΊ͆̄ˆʃɄȂɋȄɃʄˊ̄ͅ΅όЂш(~|-~ʿ}Ŷ͆Ό͌̆˅ʦ˄ΓψЉъ҆цӌN}ۇ;ږք Єυ΅̈́ƈ…ÆĈŃƅDŽȄɊʄ`锸|}T|ſƼ~  +/~}-~~ȹ2}}B~|ĽȾд„ƒÇĊŊƈŊƇƐǎ>ۄ~|~3}ǿ{ż~ՊчЄτΆ͊̌˃ʇɂȎǃƅɉʇ˃͇̅ΐ+}{~+}Ⱦ|ʿô̍ˆʒɂʚɂʄ͘΄ϊЃяЂѐM폨~|لۄ8ؕՄ τ΃̈́̆˂ʄ „ŠÄĂņƆdžȆa璷{|~S~{ýĻ} -􂋔}|~-~}ʿ}Ǹ􅬃2~||~?}ľ{»ƼγĘņĄňƠƊnjȂɄȇljƉljȃɄʉˇ̇͐̆̈́΃͙΄>≤4ƿùǸ܊؇ׄքՆԈӌ҄ф΄̓Ή̈́΄ςЉч҃ӄԋՌ,󂍖,żƻʺҎӌ҆ѰЄԇԏՄ֊ׂׂؐؐMJքՃԄӅLjƊŅƂDžȆɇʃˆ̄̈́Άυ`XľŅĂń-*ǿƼξ 3􂊓Aſºöչ ‡ÅŠЂ„–ƉˆÂĆňƐDŽƌǒȗ=~|~2~|ļ}ɿôֈӃ҄хЈς΄χ΋̓̄˅ʈɇʊˆ̅̈́Έϑ(}+}Żƻ˻ӛ͈̄ˌʆ˂ʉʌ΄ϙЉф҄ӎ҃ӍL~}; фЅς΄͆̅‡ˆÊĈłƈdžȆd~Qÿľÿ/~},~û~ȹ 5~~D}¼}ĽƼð„‰…ÈĈņƎŊƆǂƘLJ<}~{}2}{º|ǾՊϊ΋͈̄˅ʄɆȊǂƆɋʇ˄͈̇ϊ(~|+|ĺ~ĺ~ɺц̘ˇʏɂʇɅʆɄʄ͋·φ·χЈъЄч҅M}|~݆;ԅ҄τ΅͂̄ˉ„ÆĈńƈfȉ}~P}¼~ɿ1}~|-}}Ƿ󆫂 2~}}?~~||ûźĆƕĆņƚDŽƔǖȅǎƅLjȂɆʇˉ̂͆̄ˈ̉Ά͛΄<ہ2Żȹ܊؂ׄֈՌԆӊ҄фЅϊ΅̓΄Љх҄ӈԒ)󂍖+؝҈φЂώЂя +ԋՅևՈֆ׈؋׃؆وK;ۄلքՅӄ҉džƌŅƃLjȊɈʂˈ͇̅dU¾ýƺň-Đ󂋔,ƽξ:?»ȴ–Ç„–ƈˆÂĆŇƐdžƍǐȘ=}~1~ƿõׅӄ҅шЌχΊ̃ͅˈʄȅɆʌ˄̆̈́ΉϏ(|~*~·|̅͂̄̈́̈͊ʄˇʅ˂ʕ +ϋщЉф҅Ӎ҄ӊL}=¿τ фЄυ΂̈́̉ɄńƏÄňƅLjf|~T|¼|źƿ/􂋔}},ļ¸~ȹ4}=}Ľ~Žź滮…ÅĉņƏʼnƆǂƚLJ;~|}~2}Ž~ɿ³ՉтЄό΄΅͍̃˄ʄɈȄƆɌʆ˄̈͑)~{}*}{ɾˇʖɆʅɉ͉ΗχЉчІц҆L߃~|=~ӅфЄτ ˇʅ‰Âĉʼnhƥ{}~P¾~{{øʼn0ޕ򁊓||~/~»}Ʒ󫫄9~|~>~|¼}ü~ø亭ĆńƗʼnƚDŽƔǖȆǍƅLjȂɆʆ˒̄ˌ̍͛΅;2ļƼȺ܈؃ׄ֋ՊԇӉ҅уЇϊ΄ψЇц҃ӈԒ)󂍗󀆍*ǽźƶ҈щЂώЃчЈԊՊքՈֆ׈؈׆؆نK戢=ڄׄԆӂ҄ш ʄɂdžƓńƄǏȄʈ˄̉fT¾ʿŇ-暪*¹ǽͽ9;ý»ʿŽÂĆÇЂ„‚Ȓʃ‡ÅąņƎLjƐǐȘ=狪}}1|¹õӅ҈юІφ΂̈́·̓̄˄ʅɄʆ˄̆͆Έώ(}+}ƽź}Ƿ~̈͑̂͐̆˂ʌ˄̄ˈ̄ϊЉуҎх҆ӇҊӇJ狥|D~|뽒҄фЂτ΃͆̇ˆʄɄ †ÂĄÄĆŌl}~|O~Ⱦ /}􀅌~,ž}¹~ȸ􅫃 3񀉑}=}~žøٴ‹„ÃćŊƖņƟDŽ<动~||~3~{´шІΈτ΅͏̄˄ʈɊȈDŽȃɋʇ˃͉̇Ί(~|~*~|ļĹ|ƶ}̑˃ʐˉʏɒʅ υ΅τЊψЖцM护{~N}{껑̈́̅ˆʈɄȄ ‡ÆĈl|}{P¿}ſ~ǽʾ +-|}-~ü|}Ʒ 8|=~|ľ}Ľ~¶׳ƄłƆňŋƒǂƕȊǑȊǃƍLJȄɆʅˇ̄̈́̈ˎ͚̎΅:폮3ƾȾɺ؇׆քՃֆՅԐӄτЂτ΂φ΄χЈц҂ӉԈՉ(􂍗􀆍+ø˿ͼӏ҉ц҂ф҈ђІуЉфԊՅք׋ևז؆M폪O–Ԅӆ҄шІdžƔńƆLJLjȂɄȄɆʌlQ¿ſóą +,,úǾͽ 4:ſüɽ޹˜Ç‚ʑ˂†ÅĆņƆǂȆLjƑǏȘɅ9ވ~~3}ļúĵҌфЂцІϏ΅ʄ˂ʄɄʆ˄̆͆Έύ)}|)¹}˿ξ֊ͣ̇ʌ˄̃ˇ̆ϋЈфҍхҊӄ҉ӆI퍭~F¿~ԉфЄς΄͆̈ˆʅɄ †ŒÇąńp}~|}N||~ľ /ɏ񁊓}},ƿ}ù~ȸ 3򁉑|~<~»ƿöβ‰…ÃćŊƗŅƟLJ9܇~}}1|º¸ôъЏσ΅͐̃˄ʈɊȈDŽȂɌʇ˂͇̊Ί(~|{~*~|ɾ̼ԑ˄ʒˈʍɎʄ΅σ΅ϋЈψВчH댫}~H~}҈τ΃̈́̃˅ʊɅȅ„ˆÉmͿ|~}~{|N{{¾}¼̿ ++ǎ||~/~Ľ|}ƶ񪪄 +3{}~<~}~Ž~̱ńƆňŋƄǂƓƜǑȋǂƍdžȅɆʅˇ̄̈́̈ˏ͚̎Ά9䋨2ɿɺ؈אփՅԐӄ҄ш υ΄φЈч҂ӊԇՉ(􂎗*ȿŹó܏Ҋц҂ф҉ѐЏшօՅև׈ֈג؇JIڍքӄ҄ъЅυ΄ džƔŅƑLJDŽȇɅʄoLýǹŅ +3Γ*ĻȾͽ 4<ļȻӷ‰ÂČÇꂌЉ…ǂ’Ê„„ÃĊŅƈǂȄLJƆƊLjȂLjȐȄɃʆ7ց}0~ƾ|Żĵ҄тҌчЇώ΄̈́̉ɄʄɂȄˍ̅͆΂τΆϋ(~},~Ⱦź|Ĵ̗̋͡˅̅͂΄ϊІх҂ӈ҃цҒӈI~L~ǵτ·͇̅˅ʅɇȄń„‚ƒ‹Çp}}}}}~~M}}|}~ŷ0뙨|~,}}ú~Ƿ򄪄/󁊒}};~|ľµ}ȱ„ÈĈŇƙŎƚNJ7Հ~~|~/}ļ{ùôԌЊφΒ̈́̄ɅʃɈȈɋʅ˅̍͆Έ(~}|)}Ǽ~ø{óˇʋɋʅˉΌυІюІҋыG}M~}Ŵ͉̄ˆʅɅȆdžp|~|~|||}~}I||{¾|}õѾ,꘦~{},|ƾ|¸}ƶ𩩩6񀈑||~@~}{¼ƾ~|ƯŏƃŊƘǂƝǐȊDžƊDŽȃɅʊˆ̄̃ͅ˓͕̒Ά<܅/ûʺۋ׋ֆՒԂӅ҃ъ΄τ΂̈́Ќф҆ӌԇՇ(􃎗*úʿʹ҆щ҂ш҈юЊх҅ԅՊք׆؎ג؋FJ̺ԈӅ҅цЅυ·ƅŅčńƄǂƈDŽƍNjȇqJ½ʼń„.򝬻.żɿͼ6=üŽǺ͵’Ê邐Ј…‚ƒæÄ‚ăƱŅŅƏǃƈǂƋȄLjȐɂȎ6~/}}ƼĵՈҋчЋφΆ͂̊ɄʄɂȄˌ͇̅΂τΆϋ(~-}ź|ʿ˻̋ͣ̔˄̄͆ωІх҅ӎҒӉԀ~~¿~͉̆ˆʅɇȅń–‹sﳼ~}||}}~~L~~~}||¾|žǺ0}~/}~ĺ~Ƿ𪪪4󂊓}~:}}³|¯ …ÈĈŇƙŏƙdž<~~}/~|ǿ|ĺô~ӋЇφΓ̓̅ˉʂɈȈǂȄɆʈˆ̎͆Έ(~~}*|ø{ɽʹͬˈʉɋʅˉ΋τЊъЌъG}}N}ˇʅɆȅdžƄńt}|~{{||}}~L}}}|{{{ýƹ+~|}.|ǿ}¹}ƶ響5񁉑|}:~|ž|ǿ~{ +ňƃDŽƂŋƄǂƏǂȇƟǐȅȄDŽƈdžȂɄʌˈ͕̂̈͂̇͜΄φ8܂/ƽʺڋ׊ֆՒԃӅ҈фЈωЊх҇ӌԇՇ(􃎘*ʿĹԠ҂щ҈эЉх҉ԄՋփ׊؊׌؊FL¿҆хІυΆͅʄƆņĎŝƋNjqJý̿…/*ƽɿͼ0;ſƾǸdz +‘Ê炖ЅŽ‚Ç’Æ‹ÇĆʼnƍǂƊdžƑljȊ +ȍ<򀇎}}.~º~ƽĵԋ҉цБτ΄̄ͅˇʈɂʄˆ̇͋Έό'~)Ĺ܅͍͆̇͂̏̈́̃̉˄̆͆τЇц҆ӄҒӄԂӉE~|S~¿ٍ˄ʄɉȂDŽƆ +…w򞡤~}|}~~F~~}|~ɼ + +/ה􀆌}1}¹~Ļ~Ƕ𪪩2􂊓~~:~|¼~º³꼯‡ÉĂņƜńƂŎƙǃȆDŽ6||6}}ŻôшЇυ΍͉̄ˆʇɃȄɅʈˆ͈̐Έ'~})~Ⱦøۍ˂̖˂ʆ˛ʃ˄̄͆ΆχПюH~}{T}ʍɅȊLjƂņ w𝠣}|~{|}}~~~G~}}|{}Ȼ +,Փ󂋕|~0|}ù}ŵ2򁉒}}:}{}軭ňƈNJƹȈǒȆNjȇɆʉ˛̂˒̈͢΄60ȿ¸ʺ؄ׂ؇ׇօՑԊӃ҆уЇφЄш҈ӏԈՇ(􃎘)źʾǶ҂хҌхЌу҇ӄԆՆֈן؍HႢSߍІϊ·̅˅ +ƅŇĒņƂŎƂňƂLjƅxIþ®† ,ܘ)Ǿ̻2;ǿǸŠÒ悚ЄŽ‚҆ĢÇćʼnƌǃƊdžƑljȆɆȍ9󀇏~|~.|ļȾĵӊ҉цЏό΃͆̄ˆʆ˅̇͌Όώ'򀅌~,~ż}ʾȸ͈͍̇̐̂̈ͅ˄̂˄̅͆΃χЇцҠӍԀۀ¿| ¿ˌʅɊȄDŽƅ zꇉ}~}~~J~~}}}ÿ}ľ}˿ +/~}~0~úŻǶ着2昨􂊓}9}žü³麬†…ËąņƎłƍŋƢdž4}{}-~{û~ƼóӇшЈϊΌ̈́̃ͅ˅ʈɂȄɄʇˇ͈̐Έ'})}Ļ|Ƚ~Ƕ͕˂̎˂ʆ˚ʄ˄̄͆υЊт҈ц҆ёҀ~~~{ɄȄɄȄǂƅLjŅĆz膈|}|}}~~H~~}}|||½|ü|ɾڿ 2~}|}3}~ú~ŵ2䗧򁉒~|~=~|ý~º蹫ŇƊǎƸdžȄǓǎȇɇʈˆ̂͆̂ˋ̃˒̈͢Ά5.øɺڇ؈׆ֆՍԊӃ҆фІτЅш҆ӐԈՈ()ĸνԇ҃ћ҂хҜу҅ӄԆՆօ׉؂و؆هؐCფVЌυ΄Έ̈́̄˅ ƄňČŃąŃƋłƊœxUüİ +,򂋔.ȿ̻3윭9ĽǷ￞ŒŒÒ䂟Ѓ‹…؆ĨÄĈÄĆňƒDŽƊDžƇdžƄLJȃɌȃɋȅʆ9􁈐~0}ǾɾĴ҄Ӈ҅эЉϏ΂͆̄ˆʄ͉̆ΎϊІ&󀆍*|Ĺп͖͒̊̂˅̃ˊ͇̅΄χЅх҈ӃԄӊԅӐAۀ}|Z}~ʌɄȐDžĆÄ}}}~I~}|¾~ *Î󂋕}.~ĻżǶ4􂋓}7|޳麄 „ƒ„ÊČņƊńƔņƥNj4픵򀇏},|Ž~ǽ³҇чЊώΎˈʅɄʆˊ̌͌Ί'~({ʿ·νӄˆʙ ˘ʂˉ̃͆΅χЂѦ҂ӅA󀆍|{Y~|¾}ȋNjƊńăń}|~}|}~~G~~}|{~ƿ}˿ڿ +*񁊔|~-}º~ĺ~Ŵ쨨1ߔ򁉒~|8~{ļ縆ŇƊNjƆDŽȄǂȘDžȅǨȄɈȄɅʉˎ̄ˌ̂ˈ̅˅̆͆Ά͈΃͋Ί4-ûùɹن؈׉֎Պ ҈уЅτхҊӎԋՉ'*ƽɾijҏэ҂ц҈тҘу҉ӃԆՅֆׂئكڄAქ\¿ϋ΄͈͆̂̄˄ȄńĄÂĆŌĈłēŋ}FþƿƱ +Ȓ0̺2晬:ºǸᄚ†ŠÐăЂ‰ˆֈ”ÂĒÊĄÃąʼnƏDŽƊDŽƈdžƄdžȃɍȃɌȏ6ꕷ||/~ɿôԄӇ҆юЈς΄ψ΂͇̄˅ʄ̅͌΍όІ&􁆎|*~Ƚ}ʾ~Ƶ͖͒̊̂ˆ̂ˊ̆͆΄φЄц҃әԂӏA܀||}^||¿ϕɌȊNJƄńĆÄ}~|}~D~}}|þ}üܿ +阧}}~-~|żƼǵ4ߕ􂋔~7}Ľ}ǿð躆 ’‚…ÆćŃƆŇƉńƔņƊǃƌƋǍ6蔶􁈐{{~0}ǾȽ³҈хЍϋΎˈʄɆȄɂʅˋ͎̉΋&򀅍{~'}ƻ|Ƚ}Ĵˎʎʆˈʂ˗ʂˉ̄̈́ΆχЃшӇ҄ӎ҅A~{{|[{{~~ΔˌDžƉńĄ„~|}{|}~P~}||{|~ھ ++痦||},}{úĺ~Ŵ먧1ޓ򁊒}7~|¼|Ž渮ŇƋljƇLJȗLJȂǔȂɒȊɄȂɆʈː˖̅̄̈́Έͅ΄ͅΈ30Žĺɹن؇׋֍Վ҇фЄ хҊӋԍՊ'*¹ø˺ґы҂х҉тҘт҉ӃԅՆևׂ؈قچلڎمBᄥY¾ՙ҇΄͋̇˄ʃɆńĄÂĆŎĆņĆŖĄÀEÿDzĄ-/̺󭭭2噫:üļȵ†ˆÂ‰ÏĄЈŠÈ†Í‘ÒĊÏćņƒǃȍDŽƊƆDžȄɞȐ7ꕸ~~-|¹ʿóҍюЈχ΃̅ͅʅ˃̅͊·όЈЅ&}(}øĸͼͤ̊˅̇ˉ̉͂΄τІц҄ӄԖՄԆՅ@܀|}|}}~~`~~~}}}ÿ~ĿȇljƍŃĄÇ}~}}J}}žîۿ.􀆍}(}ƽƼƵ넨0ߔ􂋔|~6}~IJܴ‚„„˃‰ÆĆʼnŇdžƎņƈńƊLJƉDŽƑLJ2锶}}.~{Ⱦ²щЈόΌ͂̆˃ʄɆȃɄʄˆ͉̍Β&󀆍|(|·˻Љˌʎ˅ʃɋɊʄˉ̃͆΄φЄх҅ӄԝ@{|{||}}~`}}}||¾|¾}½ƂńƈŊĈ„|}~||~~C~}||Ŀ~ļٽ +|+~|ĻŻ~ųꧧ-ݓ򁊓{}7~|ſ}ǿ°ڳňƗNJȈdžȍǑȒɊȏɇʆˈ͈͍̂̄˒̆͆Ύ̓΋͎΄6+Ǿźȸ؇ׇ֍Ջԃӆ҂ф΄ςЄх҇ӌԈՒ&(Ƚɽ׉Ҏф҈цЈтЌш҄ӃԅՅօׄ؅مڄ۝>ᄦ򀇎^Ŀ̈́̉ˊȇńĄÄĄŃĉץČĀE¼üȳ +,*»µ̺񭄬1䘪7ſƽɶ⸅ŒŠĊЇ…ĄÆˆÌÕĊÎĈņƈǂȈLJȝdžȄɞȄɂȊɄ4ꖺ}}*}ú²ҍяЉυ΅̓̄ˈ̅͊ΈϋЏ&~+|ȿ}ʾ}ò̄̊͞˄̈ˌ̉̓΄τІф҄ӆԅՃ֛>܁}~||}~~a~~~}|ÿ|¾}̈ǂƄLjƊňĄÇ{~~}~B~~}|}îۿ+ٔ~|(~Ǿǽƴꄨ0ד󂋔}5~üº}ŵ崈‚É„ŒÅĆőƂLJƍņƄňƊLjƈDžƐlj4镹|~|~.|¹ɾэЏφΊ͂̆˅ʃɄȃɅʄ˅̌͊Γ&􁆎}'~{Ǿ|ȼ|±ތˊʄ˂ʇ˅ʆɔʈˈ̄̈́΄φЅх҄ӈԄӂԓ>ڀ|}{{|}}~~m}}}|{¾~{|ĿƄŌċt~}}|}~D~}}|{|žٽ + +ד}{~*~}żŻ~ų駧6Ւ񁊓|~6~}»|ó㳪ƖDžɄȆLjȌǏȕɊȋɅʆˇ͇̃̉͏͉̄̆͆Ύ͂Ό͎Ά4򀈐.źǷ؊׈ւՅֆՋԂӆ҂хІσЄф҆ӌԊՒ&(Ĺ÷ȷҔт҇шЇтЌч҄ӃԅՃևׄ؅لڈۄڂۓ?Ω􁈏bþ҈̂˄̉ˊʇɄȆDŽƂńąÄĉÖČЅ}Džȳÿ ++ߘ)ü¶˹񄬆1ܗ6»ȿʺ븇–ÄċЅƒ†ÈĂąĆʎÈăŋĎÊĄņƏǒȉDžȆljȂɨȄɄʄ3~|+~żӐҌшЈτΆ̈́̄ˆ͈̄ΉϏЉх%~'~ĺø˹ώ͚̄ʉ˄ˉ̉ͅ΄τЅц҃ӅԇՐ֍>݁~|}~f~~|~}ý~ҎƋŊĈÇx}~}||~B~}ľ~ºîھ  +*~*~ȿǽƱۨ0Ύ󂋔}5}ƿ}ż~ƶ꺊‡Ê†ÆĎŒƆǒƂŌƈǂƄdžƂdžƐnj4}{~-}úɿЅэЂτЅχΈ̈́̅˄ʇ ˇ̉͋Όψ&}(}¹¶ɸ͔ʉ˄ʈɄʂɆʆʄˉ̃ͅΆτЄф҈ӆԂՐԇ>ۀ}{|}~~f~~}}{ÿ}|~ъăŇĊƄr|}|{{}~D~}|½}ؼ*}~)~}ƽƼ~į٧/̍񁊓|8~|ž|û}ŵ鸪ƈǃƋdžȈɂȄDžɆȊǎȈɄʊɎȊɄʆˎ͇̄̎̈̊͆ͅΞ͂΅̓Ί4􁉑-źƵ؄ׂ؎ׅֈՈԄӄ҄шф҆ӊԋՋֈ&(ɿɽоԒ҄уҏшЂфІф҄ф҄ӄԄՆօ׃؄وڄۅ܏ۄ?℧d¿½½؎ˌʊɇȃLJƄłćÈĊÂĄÄĕƅyEĿǿȳ¾ ++(Ľ¶˵ᄬ3Ӓ6ž̻𾆰‡ÃˆÄĐЅ‚†Ê„ÂĆÊŽÈĄŋčÈĆŅƏǒȄɂȆLjȆnjȂɨȄɄʄ4|~~.ƽ|ӉӍ҉щЉτ΅̓̈ˆ͈̄΅ϏЈц%'|}ɽ|͖ٓ̄˂ʈ˄̈́̄̈́΃υІц҃ӅԈՖօ=~~}|}~~f~}|~~¼~̊ńƆŎĈćo|}}~@~}½üî׻ )Ǝ}}*~ȾŮѨ0͍򂊔|~6~ü~Ǿȷ빫†Ž“Ò†ÃđŒƆǛDŽƈǂƄdžƂLJƃDŽƄǎ3{~}}-~ż{ʿϾѐІψΆ̈́˅ʂɄʇˇ̊͋ΊυЄ&~({ʾ|ȼ{̞˅ʇɂʄɆʊˈ̄ͅ·τЄу҉ӅԇՄԂՇA}}|{|}}~~f~}|{ÿ}Ŀ}}ʏčÈ…r|~||}~A~~}|ºֺ *č􃍗||~)}ǾƼ~ĭϧ2̌{}4}}Ž~ƶ鸆ƈǃƉdžȊDŽȂɆȊǎȈɄʄɂʅɍȈɆʄˏ̓̈́΄͂̋̈́̋͆Υ̓Ό3׀*úƺŴׅؐևՈԄ чф҆ӊԌՉօׄ&(Ż÷ƵӔ҂фҎюІф҄т҉ӃԆՆքׄ؃وچۇ܋>ށh½ъʄˇʍɈȄdžƅłćÄĎÂĆÂĒȇŽqCýȳ*˒*Žö˳֬1ґ6Ļͼ񾯈ŠÄĐЃˆÐćÊąÆŽÊŇĂŅċÆĆńƌLJɋȄɅȄǙɢȏɄ2}󁉑}/|ȿ|Ͽҏӊ҆шЊυ΄̓̄ˉ̈͊ΈωІш%||&ƻøɷ͂̅͐̑˄̈́̃͆΂φЈц҄ӈԈՆ։׈=~~|}~m~}|¾}¼ŘĆЅk}}|~~@~|}Ľ«ϻ ,𘨸}*ȾŮЧ +/Č񁊔}~4}ƿʻ캉‚ʂƌ’È„„ÄąńƃņƊdžƊǘƎǂƌDŽƂnjƆǎ2|񀈐|~+~{ƽ{ʿνەЄцЈυ΂̈́΂͇̃ˌʆˇ͍̊ΆφЄ%{{~&~ʶǶ̛˅ʆ˄ʈɈʈ˄̄͆΄ψІ҇ӈԇG}}{|}~h~}|{|Ŀ~ĈĊȌp||~{}}~F~}{ÿ|ûκ+~󀆍|*~ȿǽ~ĬϦ.Ë|}4~|Ľȿȹ급ƎLjȐɇȊɄȇǎȊɂʆɂʅɋȆɆʄ˄̂͆̆͆Ί͇΃̘͈̈́΄͂Ά͂Β͆Ύ2׀,Ļƺij؆ׇօՅԆӄ҄Їч҈ӈԍՆֆׄ%'ɽμӚ҆х҃ь҅ԆՅֈׅنڈۇ܅DjÿʋʌɆȏDžƆņĠ‡ɜtDºǰ .󃌖+ƾ÷ʲ֬1ɏ8Ľƽ򾯯 ŠÄĊʼnЉ‚ÄŠÑąÌĄŠÊŇăńċÆĆńƌdžȆɊȅɅȉǙɢȋɊ0ӂ|~+}}ξܒӋ҈хЊφ΄̈́̂ˉ̈͋ΈψІш$||})}·~ɽѿΑ͂̆͐̐ˈ̃̈́΃χЅъ҄ӉԈՅքׅ<~}~d~|¾~½~ý}ŎĄÎĄÌŠl}}~?~}þ~žͅ *􃍗~}*ºɾŭЧ.}|3~»}Ļ̽~‚ʃŌ’È„ƒÆąŋƌǂƎǖƑǂƋDŽǍƆnjȄ1с{}-|Ⱦ|ʿͼ҅чҍцЇϋ̂ͅˌʆˈ̊͋·φЄ%{퀋{|'|}ȼϽ̘҄˄ʆ˄ʈɄʈ˄̄̓·ψЅӄ҆ӈԄՆֆ=}|}~~d~}}{}}»|ąÈÆ„Ȇf~|~|}~E~~}|½}ļͿ̸*󂌖}|~)~ǽ~ìΦ2|{~3}|¹˼}ǂȄNJȑɅȌɄȆNJȊɂʆɃʄɋȆɆʄ˄͇̂̇ͅΈ͈΃͎̈́̒΄͂Ά͂Β͈Ό0؆-żƺðمٍ؆׆օՃԄՂԇӃҌш҈ӈԈՆֆׄ%􀇎'ȼ¶ijلӚ҆х҄яЄ҄ӄԄՆֈ׆ڄمڈۅ܇݅>fþ½»ʎɄȎɄȌljƇĝўmEþûŬӾ **ǿķʲի/ĉ4¨ą‰ÄƅŋЅ”ÊĂņņĄÂŒÐ +ŅČÄĄƊljȕɆȊNJȌɗǒȄɌ2م}~~,}}ͼԔӊ҆ьЄυ΃͎̆͆΄σ·ψЉф$}}&|ǽ÷Ƶ΍͊̂͆̑˃̄τЉу҄ӄ҄ӌԆՆւׇ<쒸~|}~k~}|}þ}ƿćÂċĊ̋c~|~>~|ƾοǹ*䖦~~,»ɿĭϧ1}}4}ƿǾ|­‚‹ŽÂŒ’ƃ†ÅĈŋƎDžȅLjƂņƚƄǔƈljȇ1ׄ|}}+|ɿ|ʿ˻։ҐщЃύ΅̅ͅˆʈˈ͉̊Ήω%퀋||)~{ż¶Ŵ͉̘ʇˈɆʈΊςЍщ҈Ӈ׆;ꑶ}{|}~b~}|{þ|¼|ĽË‚ˆb~}~{}~~>~}{ſ~Ž̾Ƹ +  *㕤}􀇍}.~Ƚ~ëͦ.||~7~|Ľ~ż{Ϳ~ǔȊɂʆʆnjȐ +ʅɌȄɄˉ͖̉·͇̉͑Χ̓Ί7߉򀈑+ƽźِ݉؉׃֍ՅԄӂҋш҇ӋԈՉ։&'÷ȼ̺Ӗ҄х҄юЄчՊւ׈ׄ؉وچ݄ބĻħ̾ +ꚪ񂌖0ķʱԫ +/ˆ5ĽúƭDZ†ÄăŋƇ˜ÊĊņĐÒĊņċÃĄņƊLjȎɂʆɇȈljȎɖȄǐȄɏ0ߎ|-~¹}˻Ԓӊ҅ьЅυ΂͍̇͆ΎψЌф$}~&~ù~ɽνыΌ͎̂͆̐˄̆Ћу҄ӄ҄ӌԇՅւ׈8勵~}~^}||üÇģ͌a~~}~;~|ľǿͼ)󃌗~}.ü|ʿĬΦ .}}}3~|»~í˭…ƒƒšÄŠ’Æ‚†ÅĈŊƅnjȅLJƂņƊǂȎǞƄljȄ0ލ~{~+}|ʾʹֈҐъЂώ΅̈́̅˂ʋ˅͈̎΋ω$퀌|}'}}ȼͻυ̠͆ˈɆʈΌςЋы҈ӇԂՉ>䊳}|}~]~|{¾~{ľЂ +^~}}|}~;~}{¼Ž˻񿆷  )񂋕}|~*~º{Ⱦ~«ͥ.|||~6}{ȿ}¬ɫ +ǘȇɊʆɐȒɊʆɋȃɄʆˉ͎̉΄υ·̉͒ͅΧ̈́΍τ0咹+Ǿźِ݈؉׃֎ՄԄӆ҆ш҅ӌԇՋ։$'Ⱦ¶¯քԇӘх҄фъЄчՋւ׋؋وڇ݅;돺􁉑_ſȇɣȍnjƊŃęȇ„^<þļƆ *(ĸɱԄ 2􃍖4ƽɲбÆĄŊƉЇÂēÊćńƆŇĆÒĒŇĂÆĆŇƈȄɉʂˇʄɅȄljȎɐȄDžȂǎȏɆ0▼󁉒}~*ú}ʹՅԐӆ҈тЊΆ͆̊̓ΑόЇч$~~*|ʾ÷ijψΆ͌̊͆̐˂̄͆΃υЊх҅ӈԏՃֆׄ7}~}Z}|¾½ĆœĂ΍Z~}}~~I~}|ǿ˸澸+ד~|~(|ļ}ʿĬΆ 2}}3~ƿ~Ļdzϯ…Ä…„ˆÎć͆ŇĉʃÉĆŊLJȅɇȇljƋǂȌǜƈNJȂDŽ4񀈑|}*~|ɾȸ~ԇҐчГ̈́̍ˉ̄΅͈΍ψ$퀌}}&{ȼ¶~ñ̜͊˂ʇɅʄˆ̄͂΋υЈчҎӅԄՆ8އ|}|}[~~|{~ƿŠž[}||}}C}|Ŀ{ƾʷ伶 +֒}􁆎{}({û|Ⱦ~«̄.󘩸~||0}Ž}¹ƲέȂɓȊɇʅ˅ʇɆȒɒʆɃȆɅʇˈͅΈτІυ΅͂̆͒Χ͌΅ς΅3+ȿŹϾۇِ؆הԄӆ҂ы҃ӄՆԈՌֈ$&ùɼʸԉӅ҂ф҂я҃шЃх҆Ջք׈؇َڅۄ܆8匳򁈐\þ¼ƾɆǜȄǂȎnjƈņ„ ÈŒ_Hļѽ¼ + +,ݗ)¸ŸɰӪ-󂌖4Ľ͸ճ + ‰ÅĄņƊDžЇÃĒÊĆŇƈņÒĒŏąŇƉDŽȄɈʄˆʇɌȏɐȄDŽȃǍȏɇ/}*|ĺ}˿ȷՆԎӆҖΆ̈́̉̈́ΑωЋч$~&ź~ɽͻЍ΅͍̉͆̐͆΃φЊц҄ӈԎՄֈ:ۀ}}V}ý~}~Ζ݌ Y~~|}~;~}¼}ȿɵ׺,񂌖~(|Ž}ë̈́/嘨~}~2|ûǾ˹ݲ …Æ„ˆÏĈˋÆÅÄĊȃÅćōȍȆljƋǂȋǝƋLJȂDŽȅ/|*~{¹|ɾǶԈҋшІψЄ̋ˊ̄͑ΐφ&퀌}~&~ĸ}ȼ˹Ά͊̊˂ʐ˂ʈɄʄɄ˄̅̓ΊφЈц҄ӃԇӅԅՄ7|~|~Y}|}ľ|ƾ}Å Z}}{|}F}||ƾȳո *~}({ü|ɾ~ª˄/䖧}|}2~{ƽɸ۱ȃɒȊɂʋˈʆȒɒʏɅʇˉ̇ͅ·υЇχΊ͒Α͎͂̔υΈ0*Źμۈً؇ׇֈׄӌҊԄՂԇՏֆ&'˿µՆԉӅ҂ф҃ю҃шЄф҆ӄԂՋօ׈لڄۆڄۄ܆8ᄫ񀈐W¾ſŽȎǐDžȝnjƆŇ̂ƒWI¼żϺݾ ,(¹ŸȰ҅.뜭񁋕3úо㷅 ‡ÇĄŃƍDžЛÆ +ŊƈŊĊłċŃƊŇňĂņƌdžȅɆʋ˄ʈɆȄɄȂɄȂɈȈǂȈǎȄɂȏɆ1~~}|(}Ż}˿ƵԋӜ҂фЂφ·͇΋όБш$~%}÷~ñ݌Ή͚̎˂̄̈́΄τЍщ҃ӆԇՊք:|~Y~}}ý~ҍȆ‰Y}~9}ľ}ȿƭι +)ː}})}ƾ}~ë̥ -ۓ}}~2~ǿ}¸}ϿÃ†ŠÇŊć˜ÐĔÂćŋƈǂȈɄʆɈȄdžȐLjƂœƅǂƖǂȇ/}}|{~+|ú|ɾ~ŴӊҋъЂыЃτ΂̅ͅ˄̉͏Ίώ(퀌}~&|ɿµ}܏̌ˈʊ˃ʉɆʂ˄̅ +όЇц҂ӎԅՅ6~{}~W~}|þ|}ƾ…[~~|}~A~|¼|ƾ~Ĭ̷ +)ɏ||~(|ļ|ɿ}ˆ .ْ||}2}ž||ͽ뷄Ȇ +ʊˈʊɖʄˆʆɂʈɂʆˆ̆̈́΂ψЂчЄτΈ͌΂̈́Ή̈́̆͆̈΄ͅ΂͎΂χ/؁򁊓)Ĺ̺ڊي؊ׂ؋׃քՂԄӆ҈ӆԏՉ֎ׄ$&ƺɼȶӉҎч҃ъІт҄Ӆ +֌ׇ؆قڊ܇7Y¼ŽȒǍȈdžƐNJƄłƈńĊԈ[<ýļ˲ӽ + *Д퀊)úŸȯҩ.ᗫ3ŽǽĤ󾈮†ÅăńƆǏДÈ +ŋƉĖŅƆŅĄņĂņƇȄDžȅʅ̈ˈʄɈȄɅȂɇȈDŽȇǏȂɄȎɊ-ه񀉒~(}ż}ʾ~ijԇӘ҄υΆ͈ΊόЊф҂ъ$&|Ƽʽ˹Ї́Ί͇̅ˎ̌˄̃̈́΅σЇь҄ӆԄՉօ8蓻|~S~|}ć҈ɇŠS~}@}}ǿ~§Ķ )~(}ƿ~~ª̆-ΐ}~0}ļżê ŒÄㄊŒĜÈĂʼnēÂĆŌƇǃȈɆʅɈȄDžȐLjƂŐƉƖǂȉ.׆~})|ĺ|ɽ}òӉҌшІф͆̂˅̅͊΄ςΉϏЄ$퀌~~&~{Ż~ȼɷΏ̉ˋʇ˅ʈɅ̅̈́΂ϐЇч҂ӈԈՇ5撹􁉑~{}~Q~}{ľ|ſ~ǿ~DŽW~}|~8~|ľ|ƽ}Å + *~}(|Ž}ɿ}ʅ0̏|}~3~|»ĺ©”ȈɆʋˉɖʋ˅ʅɅʅɂʆˆ̄͆΂ψЃчЈτ·͌Ή̆̉͂ͅͅ΄̈́΂͎΂ψ/ދ)ĸʸڈٌ؈׆؅ԅӄ҅ӅԊՄւՉ֏ׄ$'¶µоՍӊҒт҄ъІт҄ӄԄՂ֐ׇ؆كڈۈ܄9TƾɇȒLjȉLjƎNJƎŃċӄX8ſĻǬɅ +(ĺƹȯц+Ӕ.ɯċ„ÄăńljȄɃЃĄÂĉÏĆŕƙŊƖņƊDžȅɄʄ˂̄˂̈˂ʈɂȏɂȇǒȄɌȎɌ.Ⓗ}}(~Ƽ}ʾ}°ߎԉ҅Ӆ҃ӅϐΆϋБш҈$|(~÷~·̓Έ̟͊ͅ΂τІх҅ӂ҈ӇԃՋֈ5򁉑}Q~|þ}ſ|º}ŅċĉP}}~}~8~}ƾ}Ͻ廵*|}*}ǿ~~ªˤ,Nj}~1|}ɳʬ +†ÏĖŒËąŊÄĂÆĄÈĂŊĆÆăÄćŋƅdžȆɎʈșǙƚȄdžȊ.􂋔||(}Ļ|ȼ|݄ӌҝ ͎̃͌ΓψЊ$퀌~{~&}˿µ}ҿՏ̆˙ʈɅʄ˂̅͂·υЏч҄ӅԊՅ5ވ񀈐|~R~}{|ľ{|̅W||}|}:~}ƿ|ż|ͻ㺴 +{|~*|ž}ʿ}ʣ +)Ɖ|}4~{ƿ|ȾDZɪ ‚ăăɄȂɈȌɆʘ˙ʋ˕ʆˊ̄͆΄τІЅшψ͑Ν͇Ί͎΂τЂτ.(÷ǵچڅٝ ԎӃԍՒֈ׊$&Ƽɼƴ܎ӊҎфІь ӄԃՆֆ׎؇لڅۉ܆6捶RýľȿʆɊȄǂƢDŽƎLjƎńČЄR;ú¡*Ő쀊*ŻƹǮѨ-̎/ƾżθа ƒÄăńƃdžȏÄćÑąŌƄNjƘŌƔņƉDžȅɅʄ˄̄˃̉ˈɂȏɂȇǒȄɌȎɊʄ-~|(~ƽ}ɽѿݎԓӄ҄ӅϐΆϊВч҉$|(|ɽʽɷΈ͂Ή͉̟ͅ΂τЅхҐӇԃՈև7ۀ|M~}ľ~żƄňĉĂˆO~~6}¼}ƽ˵Է*򀆍~*}~~ˤ ,􃍗}4}ŽĻ}ͻ۰‡Ïĕ‘ËĉŇĂŜĂŊăÉĂÅćʼnƅLJȇɎʈɆȋǃȆǔƐǂƇnjȅɂȆ-}~{~(}Ż|ǻϾ܋ӆқ ̄͂̇͋ΒωЋ$쀌~{~%{ǻ~ȼȵ̆ˎʄʌɂʄ˂̄͂ΈσЍы҄ӅԈՅ5~~{~M~}ľ|¼}ûŇ̄M~}}~D~||ļɴӵ ++얦퀊}*|ƾ}ʿ}ʣ +.򂌖|~1|û~¹|̹ٯ†ÃȄɇȑɅʌ˄̊˔ʌˌˇʆˈ̆̈́ΆφІтІшϙ̘͉΋͊ΆτЂφ.򁊓(¸¶ıچٛ ԄӂԈӃԋՓֈ׋$%¸µϼӊ҉ћӅԂՇ׋؊مڃۊ܅5წMſü˅ʈɅȄƞǃƏLjƍńČÉN8¹кڻ + ++żƹǮШ +*1»ᵎ‚ÄăńƃLJȏÆĄÇąňĂŌƊDŽƆǍDŽǓƆłƇŅƅȆɈʆ˄̇˂̉ˈʆɆʆɊȄLJȍɊȌɒ.ԁ񁊓}~'~ǽ|ȼμ؈ՆԛӅЄ +τΈσЇт҉ю҇$󀇎}%ĸ|ķ}ҿӘ͆̐ˊʂ˄ υЄц҈ӎԆՄֆ6}}J}½}üȿȋŇĊĄŠ†K}~}=}ý}żƭŴ*}|)}~~ʤ2򂌖||5}}ȿ𹪪 ĄÇăŅđÄÅąłĄńƊłƆłĒłĊŔĈŇƃDžȋɈʂɊʈɄȂǏȂNjŅƈǂȇƊǎȌ-Ҁ|}(}Ż{ƺͻ׊ӆҚхτΔͅ΅ϒЂфЌ$|(~¶{µ|нˉ̄˂̊ˆʜ̅͂ΆχЇш҇ӄԈ6|~|~J~||ǾDŽĊʅO|}|~7~||ûŬą +*|{(|ǿ}}Ʉ.{{~4~||ǽ‹ÂȆɄȇɆʇɂʌˊ̃ˇ̌˄̇̇˅ʂˆʆˈ̆͆·χЄцЄшЈτΊτΊ̈́̅͏΄ͅφΎτ-ل(¸®ފچٚ؅քՔԆՄ֒׍$􄑜&ɽɼıؚ҆ѓІτЄӄԃՅևׇ؈وڄۄ܇3򁉒J¼»ļ͌ʆɊȄDŽƉNjƜdžƅƈŊĆ„†L4¼˲ʅ,Í򀆎*ƼǺƭШ-􀆍1ǿĺǩ‚ÄɄȇɃʅЍĂÆŇŌƅȋǂȅƊLJƆLJƄŃƄņƊDžȆɆʈ˄̈˂̊ˆʃɋʄɊȅDŽȏɄȌɓʄ,܎}'ǽ|ǻ̺ևՇԚӄ҃фЈ΄ΊσЇф҅ь҈$􀈎}$}ʿʽǵ͆̆ʈˎʂ˄΄υЄч҈ӎԆՄֆ7䍹}~J}ſ~¼úȄƌʼnćэ† H~|~?~|ľ}Ļ꽵 *╥􀇍|(~µ~ʅ0񘪺||0~ƾùȰ¬ ÄĄÆąńądžÄĂĂÄČņƇŅƘċœĉņƄDžȋɈʂɌʈɓȃNJƂńƄȇƊǎȊ/ڍ~|(~ż{Źʸ~ԋӅҊуҌхЂτΏͅ΅ϑВ$|%|ȾɼƳ̐ˆʜ̅͂ΆχЇш҈ӄԅ7⌷~|}I}|þ}~¹ņĊ˅O}{}:}{¼|¹~о軳 *ᓤ쀊{~(}~}ԿȄ/퀊{{~0}Ľ~ǯŒÍɂȆʆɂʋ˅̃͊̂͆̂ˏ̅ˈ̆˄ʇˉ̅ͅΈχЅцЅыЄς΍σΊ̈́̄͐΄̈́΃υΌτЃυ,(¸ѿۋڅى؄ٌ؄ׂքՄԂՐԄՅ֑ג$􄑜%ʵͺ҇ђЈσЄӄԂՆևׇ؈وڄۄ܆2ꑽKſȿˌʉɇȄDŽƈǎƚdžƄłƉʼnĆ„‰IAýť ++蘪􄏙&ǽǺƭφ/􀆌.üȾεǰÅ +ȄɄȆɅʄЃĈņĄŅƃńĂʼnƆljȃDŽɄȈǂȆDžƃljƃōƌǂȇɇʈ˅̄ˆ˅̈˄ʄˊʃɊȅǂȐɄȐɗ.}|'ǽŹɷ׌ՄԈӃԋӃ҄цБς΄ψЄьҒ$퀍~%ĺ|ķ|нҗ͉̊˒ʂ˄τІш҉ӊԆՉք2܁󁊓}H}¼~»}Ⱦ}ȄDŽƍŊĆϐJ}~|~7~}ž}¹}͸Զ*|~)~¹µ~ɇ-ᖧ퀉|1~û}Ǿ~λ֭…ËĊēÈćÃċŅƃLjƅǔƎŒĈňƂNJȄɉ˒ʄɂʐɆȂNJƆȐDŽȂnjȏ,~|{~'~ƼĸǶՄӂԇӅ҄цҌуЅψΈ͈΄όД$}&~ù{µ{ϼцˈ̌ˈʓɃȄɄʄ·φЋш҅ӉԄ3ڀ񀉒~|~I~|}|ƽ|ƆÄơL|}~{}~9}|ý||˶ӵ  +{|~/}~}Ӿȡ){~0}|Ƽ}̺Ԭ†ÄąÃɈʅɅʅ˃ʄɂʈˆ̊͂̄̈́̆̓̄͆̃˄̊˂ʍˌ̂͆ΈЊЍѐЇς΋̈́̂͐΂͐΍χЂυ-󂋕.¸˿μۇڅك؇ٌ؃ׅևՇՉԈՄ֌ה$󄑜&ɼ°،҂ӊ҉эЄЅφ Ոօ׋؈لڄ܄ۄ5ᄯHú΄̅ˌʊɆȏLjŇƍǐƑʼnொJꀊ5ĽȾҽڻ (􀇎&ǾǺŬΈ*皫󃍘.ù۲‚ÆDžȋɊЕŅ ŅƆǐȄɒȅDŽƃljƃŌƍȇɈ̄ˇˎ̐ˇʃɊȄǂȑɃȏə.Ӂ􂌕􀅋~&ǽĸƴՄԈӄԊӃ҄цБς΅χЄьҒ$퀍~%~ʽƳ͂̄͊̋ˎ˄ ЈцҊӉԇՉ4~~H~ſ»ĺƅDžƌŊćΈ‘H뀊}}5~ſ|Ǯń +ߓ퀋􁇏|~,~|ùµ~Կɣ-Ӑ~|2}¸¥ﶩ…ÌċŅÄĊÉąÄĊŅƅdžƈǒƎŐĆňƂNJȄɉ˓ɆʄɃʇɆNjƅDŽȂDŽȎDŽȂDŽȂɆȑ+р򁊔},~Ƽ÷ijԉӍҌтІψΈ͈΄ϋЅтҎ$󀇎}%}˿ɼIJˈ̌ˈʔȅɄʄΉφЊш҄ӇՅԄ1~}}E}ľ~¹ƌĆˈJ|~|~7~}Ľ{ȿƬò (ݒ򀆎{}&}{~}ҾDŽ -я}{~,~|ƾ‡ÄąÔʆ ʄˊ̄͂Ί̈́Γ̂ͅ˅̈˃ʋˍ̂͆ΈςМхцЂшІςΊ͢΍χЂχ+؄&¸ʽ˹ۈڎو؂׆և ՈԈՄ֋ׅ؃ل؂ه$󄑜%ݵ˸҃ӊ҉эЊυЃфՈֆ׊؈لچۄ܃ۄ2􂋔Fľɿ͈̆ˋʊɆȏLjƂņƍǐƒň௉K񃎗8ĽƼͲɸ +䗨󄏙'ȾǺŬΈ *ؔ.ŽǽȪ‚ÅDžȌɋЅňƄňƈńƊDŽȅɊȄɄȂɇȆDŽƄDžƅŇƌdžȆɇʅ˖̆ˎ̈˄ʆɌȄɃʑȊɏʂˍ+ۏ}}}%ǽ÷~°ՊԂӄԊшЙχЈшҒ$쀍~%|ǻ}ķϼӅΈ ̐ͅˊʆ˂̄χЉт҉ӋԇՄ4߉|}~C~|¼ûɊƂdžƆŌĊˆ–H񃎗||~5}ƿȾ繳 (~}&~}úµ~ӿȎ*Ê}|0~Ľ}ǽ}ʱ« „ÇđŇĄňĂŏĉŅƣDžƎōĈʼnƃljȇɎʂˊʂɊʂˋʅɂȈdžƄǐȌnjȐ.ڎ|||)~ƻ}ԋӔ҄тЇτ΂̈́Ό͈ΈψЖ$􀈎}&{ƹ|õͺё̌˄ɄʃɄȊ ΋τЈч҄ӆԇ0݈{|}E}{ĄłĆņċˉG{{}4~|ľƽѿ渄 +(}|&}|¸}ҽǍ)‰|􀇍{~-}û|ż|Ȱ‰ÆĂÅąʈ˄ʈ˅ʄˉ̅͆Έ͆̈́Έ̄ͅ˄̆˄ʇˋ̆τΆυЙуЏцЂφΌ̈́΄ϒΑυЈЄ+)¸ȼȵیڏل؂ׇքՒԈՈֈׇ؂ٍ$󃐜&ɼؐӌ҅юІϊԄՊք׈؆لڂلچۇ0卺D»ƼΊ˂̆ˆʄʇɆ ƆLjƄŊƂǖƂņƉŅĉÆD5ľĺƥ )􁇏'ɿȺī͆)Ȏ퀊/º¸϶ǯ „ÂąȈɑЍƄňŅƈdžȈɆȋȅɅȆǂƆDžƄŇƊLJʄɆʆ˗̅ˏ̈˄ʆɌȄɂʘɐʂˎ*|&ǽ}ҿ܊ՊԂӄԉшЗωЈшҒ$쀌~%~÷˾IJΉ̈̈́̐ˇʄϊЈ҉ӋԇՄ3󂋔}}B}}üɿ}ǕƅŌĈ„ˆD~}}=~ƿƼ~Ͷδ (ۑ쀋}&~}ĺµ~ӾȎ,|/}¸н֭ ÈĎŃƆĆŅĄŎĆňƦDžƌŊċňƄLjȇɍʊˊʉˋʄɆȏǏȋǍȋɄ+{~(~Ż|оԊӅӎ҄уЇτΌ͈ΉψЇтҍ$􀈏}&}ɼð͑̌˄ɅʂɄȊ ͆ΈτІщ҅ӆԅ0񁊓||~@~|ľ|ºǽ}ɉńĆŅĊ̉F}||~6}ľĻ}˵ͳ +(ڏ􀇎|~&}|¹}ҽƌ)󀆍{~,|ϻԬˆÏĈ˂̄˂ʊʅˈ͉̆΅͔΄͆̂ˆ̆˃ʇˊ̆τΆυЍтҊтЊтҊхЃψΈ̈́΄ψ΂όΒτЎ+(·ǺıۋڏׇփՓԇՉևׇ؄نN򃐜ȼõʶӌ҃яІϊԆՈք׆؉ىچۅ0Dſĺ̌̇˅ʌɈ +ƆLjƄŢƂŇƇńĉÆLꁍ?žһӹ )ᔦ򃎙'ɿȺê͎)-ǿǽžܲ‚ÄĄȈɎʃЂƊDžƂNJƂňƂLjȄɆʇɆʏɈȉDžƂŅƉLjȄɊʆˌ͎͈̆̆̈ˊʄɆșɍʂɍʃɈ*Ӆ}~%ǼμمՅԃӋԅӃ҆цДφЍч҅ӃԄӂԆ$쀌&}Ƚ~ŷκѐΌ̏ͅˍ ϊЄф҆ӉԈՈ-瓿}?}Ľ~ĽƼȅǘƆņĉΆ D􀆌~}5~ƿúƩ +(~~(~}Ļõ~ӾǢ(}󃎘􀇍|/}Ǿ~ǽƫÄĊōƖŋĈƉNJȃǕȂǐƂʼnĆʼnƇLJȈɄʂ˄ʐˇʋˆʅɎƄDŽȇǖȆɏ*ф|}&~Ż˾ͺ׋ӓ҃цІψΌ̈́ΐφІы+􀈏~%|Ƽ}ö̹͑̌˄ʒ˄͈̂ΆτІы҉Ӆ1咾~|~@~|¼}ûŻƐńĂňĆʋC}|~0}Ľ~¸ħ *􄏙}}~'}|ù}ѽƐ.|񂌗{~,~|Ž}ƼĪˆÈĊˌ̄˃̉ ̇ͅΆφΈώΉ̈́̆ʄˊ̈̈́ΊυЊэҊшҊхЉτ΅͘Ω+؉&Ÿދڌقچق؆׆ֈՌԅՏֆ׆،&򃐜&öʼӿԏӍ҄фЂшІτԉՅք׆؋ىڃۅ.󂌕@¼»̙ͅ˅ʆɉȎdžƄńƄňƊŊƄłƇŌĆF4Ľɿ˭ķ +))Ⱥê̦)-ļ¸˰ą ɉʏЍDŽƃljƂň ȅɈʄɎʄɊȂDŽȂNJƈNJȄɉʆˊ͈̍͊̇̅ˏʂɉȕɏʂɌʆɇ*~&Ƽʾ˸քՇԅӊԅ҄хДυЏц҅ӄԆMø˾ıΈ̈́Ό͆̎ˍ ϊЅх҅ӉԈՆ1ځ~=|ƾŻ~ˉǚƄņĊΆA䀌|~4~|ž~н׶ *я뀊}'~}Żö~ӽǐ1畧|/~ļ¸θʫÄĈŊƇǃňƌŊćłƈǓȂɏȈljńĄŋƇDŽȆɅʃ˄ʆ˃̐̌˅ʆɃȄɆȂDžƋDŽǘȂɒ,􀆌}&~ĺ~ɼɷԉӓ҄цІψΌ̈́΍φІь&~~&~·ʼ¯͒̌˄ʒ˄͈̂ΆτІы҉Ӆ/ـ}=~{~Ľ~Ĺ}ɅƐńĂňĆÆŒD~{}?}{Ľ}ɿϻյ )Ў􁇏|~'}|ú´}Ѽŏ)唦~{~,}º~̷ɩ†Êċō̃˅̌ͅΉτΔςΐ͂̊ˈ̈͆ΆψЊѐ҇ы҅цЍσ·͕ΐςΎςΉ+􃍗&÷нۉڍقڅك؆ׅ։ՌԅՋֆׅؑ"񃐛#ɽöɵӎ҃фЂшЄτԉՅք׆؋ى4=üЉ̚˄ʆɊȎdžƃńƅŇƋŊƄłƈłąʼnņDꃐ:ĽƼœܺ +)֓򃎙(Ȼé̐)홫,Ƚӽϯ ƅɉʈˉLJȍNJŅƄǂȇɉʂ˚ʄɅȄɂȆǎȆɇʄˇ̂͆̈͂·̔͆̄˅ˆʂɆȄLJȋɈʂɄʂɍʉɉ)}~}$Ż~ɼǴՆԆӇԈӈЋ·φЍц҄Ӊ'|#}ʾ~ŷͺТ͇̈ˈʄ̈́΄υЈц҇ӆԊ.񁊔}<|ž|źȎǘƄņĎȉA􈔟}|~1~|ž}Ⱦ}ɰ±)}'~}żö}Ҽdž(ӏ쀊|,}~Ƚä걌 ŌƍNjƍŌƈDžȉɂȊɂȉɆȋǂƈŊƆdžȆɆʅˋ̈̄˂̆ˆʎljƉǰ-|􃍗}|%~Ĺ}ǻŲӓ҈чЃχΏ͆ΈςЄφЄѐ"~{~#|ɼ}ö˸΅̄ˈ̎ˆʂɄʆɈ ͈ΈυЅш҇ӈ+~|A~{Ľ{ƾùƗňĈ ‹B򇓞~|{}4}{ü|Ƽ|ǯ)~󄏚~|*}|ĺ´|лŠ(ю~{~,|ǿ}Ƽ谐ÇĈʼnƊ͇͋̐ΆЄυЍυ΂ͅ΂͇̎͆ΆτЈт҆ш҃Ӝ҆фЃφΆ͈̈́ΣχΉ+ց%̹ڒو؆׃քՓԇՆփׄֆׄ؈ڇ"񃐛&øʽӿӉ҄ӓ҆чЈ ԇՈօׅ؈نډ/<ĽŽʿ̖͐˅ʅɎȇǃƄNJƇƎƄńƃňƌńĆÆ†B/üùεǵUɻ̆)ؓ򃎘0ƾøȩ𵭭ʉˎ̂ЊȋljƃńȇɆʅ˃ʅˈ ʈɂȊǎȆɆʄˈ̂͆̈̓ΊᾹ͇ ɆȄLjȈɊɅʂɌʊɋ)ۑ%ź}Ǻ¯ӆԋӆЋΈφЌц҄ӈԄ$|"ź̾¯ߖ͇͂̋̇ˍ̈́΄υЉц҆ӆԊ0܅}}~=~ü~ºĹ̓ǗƅņčЈ>텒󀆌}1}ĽĻܴ)Ў뀊}(~}ƼĶ}ҼƏ)É~~+|ƾø̴}ŊƍDŽLjƍŊƇDžȟLJƃʼnƆdžȅɅʌˌ̈˄˄̈˃ʍNJƈdžȂɐȂɖȅ)ڐ~~%~ù|Ź~߅Ӕ҈фЂωΎ͇·χЅя"~{~&~ĸʽ̜ˆʂɄʆɈ ͇ΈφЄш҆Ӈ/ڄ||}:}}øʗĈňĈ +Š?넑~|~1~|»ùҿ۲0΍|~(}|ϵ|кĎ-ˆ}}~,~{ļ~ʳ%|ɆĉōƋ͇͊̐ΆψЂϊЃφ͉̏͆ΆτЇу҅Ӆ҅ӈ҃ӑ҆фЂχΆ ͈΢τ·-󃌗%̿Ǵړو؄ՄՐԇՆևׅ؏"񃐛#˿Ķȴ҆ ЈфԇՈֆׄ؈نڇ/∺:ǿɾє̖ˆʅɍȈǂƅljƆłƗŃƄňƌńćņ<󉖢2»Ţ⸄(Ւ񃎚&ºɻˏ)ȍ,ûȽѹŮ&ʇˉ̈ЅɈȈdžƄŅȅɇʝ邀~ɘȅɇʄˋ̇͊΂͆Δ͆̄˂ʄɊȂɆȅɛʊɐ)~%Ĺ}Ÿ}ѾۆԄӊԊӂ҄тІςАϊІьҐ"|#~Ÿ̸φ͎͆̂̄͌̄ˆʂɆʂ˄̄͂΄φЈф҄ӇԆ0􃌖~>~ļŹȇdžƇǗƅńĒό?惑|}/|ü̲ąZ~~~}ƽĶ}ѻŠ'}~+~ûȾޮ'|~ƊNjȆȈLjƆńÄĄłƅDŽȈɆʆɂʆ}njƈDžȆɅʎ˔̄ˆ̌˄ʋɂȔȅɄȂɈȅɓȈ*󃍗~}(~ø|÷|нӅ҂ѕ҅ЄωΎ͆ϊЖ"~{~$}ɿ~ĶʷΖ˂ʐˆɈȂɅ͇ΈτЇч҆Ӆ.򂋕}<}ƿºøƎłƆŃćŌćˍ?䂏{|~0~{»~ʿ~ʱÇ'}󄏚~}~'}|ݵ|Ϻß(|}.}º~ǽܭ){}ƄŊƋDžΈ͈̆˄ʄ˄̂̈́ΈτІфЂюῌ·υЂф҂шҘӕ҅ъΉ͍ΆЙφΉυ,%ʿʽïڄقؖل +ԄՏԅ֊ז"$ź˽ѽԐҌч҅уЎЅԇՈքׇ؇نڅ.<ƾʾ͔̖ˈʄɒȎLJńƔņƂŊƅƈұĆ<솔-ƼѷɆ((ºɻʤ(,ùƤ䲅'ˉ͇̋ЅɈȇLJƅŃƄǂȅɇʄ̄˂̎ߙ}ɐȅɆʆ̈͗ͅΖ̈́̄˂ʄ +ɌȆɚʊɐ*،}}%ùöͺ؅ԄӊԊӂ҄тІΌϋЅьҐ"}%|ƻͿ̃͋̅͜˄ʄɆ˅̄͂΄χЇф҆ӈԅ/ފ~:~ƾ~ǿźʆȆdžƇǖƉńĒЌ=~~0|»~Ƚ¢㵅 (΍ꀊ}&~}ǽĶ}кĐ(􄏙|~*}}Ĺ˱/}ljȊɃȈLjƆ ĄłƅDŽȈɚޘ~|NJƈDŽȆɅʋ˗ˈ +̅˃ʉɃȖdžȂɄȂɈȅɓȊ(֋~||&~·˸ӆ҂ѕ҄ЅωΎ͆΂τ΃χИ"~|~#{ź˽ݑˉʏˆʂɌȂɆ͆·υЇч҆ӄ-݉~~}:}Ľ}ŽĸȄǂƎłƆŃćōćʏ;􀇍}}-~{}Ƽ᳄(̌|~&}|żµ|ιÍ(򃍘{}+|ǿ|¸~ɯ 1|ŊƌDž +΅͆̆˄ʄ˄̂̈́΄υЈЄфЃх坥΍͈΅φЃф҂шҔӄ҃Ӑ҃ъЃχ΂̈́ͅΗςІφΉω)ݏ򃍗􀆍'ɾȻҿڅقؖׄ֊ՏԅՂքՃֆי"#ĶƲфҍхҋфІς΅ІԆՉփׇ؇ن1䎾򂌖;ļĻ˿τ΂͇̅ˈ̖ˈʅɑȏnjƔŅƂŊƍňąÅ†A惓8øǦ鹳(ӑ񃎚&»ɻֿɐ(󀇎.ƽɾе¬3͇̎ʈɆȅdžƇłƄǂȄɋʅ˕$ϔ~ɆȈʅ˄̂̈́̆͞ΐ̈́ˈʄɆNJȉɒʆɊʅ)|%·ȵՆԂӊԆӄ҂ъІτ΂φ΄ϊЄф҂ӆ҄ӌ"~|#~Ƹ˷Μ͊̇ʆɅˈ̂̈́·υЅх҄ӃԇՄ+}~9~ü¹}ǻɉȇLJƇǍƄňąÂĊ„ʎ>~2~ĺ̵Į(}򀆎}&~}ǾĶ|ϹĊ)~+}ƾʿӿԫ:|ڕȄɂȈɋʃȈDžƆʼnƄDžȈɆʏ$Γ¿}ȄƇǃȆɅʍˆ͈̊̂͌̂˄̆˄ʉɃȆdžƄǂƈǏȇɒȋ)􃍗{~%~̿ǴԘ҆тЊφΏͅ΄τЖ&}{#}̿~ķɵ͇˃ʇˉʋˆʆɌȂɇ̆ͅ΅φЄф҈ӄ,󃌖|}<}º|Ź~NJƆŃĒōć̊ˆ<}/}ǿ¸˳„*|󄏚|&}|Ƽ´{͸Š(ޑ큋}-~|ļȾѾӪ7{~ٔƊǑȂψ΅͆̆ˆʂ˄̂̈́΅ψГ)՘¿φ͇΃ψЅц҅ԋӂԋӅӉ҅щЄτΐ͉΍τЖω)&ȽƸκۘن؂׊ֆՏԅՄքז&$ƻ˽мԋцҊш҄ъ΄ςЈӅԅՆօׄ؄هڄ-:ǾΊ͇̆ˇ̎ʄ˄ʈɄȃɉȂDŽȊǎƔņƐńĉDŽ:僓,ƿɿҹȄUûɻվɊ+斩,ûĺğگ:̈́΂͆΍ʈɆȅdžƇłƄǂȄɋʅˊ̋*ÿʈɂʈ˅̆͆ϘΆΊ̈́̉˄ʄɅȂǍȆɒʈɍʆ'؋~~$~˾ıӋԊӄыІτ΂φ΄ϊЄф҂ӆ҄ӌ"~#}ȽͿޝ͉̇ˆʆɄ ͆ΆτІф҄ӂԈ.ފ~7}~Ž~ɽώȆLJƇǍƈʼnăÅĎʏ8}~~~1~ǿ¢Ⳮ.͌ꀋ}}&~}ǾĶϹÉ(͌~*~û~Żʰ>~}~~ȋɐʃȈDžƅōƄDžȉɆʒ4̀ȆɄʋˇ̌͌̂ͅ˄̂˅̅˂ʊɄȄdžƄǂƊǎȄɔȍ(֊~}}$}ɼ¯҇тЊυΐͅ΄ς΄τА,}#|ǻ˾ӿ܌ʆˉʊ˃ʊɋȃɈʂ˄̄͆ΆτЅу҇/݉~}7~|}Ļ}ǻ~̈́ƂDžDžƅŃďőĈ̈ˆ9|}}}~9}žɾᲬ(ˋ||~&}|Ƽµͷˆ(ˋ~􀇎}~*}º}Ĺ~ɯ@}|}}~DŽȂNJȆɃȂψ΅͆̅ˇ̈́΄ωЅђ+Ӆχ΂χЄх҂ц҆ӈԊӂԌӂ҄ӊ҄щЃτΒ͈ΌςИϋ(ݏ󃍗%ǻöɵه؂׊փՌԄӄ Մքב+쁏$¶ķűхҊ҅ч ΄ςЈт҄ӅԆՅքׅ؃ن0䎿󃍗7ǿ¹µԏ͆̆ˈ̍ʄ˃ʈɂȆɎȊǎƔņƏŅĆʄ;߀3ŽŻȦ踱 Zҏ񃎚󁇏ûɻԽȉ)Ґ񃎙.е>̈́΂τΑЉɅȆƆŅȅɆʆˆ̊͆6̋~|Ŀʇ˃̊͊΄ϣ͆΄͂̄˅ʂɖȎɄʊɏ+~$~ȻӿݏԉӅ҈тЋφ·ωІь҂ӌ"}'øƹʵ̇˛̈ˇʂɉʉ˂̄͂ΆωЄфԅ,}6}˿ϑȇNJƄLjƂņƄńŋĆı˜;}򀇎~0~ž~ƻʹ¬ &􀈎~%~}ȾĶθÄ)}􀇎}+~|ӿӪD|}ʉ˄ʈ˄ɂȈLjƃņĂÄƄDŽȊɅʇˈ̄0ʊ}{¾ʄȆɄʈ˅̓͂̊͂̄͒̃ˉʃɄȄdžDžƃǮȆ)􃍘}%}ɾǺ~ѽܑҋцЇτΓτ΅φЃфІцN|}¶ŷȴ̐ʂˊʂˊʇɎȃɉʂ˅̃ͅΊ҆.􃍗~|6~|ƾǿʽ~̈́ƈdžƅŃčœ…Є<|}~=}ļ}ĺ˳&󄏛}~&}|ƽµ̶(||+}ǿ{ʿѽҩC{|~טɃψΆ͆̄˄ʅͅ΃ϊІщ҅ӄ4яφЄщҊӋԄӄԝфЂфЄσΉ͂Ί̓ΐΆτ΄ςΎτ)%źİً؆ׇւՎԂӆքՅֆ׃؄׆؆ׄJ끎ɽ̾ϺӆРчІςΈσЈф҃ӄԄՄՅمڄ+6ŽƽķԆ͂Ό̈́̉ˆ̇˂ʆ˂ʄ˄ʄɂʆɆȄɅȋǜƄŏƇňĂ˄8߀.ûҹDZ'&ļɻԽȄ*큌+ƾƻğٮDωЄωЄЈɆȆǂƈńȅɄʆˆ̈͆΄6|ÿ}̄˄̉͋΄ϋϟ΃͉̃˄ʄɔȏɃʔɎ+׋퀊}$~ɾ~ƹκ׎ԈӇ҆тЌφ·ϊЅњL}|}ɾ|Կ̊˔̎ˆʂɈʉ˃̄͂΅ϋЃхӄ/܆}}4|ƾ~ļµϓȈNJƄLjƂņƂńƄńĂņĂńĂÈĄËˆ’‚5݁}.~û·¡ಇ 'ˋ뀋}}%~}ȾĶ̸Ž(|})}ǾǼʰI|~˃ʉ˄ɂȈLjƃņĄŃƅDŽȉɅʄˆ̄?Γ~{½|ʉ˃̫͇̄˄ʅɃȄǂƆDŽƄǑǝȇ(Պ~|%}Ƚ}ķ̸ՐҋчІτΓ̈́τΆόЅщ#|{!|ȼ{̾ҽ۝ʂˉʈɋȆɉʃ˄̃ͅ΄ς΄τ҆,څ~||5~{ļ}ú͇ƈljƅńČœĄŒÈ‚Æ„9ۀ􁈏~|~G}º߰'ʊ||~%}|ƽµʷ({􄏚~|~-~|Žƻ~ɯJ{}ɇʈɂʆɃȉΆ͆˅ʄ̈́΄ϊЅч҆ӄ8ՙľ҄Єш҄ӒԄӄԄӄԎӃ҈уЅσΈ͂Ί̓ΏϊΎφ(ݏ󃎘%ĸ˾ӿݐً؇׆ւՎԂӆօՅ֌ׅ؈$ꀎ"øŷİуНщЏυЈӄԄՄքم-ቾ򃍘5ûǺԉ͂΋̊ͅˆ̆˂ʆ˂ʄ˄ʄɂʆɂʄɂȈɄȋǛƄŊƈņẴ7ㄖ0Ǽǥ涰 (я񃏛&ļɻѽlj)*û¶еIЄЇɇȅDŽƇDŽȄɊʄ˅͈̂΅A솸~ſ̉̓ΏφΈτΉύΈ̓̅˄ʊɇȯɍ(}|%}Ƚ}öȵՇԅӌ҈тЌϊ΄ώІь҂ц!}|#~Ĺǹȴ·̋ˋ̐ˉʋ˅̆ϊЃчԅ(|9|ļ|~ŸǐȊǍƃnjƏņĂňąÇŠ„:႔}}},}Ƚ˳'􁈐}&~}ȿĶ˷„)咥񃎙~}*|ļ~ø֩N~~̎˅ʂɅȆDŽƆńĄŅƃdžȇɇʂˆ̆ͅ;ꅷ}þ̋˃̇Μ͂Ί̄̆ͅͅˈɆȕnjȇǃȆǒȇ)|{~*|ƻ|µdzшҍщЃυΌ̃̈́ͅ΂φΆψЄы"|{#}¸Ÿdžʃɍ˅ʏȄɄʂɇʃˆ̂͆Έχ3󃍘􀆌{~5~{º{Ǿ}ķȇƉLJƐłĈńĂŊĊÃēĎ<߁|||~-~|ǿ~ƻʱ *󄐛򀇏|&}|ǽµʶ(䑣}|~*~{ú}ҿԨW}}˅ʂɅʅɅφΆ̈́̄ˇ̄͂ΆτЅт҇Ӆԅ;򉽽Ŀӌ҂ӰԍӇ҇Єό΄͐΂ϔΆτΈ.*·ɻκ؈ٍ؉׃քՍԆӂԌՆֈׄ؋"逎#ɾ̾ιӊчАѐЇυхІф҄ӂԇՇև35żʽϋ̈́·͉̋˅̌ˏʅɃʇɄȆǂȈǂƋLjƄŇƉDŽƈÌ6慘􁈐*ƾ·ѸTļɻѼƄ)떩/ȽţܮQшЅЇɇȅǃƉDŽȄɊʄ˅̂͆΅τA}ý~χ͂ΑτΛύ·͇˅ʋɄȰɏ'ې~$}ƻðӏ҈тІτ΂ϊ΄ϐЄъ҄ц!||"}˿}Ӿ݊̉ˋ̐ˈʅ̆˅̄̈́΄ϊЂш0ۄ~2ºżɼʆȂǐȊǎƂnjƐłĄńĆŅć†Ҋ…7臘󀈏|~F|ǿ}øӿׯTˊ뀋}~}ȿ|Ķ˶(Ѝ쁋}|*~¹ʿ˳R}ψ̅̆˅ʂɅȆDŽƆńĄńƄdžȇɇʂ˄̇G|}̄˃͉̅Ζ͇·̊̓̆ˇʄɅȐDŽȂDžȉǂȆǒȇ)ُ쀊􀇎}$|ź̿®чҌъЃτ΍͆̂͌ΈφЂю!{{&|ɾ|ͿѼ˙ʂ˅ʒɍʅ˅͇̃Άψ1ك~}~3~úȻɄdžƈLjƏŃĊąňĆĔŐ8熗{}2~{Ž|ѽծQɉ~|~}|ǽ{µɵ+ό뀊|{~,}ȽʱS|~ΆˋʅɅȃφ΅̃ͅˈ̄͂·υЄт҅ӆF¼Ն҃ӆԂ՜ԂՊԅӃԆӆ҈Їϲ΅υΏ(*Ƹȴ؈ٍ؉ׂօՍԆӃԋՈֆׂ؎"耍"ŹŸïхБѐІτЄуІу҆ӂԇՆֈ1ᇸ񂍗5ȿ΍̓·͉̌˄̐ˑɄʄɆʅɇȂDžȓLJƅŇƉdžƆË7.ļȽğܳ'Ў񄏛'ļɻлơ)֑󄏛󀇎*ǾĹѷV򀆋ф҄чЅЇɅȇĄDŽȅɇʆ˄·L¿|žτΣψБσ·͆̄ˆʰɃʇɐ(|~&|Ź˽Ҿӄ҂Ӕ ІΆϊΊόЄф҈цH|ƺǺȴΔ̈ˈ̈˃ʈˎ̃ͅΈχЄх/󃎘~2~}̄ɗȊǎƂLjƂDŽƑłĔŇĆÂċŊ„9~|/~ļȽɯ&~~%~|ɿ|Ķʵ'~~-}ȿƺ| ڪW}၆͉̅ˆɃȇDŽćńƅLJȈɄ̆P{ý̄͋·͆΂͔΍̓̈˅ʇɊȏDžȄLjȆǕȃɄ({~}*~{øɼ~мІтЉыЂτ΋̇΄͌΄ϔH{~ĹƸDz~͎ːʂˈʄɂʌɍ͈̈΃φЄ.񂌗}3~ȿ}ȿ|ͿȆLjƆLJƊŇĆŃćńĂÄĄÄĄÈĄÒˆ;튛}{~/}»Ǽǭ &}􅐜}~%}{Ǿ{´ȴ*}}+|ƾĹ{٩W~|ˊʄɅχ΅͆ ˄̃ͅ·χЄӆP¿ýӅԅՊԄԊՌԄӆ҆фІϮΆυΑ(쀊+ʿõî׆؂׉؋ՋԆӌԌՄ֔HͿιԄ қђЎт҄ӈԈՃօׄ.2ƾƼƸцΕ͊̎˃̇ˑɕʇɆȂɊȆNJƄŌƊDŽƅѥˆ50÷γ PŽɻϺŅ(큍.żǤ௨W脈҈хІЇɅȇńĄȆɇʆ˄ΆQ~}}|¾~ĽҗςЉϊЍτΆ͆̄ˇʑɂțɄʇɑ(ޗ񂍘}}%øȺ̸֛ Іυ΂ϋΉόЅу҈ц |"}~Ӿ͈͆̈ˌ̆˃ʉˎ̂̈́ΊχЄф҄+~}~0~|ƽƸ͈ɕȋNJLJƄłƊłĖŒĈ̆6}|~-~~øѼ̬ 'Ӌ뀌}~%~|ɿ|Ķɵ)~,|Ž~¶͵]񀈏}ׇ͆̆ˆɂȇDžĈƅLJȇɅ̄̈́R~~}||{}»͌΅͇΂͖΄͂Ά̓̈˅ʆɊȐDŽȅLJȅǖȂɇ'ݖ||&~Ƹ˷фІтЈьЂτ΋̍͌΅φό {!|ʿ}οѼߓˌʂˈʄɂʆɍʄ˂̇͊΃φЄф(}|~}1}Ǿ{ŻŷDŽȆLJƆLJƊʼnĆĈńÌąÅăÊĈƂdž 6|~{}-}}ϻ˪ '҉~|}'}{Ǿ{´dz(󀇎})~{Ļ}˴W|Մ̄ˉʄɅφΆ͆ʄ˄̂͆·χЄӅU»ԆՈԆՂԔՍԃӈ҅фЈϧ·σΔ$􀇎&ȽͿҽ؄׆؂׉؋քՋԆӌԍՄֆ֌ !ƺƸî҈тЎђЍӉԈՃօׄ؄(܁1ż¸̽ӊΔ͊̎˄̅˅̂˄ʂˋɋʄˇʒɇȅNJƂŎƊDžƅ‡ 8؀/ǿȽѰSَ񄐜Žɻκġ*+ºǻҺ§ +Wӄ҈хІÁЂɊȆƄłĆȇɉʄ˄̄]ӁNJ~~|~яφЂψЄτЈυЅω΂̂ͅˋʅɆȈɂȐɄʆɏ)Ѐ~%~ķƲӈӏ҃хЄϓΌχъЌ!|"ƼȻȳэ͉̅ˋ̍˄̆ˇ̇͆΂ύЃц҄(|0Ǿù|̾ЎɒȋLjŅƎLjƐłƆŇƋłĆņĈˆˆ8ރ~,}ǾȽ~ũﱄ +&}}&}|ɿ|Ķȴ)㑢񃏚򀇎~*~ûɾ~ħ䫆T~|}~~ с΅̓̆ˆʃɆNJĈƅLjȆɄʄ̈́VҀƉ~}|{ÿ}ƾ~Ѕ͆΂ͨ΅͉̄˃ʉɆȟLjɒȂɉ+}􀇎~"}˿~öűфЎэЃφ΄͍͂̓ΑχG󇓡{}źǹƲВˍʂˈʄɂʄɐʇ˃͇̅ΉυЄ*ލ{~0~Ž{˽·ȒljƌŇĄƇłƆŌĄÕēÈ6܂}=~|ŽǼ}ç%|􅑜|~%~|{Ǿ{´Ʋ)ᐡ}+}Ǽ}å㪡X}{|}}~~π̃˄ʆɇȃΊͅ˄ʂɆ͆ΆχЄфԄVل͎¿ŽֆՇԧՄԊӂ҄ +Єψ΂͜ΆςΙ%Ճ(ƻʼ˷؄׎؍׃ֆՃԇӐԈՑևG͸בҗыЅфЇш҂ӆԆՅօׄ*1ĻȾôϐ΄͂Ί͊̎ˎ̉ˎʃ˅ʈˋʂɆʆɈȂǎƎLją4䆛*Ļ·ʭ &'Žɻ͹à)锧(÷ɫꯆRׄӄ҃чЄσɈȈǂƄłĆȇɉʄ˄̄τYӈ~}}ҊϑЄϊЂφЄϊ΂̈́ +˄ʈșɅʅɊʄɄP􄏚~~ʿ}҂ӓ҃цЃϓΌϔЊF􈓢}·~´ӽ͇̅˄̎ˆ̄ˆ̈ͅ΃ϋІх*2~ƽ~ɿŶʐɎȌǎƒdžƍńƄʼnƒŇĈɄˆ 5싞~9|û~·͵©&Ҋ끌򀇏|~$}|Ķdz)̊쀌~}.~źϻƤT~}~΅̓̄ˆʅɃnjƄĉƄljȆɄʄ̈́[ч~}|ÿ|ǿѲ΅̈́̅˃ʉɆȟLJɒɋ%򃎙~}"}Ƚ|ӾэЄυ΄͈͆̔·υΈτH򇒡|}Ѽ̆̊˗ʄɄɐʅˆ̅͆ΊυЅ(~~0}ż}ǾôʍȎljƊňĄłƄŅƉňĄÎĂŎčDŽ7ꉜ~~},~{º}˴&Љꀋ{}~$~|Ǿ{´Ʋ)ʉ}|~.}ȿøιģT}|}~ʇɅȂΉ͇̂˄ʂɆͅΈЄхf،¾ƾՅԨՆԈӃ҄щЅχ͝ΆςΚ%"Ĺǹű،ׄֆՃԇӐԈՆֆՈք !Ǽǹ®ӑҖьАш҂ӆԅՊօׄ)0ºŻʻфϒΊ͊̎˒̆ˌʆ˂ʊ˒ʇɈȉDŽƔLją2򎢰,ȼҺǭO׍򄐜Žɻ͸[ю򄏛ƽʿ˨Tӄ҂цІσЅȉDžƄń +ȅɈʄ˄΄фR~|ÿ~~τэЈϏЋυ͆̊ˈʌɃȕɆʄɌʆ(։쀋}}%}Ƚ̾}κӔ҂ф҄фЄτ΂͌ΒϋЉ 󇓡"ȽɻȳҊΆ͇̙ˈ̋͆ΈςЏф'ك}/ż}Ƽ}̾υˈʐɄȏǐƂNJȆƋœƒŃąÂĊޅ 6}}~-~ȼ}ۮ%}}~$}}ĵƳW}}|}Ǿ~ȭ}X}΄͂̅˅ʅɂȉƉłĉƅljȆɄʂ˄΄ іP~}{¾}ǿ}х΄τΆό΄ϐΆ̈́̄ˈʆɈȊǂȌǦ%Ԉ||"|ƻʼ|͸ىфЂѐЄτ΄͆̒͘Ί 񆒠~"~ǻȺƲЏ̅ˆʂɉʊɈʇˈ̆͆Ήω(ׂ~|/~Ļ|ĺ|ʼ·ɎȋLjƊńĂńĆŎƈłĆÍąŊĎΝ +5||}*}ǿƻ|ҿڭ%􅑝||}~%~~|Ǿ|´ű)||{~-~|Ž}Ǭ| +Z쀉|~̅˅ʃɅȅLJ͈̄˄ʄͅΉτЄ؛QŽ؅Մ֗Ճ֎ՇԅӃ҄ъЈό͒Ός΍σΆ%ۍ򄏚􀇏#¶õԿ؄ׂؐׄքՃԇӓԇՂԎՊF¶͸׎Ӆ҅чЄэЈчӆ҇ӅԆՊֈ)އ񃎙/¹òՆЎϋ΃͎̏˃̊͆ˊʌ˂̇ˑʃɅȂɊȞDžƃŅÆƒ + 4׀*޶ƣᲬ&񀇏%Žɺ̷*쁌󀇏)Ļƻα Y􄎗ӄ҃хЄφЅȄNJƄń ȉɆʄ˄΄фV}~ƽэІϑЈφ͈̆ˈʋɂȕɆʄɆʍ)|$|źȺȴӒ҄т҆фЄτ΃͋΂τΐυφЈE򇒡}øõӽ΅͇̙ˈ̇Ά͈·σЎх&򃎚}-~ĻùŶԉˎʋɃȍǐƃNJȌƈōƂLJƑŃąÇĉڅ9䉛򀈑|}(}Ž~ȯ&Չ끌􀈏}$~}}ĵű)~(~|ż|ɽ|ӦV򄎗}}~ ΅̓̄ˆʄɃȇƋłĉƅljȆɄʂ˄υP~|þ}Ļ~҅τΆό΋ωΆ̈́̆ˊɌȅDŽȊǧ%􁇎{#{ĹƹƲԄњЄτ΄͆̓΄͌ΊF~~|~Ѽ͏̅ˆʂɈʊɉʇ˄̂˅͇̈΂τЂϋ'~|-}úĴҋɏȉLjƋ ąŅƂlj ĆÅăńĆŊĉҚ3√{|,~|û}Ǯ~&ӈ逋|~~$~}|Ǿ|´İ'푣󄐜}(}{û{Ǽ{ҾѥS||}̄ɅȅƆ͇̆˅ʄ̈́·τօO¹مք֍Մ֐ՅԅӅ҇цЉϋώΖτ·%#˿ο͸ۄؚׄքՃԇӄԂӎԂՉԋՊ ȽȺ®Ӆ҄шЂюЈц҄ӂ҈ӆԆ֋'-Ⱦ˻ڊЎϋ΃͍̎˄̊͌ˈʍ˃̇ːʃɅȇɉȚDžĆÆ‚ 6錠)¹ǻδNڍ򄐜Žɺʶ'(·ŢتTӄ҂хЅυ΂ІȃNJćDŽȊɄʄ˂̅қQ}þ}ԖЃцЄцЄψΆ͈̄ːʂɅʉɂʆɄʕ%ݕ#øĶӅ҂фҌщЇφ͉΂ψ΄τ΍ωЄ 񆒡!~ȾʼȳՎΆ͆̈̊ˉ̆͌ΆτІэ&|~-Ļ~ο΍ːʈɄȄLJƃLJƅNjȆDŽňƌNjƉʼnąŇĊăɄ3}~)~ƻϺȩ%}}~~%~~|}ĵİ)،􁈏~(~ºŹ̴S󆐚||~̈́̃ˆʈɃdžƆńĈńƉDžȃɄʅυQ~|½|ΉψΐτΆ͊̊˃ʍɫȇǍ%۔~~#~~õэАψ΄͇͎̈́̆͂̑Ά!~!}ǼɻƲӑ̆˓ʅɋʂˈ̉ͅΆό){􁇎}.~¹Ⱦ}̽~̈ɃʅɃȅɇȈdžƗřƂŅďŐƏǔ7󐢱|}(}Ź͸ƨ%||}}~%}}{Ǿ|´ï)׋큍򀇎}(~}øʳS񄏙{{}̄˂ʆɆȇdž̓̊ˊ̄͊΂τЄфօSľƽՈ֊ՏֈՄԆӆ҇чЍςΆτΈσ΍όΉ%#ȽʻDz؍אևՅԌӅԃӑԏՆEø³͸ڏӇҋтІцЌтҊӊԅՅ֌*뀋.ŻıӏЄςЈψΈ͆̃ˆ̅˄̍̄̈́̋ͅˍ̏ˉʈɅʇɊȅȊDŽƄʙˆ1򁉑+ǾԿͭ%􀈏$Žɺɵ)ޏ)ȿʾҹ +SІφ΂‚ЅȃNjƋłƅDžȇɃʄ˃̅ЄҢQ~ĻюЅцЄцЄύ·̈ˌʂɆʄɆʆɄʚ$ς~}~&~}л҆҅тІчЉφ͉΂ϐ΍ϊG~}Ĺöӽ·͊̇˃̊ˈ͊·υЄэ'؅뀋~},úǽǷґ˅ʂˈʈɈȅDŽƇǂƆǍȅDŽȄdžƎǐƉŃĊņćÄĄ 4ކ}+~ƾ~~¤⬇%׉쁍􂈐}~$~~}õï(}(}Ũ驉T􆑛~̃˅ʊɃȇƆńĈŅƉDŽȂɅʅ τ N}þùчχΖτ·͈̇˅ʌɈȂɞȈǎ%΁}|}#}ʿ|Ϳ~Ϻ݌Ќψ΅͌̅̓̈͂̇͐΅D}~|·~´Ѽ̅˓ʄɈˇ̌̈́·χЄ&ׄ}|,~¹~ƼƶфʆɄʎɆȈLJƕŌǍƄĉŃƍŐĘÆ”2܅󂊒~|,}ļ}ʾ}᫇%Ոꀌ򁇏|}~$}}Ǿ|´®'~~|~(~|ǿ~~æ程S򅐚}ʄɉȆƆ͂̌ˉʃ˄̃͊΂τЄф քOſ؇ֈՑևՄԌӊ҄чАΉτΉύΈ'Յ􁈏#ƺƷ׌֋ՆԌӄԅӅԃӇԐՄ ɾɻ­ӅҊтІцЌт҆ӉԄՆևׄ&މ򄏛/ɿ¸ͼяЄτЇχΈ̐̆̓̅͘ˎ̐ˉʃɊʆɇȃDŽȈǃƄЋ’ 0䊠)úŹǨ豇M܌򅑝Žɺȴ)Ĉ)ƽƻʬﮉTфЅω΃ȂЇǎƈŃƆlj˄̄̈́ҝ†O~}Ƽ}҉ДхЍψ·͆̃˄ʃˇɌʍɂʆɃȔ&}#}ɾ˽ɵ׌юЊφ΅͏͆ΊύE~}ʾ˽ȳԄψΆ͉̅˄̈ˆ̈̓ΏυЃш,򄏛􁈏,ù~ŻΓˑʆɊȖNJɍțǎƗŃĖ„4}~,¹Źɰ&}~}~#}}õ®'}}*}Ǿ}ɽмʢ R񅒜~}(˅ʈɈdžƃņҹ¹ňƅɅʃ˅МM}ľ|ź|ЍςЎψΌ͊̅ˆʋɆȂɎȄNJȊǎ'􄏛|$|ȼɻȳЕφ΂̈́΄͋͒̈͏G섐}~|ȽɻƱӌ͊̈ːʂɆʈ˄͈̊΅τЌ%򀆍~-~}Ĺ̈ʂɄʒɈȆnjƅōƋDŽƆǕƆőÈċʄ/|~},~÷ǯ&|}|}#|Ǿ|³'||~*~|Ž|ȼϺɡ R}|~!ɇȈDž͆̎ˈʂˆ̉Іт҅סljSſՈ׏ևՋԉӇ҆υЖχΈ͊΄χN÷´ϺוֆՂԄՄԎӂԒӈԏ# ĸ´ͷڋԋӄ҈тЈхІч҄ӊԉՄք׌%-ȿƵӇхёЇφΈ͕̄̈́Έ΄͚̏˗ʃɖȂDŽЄ²„„ /π(ǾʾεN􂈑ŽȺdzU􁈐û÷ϦS…"ЄωΈłЂЇNjƈńƈdžʄ˃̄̈́Є ̈́Jľ~ƼԄЖцЌψΈ͆ʄ˔ʔɂȗLْ큍󀇎}}ƻǸ®ҋьЌφ΅͏Ά͆Ίώ }~|ĹĶӽψΆ͊̂ˈ̆ˆ̈̓΋ψЄш҅%|}~,¹}ø~˻̖ˌʆɌȑDŽȄɈȂɉȕǎƘłčÃĆ„ +1㉟}~}+~ƾ}ɽϹǧNۈ킍|}~~~}}|ôT卟񄐜}~żźɱ P삐dž(ʋɆȃdžƃŎąÂćňɅʃ˅$СʇL~ý}ź҉σЏχΈ͋̆˅ʊɆȂɅȃɆȄNJȈLJDŽOב쀋|~~|ŹŷЍϊ΅͎͓̈͐E西삏|~}{øõѻ͉̉ˏʂɆʈ˄͉̉΅σЋ&{|}+~|}ʺԋʂɄʒɈȆdžƃŏƖǔńƅşĆÈ .ም|}|+}ż|ȼ͸ƦNه끌{|}}}||Ǿ{T㌞|}úĸȰOꁏ~~ʼn)ɅȉLjƇ̎ˈʃˇ̈Іт҆"קщLľՉւ׎ֈՋԋӅ҆ъЈЋω·Ϗ΄ω#ߖ􅐜"̾ȳ׍։ՄՅԚ҈ӋԍEʾʻ­ԊӄғфІш҃ӊԈՆւ׋&ꀋ󀇎+ȾȽۊїЈχ΍͉͆̂̈́̄Ά̈́Ί͎̎˘ʂɍȃɆȂDŽЃª„Š 0鍣񁉒(ú÷Ծ̬'󅑞#ŽȹƲ&둤'˿϶R򆔠̉(ЄϊΈʂՂЇNJƄńĄņƈDžʅ˂̅*ЙӈJ|¼~źҘцЊϋΆ͉̆ˈʂ˅ʌɈʚ$π}~~#ø´ѻяЍϊ͇Έ͊΋ϋF饿탏}~~}ɿ}̾ȲЈφΆ͗̅ˆ̂̈́̄ͅ΅ϊІф҆%؅ꀋ+¹|Ƶῡ̕ˈʄɎȇDŽLJȖɇȄDžȆǃȇǝƊňąÅĆ„ 1р}~*|¹¶~᫦L~~||}}|ȿ|ô&Ɇ뀌􁈐}*~ú¶~¥䧟 O}χ,¿ɍȈDžƅŊĆÆąŇȅ˅'ϘъI~{}øЊςЎόΊ͆̈ˈʆɂȍɄǔȅǍ$|}}!~·~ϺψΎͦ̊͌E磾낎|}}|Ƚ|ʼƱ׉Ά̈́̆˅ʋːʈ˄̆͊ΆσЉ%ׄ~~,~{ʿĴ͋ʖɈȌǒƈDŽȇǒʼnƄŤĄÒ† + 2􂋔|}'~{}ӿߪP}}{{||{Ǿ{Կ)Dž򀇏|~(~}}㦅N~|͉-ȆǑ͆̋Ʌʆˈ̄͂΄τЂф҄ӄ$֞وJʿךֆՉԅӂԄӇ҈чІτЂτЄφΈϒ΂φ$Ԅ쁌!ɽȹֈՎԌӂҌӃ҉ӊԌE󆓣ĹõͷމՅԅӄ҈щ҇тЈщ҄ӆԉՆփ׉%ވ񃏛,Ⱦƻ˺ԋѓЇσΐ̈́̉͊΃ό·͇̝͂̇̈́̄ˋʇɅȅɆȂDŽͅ„‚ЋŠ+/׃'ǾǻƧ氄&#ŽȹŰ*Ί񄐜+ȿǻǩꬣP邑Յ-ΑтۂЇljƅńąňƅDŽʅ˃̄̈́΅(ۇH¿ž~¶ЖфЊόΆ͈̇ˇʂ˄ʄ˃ʋɉʚ$􅐜|~#~};ɴьЎυ΃̈́΄͆Έ͊ΊόF製낏|~}źŷӽЈφΆ͈͌̄̂ˈ̂̈́̄ͅ΅ϊІф҅%񃏛~,¸ʿ}ˆ̄̕ˈʄɑȃljȋɄʌɆȂLjȄDŽȈǞƆŒĆ +Ž 2򁊓}~*~ƽƺǮN݈킎||ȿ|´Կ(}}(}~ʾκǡ M񇕢~ل6ɆȑDžƄŊćÉĄŇȅɂʄ˄̄,ΙۄI~ý}ӇτЍϋΊ͇̇ˈʇȍɄNjɉȈdžDŽ$򄏛{}"}ʿ|˽ȳ֊ϊΎͦ̊͌E梼過􁉐{}~~|øĶѼωΆ̈́̅ˆʋːʈ˄̅ͅ·τЇ%}+~ȽϿ|ˍʖɈȎǐƇNjȃDžȄǐŊƅńĄŊĂŐ„̆ + -펢|}'}ļŹƭNۇ쁍{{ƾ{Ӿ'||~~(~|ǿ}ɽ͸ƠS}ׄ4ǕƇ̊˄ʄɄʇˇ̄͂΄τЃф҃ӄy՟¿ýǻڈ׏֋ՅԄӇ҉шЃυυЄφΊϙ$񀇎"ƺõϹ݊ֆՍԍӂҘӊԌ!򆓢 ʿ˼­։ՅԄӅ҈ъҐф҅ӄԊՆքׇ%+ǽĹƲҍђЈτ·Ή͈͂̈΄όΐ͈̞̈́̄˅ʒĄÌ„ˆ‹Ç /(º̿ͳN㌞􆒟Ľȹį(ꀌ(ƽ÷Կ̥P߄6·͍ՂЃnjƆņĈdžȂɅʅ˄̄ͅ-ϓ}G~ƿ}ʾאчЄτ΂υ΅̈́̆˂̆˄ʂ˄ʆ˂ʊɊʐɃȈJؑ쁌}}ɽȺ­|ӇЈτ΂όΌ͆΂͊ΆςΊώB碼ꁎ}~~}ʿ}ͿȳڇЅυ·ˊ͇̃͗̃΂ϏЃф(~,|¸Ƚ̼ˉ̘ˈʉɆȆɎȂɘʆɆDžȆǂȆǕōƑńą0݇|~'|~˿ͷJ|ȿ|³ӾR獠󅑝}|~~|Ǿ|ǻȯK䀏}8ȑLjńŅċÆĄńƅDžȃɅʄ˅/͒|H}ž|ȽϒЂύΉ̈́̅ˏʓǎȄɄȄdžȍMאꀋ󀇏||ǼǸ{ψΎ͉̉˒̏ΌB桻耍󀉐|}~~~}|Ⱦ|˽DZىΆ̓̆ˆʏˇʉ˃͈̅ΊτЅ%}~*{ƻ˺ϜʌɊȅƍLjDžȇɌȈdžŎƎŃąőĐÇ .ۆ{}(~{}ɽ˶L~{ƽ{ҽR挞񄐜|{}~}{ƽ{ŹƮ +P|ކ7ƍŃ̌ˆʆɈʂ˄̄̈́΄τЄф҆|ԗžö݄ֆօׂ֌Մԅӄ҅фЃэЂχЂφΌϚ#ޕ򄐜$·οDzևՌԉӋҒӓԂՌBźĶθՆԄӆ +ъҎф҄ӅԇՄՅքׅ%􁈐*ǽ·֔фЄщЉψΆ͆Ύ͂ΊςЌφΌ͆̄̈́̆̎ʎːʄ Ňăȃ‚‚ŒÄĂń +.㊣􀆌(ǾķӼƪK‚逌ĽǸî%푤󁈐&Ļʹ Kꃓ7͐ۂЂLJƂńƆņĈDžȃɆʅ˅̂͆0J¾|ŸԌьЄυ΅̈́̆˂̌˄ʊɊʐɃȉ"΀}!źĵкЈϔΌ͆΂͊ΒώB砺聍|~~}|źƸԽ҈Єυ·ˊ͇̂͗̄΂ϏЃф&؁~󀇏},|¸ǻ~ȶˎ̖ˇʋɆȆɎȂɊʂˌʆɌȆǂȆǂȄǍŎƐńĆ +  /р~~'}ż÷~ӾتJ√|ǿ|³ҽ(ц쁍~&~Ž÷~㦇 Q|>DŽȈLJƂDŽōㄯĄńƅDžȄɅʄˇ~{žöҐЂώΈ̈́̄ˆɋʑǏȅdžȎ"|~~!~ĸ´ιΎ͍̉ˌ̏̈́ΌE培瀌󀉐{}}~~|{ùŷҼω΄͂̇˅ʕ˅ʊ˂͇̇ΊτЄ%ր}|*~{ź}Ƶ̞ʌɉȆƏDžƅDžȎɈȊǒƍłĆņĆŊć‡/}}(|û}ѽ֩J쁍{ƽ{м%υꀌ}~&~}û¶}᥈M텕~{~=¿ىƏŃ̌ˆʆɈʂ˄̄̈́΅υЄф҆2Gžʽׂِ֍Ԇӄ҅фъχЂφΌϛ#ԃ뀌!˿ɺֿՎԌӋґӐՌBʿ̽­׋Մԃӆ҆ъ҄҉ф҂ӇԇՅքׄ%݄킎+ȽͻЕтІыЇψ΅͈΍͂΄ψЌχ΋͆̄̈́̂̈́̂˄̊̑ːʄɅņąÇ‚‚ƒÆ‚ńĄ ,փ񁊔(¹ȼãݮJ苞񀇏ļǸ­&֊򅑞'¹ɼƨ骇 K@͈̄ ЉƈņąńƅǃȈɆʄˇ;͋ېH}ƿʾ}ц҄тЄцЉχ΄͆̃˄̈ˉʍɂʄʞL󅑝}~~·}οȳЉψΆΈ͒Βώ柹瀌􁉐}ɿ~ȳއцЄς΄͇̊̈́̅͏ ΆϊЈ'ߏ쁍,}¸ź|ı~ˑ̅̌ˆʈɆȌɆȅɄʑˇʍɆȊDŽȊdžƄLjƂNjƋŃĆł0𓧷|~&~|}ǻĪJ~}󀈎ǾѼ&~}󀈐}(~}úκɟK}~C}~ǏĄŌ„ÄƒÅĄńƅLjȃɅʅ9ڎEÿ|ž~ɽ|ӋЍχ΄͈̃˕ʆɈȄǑȉLjȂDŽJ񄏜|}}|̽DZ؆Ί͓̇˄͉͈̅̐Ί䞸򀈏|Ⱦ}̾DZ݉ ̜ͅ˄ʆ˂̊͆΋φ%ݎ뀌~+|Ĺ{ð}ˊʄ˒ʉɄȏdžȄƅDŽʇɂʈɅDŽȈǕƑņčʼnĆˆ-{}*}{Ǿ|Ź©P}|Ž~Ϻ&}||~(}|˿̸Ǟ H|}A~|}ŅĉˈʆɅʄ˅͈̃ΆτЄх7ᔕC¾Ľôڋ׌ֆՆԇӃҎЅшЈφ΄ςΈϔψI􁈐ǼĶθ߆ՊԒӉ҄ӃԊӐԈՊA죾źŶηԅӅї҉ӊԅՈֆ%󅑞+Ⱦ˿ɶҊф҆тЉэЅψ΃͇΃τΆ̈́΄ϕЅω΅͆̅͊̅˄̇˄̇ˋʃɆȅŅĄÎ†‰ÌăńĆ-'żɮ JÂ逍ļǷU끍ŹӿΣ ICȁ̎䂑낄ЉƈņĂÄĄńƆǃȌɃʅˆ=}B~žõֆҋцІχ΄͍̈ˈʵHܖ쁍}}ʿɺ}Ӊϊ·Ό͒ΒώA垷􀉐|||źǹԽ}ԈцЃτ΂͎͆̌͂̆΋ψЊ&򄐝~})}ùĹՖ̄ˇ̌ˆʈɄȆɄʄɆȄɅʔ˅ʂɄʈɈȆdžȉƄLJƉdžƄƅńĆĂ3㍣~'}Ļ˾ɳ I䈚}ƾлR錞􅒞~}~|~ɽȲ F】F~}Úō ńÄĆłƊdžȄɉ=|B}ļԇЏφ΄͈̄˔ʆɈȂǒȊǑ!ەꀌ|~!~|ɽǹտ|хΊ͓̇˄͉͈̅̐ΊA䝶~{{{ùŷҼ|ҍς΄̜̈́˄ʆ˂̊͆Ίφ%}|)|÷пԅʂˆʄ˗ʉɅȍljȊDŽȃɄʂɇʇɋȆǕƈƖňĆĆ ,ጢ􃌕}'|¹~ɽDZI㇙킎|ż̿~ιR狝򄐝}|}{}ȻưF􀇍~F¿}|™ĈńŅĉˈʆɂȄɄʄ˅͉̃΅υЈ=C¾ûȹۇ׎ևՄԇӃҎтЄшЈφ·ϒ΄$󅑝%ĸŰՊԓӉ҄ӃԊӐԈՇD뢼삏ʿ;íٍԄӝ҉х҂ӋԅՋօ%􁉐*ȾʾƱۍф҆тЉэІϏΆ ̈́΄όЂшЄς΄ψΈ͆̆͌˅̇ˊ̅˂ʄ˄ʄɆȄǂƆŅ؂ĈÎÅ‰ÌĄńĆ„.鑨'ķθIꋞ󀈏üƷ%&ǾµͶ I郕Kɞ̓邐肋ЏńĈÄĂńljȇɇʅB}~|}}~A}}|}ûǸҍшЈσ΅͈̒ˑʉʋɂȍɉGՇ~􁈐|~ǻĵθφΈ͂Ζ͈΂͐Όό@䜶~󀈐ɿ~ɳ҇уЅςΝ͊ΌφЌ%򀇏~)}ùøϽқ̂ˇ̆ˌʋɋʇɃʎˆ̇ˋʇɉȂLjȔǂƐNJƄň +,܆󂌖|(~Ǿ¶ιȣ#}󁈐$ƽ~Ϲ&х쁍|}'}ȿ|ƹ񪅜E儖~||}L|~ɽłčÄČÌĆńƊNJȆB|}{||}D||{Ŀ|º~ŷψІψΆ͂̊ˉʆɓȂLJȓnjJӆ}򀇏{~}Ź´~ͷΆ̉͘˗̆͊Άτ@㛴}Ⱦ}ͿDZЅυ΃̈́̎ˆ̅ˆʄ˂͉̉΅Єτ"}*|¸¶ͻЈʃ˄ʂ˘ʊɓȇɋȇɌʋɈȂǓƭŅÄ -څ񁋔{~'}Ž̸Ǣ#~|񀇏#ļ˿}͸%Єꀌ{|~'~|ƾ{ĸ~海 Hフ}~{{|P{{~}ǼÅĉÆÏʅɇȄɂʄ̅͌ΆφDF̽ք׆ևՈԂӄ҄т҇эГυ΄ϕΌIۋ쁍ɻԽՆԒӍҚӈԇՆք@꡻낏źƷθׅքՄԂӐ҄ӊ҆ф҃ӉԈՊք&+ɾɽ¬׏тҖшЎΐς΄όЊшЄψΈ͂̈ͧ̉˄ʈ Ƅ…ֆ†Æ—ÊĈŅĄÃ„-⊣(úȻӾͨ +IǂꁍûƷվP׈򅑞񀇏ż˿Ǭ F뇚K´ɍЅłąŇĉŇƂNJȋɇG|~|}~~<~~~}|Ŀ}ʻׄ҇шЈτ΄͉̑ˑʓɆȊɈ%~!}÷~οưωΈ͂Ζ͆Ά͐Ίό@㛴}򀈏ĺȺԾׇ҇тІςἈΉ͇̄̈́΋φЌ%ք~)}ĺ·̹ϝ̂ˊ̇˝ˌʍˊ̍˃ʈɉLjȨdžƄ҇ .Ђ񁋕|'|}ƹ~Ҿ৆ +H臚~Ž}θP}}~}ƽöϺТH쇘|}}|}}~Q}}}¾}ąʼnćŏƂĆŅƌLjȅG{}{|}}~~~~<}~}}|{þ|ǾȺՊІψΆ͂̋ˈʆɎɏȒNjȄ"󅑝~} ~|}̾įֆ͒̋˜͇̉΅τ@⚳|¸ƸӼ~ՊЅυ΂͆̈ˊ̅˅ʄ˂̈͊΄ω&Ճ}􁈐~-|¸ʸˈʂ˄ʂ˘ʊɒȈɊȂɎʅˇʋɇȈNJdžƔʼnƉŅĈ ++΁{~'~{|ĸ}ѽަ H憙}Ļ˿|̷U}|󀈐}~}|ļ͹ΠBꆗ󀇎~{||{||}M|||}|Åʂɇʅɉʇ̋͆ΌE>ĿŽׇ݆ֈՆԂӊ҆юДτ΄ϊ΂͉΋Jȼĵ˵ޅԊ҇ӒқӈԇՂև@韹過ʿͿí܊ׄֆՂԅӈ҆ӈ҆ф҃ӉԈՄք)܈쁎'ɿȼѾԑтҗщЕχЊψЌюЃχΒͬ̅˅ʆLJƄą֖’ÊĎŅĄ +.Յ(Ǿ˿å櫆I»Ŷӽ%ꁍ&úȻԿզ<򋜬S¿ɆʆɉЍćąÅĂŅƂǍȅɂȇL߅}|~~<~~|ļ̽։ьϋ΄͈̄˂ʅ˛ʄɂʄɉȇɇʇ"}} ~ʿɺԽюΉ͎͂̄͆̐͆̄ΆςЈA㙲|ȿ~|ɳф҉фІτ͌Έ͇̂ͅΊχЇф(ݐꀌ}}'~ź¶ɷͮ̉ˊʄ˂ʊ˃ʈˊ̆͌̆ˈʆɑȍǂȌNJȆdžƄłĄÂ† ++}}'}ļʽ©}J~ż}ͷO抝󅒞}~~|ļɴB쉛}}~~V~~}|~|ŒÇ„ć„ÄăŋƐMބ|~{}}~<~}}{ú˼ԆЉφ΄͊̇˅ʄɃʅɄȄɆȂɎȈǂƅljȊ"❿킎||~ }ɽǸҼЉ͍̕˂̏˃͈̄̇ͅCᘱ{~ƽ}ο{DzЄυ΅͐̂̈́̄̇ˇ͊Άφ"܏||(}ùǵ̒ʄːˍʄɅȜɅʏˇʄɈȉDžƄnjƄőLjƆŋÄ.|퀉|~(|ú~Ȼ|J~}􀈏ûʾ|˵O剛񄑝~|~~}}{º˾DzO뇚|~|}}~~S~~}}|{}{¿͍ɇȄDžȅɂʅ˂̌͆΂͇M刼=°ۅׅՄֆՃԊӇ҄фЂφРτΈ̈́ΊψJ󁈐ĸο¬ӄԎӨҌӆԈC靷瀍ĺƸθׄօՅԖӈ҇ӈԉՆֆ"㔾򀈐(ǻμғтҞфІψЂϊЂψЊю҈чЈφΎ͇͉̄̋͆̆˄ʂɄȂdžÄĈ̊ÄĎÆąÍďņăÄ ,ʁ(µȭHς끎»ŶҼR썡ŸθG󌟯򀇎T¿njȇÄÆƄÆĂńƂǖȅO~|}~;~|ý~ȿ};ֆыЂϋ΄͈̄˂ʄ˜ʄɂʄɈȆɈʊFّ~|ƻõ~˵ώΈ̈́̂͆̊͆̄͐Ύ?☰ùȺվאуЈϕΈ͈̈́ΊχЇ%~)~ƻdz˲̅ˆʈ˂ʊ˂ʆˈ͈̎̇ˉʅɖȄDŽȆǎȈNJƂń‡ ++}&~ȿǰG釚񄑞~ļ̿|˵%΂끍}|}%~}ºɼìB퉜~~|}~Y~}|~¿Çč΍ƒÄăŌƇǂƇO}{|}~8~}{}ƽ|̽Љφ΄͊̈˃ʅɂʅɅȄɆȂɄɊȍNJȌFא~}~{ʳ}ɳΉ̨͋͊̆ͅ΅@~¸ǹӼόЄφ΄̈́̂̈́̂͊̆ͅˆ͍̄·υ"暾삎~}'}ĺ~Ų˕ʂːʄˈʄɃȏɄʆɈʉˆ̇ˇʃɊȉǂƅǞƅDŽƇʼnĂÅ+풧|~(~}ƽ̿ůG熙}ºʾ{ʴ$́逌|{|~&~}|~Ȼ A눛}}{|}~~~W~}|{}ŗȋȆDŽȆɂʄ˂̎͂΅͆O>¼Ļı׉ևՂԌӆ҄ьЈςВτ·ͅΊϊHޕɺкӅԉӉ҃ѓ҄хҎӆԃՇ@蜵ɿοí֌ׄֆՄԑԄӄӇ҇ԊՆօ#'Ǻ̸ҶфЅϚІѐ҇ЈψΖ͇̈́̅̏̊ͅ˂ʄLJƃŇċƋÊćÏąŅĊłƄņĂĂ,􃍘'ĻƸ̵KĵѺ%ԅ񅑞򀈐%ȿµȱ=󍠰[ȇɍЋ̅ÄƇljȅLjVŁ}|}:}ý|¹}ξՅцІϊΆ̈́̋ˉʂ˓ʋɃȅɌʋF҄􁈐}~·};¬όΉ̈́̂̈́̃͌̋͂ͅΈ͏@ᖯ~Ǿ³|ɳҏшЉϔΉ͆΄όЈ&󅒟󁈐'~Ǽ~űՄ̆ˍ̃˖̂͆̌ˎ̆˅̉̈ͅ +͆̅ˉʈɈȂɆȂɐȆ ȎŅăĉ,쒧|}'}¹|÷˶ȡ G~û˿ʴN􎡶}}~}|}ƹ~ѽ楅A戜񀇏}~]}}¾~|¿صτއĄŔƆVĀ|{|~~:~|¼{|̼ԆχΆ͇̈́̂̃˄ʂɆʈɂȄɄȂɎȊNJȏEЃ򀇏|~}|˽؄͍̗ʏˈ̂ˈ̌?ߕ􇕢}Ƽ~{DZЇφЄχΗ͈̆˄̅͋Έυ#񄐝񀇏~'}ź˿}ðԐʄˈˇʄ˂ʄˈʃɝʊ˂̊ˈ̈ʉɄȄǂȐǂƅǃƄǂƑljƄ„.ꑦ~{|(~|{µɴƠ G}~􂈐ºɽȳN򍠴|􁈐|}~~~~|{ǿ|Ÿ}м䤆A䇛|}~^~~||}{~ִ͗ȏDžȄˇ̋̓̇Xʅ:¼ǾðۆևՅԅӂԅӄ҄чЂцЄσГϐ΍ό!׈ ȼôDZ߄ԋә҆щ҇Ӆ҈ӊ?皳ùǸθׇֆׄևՓԈӆ҄ӆԊՈօ#'ƺʶۅЊуҗф҉чЙѐ҂ц҆Ӈ҅цЈω·͂Ά͂ΐ͆΂̈́Έ͉ʄɃȄljƃŊĆÚĂÆĆłĊŃąŇƅŇ,򖫽󃍗󀆍(Ǿɼкͥ Gт삏ĴϹ$耍%ƽ̿¨쩆D쌠^ÿ޺ԄǎЋÊ„ÄƇDŽȇLJZ}|~}~<}ü~Ļ~ͽцІϊΆ̈́̋˅ʂˌʂɅʒɍʌE򄑝|~~}ɾȹйӋΊ̘͎̈́̂̈́̂͒?ߔ􇕢~¹ɻԽЏшЋυ΂όΈͅ΅ϋЉ%ր}(~Ƚ}­˄̈ˋ̃˒͊̂˞̐͂̆͆·͆̆ˇʊɆȂɆȄɊȊɂȄɉȄƄƄ +獥}}*~ļ~Ǻ}ϺդF뇚򅒟û˾ȳ$񄑞񀇏}~(~}ǿö̷˟>䅙󁈐~}~a~}}}ÿԅƒÎËĆœƅZ|{~}|}~>~|}ù}˼χΌ͈̂˄ʂɆʈȅɄȂɍȎNjȐH~{}~}|ȼƷθ̘͌˂ʒˇ̅ˈ̊>ޓ򆓡}ǹӼوφЄωΗ͊̆͌Έτ#􁉑|&}ƻ˿|Ӓʄˈʄ˃ʏ˚ʂˈʈ̊ˉ̋˂ʊɄȘǂƌDŽȈnjƄłĄÂ†,匤~||~(|ú}Ÿ|͸ԣF醙񄑝~ɽDZ$ޅ|}~(}|޵ʶʝ +>℘񀇏}|}~_~}|ÿ~|ÿ|½ȊǂƄDŽȄˇ̈͆̇Y΁:»¯ֈՆԄӂԇшчЄσГϐΎόHø;־Ԋӗ҆э҂ӈ҉Ӈ>嘱Ǿ¬ֆׄֈՖԊӄ҃ӅԌՉ&܃'¸ƺDzЅцЇт҅Ах҂фҨъ҂ӊ҈ӈщЄϊ΅͆΃̈́Ί͊΂ͅΉ̈́ +ȆDŽƄŴĒłąňƅň„ ,푩򃍗􀇎)̿ԿۨF񋟳ôηP抝ĻɻѼѣ?ꈞ_¾څǃȎН„ÄĂŇƓc˅~~}~;~Ƽ}̻}ЌφΆ͂̐˚ʈɂȊɄʂɉʅJ坾끍}}~~}ź³DZφΊ͂̈͌̆ ͋̕>ߓ򆓡}޳|ȲӉ҇щКόΆψЋ#܉}}}'ɾ}Е˗͎̈̂͋̒ͅ΂͈΂͐Έ͆̆˅ʦʋɊƄ†Ä‚-ތ}~(~Ǿʽҽ쫄F|ºʽDZ'~而}|}~(}ŽƱ;܃󁉑}~k~}ÿ~ÿ~þƒœƒÄąńƊņ^Ʉ}}|}~:~}Ļ|ʹ|ψΊ͈ʐɂȊɆɅȎǎȍE䜽逌||}~~~}|ø~ů͈̙˃ʨˈ̄>ݑ|û~{DZчυІϏΔ͉̄͆Ε#ڈ}||'~ǽ̿|ѿ΅ɅʉɄ˒ʠ˄ʅ˃̊˄̂̈́̄͊̆͆̄ˆʈɈȈdžȇljɉȈdžƂńĂČ`܋~|}}ƽȻ~Ѽ몝F~~{ȼư'}|{|}%|Ļ̿İ + <ڂ񀈐|}~g~~}|½}½}½ЗDŽȄɂʆ˓̄]Ј9ׇՉԄя Гυ΂͈Άς·ό!񅑞󁉐 ʿǸ̵ԈӔ҉ѧҊ@䖯󀉐¸Ǹη؇օ׆֎ՔԊӅԆՔ#፸ꁎ񀈐(ùƺưՔЖы҅ю҆ђҋԎӃԇӈ҄чЇϏ΂ό·ϊΊ˄džȄņėƄŃąņƄƉʼnƇŇ…+䐨񂍗&ϵ¨󯄢N؂탐񀆏ǿó̶N΂򁈐ºŸ˶ž F⇜hĿĿƆDŽƃDŽƂЇ„ÄĄņƄDžƉd}}7}ƿƽ}ɷЋφΆ̓̏˛ʇɂȐɊʄ˂ʅCݒ~}~~}|˼վ׆Ί͎͂̈͌̊̐͊=ޑ|ɻԽڑъКϋ·φА#~~'ʿ|ҿЅʋ˂ʆˍˈ͉̄̌̆ͅ΋̈́φϘΈ̈ͅˉʈɄʇʆʅɄȂDŽƄńČ ő,݌~~%|J눛􆓠򀈎ɽưL튝|}}~}}ûʽ:}򁉑~|~h}þ~ÿ}½}ƆƒÆđŅb~||~6~|ĽŻ|ǶՇΊ͇ ʐɂȊɆɅȍǏȏDۑ}|}~~}|ɿ{ʻԼ͇̖ˆʃ˄̡ˉ@ܐ{ǿȺһىτІϓΗ͂̄͆ΔNޒ~}}~ɾ{оΊʋɖʎʑ˂ʆː͇̄̓̅̈́̉̇ͅˇʄɌȄǑ ԊȉDŽƂń㳄 *ۊ~}}%~{ȿ˾ԿJꇚ򅒟ſȻĮL뉜􁈐{||}||ºȼӿ :|}{}~h~|}½||ŗƊDŽȄɄʅˇ̂ˊd6Ľ¸μ܅ՉԇӅ҃єЂχЎυ΂͉΅ςΈύC㖼끎ƺ²í܇ӔҊѧҊ?䕭򀈐ƽ¬օ׆֒ՒӄԆՔQ旽źǺįϔЕы҅ѐ҄ф҆ӄԄӄԋӆԅӅ҅шЈψΆφ΄ψ΄˄ʄɌƐłĆņƇ ȅǑƄŋƊń… -⏧񂌗%ƽŷƯF򋟴ƿ³˴&󍡷$õů?ځiÿĿ¼ˆƂǏЛ…ÅăņŊƆh}}~5~|û}ǽŲԉφ΅͈̎ˇʇˌʗɏʈ Ն} ƼƷ~˵Ί͈͆̄͐̍͋̈̉ݏڄû´|ȲӎэЊσΐυψЋ%曼끎񀇏&|µѾЊʌ˄ʊ ˉ͇͇̃̈΃͋΃υΌύΈφΊ͆̊ˆʂɆ}ΈʊdžʼnĄ +)~|ˆ  *܋~)}ú|µĮH耍|ɼĮKق탏||¹~Ⱥ}ϻ賂8~u~}½~~ſ~„ÅŋĄņg|~|}2}{|Żð҄Ά͉̃˓ʅɂȉɅȂɆDŽȂDŽȂDŽȖ ԅ􆒟󀈏|źĵ}ʳὑˆʈˈ̄ˆʔˊ=ێ삐¹~{ǰђφ΃ϊΖ͂̄͆ΊτІ"䚺逍}({ʿϼțɘʆ˃ʉ˒̙̈́̄̍͋̆ˆʊɅȂɄ|̐ņ㯠+~}{*ڊ~~}2~|{­!~{ڄ"ľǻíKׁ낎~{{}ƹ|ι:~}~m~}|}þ}ľ}ƄDžȄɃʑˇe6¸ʷيԇӅ҈цЂфψЌϖ΍ϋCۊ˼ѹքӋ҂ш҉х҅Ӆ҈ѓ҉=㓫􇕣ȹηْֆՃ֊ՖԇՉք׆"񅒠&ƻǺîՇϗЂфВф҄ъ҈ӂ҈ӘԊӌԅӄ҆ьЄ·Ӊω̆ʈɄ ŅƅŃƍ"儂ǍƊŅ+Ꭷ񂍘6ȿȺɳ!܂򀈎 žɳMކ􆓡ǿͿ 7l¾ľƈŋƄЇ„ÄĄłƈņƓ\}~}~4}ƾ}Ƽ҅φΆ͋̅˂̄ˆʈˌʖɏʅC~񀇏|}|·~«Ά͍͈͆̂͒̍̂͆̅<܍삐ƾʻԽߎѐЋΒτψЋ%탐􁉑|%|·¶нύʋˆʉ̄ˈ͈̄͆̈΂͈ΘϋΊφΆ̊ͅ$ʾʈdžƆň +—‚Æ!}Ȇ+ۊ󀆎~&}ż~ŸDzĝH숛􁈐ſȻíN~}}Ÿʶ֝:剞|~k}~½žƒÑĈńƋ[|}|}4~|Ž|Żп~Ї͇̋ˎʏɃȄɆȂǔȗF}{|{};̕ˆʈˉ̃ˆʕˉ=ڌꁏĽȺӻБχ΃ϊ·͇Ύ͆ΊτЅ#삏򀈐{~&{μ΄Ȝɓʆ˂ʄ̅̈͂ͅΆ͂Η͂Ή͋̆˅ʅʅ#ȽɎņđÄ"| ,ى~}&~|Ļ}ĶŰÜHꇚ󆒟򀇎ýƺN󌠵}|ƾ|÷ɴ՛A㈝~{}f~|}ý~ŔƆDŽȄɄʃˇʆ˔\5ļűׇԆӅғψЌωφ΂φЅόEՁǼŶǰӌ҂ш҈ч҇ӄ҈є҈?⑩򆔢û¬׏ևՃ֊ՈԄՋӄԆՇքׅ#􆔢&ǽȻ­ՈϐЅωВф҄щҐӏԂՊԃӔԋӆ҅ь"Ћφ̆ˇʇ +ǗƇǂȆ!ȇdžƊņ,񃍘'¹˽̶ɡE򌠵ĽȱKꁎ񀈐Žʽлܠ<댣􂋔e½ĽÇČńƄłƅЏ„ÄďŢS~1~}Ż̺τ·͆̅͊̄ˇʄˉ˅ʋɈʐ˂ʆB遍~ǽɺϸ͚͈҆͆̂̊̄͘<ی遏ô}Ȳ׎єЃχЃχЉωЊL~}}Ĺ|÷|нІʇ˓ʊ˄̆ˈ̃̈ͅφ΋φ ЏχЄό ̄1}|~}ˇdžƓń΋*вĆUڊ쀊􁈏}~ȾȺʵԠD過}þǻM䅘򆒠􁉑ƾµŰš 7ځ}}Y~}ŠÉĖŅĄV~~}0}ǿ|ĹʸԄ͇̖˄ʘɊȂǎȘB럻而}ƼǸζє˂ʌ˃ʅ̈ːʆ̈́<ڋ耎󁈐ƾ~|ǰ֒Ϩ΃͉Ώ!~􂉑|~%|·{µ{ϻΚɃȉɍʌˉ͚̆͂̄·͉Έ͇̄˅+||}|ʈɇŇĉÆ,ΰ~[؉򀆎|~~}ƽ~ƹȴҞD~而|¼~ƹֿ~L℗򀈐Žî 9؀||~Z}|Ŀ~ſǿ~ĿŅņƈDŽȄɏʢT4ƾѿԆӄ҄ьфЃψτЉσΎϘB¸οսؒҊ҄ф҂ӈҕх҈<Ꮷžȹηݒ֫ՄԊՏ"ڂ%ɾɼ¬ՔЇϊІтЈц҄҄ӄԄӅՄԕՍԈՇԍӄ/ՇЈ̆˔ȆǂƆƆNj*շ¿ɅƍńĄ)򃎙*ĻͿϺ٤Iނ􁈐üƯKꉝĻȺʵǞ 7߄񁊓YƿƆÒĈƄЏ‚ÆĊťƅM|~2}û}Ĺ}Ʊ·̌̄ͅ˄ʇ˄ʂˈʅɍʐ˂ʇG◷}|¸ôŮ͚̃̋͊ͅˌ͇̅;ڊ瀎􂈑»ʼԽވѕЂψЂωτЈόЄ'ك󆓡|}%}ź}ķ}нЄ˂ʉ˔ʉ˄̆ˆ̆̈́̇̓΅σ΋ϕЌψЈύ2󀈌~ˇdžƎńĂØ†Å2~}„(ڊ퀋|)~ʽ}̷㥚G순½Ǻֿ}J}耍ļ5}V}|ƿŠÈĊńĄŌŇM~{}0||·|İχ̋˄̈˄ʘɚșB|{ĭ͒˃ʌ˄ʄ˂̌ːʆ̈́<ى򁇏ȺӼВϔ΄φ΄ϊ΂͇Ώ"ׂ񅒠{|%|ù|ö|ϻϖɂȄɃȉɍʌˉ̋ͬ΃χΊ͈3}ʉɅňĆÈĄ2~}|,؉􁈏{~%~}ȿɻ|˶ᤄD뇛󀈎~ŸԽ|J|~û˾Ծ3폤|~R~|Ŀ{ſŽČŌƊǂȆɉʩO0ɾ˶ֆӄ҃ё҄юЂψЊςΎϙB蛼ꁎ񀇏Ǿȹ˳ԑҊ҆ьҕх҈<턒¬ג֔ՄֆՄ֊ՂԇՎKއʼ¬ՔЎϊІтЅы҈ӇӄԅՂԤՂօՇԉ1І̇ˌʅ˂ʄȍƋdžȅ2ꃂÿDžƆĄ)ߎ󄏚&ƽ´Ҽ詄D򌠵»̿ĭNցºŸŰ4Tļ„ÓĈІ‚ÎČņƆłƆƅƍJ}}~.~ļ}нϓ΄͇̎˂ʉ˘ʜG܎Ǿ}˼ӻ}͇̈̆͢ˉ̉ͅ;ڈ򁈐ýô}ɲ؇ьІώѐЋϒ"ڋ}}$}Ǽ~Ÿ}ѾІʄˋʂɊʈ˂̄ˆ̐͆΃υЂϖюІъЇ<~̄ˆLJƄłĄņƂńăŊ‡>ŏ~|þÆ*ڊ}%~|¹Ϳ~ϺF낎}~ƹԽIꈜûʽ~л1݅򂋔~N}~~Ǿ¾ŠçĈL|||~1}ú|μ̈ˋ̅˄ʄɆʇʌɆȇɅȗɆ@ڍ󆒠􁈐Ƽ|ʻѺ|֡˅ʏˊʇˊ=؇~~|ǰЇς΄ϒΉσ΄ϊ΂͆ΆτΈ!؊􆔡||$|ź}ķ|ϼϖɊȆɓʅˇˈ̂͌΂ψ΂φ΍ϊ΅Їχ΄8~}ӇʅDŽƄŇą ƅ9}{½„*؉쀋|~~%}{˽}͸󥅗G~遍|ſ}ĸӼI釚ɻ}κ8ۄ}T~|ſ}ƿ}ŽĊʼnƉǂȍɍʆ ˄ʄˎI2ǻíӈҊӄ҆ўІσЉϝ@⒵ù²ݏ҅х҂х҇ь҈тЈц҆=냐ûȹηׇ֒ՉփՄ֊ՃԅՆօՇ!󁉑%˾î֒ДхЍш҂ӄ҆ӃԕՂևՋ֋ՌֈՄ8򂇑چхЄ̈́̆˅ʇ˂ʄɃȅnjƅLJ>ʓĿȅ† +Sߎ􄏛ȿĶտE񅒠˾«I񋠶µ +2㉢PĻþ”ÄЇ ‡ÉĎŃƞčG}~~-}żɾȵ҉͊΃̛͇ˉʂˋʝAԈ󀈏øŶ}ȱ͈ͩ̄̇ˈ̋̈́;ۇ~񀇏þʼս҇ьІύЃёЉϕ!ᐱ~}$}ȾǺ~ҾҌˌʂɊʈ˄̂ˆ̈͌΃ϕЂшЄтЄьЊч?}֫̅ȄdžƅĄņƂńĄÄŠ‡ÂĄA}}ſX܎}}~|Ļ|ѼE퉜~ŸһHـ탐򀈐Ⱥ˶5}O}|¼}~†àĂÄĄčG|~}}-~|ĻȽ~ƳЅː̄ˏʅɂʍɅȈɄȋʊɆBӇĵ|ǰҎ˂ʏˇʍˋʌˆ>چ}½ȺӼЌϐΐςΆϐΆτ·!ߏ}|$|Ǽ~Ÿ}нЖɊȈɒʄˎ̆̈́΄ς΅χΔτ΅σЊB|Ԫ˄ʆƆņĄ ŅJİ~|ľ|þXۍ||~~}{ú{ͿкF눛􁇏þ}÷Ѻ򠊊H낏ǿ~ƹɵ4~|~M~|{|}ƾĆʼn ƄLJȉɎʄ˪E쀇-¹øͺׇҍӃ҆уЇєІχЅϞ@ڋȽ˻ζٍ҅хҐы҈тЈъ҆>ዡ遏Ľ«׌֐ՐւՆֈՂԆօՄK电ø̿îדЏτДфҎӄԄՄւՄֈՂֆՎֈՆւׇք?ܰфЄ̅ͅ˅Ʉʆ˂ʄɄȄNjƅLJȂɄ@ſĄÂ… (⑨􁈏&ƸE󌡶ʽKރ􇔢ƾͿл4򂋕MǾ”ʼnÅĒŃĈŊąŇF󄑝~}}/}żƺѾϏ΃̈́̂͊̋ˆʂˉʈ˄ʟ@~ꁎǽ~ο־̃͞˓̃ː̌:ۆ}ÿõ}ɲڄҎѐЄтЌЇћO䔳}}~ʿɻӿʈˋʃɆʈˏ̈ͅΎτҍтЙхЃф҆E̓̄˃ʄɂȄDŽƎńć…ÄąH¼ý+厥򃎙~}+|ƽ~õԾC삏~þ}ķй🅊I~~ǿ~ŸƱם 2}I}¼žǾ~…ĆĪÄćD񃐛}||~,~|ĻĹϽ̈́̂̈́̂̈́̊ˍʋɇȗɄʃɉʅ@}而~Ƽ}̽Լ~̅˄ʂ˅ʆ˓ʆ˒ʎ˄:څ|~~|ǰمЌφΝІυ΅χ΅L⓲|~|}ȾǺ~ѾєɌȄɇʌ˂̆͂΄͈΂ϊВωЍωK~˄ʅDŽƆńȆ„L~¼T㍣}|~}{Ļ}ҼC~ꁎ}½|¶ϸH}}ž}Ķİ՜8߆|~I~|~üż}ɿĄÈĆŐƄLjȄɓʂɎʂɅʉɄʇD,¹˿îԐӉҍъЂτЈϊЂϒЈхEցùĵëҎтҖтҗы҄:቞怎ĿȺζ׌ֆ՜ւ׆ֈ֋N阸聎źį؏ЍψЏш҄ӊԄ քגք׉Մ։G҄ф̈́̅ˍʄȄLJƇDžȄɅG† +X꒩¹ȺíF႖򆓡þɼ־H遏󁉑Ľ˽˶ܡ/拣F¼üúƿ‡ÂІŠÄĊłĄňĂŜĄńƉD~~1~ż~Ǵϊ̄͊̊˒ʉ˃ʠ?~}Ǹ˳ԝ̆ˑ̃˔̈:ڄ~ʼսՄҎѐЛљ!뙵~򀈐}#}ʽ҈ʇˌʃɆʆˌ̌̓΅ςЄψфҔтҌфЃфF~}~}̈́̄ȄDŽƎ Ƈ…ÄąM~Ľ U否􄐛򀇎}~ǾŷF퉝|½}öϷ힉K߂򅓠Ž|õɘ1|J}ľ~Ż˿»ÄĈņA􄒟}~}.}ú}Ʋῡ̈́̊ˌʐɇȗɄʄɈʅ@}|Ʒ~ɲ҅˄ʂ˅ʇ˔ʂ˕ʍ˄:؂}ȺӻӊЋΠτЅΈχ΅#阳}|~#~|ʿȻ~ӿђɌȄɊʌ˄͈̄͆΃ϏЅυЃϋЋU~}|}~|˄ʄDžƅńąÅ†„Nĕ}üž U㏥򃎚|~~}ƽ~öԾF눜{􁈏|~Ͷ띈Kށ􁉐ü{ȗ1~{~B~|¼}ùɽÊĆŎƄNJȄɐʈɂʌɂʎɄʄˉA+ǻ͸քԊӊҌчτЈϞЈц?ꁎ󁈐ǾͽиمҌф҈фЦщ=􂉐ÿ«ڊ׋՝քׄւՄֈՄJꂏƼµűؑБψЇь҂ӄԄՄԇՃ֎׆քׄ֊׌T􃍚̀҄фЄ̅ˍ ȆLJƇDžȄɅK»Ć'딫(úʼůB󌡷怍½ȻԼ󢆍H冚ûȺDZΜ +6CýƿĽ„Ѕ‡ÈŏĊÒĂŅƇnj>~~}-}ĺ|ȼϽχ΍͇̈˕ʉˊʛ?旱ŽІ͊̆ʐˆ̂˗̅9؂}~õ}ɲهҐьЌфЂфЄѐЂφI󁉑|}ø̿­}̄ˇʃ˕ʆˇ͇̈΄Ϗё҃ђ҇K}}~̃ͅ˄ʂɄȂDŽƎłƄʼn„ÄĄڲ~}G|}||º¼Q𓨺}~|ǹʛ J탐~|µ~Ͷ霈H􍢸瀍üҽ5ۅ}~D}ƿ~ž}Ĺ˿ŒÅƒÓÅĄņƆC~}}|)|¹{ǻλՆ͆̆ˊʆɇɈȄɂʛɉʅ?喰􇔡ü~ο׾Η˄ʆəʆˋʇ9ׁ󆓣|}|ǰ׊лό΅H~񀈐{~~|ʽ|ʚɅȇɉʆˌ̄͌ΈτЅьІцЊG||}~˅ȄńĄąÆĄ†ر}|F{|{{ +Q󀇏|~~}{ǾŷȚ +J~낏}¿{}˴盇H򌠶~̾л2ل|}E~|ľ}Ľ|øʽ…ÊĄŐƅdžȉɂʎɊȒɂʅˆ̍?)ɿ¶«݆ԃӇ҂ӄ҈цДϤЄч?웶¸ƶŮՌ҂ш҄шІтБуҎц9ޅ򁇏¿Ⱥζߊ׶Մ֌Յ 낐#ȽĶDzцЅυЇςЈψІшҋӄԋՄքׂ؄ׄ،׆؊׊F҆̄ˎʂ˄ȅNJƆDŽȄɄ߷D¾ǿ'$ż̾DZϟBთ󆔡ǺҺ!탑"Ÿ­ 7Fžüɾļ„Ї…ÎĂÅđÍćńƇǍȅ<􀆍~~,~¸÷İфΏ͆̈ˇɌʊ˃ʄ˃ʜ>ޏɺ͵Ջ̓̈ʑ˅̃˗̄:׀򆔢|ʼսчҏфЂцЌфЅя(怍􂊒~#}ĺį̆ˈʂˉʂˉʇˆ̇͋΅ϋЉъӎ҄ӊ҆I뀌}̄ͅ DŽƎłƄŋ„ÄĄފJ~}Ļ}Ž(|}$~ȺîЛA퉝}¾}˴囏Gㄘ|˾}͸0񐧺}?}»}üƹŸ‚Ó‡ŒÅąņƏ9󇗧}},}~ï͆̂˅̅ˊʆɍȄɃʜɉʅ>܎󀈏ſǸ˴ӗ˄ʇɆʂɐʅˍʆ9{ȺӻэЗσОχ΅G򁈑}~~|øͿ®˝ɂȈɅʈ˄̇̈́΅΋ЊчЇтЄфЄJ~|~˅ȄńĊÆĄ†܄G~}|ÿ¹|ü(򕨻||~$~}ȿǹ¬ΚA눜|Ͽ|ɲ䚏Gთ􇔡{ʼ|̶0퀉|~A||º~ĸ÷†ÉĆňƇDžȎɂȆɐȌɈʄ˅̇̈́΃͆:.ǽȼʵԄӄ҃Ӆ҇цДϤЅч>䓰żοӺږ҄ѓЎуҎц9݃«ٍחփמֈՄG탑ʿƸɴшЅυЇςЇψЇцҌӄԆՊ׉؉׆؅ׄK񄐟҆фЂτˍʃ˄ȅnjƄDŽȄɄ䍎G¾¿T뀋ƽοȲ՟K󍡷瀍Ŀƹи럋G釜ǿõӽ 1>˾ʽ›†È†ćņƆdžȒ;}}/}ɿ~ɽ̸͉΄̇ͅ˒ʦ˂̊Bڋ낏򀇎ú³ª̏̈ͅˆʉ˟:}~õ}ȱنцҘхҏфЄтҎф ׀瀎}#~~}Ƽ}õƲ͇ˇʆˌʊ˅̊͂΍σЊф҂фҒӃҏM삏}݈ɅƔńĂʌ„Ä ŶK~}øŽ &~~}}#~|¹ʼůោA|ɲ♎I낏󀈐ƿɻɳ}1΀~>}ľ~ºɼ~̾šŠÆĄʼnƋLJ=||(|Ⱦ}ǻʶя̆ˈʈɈȇɇʆɄ ʄɐ=ي過~ω˂̋˅ʌɠʆ|턑}|ǰόЋςЄϋАωЍ􁉑|~$}}|ź|İʨɃʈˆΈͅ΅ώКф҉Jꁎ~|~ ˇȄċÅĄÄ‡„Y~}|Ļ&}}||~~#~}{Ⱥíߞ~삏~;{ǰF過žǺDz}0~}A|ü}Ǻ}˼ˆÈċŃƄǛdžȈ Ɉʅˆ̆͋΄υ7(ݶѽٍӆ҉шЋχЂшыцЇц?񅓠Ǹǯ֕҆шЂϊОф܁Ⱥζ֍׊ւׄ֋א։׍F݃Ⱥ˶ӕЄτЂϊЄш҅ՉԄՅ֎ך؄ىM򅓣 +҆ф΅ˏ˄ʄɂȊnjȄʺ[¾Ƚ¿Pˁ킍􁈐Ⱦʳ磘თ􇔢D޽Ÿζ蝊G񆓡žθ .Ӄ>üǿûЄ“ÆɅÃĊŇƆLJȓ=񇘭}~*}Ƽ¶}Ҿ֋΄͆̊ˎʧ˃̇Dք~ĽʻϷ͈̍̇ˆʊˌˑ:샑ɻԼԈуҙцҌуЄуҍфEׄ聏}}~~~}ȽŸȴΉˆʈˊʋ˅̇ͅΌτЄфъқӂԇG뀐||ۇ̂˄ʂɅƔńĂʌ‚ÆޑI}½}Ƚż M˃ꀋ}~~}ú˽ư柇B퉞}οǯޗJ憚|}ľǹį蠐.ሡ쀊}|<~|~̼–ˆÇĄʼnƋLjȈ5~|}*|ĺ|н̄͆̆ˈʈɈȆɈʄɆʂɌʂɑ=ԃ~}ûȹ͵̈˂̋ˆʌɖ˄ʆ<ꂏȺӻ~ϋЋϖЏϊЋHփ怍||}}}|Ƽ~öƲʨɂʉ˅͈̂ͅ΅ωфЅтҒщI{{~ˆDŽĈÅĄÄˆܐK~||ƻû Mʂ~|}~~}|¹ʼį䞇B눜|̽ŮܖJ䅙{|ü~Ÿî柏/߇|{~9}{ƿ}̿~˻ˆÎĄŃƄǓȆȉDŽȄɊʇ˅̆͌΅ω5'Ȼîۅӂԅӆ҈щЈχЇцЄъЂхЈЇ<܇샐»Լݕ҆чЅυОф<򇔣֌׊֌؉׏֊׋G݇ø˽͹ѕЃϑЄш҅ ԄՅ֎ׅٓ؉J񃓥􀆌†҆΅˓ʄɂȊnjƄǂȄ䕠Hþ³%ч񃏛#ɿ´˵죅C󍢸聎ķ̴㛉E쉞怍󁈐ü̾ʴ,挥򃎘:ƿǾƵ‚Ö‚ÅĉŇƇDžȍɂʑ6|}~~/¸~ȻįΈ͇̋ˉʈ˄̈˄̔ˊ<Ӏ}|ſôìч͈̉̊˃ʇˈ̈ˌ̈́=􌡸遏}´}ȱҖі҄цК ۅ遏|!ɿǺʶЏ˃ʝˈΆωЇьґӑF}~|Lj&Ɇƒʆ…ĔF}̿ MԈ􁈏}~~~}Ļ;DZ򦆒 +Bۀ;ĭڕE}¼}ķ +-𑨺󃎘~;~Ľ}ȹͻˆÇćŇƇǎȈ<{|}}'~}ƺ®Є͈̆ˉʅɂȊɜʂɘ<|{ý~«ϒˇʊɛʋ7󋠶瀎~||Ư֊ЋϒЂшАςЈφ"ڄ瀎{&ǾƸɵɅʡɅʄ˂͈̄ΆψЊш҄ц҂ӄ҅F|}{~ńƃDŽ˄džƂńĉ ˆJ|ĿʾоM҇쁌򀇎|}~~}}|¹˽ů𤆑B탐~˼ìؔE|샐󁈏|õտޙ-񂍗󀆍}=}ü~|Ʒ˺…ÆÄƖǂȖǂȅɈʅˇ̇͊·ϐ7耏󀈏'ȽɴքԆӆ҄ьφЉфЊшВ؃瀍򀇏҄ľȹȰ҅ь҈ёЊЄЋъ7ǹ͵ދ׊֑׃؈אւ׈ֆ"ሧ"ĺͿлцЂѥӇԈՇև׊؇م؆قڄمI끐҄ͅ΅̈́̂˒ȊdžƂŇƂDžəJŵĽ &ً"ĵ̵DთöʲߙHۀ􇕣ʼŰ垓*;»ƾ;Ȃ‚Ö‚ÄćŇƇLJȈɂʄɂʕ2聕|,~ȾɵΉ͆̌ʇˇ̈˅̓ˋ<􇔡Ŀʼӥ͇͈̋ʈ˄̈ˋC怍~ȻԼ~Җі҅хКC܉ꂏʼ}͹ґ˄ʜˈ·ψЇъ҈ӃԈӍy򅘪~ɅȃDŽƃŅĊłĄÉ‡„èG~|̿Ǻ Lތ򄐜|}~~~}|ļ|οȱ@퉞~̽«֔E鈜~~|µҼʘ.~}~~>}¹|¯տˆÆćŇƆǐȈǂȄ5怓􁉐~{~,}Ǽ˾ȴ͈̆ˊʐɜʂə=򆓠􁈏¾ɺζʐˆʊəʍ7}ǹҺ}ъЈϝЛLۈ聎ɿɻ|̷ʅɆʙʆɅʄ˂͈̇τЉщ҄х҃ӄH~}ԅ$˄ȄDŽƄŃċ +„L}{˾ƹ L܋{|}}}|{ú{̾ư@눝}ʻՓE熛}}Ŀ{кɗ .}|}}@~|{Ծ„ÂĆ ƕǂȖȅɇʇˆ̈͆΋ϒ4(ùŸϺԈӅ҄ьЂϊЛхГ<ſֽ҅ы҉ёЊЄЋъ7샑؊׈֠ךK⌧Ƽ´ӾшЃѡӈԈք׉؉ل؄لڄzΆˆɋȉDžƆŇƂDŽȭJĴͿO㏥ŶͶC󍢹遏µǰܘF遏ƿǹМ ,с쀋:ǿǾǴķ΂ƂЈ„„ÄĆňƅljȆɈʓ6󁉑|)}Ĺ}ķκԄΆ͆̒ˈ̄˂̄ˇ̏ˇ̂˄;픪󀇎¿ôĭЗ̄˂ʔˆ̂˖<순~||ǰ҄тҌю҇ф҄ҒуІE߈ꂐ¸Ϳм̓˅ʈ˂ʍ˅̈́·τЄчҌӈӍD|~}/¿ɆȂDŽƂŔĂÄ…(̞ljG}}ɻοL菤}|}}|ż}Ȳ}Aۀ˻ҒD~Ŀ~͸Ó ,Յ쀋}?}ƾ}ûνƴ„ÇĄňƈDŽȂɉȉNJ2󊠶񀈐{~'{¸|ö͹͆̅ˈʂɄʂɬʇɑ;쒨탐~³ëχʎ˄ʎɚʎ6ꇛ}{Ϳ{Ư֐ЂϠЂτЂτЏDއ聎˾~ϺˆʂɆʎʉɄʃɅʅ˄̆ͅ΃φЌі҄G{}|ވ/ȅńĐ"ʝƅG|ľ|ȹͽL玣􅑝|{||{û|Ϳǰ|A~ɺ׿~ёJ}ý̾}̶ )Ԅ󀆍|~9~|Ľ|¹̼ų‚Æ„ÄĄÂĄńƈǂƖDŽƆDŽȄɆʈ˄̉ͅΎϐΈ2&ɾʼԿچӆ҈ъЈтМьА;ȹɱևщ҄ёЂхГц҂ф6򋠷邏􀇍Ƹ͵ݐׂׂ֠քׂ֊׎F匧ǾķшЄјЄфЅ҄ӆԅՃֆ׌ؖلG怒/΅͂̄˃ʓɂȄLjƌńȄ!ѣ͇FſĄ%󁈐$ŷη?იŭؖ EނľŷӼȖ *ۉ󄎚Aļ®˹Ղ͂Ј„…ÃćňƄNJȅɉʔɈ0醛򁉑|})ɾȻӾχ͈̌ˈ̂ˈ̋ˇ̐˅:莥過~ʼѸז̄˃ʔ˒͉̃6ၘ~~Ǻӻ~ӊтґхҋф҃фҐуЅD㋣ꂐú}´Կ͖˄ʈ˂ʅ˃̄ˆ̈́ΈτЂцҌӕA灔|9ɆƄŐŇ)ؗՅI~üı¹M}ż}}ɲD튟ɺ־}ϑD뉞½˾|ʳ E򃎙}|6~|üƽ̹|־…ÇćʼnƇDŽȃɉȉǎ0煚{|-~ǽ~Ǻ~ѽ̈́̅ˉɲʈɐ<捤瀍}¿ɺϷˆʎ˄ʍɛʎ6}}ŸѺ}ѐЄϤЂϊЎMኡ聏¸|ҽ~ɅʎɂʇɆɅʉ˄̆̈́΃υЈю҆ӉC倒{/ȅŅčŃ(֖ӇH}¯ +N󒦹|~û|ο|DZD뉝~~ȹԼ|͐D鈝~~ʼ{Ȳ 9ߋ|{~6}{º~Ļʷ{ս‚ÅÃądžƖDŽƅDžȃɇʈ˂̊͆΄ЉϐΌ0*ùíӆ҈ШэЏ;Ŀֽ܈ч҅ύЂхВч҂ф6煜ׂ֤̿ؐׄ֊׎B菧ɿǹįҌЄјЄуЅш҄ӆԄՃօ׈؋نډـ턗ΆʐȄLJƎŅƆ*ޛۄHɵǽN끍¹ƸηD󍣺낏ϿëԕD񌢹냐¼õϸ 6搨􀇏3¹Ѿõ ۂӂІƒÄĉňƃNJȆɋʅɄȊɈʅ2䂗򁉑~}%}ø̿¬~΅ͣ̑˂̜˅;ߊ~}~õĭЊ͈̂̆˅ʐ˓̄̄ͅ5~ᓘƯҤц҂ь҂ыЇA⋣邐Ļŷ®Σʆ˅ˇ̅͆·ςЄч҄ӎԈՇԀ텖~}¿ȄǃƇņĆÂĄ‡zŒ獏¿}Ľ˹}¸QȀ逌􁈐Ž~³}ɲ@ۀ񅓠~~ȹԼːF󆔢ɻư ;풨󀇎}5|}ɿ|˶ζ‡ÈąŃƊLJȇɄȎǓ/さ}|%|˽}̈́̅˦ʈɈʍɍʄ:݉}|}ëΆʌ˃ʍɚʓ6}ߒȾŮЉφЎτЂϢЋA灎ú~ö͈ɂʄɂʐʇɊʆ˅̆̈́΄ςЈщҍӂԇӀ넕}|ƅńĈÌ/匎݄E|üɸ|R򀇏û}|ȱ?}}ƷҺʏF~񅓡ĿȺĮ ;됧|2~{ǿ|Ǿ{ɴ̵…ˆÄąōƅǃƎǃȄɉʇ˄͈̆·υЂϕΊτ/ꆛ&ȽķDZԇҢфЂщЃђЄуІ=厥ꂏ󀇎¿ȺɱՈц҆шЂψЄфЏш҂х6痝ǹ̴׉ֆ׎քׂ֢׋A珧ʼDzԎЂљЋф҄ӇԃՄׄ؉يۇ@󉚰􂉑A¿̈́̃ˇʆɆLJƉŃĄŌ0ǐ푓E»оǽK΃¹ǸϷEი;ГD߂˴83ƾŻлӻ +قЅ…ƄÄĉŇƄdžȉɇʅɄȊɈʉ.䂖󂊓(Ǽ}µįυ̒͠˂̚ˆ̄8އʼи֔̆˄ʑ˓̖̄̈́ϋғфЎц҂њ҈B䊢遐żȺƱЫˍ̆̈́ΉςЄц҄ӉԂՄԊ?򀈐~}}~~~}~}9|¿ʄDžƈŅċˆ¯肃Ľ}о~ùJֆŽ~´}ʳ>~ǷѹȏC슟瀎񀇎ýǹ¬} +|~}4~ǿú~̶dz‰ÈĄńƈLjȈɃȎǒDž.⁕񀉑~(~Ż|®̆˜ʈɈʈɎʅ9܆ȺϷԇʈˆʌɔˆʖˏ̇͆ЊςВτЂϣЈA≡瀎ûƹİΊɂʄɂʄʋɂʅɋʆˇ̄ͅЇфҋӇA션}||}}}|}|7{~ɄƄŅĈÍ}恂¿~»|μ}Jԅ킎û}|ȱ>쉞~}ŶиƎGꉞ~Ÿ|,{}|~2}Ž~¸}ʵŲ„ˆÄĆŌƂdžƆȇǃȄɈʈ˄͉̃ΈφЂϓ΋χ.ꅚ&ȺɴӆҠшЄђЄуЅц8㊠ֽۉф҇шЂψЄтБќ҈ӄԉ׊ւגքׂ։؎ׂ؉׈Aꎦ¸Ϳ˶ժЊц҈ӆԄՄւׇ؄ًڇB􊞵7܄̈́̃ˈʅɋȂDŽƊŃąŌ7A¿ºíȽLۊºȹϷ>􎣺샐̽׾͒H򍣻턒þ̾ǰ)ʀ4ļɿѻ̸ނЗ‚ÆĆņƅDžȆɈʆ˄ʆɆȆɊʍ/ゖ}~%|ŷƱх̃͠ˆ̂ˋ̔ˆ̆>ہ򆓡󀆍~´Ĭˊ̈˄ʐˋˌ̘͉΃͆΃ϋ҆тЍцЅы҆Ӕ҈狡聏ބŽ˽ʵ̔˃̒ˌ͇̆΅φЄц҃ӇԎ=肖󁊒}}~G~}~}DžƇņćȃ:~C»¸ K㌠􆒞~Ž~ô}ʳAۀ򆓠}ŶϷčFڀ|}ŷԾꡍ +1΁쀌~}4~Ž}ǾлƱˆÄĈńƆLjȊɄȌǔȉ-⁕󂊓|}({ɾ~öŰ̈˂ʆ˄ ːʃ˜ʈ;ڀ}«Ήʄˆʊɠʖˈ͏̂͊РύЈтЄтЈшF加怎üɼȴʊɂʄɆʅɑʊˇ͉̄΃υЃцҍӇA灔񀈑||}~~B~~}|¿}|DŽƂʼnąÇ‰>}~K¾~~Ѿ~Kዞ򅑝}û}|ȱA~|ĴͶÌG󆔢{ÿ|öӼ蠌 +*̀}|6}ü|Ƽιů‚†ÉĆŐƆǂƐǂȆɆʆ˄͈̄ΈψЃϑΌϊ.酚'źʼ˶ӄ҆ф҉҈тЌт҇ЄЋщ9ᄛȹɱՏъχЂфЙѓ҃ӈҒӃԉנ֌׊ׄ؂׈؈C폥º´ϺѓІъАч҇ӄԈՃօ׃؆ٍڇ<H̅ˈʆɆȈǂƄņĘ;FŮǽL鐤ºȹϷ@ი˻ռɑD񀇎ʼì𦑊.ӄ򄏛0ºù˵ނЇŠÆąŇƅǃȇɉʆ˄ʇɂȉɆʍɅ.䂗|}(~øǺȳ̃͠˓̔˅̉8~탐~ɻз̄ˊ̉˃ʎˌ̂ː͈̔΄͆ΆϊІтІфхІы҆ӆ +Ӈ҄B抠灏ž|Ϲ}̓ˆ̊ː̈͆΄ψЄц҃ӆԎ;〕򂊓}~G~}~ԹȄdžƆńĉDŽB}>|ǿԾ$L򐤷}󀇏ļõ}ʲ?튟}¼ĹͼD튠聏򀇎|õк國 ++ς󀇏|.}ļùӾ̲…ÆĄƆdžȎɄȋǕȍ,⁖{|%}ƸƲЉ˂ʆ˄ʇˇʄ˄ʄ˜ʈ;}낏}ǹζӋˆʋɠʑ˄˓̂͊ΣύИщ@䉟倎ü{Ϳ~͸|̉ʆɄɜʉˆ͉̆΃φЂч҅Ӌ;~|}~E~}|ÿ}ҷDŽƄňąÇ…|~{þ~ŽӿӽM|û~³|ȱ>쉞~|·˺D뉟怎{ϸ㛊(́큍{~0|ºѽʰƒ…ÉćŐƆǂƌȆɄʅ˅̄͆΅ύЃϐΌό3ꆛ쀉%ȽͿ͸׈҅ф҈т҈҅фҌтЏы<ہ􇔢ռЊяЅфЙѓ҃ӈғӂԌգ֌י؉@쎤턓ûƸԾӅчЂфІцАъ҄ӆԊՂֆׂ؇مڋ<胙H¿پ̈́̆ˆʄɈȈDŽƃŇčŌ>FļƯúJ逌¹ɺϷ=􎤻샐ɾE󎤼þȺֿꠎ (Ԇ2ȾëѶ‹ƒŒńƊɇʄ˂̉˄ʑɄʎɏ,醞~}$~ƻɻɴ҇͘͏̉˂̌˄̉6聎}|ŭЊ˄̎˂̆˥͉̓΃͆ΆώЊъЌх҅шҐӈ@扟怎Ľ~ĶԾ͊̈ˌ̄ˎ̉͆ΆσЄц҆ӄԅՅ6}}Q~}~|DŽƃʼnĄÊ„CԮ||}~~>~~}|þ~ºӽϻ "而$ļõ}ɲǔ(ۀ~ȖË~ڀ}~Ͷߚ'׆򄐜}2~úɿ~ŭͳĄņƂdžȄɈʇɇȅǑȎǂƇ,煝~}|'}ĹǺdz̆ˆʅˌʍ˞ʋ6􎢸怌|{ë΅ʄɒɏʃˏʐˆ̄˂̆˒͈̄ΔςΈώЇф҈D䈝􁈐ü}µҼˤʄ˂ʈˊ̂͆ΊτЈц҃Ӊ6||~J~~}|ÿ}{ʈŅćŊCҬ{~{|}}~>}}|{½}Ѽͺ "~$»~´|ǰœ(}~Ǖ}~~~~A􇕣|Ϳ}˴ݙ)Յ􁈐|/}~ǽ}Ĭ˲‰†ÉĄłĄŒƄDŽƈNjʄˊ·τЄщЄχΆώ·1򃌖%ι؈ҋтҐфҊтЊфъ9󀆌ƸʱцЌщЃхИу҄щ҃ӎҊ҇ӄԌՔւՈ֍׆؆وC쌣섒ûɻîҍтЖф҅ч҈ӃԅՋքׇ؆كډ7R¿̄˃ʉɄȊǃƅŇćŏIڳAĿǿª KЂɺζ̘(끄ΚȏG򀇎Ƹһ垍 +.܊5ĺ˲Ҹ +‰ƒ‹ńƊɇʃ˄̉˅ʌɄʎɏ/􃌖|%|Ƚ˽ʵӅ̂͘˄͇̂̈́̃̆̌˄̊2񌟵~¯ϸҐ˄̖˥͈̔΃͆ΆώЊъЍу҆ш҆ӂԈӇB숝ýǺî͍̂ˏ̃˅͈̃̇ͅ΃υЋх҈ӄԇ7퇠~}N}~ƄŊĄÉƒHА||}~<}||ĻйŶ Hօ}ûõ}ȱʓٽ~}~C틠ꂏ󀆎̿|ɲӘ 'ׇ􅑝}~-}¹}Żϵֹ +ŋȇɉʈɆȄǒȌDŽƊ,򂋕{~'~{ǻɻȳ̅ˆʈˌʎ˖ʌ7}􀆌Ͷʇɢʄˎʐ˅̅˂̆˒͈̄τΑυ΍φЃχІц҉@ꇜ~󀈏Ƹ̉˒ʃˈʍˋ̃͆ΊτЈх҃ӆ6솟~}|}U~|Ŀ}ÿņĄÈ‰IΏ{~{|}~~<~~}|{Ŀ{úϷĴHՄ킎|~³|ǯȒ׼~}|}~~C늟聎˽{DZҗ(Ն򄐜|}-||ùʹԸ‰†ÉąłĄńƂNjƅDŽƈNj ̄͂ͅ΅υЇшφ΅ϏΉ͈,&·´ϺӅ҇тғыҊЋфь2遏dzԽ׌ЌтЄфЇґу҄х҃ӎҒӄԍՑօՈև׃և׆؋و@򌢸냑»ͿȲӅҔҊьҌӂԆՊք׈؅كچ7􋤽򂌕O¾¿˃ʊɄȉǃƆŊĂŋĆMՔ;־ʺ J܈􁈐ɺεϗ®@󎥽¿Ķηٜ (܋򀇏1ǿԺܾЏ‚ĊńƂNJȂɄʅˇ̊ˆʊɆʎɌȊ,ށ~}&|ʿ̾ʵ̍̄͝ͅˇ̍˂̍)숛á㹑~ۊˈʄ˄̈ˆ̊˥̏͂̆͐ΆόЅяД҅ӈԆӄ@~󀈏½˽Ȳώ͇͌̉̌͆·σЅу҅х҅ӇԆ3}~}W~}½~ԇƌņĆȃOȺ~||}}~8~|~żʰ~ԼJ办񀇎»õ}ȰȒ~}~}~@ڀ}ʽůɑ + +&ߊ~-~|·~ƒÄĂŅƈǂȆˆʊɆȃǍȅDžȄDŽƈǂȄ.܀}~|~%~{Ƚʼȳх˄ʆˎʐ˝ʆ˃̄,ꇚ~ Ḑ}ʋɃȄɗʂɑʆˉʅ˂ʖ˒͍̄΍τΙσІъҊ>쇛}ɻƱ̈́̌˅ʙˌ̈̓΅ϋЅщ҅5}}|~T}|~¾}҆ĈljRǸ}{~{||}~:~}{ſ}û~ȯ~Ӻ$ J㉝󅒟~³|ƯǑ~}|}||}}|}~@|ɻĭȐ )݉􅑝}~2}{}ֿ澪‚ƒØĄƏDžƌljʄ̆ φЊъЅχΊώΉ͊-䄛(ĹõϹ҇уґя҅тЏтЅч҂Ӆ*򌟵ɦ龕ыЄφІтЌчБтҒѕҒӃԎՉքՙփ׆؋ى>􋠷邐»´ͷԄӌ҆я҃ч҅҆ӇԃՅ֌ׄ؈م6灗XþًˌʆɆȈǂƆʼnÎĊPͿ9ϵ +M뎢ɹ͵͖@򀇎´ʳϕ *厥.ƾǼƬůЏÃĄńDžȈɃʅˉ̋˄ʉɉʌɌȉɄU鈤򂌖~~}};ɴ͛̎̄ͅˈ̋˃̎ 酗򆓠}Ե̆͘ˌʃ˄̈ˆ̊˦̅̈͂̈͏΅όЄѐъ ҅ӈԆӄ>퇚}񀇎~ͷ~Є΍͇̐̓̆̈́΃͆ΆτЄь҄ӊ7퇡~|~[~|þ~½~ƇńĉǃT˜}~}~:~}ƿż}׿ƷQ~ô|ǯǑ~}}}}~~~~@ꂐȻ«Ő 'ފ}-}ʿϴ̱„ÄƊǃȅɄʂˇʊɅȂǏȃdžȄDŽƈǂȄdžU臣}}|ʾ|˽ȳ˅ʈ˅ʑ˜ʅˆ%焖|Ҵ˗~˅ʈɄȄɖʄɏʇˊʃ˄ʖ˒̃͊ΌυΙσІъ҉=놙|ÿͿ}̶}ψ̔̎ˋ̈̓ΆϊЄш҇4놠큊}{}Y}{½}}ĿČȈRɚ|}|}<}|ľ~ú|վŶ N󏢶}􁈏~{ŮŐ~}|||} ~~}}~~}}}~}~}~@슠遏~~ǹď '݉~|-|ȿȽͲ˰„ØĄłƘǏȃɄ͈̄΃τЄт҆ъІφΊύΊ͉Ά)$źĵϹ҆цҎѐҝц҃Ӆ#ںӜ҈щІτЇтЌчЎҒіҒӂԋՉֈՙփׅ؋ى=􊞵灏ƷӼևӕӎҌӈԂՆ֊ׄ؈ه1\þ¾ˈɄʄɇȈǃƆňĄÂĆÂĆZР<ſŪ˼ + Hꁎƿȹ̴̕ H􏥽񆔢ǰ˔ '䎦.ƽĹԹѶ ~ЃÄŒÆ ȋɄʂˏ̊˕ʊɋɄȏ*܀~|&}}Ϳɳ̢͔̂ˊ̐恓탐ϣ͊̅ˌʇ̄˅̏˨̈́̌͋΅ϮхЂх҇ӂԊӄ<녙|¿~Ķӽԇ΋͎͂̊΃͑΅σІх҇ӅԅՄ/}}}}a}}½ĿŋĄÎ„X~}}4~}ýúͳԸ Eҁ끎}~´Ůǔ~}}~}~}~}~@|~ƹ־~ &݊򀈐}-~Ǽè潨„ƒÄƄljȄˆʂˆʉɐ ȆLJƍDžȄ+}{~#|˿|̽Dzҙ̋˛ʅˌ䀒낏ƿ͡~ʆˉʋɂȅɖʅɍʈ˂ʄˊʉ˅ʉˎ̃͆Ίτ΃ωΑτІшҊ=鄗{~}µѻ͉̍ˋ͍̄̃͆̇̈́ΆυІц҇2||||~_~|ľ|~ý~ŇȌ^󁅉}||~5}|»~¸̲~ҷ +EЀꀍ|ž}ĭƓ~}||}}|||}~?{}ŷԽ} &܉|-}ȿƻ§仧 ‰ÑĂŅąłƘnjȆ ͅ΅σВшЕωΊ̈́΂͏U⃚󀆍ƻĶθі҂ӎҜцҋ섗󇔢ƵէхҊцЈτЕыЅЅф҃фҋф҆т҄фҎӄԈՊքՂ֊ՐքՂք׆؈ي=񉝳倎Ŀɻ­ԉӎҊӃԏӂԉӅԃՆօ׆؆ه2䀖ꀊb½ľʋɄȍDžƆńć†ÌX5¼ɿӸٽ Hׄ򅒟󁈏žȹ˲̘?򀇎̾ìƒ'㍥-ƽɭ¬ ~ЂƒÅ“ÄńȆɉʂ˒̈˕ʈɋȂɄȐ+ꌦ}%}}ͿDZ͂̕Ύ͐̂ˊ̒~ҵݔ̅ˍʇˊ̐˭̌͋΅ϴЂхғ?烖~Ⱥ­Љΐ͊΄ώ΂ϊ΄τІф҆Ӈԅ/儙쁋}d}ýſſ}ňĈˇ_~|}~;~ƿ~ݾ  G⇚򅒟ľ~³Ĭ͔~}}~}~}~=݃򀆍}ŷһ'܉􁉑~-}ź}Ӻа„…ÄƄLjȄɄʂˆʄˊʄɄȄɆȄȆdžƏȋ(若󃍘􀇍|$||̽ửˆ̅ˊ̊˙ʆˍ}д~܅ʈˊʒɖʆɌʈ˂ʄˊʈˆʆˎ̄ͅΉτ΃ωΊ τІш҉<悕}~Ƹ΅͇̋ˈ̎̈́̈͂̈̈́ΆυЅш҆/ヘꀊ|~j~|~þĽ|dž]}{|};~}ľ~ɿ}׾۽ Gᆙ~ý}ë˓~}||}|}|}|}~=܂퍠|öѹ'ڈ򀈐}/|ȿĹ|ѹ~ίŽÑņĆłƈǃȅǓȄɃʄͅΊςЋтҊхБψΊ̈́΂͑*$ǻĵͶӕ҈ӊқцҌ恓׺ц҉цЉτЕьЅу҄фҋ҇т҄ыҋӄԉՉքՃ։ՊքՂք׆؈ى<톚􁈐ͿDzքԇӌ҉ӋԆӇԃӈԄՇքׅ؈ن/ꇝ󄎙d½ſľʈɈȊLJƇńĆĂÈd4žƼŦø E苞ĽǸɱҘ@㇧ʼ‘ (ጥ.ƽ˿ٿյ~ЃƒÅ‘ŇƅǃȆɆʃˆ̃ˆ̈̈́̋ˊʋɏȌɉ(큋􀇎~"|};ůՇ̓Ή͌΍͒̅̈́Ή +}ԉˋ̉˄ʌ˄̄ˈ̓˭̆̈́̇͆·ψЃѨҔӄ<􇕤|˽Ȳό΄͂·͇ΊψΊχЇф҅ӊ,늣􄎙}]|~ƿžȄDŽƄńćȌ[~}}~2}~ǽȭɵD}½~ëʓ~}}}}}~~~~4ℵ؍過õϸ (ڈ~,~Ĺ̰éąŅLjȆɌʎ˄ʒɄȦǂƄ(ރ쀊}#~{|˽î̄ˑ̄͋̊ˆʍˍ|ɋˈʕɖʆɂʆɄʐˊʆˈʐˆ͉̉Ήτυ΄ύК:򆔢{ɼưҋ͈͒̎͂̑΄χЅъ.ꉢ򃍗~|~T~{ſ}ľ~ļ~ɄƄȆ\}||}7~|ƿ}Ƽǫdz!|􁈏҄}~ɒ~}|||||||}~}~4֌瀍Ͷ벋 '؇󁈐},}~·ʯ¨ÈćÅĆŅćńƇǃȆǐʆ˅̄͂ΊςЈэ҃ьІϊ΄̈́΂͎Έ(懠􄏚#ǻĵʴӅғӂԉӍҋцҋЊтҊшЂύЇЉђЮѐ҄ӉԉՈքՂքօՄ֎׈؃ُ:惘򀇎õͷڋԓӍԂӔԈՃևׅ؊.TžüЄ̈́̄˄ʄɆȈnjƈńć͉\3ƿ¸ͱι*E瀍»ǸȯЗ7燺ޑȺԼ󸐉XߋƾɾҵȮ~~~~…“ ƆDŽȆɆʂˆ̄˂̍̓̌ˉʋɐȆɊR~󀆍||}̽­΄͆΂͔΍͑̆̈́΋Ίˌ̈˅ʌ˅̃ˇ̔ˮ͈̃̆ͅ·ψЂѢЂτғӅ@나؀ͷϊͅ΅͆΋ςΔψЄч҅ӈ.}~O~|ſ~»|ûȋǂȅDŽƄńĊnjT}:}ø}ѷ϶  F~逍}}}Ȓ~}}}}~~,җ~˴誉 +]׆~~¹÷ŨݷĆŇLjȆɋʅˇ̃ˊʌɄȥƉN}{~~{ʿ|˼ғ̈͐̄ˆʍˌ̆̅ɍʂˋʕɖʆɂʆɌʈˍʃˈʒ˄͈̊·υ΂τ΂φ΂ό΄σК8遗Ϳ~̶~э͑̋̓Α͌΄χЅъ/|}O}{Ľ}{¹~ƈŇƅńădžS~~|~<~||еε + C}|ÿ|οؿ|Ƒ~}||||}~}~,Ж􈙤Ϳ}ʳ樈YՅ􆓠􁉑}}~ç۶ÊĆÅċńćńƆDžǏ ˆ̄͂·Јф҂ӈ҄юЇω΄͈΂͍·ͅ'&ƻôȱґӇԊӊ҆ы҇ӉӉЖшЂύЇтЈђЮц҂щ҃ӊԈՅֈքևՂ֌Մփך8񅜽ބƸӼ؍ԒӊԂՒԍՃֈׄ؊/􀆍Pľ͊̄̈́̄˄ʄɊȆnjƉŃĈ̊T9ǿȽ׼ջ Eԁ󀈏ƷƮ͖,כňƸѹ '݊*Ǿȼʭ㼫„~~“ÆăŅƈDžȅɆʆ˄̄͊̅˂̇ˈʇɉȅɓȌL|~|˼ֿӢΉ͏̋͂΅̄͡ͅˈʐˇ̜ˌ̆ˊ̂˒̄ͅ·όϊЅЅσЄхҊӊ8~􀇍}ŷԽΆϘΉσІψώЃф҈ӄ,}~}O~ž~ƽŇƊDŽƈDŽƃńąĈT~}}}4|Ƚ׽ҵ + Bÿ|ؿő~} +}~}~)~ć‡~̿|ȱ⧈ 'Ԅ~*~ú¶Я‰…ÃĄƄŃƆLJȄɋ ͆ ɄʈɇȄDžƍǂƇǂƎL~{~}ɾ{ɻվҋ̗̈͑˄̌ˌʂ˔ʆɂȇʅɒʉɂʅɏʃ˧ʅ˅̆ͮ΅υЖ:}퍬|öҼΎ͐̆ͣ΅υЇх҄)|}~|J}ü}žżƄÄĒƅńăňP}|||~7~{ǿ~Ƽ~ռд Bރ~½{;ֽĐ~}| |}|}~%Æ}~˽{ǰᦇ (Ӄ󆒟􁉒}*}~׿ήÅċÅĖŅƅǒȅɄʅˈ̄̈́ΈσЋт҄ӂԆӂ҄фЂшЊυ·͈Έ̓΅͍LźŮٌԄӆԒӆ҂ѓ҃ӌҡхІϐЈъЂцЂшЎтУф҅ӆԮՅօז:恛ʼ¬ՎԐӆԤՄօׇ؅ل)䀕쁌Lüž¹ʆˋ̃ˉ̄˃ʄɅȄLjʼnćЄQ6ƾ·£׺F凛ĿŶĬʕ,Ɋȋ݁Ķζ請 'ڈ+ȿǻƧմ‚~~‘ÅăŅƊDŽȅɇʅˈ̃̈́΂φ΂̈́̄˂̈ˇʇɈȆɒȐK銦󄏚}~ɿɺӼҜ̈́Έ͌̐͆̂̄͠ˈʙ˃̄˂ʗˋ̆ˉ ˎ̃ͅΊϊЄψЇЄτЄшҊӏ-菶뇓~ȻîҌϕΉψЃϖЄх҇ӄ,}~A~}žǿ}ŻƈĉŒƆdžƄńĄÈ‡Q|~0~ǿ}طH튞|Ϳֽ~}}}~~ʽŮݤ,т󆓠~)~϶ּʬ…ÄąňƆLjȄɊʂ˄̄͆ ɅʌɆȄDžƍǃƅǂƇdžK牥񃎙~|~~}ȽȹѺ~ш̜̍͒˂̌˅ˆʂˊʂˈʅȐɎʉɂʅɆʅɳʅ˄̆͟΃͌΄φЕы/捵醒}ƹ­Ώ͐̆͞ΊτЂъ.|~􀇍}B}|üž|ŋÇĚńĄÄˆO󀇎{}2}ƾ|ٿ׶ I뉜{􁈏ľ̽Ի~}|||||}~}ɼìۣ(Ё񅑟􁉒}~)}¹~Ժȫ ÅċÅđƄŅƅǑȅɃʅˉ̅̈́ΈςЊу҄ӃԆӂ҄фЂшЊυ·͈ΐ͎MĹ؉ӂԅԖӊ҂ѐ҂ӆ҂фҢфІϐЈђЂшРтВф҅ӆԙՄԌՄֆז؊/򋗟ɳՏԐӆԞՊքׂ؊.䁙AüŽ˅ɉʅ˂̋ˇ̅˄ʄɄȈLJňĂ҇L2Žǻƥ޼C󎢸怍½ĵªǔ ƅ´ʲ㨊Xօǻϱ ‚~~~Б‹ÇƆǎȃɉʂ˄̄͋΂͆̌˂ʆɈȌɌȆɄʄɇJ燠~}~~}ǽǸϸ}ԣΊ͎͙͇̄͂̉̂̃ˏʓ˂̌˄ʑ˖̌˄̂ˆ͈̆ΈςЄφЏτІщ҂ӆ҃Ӗ%֑񌜣˾}ʴՏϑΌόЊтЊц҄Ӈ*}逋}A~ƾ~ɽ}ʼnĖńƂōƊŅĄąH񀈑|;}ŽŹť׶A}過}¿̽Ի𿏎~} }~䄘«آ&~*~|ż¶ԹħˆÂĈņƆǂȉɅʇˇ̂͆̂ˎʉȞǂƆǑJ憟}|}}~~|ƻƷͷ|Ӈ̂͊̂͐̊˂ʤ˂ʄˊʈ˄ʌȏɊʍȆɂʇɇʄ˔ʈɐʂˇ̇͊΂͋·͊΃ϋЏэЅ+Ր~ɼ|ȳ΢͈ΈςАυІу҅*||~H}Ľ}ǿǼ}‰ÄĂÖąŇĈĈF~{~d~|û~øäֵA|瀌|ʼҹホ~}|  +|}~プ֠'~􁉒}*}{û~Ҹ¦ÃĒłƄńƆNjȇˆ̎̓ΈσЄш҆ӂԅӃ҄тІъЂω΅͎Ί͆΅Ή%튤!·;սڤӊ҄ј҄т҄тҊх҅шІώЄтЄьЂϒЅҖьЌф҆ӆԆՂԊՈԊՃ֋ב؋ׅ+ܕöйզԈՄאօ׆؃م'䀘󀇎Büƾ÷ˉɖʓˊʅɄȇDžƈłĄÒ†G+ºʿʪݻ Nր􁈏ôĒ눜ǯݦ +&Ӄ)ǻھɫƒ~~‰ÇƈǎȃɈʃ˄̈͋΃͆̂˅̋˂ʇȌɌȆɄʂɌI~}~~~}ŻŶ~˴ӡΊ͉͇͐̂̈́̇̂͑̃̃ˏʝˊʏ˖̍˄̆˄͈̆ΒςЎχЈя҂Ӛ!уѺАϏ΍ψБш҄-}逋~~=|ǿ|ļĸ~ǑĞŊƋŅĄÈ„D􃌖|};}¹Ǽť׵@߃񅒟򀆍˼ѹ켎~}}}}}~ꍫ˻~ӟ +&탐}~(~ƾö~Ӹ¦†ÄĂńƏǂȈɃʉˏ̄ˍʉȜǃƆǎȆI߃쁌}|}~}}|ùõ}ɲѢ̋˂ʥʄˊʈ˄ʌɂȎɄʂɄʌɂȐɆʄˏʉɏʆˈ̇̈́͆Έ͊΃ϋЎюЂъ􆎎ϹӆΛ͇ΉτЈψЉ/|}}:~{ƾ{úö}ŗÄĂÄĆÔĈĈ +F򂋕{|~7~|ƺĤմ@ނɻз꺌~}|||||||}~錪ɺ}ў +S낏󁉑|}}ż}ѶÃĒłƄńljȇˈ̆ ψЅчҍӄҌъЂό͏Ίͅ΍φI懣ʻйءӋ҄ш҂ѐфҊч҅шЇϓЄыЄϑЄфҔьЍх҈ӈԂՄԆՈԊՃ֋׎؎ׂ؊ǹֿچբԇՉք׈ֈ׈؄,〘:Žʽ̑Ɉ˕ʊˌʄɄȈDŽƇѥĉ +C􀆍<ǿʪܺN冚׾أR󇔢úȼؽǪ„~~~~~~КƒÉăńƃdžȐɂʇ˄͇̊·͋̈ˊʔɎȆɊʉH쁌~¸³ůϋΈ͂΄͂Β͇̂̈̈́ͅ ͗̇ˉʋ˅ʏ˅Ɋʇ˅͎̆̅ʊˆ̆ˈ͎̈ΒϊЋё҃фъ҅߇ķτЍφΒωЉхшҌ*};~ºõȈńĒńƈńċńƊŊĂɃB퀊~-~ƽ}ɽťճ +@쉞}ɻ϶䱈~}}~ ĝ&過􁉒})}ȿ÷~ҷ„ÃĄņƇǂȄdžȂɈʈˈ̂̋ͅˈʊɍljȉǃƇnjȋI߂ꀋ}ĭ̺͜ˊʇ˅ʢɂʌɈȋɄʍ˂ʅˇʈɆʂˊʉˇ̆͂̒͊ΌφЊѠ݆öֿЍΓ̓ΆͅΉϒА,~~|~>}ȿ³ĕÌĎÊІ?~},}ļ|ǼãӲ@눜|ȹ͵㰇~}||}~ +Û'耍򀈑|~)~|ƾ¶}жąÅĂÈĊńƄńƄȉɃʄ˂͎̆΄χЃш҈ӂԄӈҊъЊτ΂ϋΉ̈́ΉϋH懡󄐜ȽǸ˳՝әўҎт҈шЂϤЍωЄь҄т҆ьАц҆ӆӎԊՌֆ׋؟ʽư׍ՔԂՆԅՉ֒א,킎;ǿƽȺ͈ʃɓʅˈɌʆˉʊɂȉǃƅńĄÇŠ@󃎙.ú¶ʩڸ +C򍢸耎Ի궋 +ɠ Tżɼؼũ‡~~БƒÈăŅƄDŽȍɆʆ˄͇̋Ή͌̈ˌʏɍȆɈʎK뀌ɿ~οͅΈ͂΄͂Δ͕͂̄͆̈̈́̅̊ˆʢ˄ʄɈʆ˄͍̉̋ˉ̆ˊ͓̇ΉϊЌя҄у҄шщ䐷DZԉЊχΒφЋяҏ(}~6~|żǾ~ŶDžƈłĒňƆňĈłƊŋĂɃ;}}}+~~ʾãұ A}ꂏ}ȹ~ׯۯ~}}~b苠򀉑|}~||Ÿҷ ̄„ÂąŅƈDŽȂdžȂɈʇˉ̂̈́̍ˈʉɄȂɒȉƈNJȊɆHނ~Ǿ}̽־͚̺ˌʄˆʒʈɄʄɂʆɈȊɄʎ˂ʅˇʄɊʃˉʇˉ͇͉̏ΊφЉѥ⏵ބưώΒͅ΄ͅΉωЂчЈ1|~}4}{ûŽ}õ˅ŇČ×ĐÈІ:~|||~,}ȿ}ɽ¢а +B|過|Ƹ}ծٮ~}||}~ 2犟~{|~*}{ȿ{÷~е +ąÆĆŅƊǃȈɃʄ˄̅͌ΆσЇш҄ӂԄӌ҈чЏτ΂όΈ̈́ΈϋK憠򄏛ĺĵŮԌӂҌӨыҘѢЂъЎχЄэ҄҈щЇҊт҄шҎӐԈՊօ׊إꔻ払Ͷ֎ՒԄՆԄՉ։ׂ؇ׇ؅.ꁍ7¹úʻ̆ˇʂɒʈʈɈʂˊʋȊǂƆńĄÆŠ<񃏚󀇏,ƽ÷ȧ׶ +D؀񅓠􁈏;ݴᴗ  + +)샐+ƽʽؼĨŒ†~~ …ÉĂŇƅǃȅɍʃˆ͇̏Ύ͈̄ˏʓɈȈɄʕE䆟뀌Ż|ʻѹ}՚Τ͉͌̆̅ˈ̖˗̃˅ ʈ˄̎͆̂ˎ͚̄̈͂Ύ͈΄ϊЎы҃фҎ҄ф쉠~ъ ψΉςЄχфЈѐҋ(~8~ǽ˺ȈDŽƕŐƅŎąńĂұĆ?}>~|Ļ˾Ϯ9თ􆔡󀆍Ҽҥ~}}~&↛}},~~}ú}Ǻӷᄁ„ÄćnjȆɈʄˎ̏ˇʂɅȅɅțLjȐɇF⅞~ú{ɺϸ|͏͎̂̃ˉ̌˂̌˂ʏ˖ʍɆʄˆʃˇʅɉȆɆʑˈʂˈʉˈʄ˂ʍˇ̆ˈ̆̈́΄ςΌφЂѫꈟ}Ϗ΍͒ΊψІфІф,~}7}ǿżɹˆƅŊĈÐăŇĤÇ<쁍~|E}{¹~ɽٿά򅒠~к~Ф~}| |}~&||~,}}||Ź~ѶńĈƅÉăń Džȉɂʆˆ̂ͅ΍σЇшҎӊ҄хЏϒΈ̈́ϏЇFꉣ񄏜׾ԛӆ҄Ә҄э҄фЌѐІуґтІς΅ωЂѐҕчҌу҉ш҄ӊ҇ӆԃՄւՌֆׄة򍤶֏ӈԒՊֈ׆؄׆؇)9ƽ¹п͉̅˓ʑ˅ʍɉʄɂʇɅȄdžƉ…;BķƥԲ ?燛ÑשX犠怎ȿ̿ؼæ  †…Å~~ЃƆǃƇǃȄɍʄˆ̐͊Ί̈́̄ˏʒɉȈɃʑ˂̅E憟끌򀇍Ǹ~ʳњ΋̓Δ͈͌̇̆ˇ̑ˆ̄͐̂ˆɆʉ˃̈̆̃ͅˍ͈̆̓͞΄ϊЎы҃фҎҊчђЃφ·ψψфЈх҃ӈ҆.눡񄐝~~1}ż}ǽij̇ȊdžƒŐƇšĆĆ 4}A~ƽ˾׽ƫ 4~Ùۜ~} }~&ԁ~~-~|żɼջᄁ + ȄŅƈńƂdžȈɈʄ˒̌ˆʂɄȆɆȚLjȌɊD䄞ꀋǿŶ}ɲЌ͔̊̋˄̋˂ʐ˙ʅɈʆ˂ʈʆɈȄɇʓˆʆ˂ʆ˂̉ʋ˂ʈ˄̊ˉ̄̈́ΎϜЄψЂφЈϔΌ͒ΊχЇфІф&釠}}2|û|ƼñǍƄŋąÉĂņăŇČ‹ˆć6|~.}Ļ~ɽּĪ 4퉞}—ٛ~}| +|}~&Ҁ󆔢}}~.~}{û~ǻӺ +ńćÉ„ÈĄń˄ˈ̂̈́ΌτЈьҎӏ҄фЇτЄϒΈ̈́ϐЊD쉤򄐜Ƽ̽и׍ӈԊҊӌ҂ӈ҇ю҃фЍьІх҂ш҆тЌφѐҒхӄ҈ф҈ш҄ӌ҈ӄԄՍֆؖׄֈׂֆ׈֔ՌԒՊևׇ؄׆؄&1ùɷҋ͆̆˒ʐˇʡɆȄDžƉѡ„>;¹öž˯ 3ꂏɝ᠏ +Vل􂊓¦ +ŽÅ~~Ђ'ֈ~|ȅɉʆˇ͎̐Ά̈́ʆˆʊɌȄɈʅ˃ʐ˅C뉢쁍􀇎ļ³ìφ΄ςΆϕΏ·͇͆̐ͣ̍̈˃ʈ̄˄͇̆͆̃̂̇̓ͅ΋̈́̄͋̏ͅ΂̈́ΆχЏъ҂фҕѓЄϐЎϒЈф҅Ӈ҅&䃜ꁍ}~2}ɿп˄ɎȇLjƋŐƊŜĉ 6}&~ǾʽҶ껧 0~~؞~}}~R}}~~}}|Ǿ̿ؽť +,Շ~}{DŽȋɉʆ˅̃ˑ̍˃ʄɄȆɈȉǃƆLjȏɐB鈡뀌ú~«Ә͙̂ˆ̊ +̉ˏʈ˄̑˂ʑɈʕ˂ʏ˅̗ˈ̄˂̄ˋ͉̂ΊώЂъЌςЍχϑ΂φ΂̈́΂͆ΌςΌφЄфЄ)ₛ逌|}4~|~Ǿ~ξȄdžƂDžƉŒĊŊĔΈ7킐~|)}Ƽ~Ȼе蹦 + 0}샐}֝晿~}| |||}~T탑||}~~~}||{ŽʽּãņĆÄƒÆ„ÇĄņ'܌̈́΃όЈюҐӇф҄уЅφІόΆ·ϑЎF󅑝ǸȱӓԓӉ҆ӊӌҡљ҂ђЈш҄ч҅ю҄ӌы҈ф҂ӊҋӃԈՊ֎ׂ؊׌ւ׍֙ՂֆՄԅՌւՌֆׄ؄ׄ)ꆡ񄑞򀈐6ǾĺijΎ͇̉ˆʑˉʜɉƄŇĄ‡9'úµػ𿫅  0܁􇕢ޢŎ &񁉑(Ļķ ʩ‚ÅĄÄĆÄŵ~~Ђ2Ĕ~Ήˈ͍̑Ά̈́ˆʆˇʉɈȈɇʆ˃ʎˇGƿ}̽Ի}ΒϑΌͅΈ̈́̐̐̓̄̈́̑͢ˈ̈͆̄͆̉̈́Ό͂̊͊̎͆΂̈́ΆψЎъ҂фҔьЂφЄόЎϊЂцЎу҆Ӊ'}}~/Ǿ¸Ͻ}΄ʆɎȈLjƊŎƌŚĊƂ7怐~}}*ȿȻ}˭߲ +,䅚􀆌٣ܒ~} }~ R신遏|}~~}}µ¢ˤ +1’}̇Ɉʈ˄̄ˑ̌˃ʄɃȈɈȒDŽȏɓA팥쁍󀇍ľ|˼Һ|ӟ͙̉ˈ̍ʈˆʐ˄̒ɄʄɈʧˌ̑ˇʄ˗͈̃ΊώЂъЌЈϟ΄τ΂͍ΙφЄх*||}0~ƽͻ|ɇȄdžƃLjƇŐĄŌĒĂΈ2}||~*~ƽ~ƹ|ʬݱ + ,ㄘסڑ~}| +|}~Oꊟ瀎{|}}||ǿɣ ņąÄ…Å…ÆĄŅ2ɗӇЊюҐӌ҄уЅφЈϊΆ͆ΈψЂχЏC􆒞ļóڗԂӆԐӂ҆ӊӌ҄ҍт҄ш҄ӑ҃ѐЈѦ҈Ӕ҈ъҍӂԈՊ֎ׂ؊׌ׇ֠ՄքՂԍՙֆׄ؅*候耍0ĺǽ°ӅυΎ͈̈˅ʏˋʖɊȆŅĆ„†2섓򁊒(ĺѲ巧 +ꉞߧ▬ +   &򏥼'ƽǺȧШ ÆĂÄŴ~~Є>닊}̐͆ͅΒ̓̄ˆʆˇʑɋʆʍˆ̈BǸ˳ΈςΒό΃͉Λ̓̊͌̈͂̒͐̂ˊ̆̈́΂̈́Μ͎Ύ͓͂̎΅χБцҔцЊςЄτϏЄς΋ϏЌф҅Ӊ$񄑞󁈐}2~żƼн}ʋɐȋLJƇŌƐńĆŎĈÈ 1灑򁊒~2~ȿ~ƸĤϪ$򍢸聎ʕ؍~~~ +}}}~~~}}~~} +}}}}~Mޅ~􂊒ú~ŸȪש +)}ه@銉~|ÿ~̄ʐ˔̊˃ʉɄɄȋNjȐɎʄAſƷ~ʲϓ͂Ό͑͆̊ˇ̕˅ʒˆ˄̎ːʆˍ̗˅̆͆̅̈˂̊ˊ̂͆̆͆΍ϗЏϢ΅τΈ͌ΒψІш$싥񀇏|/}ĺ~źϼ|ˉȅLjƄDŽƊŞĐ +Ƈ 1倐}5}ƽ}ķ¢Ω$񌡷怍ɔ֌}}~}| +߄ވ߆ +||||}~N݄}򁉑}Ķƨը*|׾ŇÊŇÅăŅ>񎎎҄ѐҏӊ҃фЂϊЇϏΊϘЊцAƿͽѸ֓ԂՋԙӋ҅Ӗ҆ђ҄ӎҗхҌӜ҄ӆԆӚҊӂԇӆԅՍ֗׏֋ՃԔՅքՈԌՒֈ׆؈$/ð҄ϋΐ͊̈ˆʍˏʄɆʎɈȈņĄÄ‹2텕5ĺ˽ɨկ$Йސ + O䈞聏˽ͮܮ $ކĂÇĂŴ~~~~ЂMô~~̆ͅΓ̓̇˄ʆˇʏɊʙˇ̋C܀󅑝ſ~³«΄ςΒό΂͋Λ͇͂̋̉͂̒͛̅͌Μ͆΃φΐ΋͓ΆϋАцғхЍЄτЂώЄςΌώЌх҃Ӈ%䂛~|-}ú}İ}̒ɓȊLjƅŌƐŃćŎĈÇ 2鄕}}/|Ⱦ}µֺ򾥟 +ۀ򆓠̧~} +߃މ߆}~M~􇖤Žɼ}ͳ䱛 -}F²}ſ}̋˔̊˃ʊɃʆɄȊǍȐɕʅA񄐜þ}Ғ̈́Ό͎͇̃̉˅̍̉˃ʇ˃̈ˇ˄̎˅ʈ˒̖ˈ̈̃ͅˈ̂˄̈ˊ̈͆ΐϘЎϊ΅͓ΆτΈ͌ΒψІх&ず~}{~-~|¸|ʿ¯|ʆȐdžƆDžƄŞÄĐ‰Å‡0烔||+~{Ƽ|Թ𽣝˦}}| ߂߄ގ݆ބ߅  +|||}~}}~~~J}򆔣ûǺ|˱Ⱊ,|ŇЇÄăņGȸƾӋ҈ӑ҃ѐЈύ΋ϐЂхЋш@⃙ſǸǰْԃՍԏԇӋ҄Ӗ҅ѕ҂ӎ҄тҊт҄уҐӗ҈Ӈԅӎ҃ӉҊӂԆӇԅՐ֘׎ֆՆԓՅքՈԌՒֈ׆؅\ꅟ탐ɿƻɵϐΐ͊̈˅ʌːʃɇʎɈȇņĄÄŠ2,úȺۿéҬ   Kقºҷ궟 +,ۀĂÇĂų~~~Љ֚BȾ}΅Ή̈́̊˄ʄˈʌɊʓ˃̄ˆ̌>僛}˼ѹτΆςΗϖ΃̈́̕ΰ͊̌͆΂̈́Α͊΂͋·ͦΆόЎц҂фҊъЖτЄόЄςΎχЕф҄W󆓡}}¸ǼʷʇɄʄɄȉɃȈLjƇʼnƚōąÇ‡/򂋕~&~ƽ̾~˯ܱ +鈝~Ɉ}  ߂ކߐކ܄ۇ݄߉ބ߆}~ H샒}ǿͿӹ񾟅 +5}ԘB~ƽ|ː̎˄ʑɆȇǍȂɈʆəʄA゚􅒞|ɺиΏ͉Ά̈́΂͊̈̈́̎˄̄ˉ̋˅̄˄̢˛̍˥̅͂̄͊̆̆ͅΐϗЋψΊ͝΋͎ΈςЇύU񅒟|~|ƻ~ȵ͏ȝDžƋŊōĈĐÆ‡0􀆍}&}Ż˽}ɭڰ 燜}LJ|߄ވ݄ݎ܂ۍۈڃۅ݄ޅ݅܅݆ |}~ H낐|Ž˾Ѹ𽝅4|~ĆÌ…ÃĄŅƅ۞AúӄҋӐ҃щЄφЇϋΊτчДц?뇟􀇎׾ԇՇԄՂԋӆԅщ҄ӆ҆Ӑ҂ӆ҂әъҖӐҘӄ҈ӂԓӂԅӅԅՐ֗׋ֈՋԜՋԊՇփׇ֍#2ǽ·ϼ·ψ΄͊΂͈̈ˆʊˈˑʍɅȇLJƃŅĄÆ‡0&¸Ķгᶣ遏Ό K󇖤򁉒ļŷؾã4ij~~~Љì넄E~}|¾|ʿΈ̈́̊˄ʅˇʌɊʒ˅ˈ̌A쉠}~Ķ}ٰΛϖ΂̈́̉Ί̈́ί͆̉΄̈́ΐ͊΂͌΅ͧΆώЌя҇ъЖσЅόЄςΎψЖY煝񀇏|}Ĺ˄ʇɅʄɄȎɅȅǍŌƘŊĄÇ‡-⁓~(~ŻȺȥ +лᜈ} +߄ވ݄ݎ܃ۅڂۄڂۈڃۄ܂݅ބ݆܃݆  }~Iᅛ}Ķ˥ >|}ӑ郃?~}|{{ɾ~ъ̎ˉʏɆȅLJȂɅȂɉʆɚʃɅ;ꈟ|}~ô|ׯ֐͇΅͆̉̈́̍ͅ˖̂ˌ̄˄̄˂̅˂̓ˢ̆ˈ͇̃͛̍͆̑΄ΉϘЊχ΋͝΋͊ΕφV儛~{~~|ȿ·оɑȗǃȄDžƋňĆŎĆÄĎÆˆ0ဒ~󀆍}(}ùƸؿǤ + κ|߈ނݏ܋ۆڈل؆ڄ݄܉ۃ܇߈|}~J߄~ǿ|µɤ +<{|ёĆÌ…ÃĄŅƄDZ񅈆@ÿź؈ӆ҂ш҃ъЃφЇωΌςЈцЙхЅ:򍤼逍ʻߵݓԆՆԄՂԋӇԄӄщҖӉ҄Ӆ҃ӢҠӍҤӅԃӄԊӆӆԆՄւՈ֘׊ֆՌԍԎՐԊՕֆV퉡샐ƼɾűЅςΊφ΄͒Ά̈́̄˂̔ˆʂːʊɄȇdžƅņăDŽ/脗󂌖'Ϳƥͩ + +砈 +߂߃߂J戟ꃑƾɻƨЩ <􀇍ّIJ~~~ЋáC}öҏ̈́̔˅ʈɍʆ̇˙̈9̹~ӄΘυЇϗ΋͙΂͆Ή΄͂Θ͑΍͂΅͉΂͊΂ϊ΂ͨΔϊЌѐ҄шДτЇχЄφ΍ωЋщR񅒠}}ʶ͊ʂɄʂɉʍɂʐɄȊLjƆLjƘŊćÄ0񋞲}})}¹~õϳ綟 ұ}}} +߅݅܆ین؆׉؍׃؅نچقڄ ݇ }~K}򁉑»ȻȭݭJ~ޒ +C~|ĿЅ̎ˈʆɂʆɅȃNJȈɢʂˑ6~~˷}҇΍͐Ί̓̉̈ͅˇ̂͋̅͌̄ˎ̂ˊ̄ˌ͊̇˘͈͈͎̐̄̈̕ͅΌχЅчЇωΉ͞΄͂̎͆ΐφ%|~0~|Ǿ~ɴɎȂɇȆnjȈDžƛʼnĄÉĎȂ.|􀇎|~(|}~Ͳ崝 Ѱ|||ބ݂ܒۄڅل؅ق؉ՊքׄւՌօׅ؂نه܄߄|}~H|􇖤ǹƬܬ B}~ܑČĆÄĂŅȦFȻӑёЅφΊχЊфЦ6탏ҾٕԐՆԅӅԆӊ҆ӂԌӄ҈ӆҋӄ҅ӆҕӊҚӌԊԐӇԈӓԍՌֆׇ؆ׇֈՊԍԐՄԂӎԆՐև$+ŻǻлЛό΂τ΄ψ΄͊̈ˆ̉˘ʉɇȃDŽƈńć +/)ȾȺԸ + ص +ކ݆܉ݍ܂݆ކ߆"I؀Ͳ㱜EŎIJ~~~ЇÄ~C~ſ|ȻЈ̓ͅ˅ʇɊʊˆ̅˜̇ˆ1ပ킎󀆋șДυΘφЊϊ΂ψΊ͆΂ϊΆόΆ͂΄̈́Ά̈́Ά͔΍͗·ϢϋΖχЇѐ҄шДτЇφЈψ΍ϐЂфT腛}}}}ȿ~˿~įˎʂɄʂɊʌɂʄɄʈɄȌdžƆLjƛŋĄ-熙}'}ɿ˽¥̩"~~}ބ݂܊ۂچۄڄن؂ل؆׆փՉքׅՋօׄ׉هڄۂ܅ }~J늡섒~ĽϷ򺜔  @󁌔}|}~~}D}ý{ǹΌˈʂɆʆɅȃDžȍɘʊː1끍Ǘϓ͂Έ͐Ι͇̂ˇ̅̈́̌͌̂ˎˌ̂ˆ̍̈ͅˋ͈͈̂̒̆͆̉̓͋̚΋φІшІϊΈ͌΂͈͐̎ΎχP愚|~||~~|Ǿ}ɾ}®ɗȂɟȅŅƕňĂÌĎÆƒ,慘|~P~|Ǿɻʧ~~}}| +ފ܄ۃڊقڄم؍ׄ։ՇԎՋԃՊ׆؄چބ||}~G鉟ꂑ}ü̾~͵𹚓 @򀋓|{|}}~~~ɐČĆÄăŅȈCľՋ҅ъЂцЄτ΋ψПхҒ0焙󅒟Ν֘ՍԐՊԄӋ ҈ӄԆӊԋӃҎӂҊӄ҆ӄԈӊҖӍԉӄԎӇԅәԌՊֆ׆؈׆։ՉԌՂԐՂԄӎԉՍևO聎ĻŹɴјςІψ΅ψ΄͌̆ˇ̊˙ʊɄƉńĉ+퉝'ݳǩѭ  +߅ޅ݂ބ݆܆ۃډۄ܅ڋۅܓ  F񎥽󇖥󁊒ûŷռAōı~~~Ї!ÁˆE¼~ȸϏ̃ˈ˅ɏʆ˒͕̌2쇛򅑝ݠυΒϋЌςΊϒΉόІύ΄͕ΉςΆτΌ͆ΆωΉτ΄ϊ΂ϒΈςΎς΄ϔІч҇яКυЈϐΒςІτM􍤼낐}~~~}}}ȿ~ʾҿ·ʂɔʂˎʈɌʅɉȓLJƈŅƓŅ+߁}~$~ƼĶδ鸞~} ܇ل؆ׂ؄ׄԅՇԄӉ҄ӄԅӃ҆ӆԂՆӈֆׅ +݅߉ +}}}~Hۂ~ſ~ŷֿͥ ?~ }$ɈD~}Ʒ͆˔ʃɇȓɃʄˊʘˇʉ*ꆚܞߎ͆΂͌΄χΏ̈́Έ̈́̍̓΄ϊΈ͉ˊ̆̄ͅΌ͆̂ˊ̒͂̄̓Σ̓͆Έ͎ΊϑЈχΈ̓Έ͍΄͍̍͐M򌣺遏􁉑|}}}|||ƽ}Ƚѽ͛ȈɘɈȃDŽƂdžƆņƆŜĈ„,݀|}$}ĺõ~̲距 ~}|߅ۇڄ׊ֆՂԊ +҄тЇч҂ч҇хҌӃ҈ՄւՆ݆ޅ |||}~Iف}Ľ}öվˤ @}~|ďˆÆĆ"ȄфKͽҕтЈτІϊАїҋц*򊠴ԅԉՂևՑԃՈԌӊ։ՉԈӃҋӂԈӄԄՌԆ҅ӐԄӄԂՏԃӍԇӓՈԎՊׇ֑ևՈԂՊԌՄԎӍԇԇ#񆔢&Ļ÷İԜυЎφ΍υΉ͒̋ˇʇ˒ȅDŽƈņăŊ2兙󀇏%ʻԸ𽢄 ބ݅ +مچل؊ׄ؃م؂ل؄׆؆قچق؇݅܅ބ + +Kᅜ肐ĽʼĨҩ ?耐ıł~~~І*ݴC~|ξˉˉ̂ˈʄˆʋˏ̖͎̇#ݠΓτЂόВςЄτ΂χΉςЄъЈψ΄͉΃τ΄σЍχ΄ͅ·ς΄φ΅Ўφ΅ώΠϔЇц҈яАΈφІϒΆςΓQ䀕󇔢~ȿ~ʽϺʈɔʃˏʆɎʄɋȐǍƄňƒłĄÄ…-}~~<}¸|̽ͦ~}߄ۆڄق؄׊֊Ղԍ҄тІш҂ш҄цҍӃ҈ՄւՆ ܄݃އ }}~F󏦾󇖥񀈐˽ȯ㲗?}|*ܲB¿}ƾ{̼͐ʅɃȔɄʅ˄ʍ˄̍˅ʉ(۟~Α͇͌΄χΉ͆Ι͆ΌτΌ͉͇̓΋̘͒̈́Ξ̖͇͂·͎ΊϑЍφ΄͂Έ͎΄͎̔͂΄̈́K򆓡}ƽ}ȼ͹̟ȈɓȄɈȊǑƅőŌĄÄ„.|}}=|{ʼ׾˥~}| ߄ބچمօՄԄх҇фЉτЃфЃъЈф҇ц҂ӄԆ چۂ܈||}~H񍤽񆕣ſɻƮᰖB|{~ĐˆÆĆ)㹺A¿ŽóԔтЈυЄϋ҉щ҂ӎ҈ш'ɃՒԅՂԌՃևՄՋԄ՛ԅՋօՊԅ҉ӏԆՌԆӂҊӒӅԄ՜ԈӒԆՈԎՊ֑׍ֆՐԌՅԎӔԂՄԄKꄙ󁉑ĻöӟφАσΐσ΄͂Ά͐̍˃ʉˎʂɄȄDŽƉņĂÆŒ`ပǽôŨҪ +߄ނ݄܊ۊڂٌ؄ׄևՂևׂօׄֆ׌؄׈ڄۂچ  Iƿ´ʹ鶛>ı΂~~~У.³A}ȿϾ͐̎˃ʇˆ͇̂̚͏̈灓ώОυЏτЎчЉυ΅ςЈψЄ΍ψ΂̈́ΆςΌϒЌ͈ΘωЄшЋьҊъЎς΄ЇτΆ͌·σΈJ}񀈏ǿʾ͹̇Ɇɒʄ˘ʄˉʋɊȋǝƈŃą0}|󀈏}2~ǽĶ~ʰ䴜~} ݅܂ۄچ +ՆԆӈ҄цЏχ΄͆΄͂ΈψЄфϋЃх҈ӆ +نڂۆކ}~Sᅜ肐}}õйş D}~ԇ0Aþ|ƾ~ν̇ʇˇʇɊʆ˂ʐˊ̅ʐ˅'倒~Έ͈΂̈́Άϊ΂͆·͓·͊΅χЄψ΅͂̇͏΃τ΅͇Ά͋̄Έ͜΋͉̈Ά͎·σΈϔЉϓΈ͊Έ̈́̂ˈ̜K솛|ƽ~ȼ˸ʑȆɂȅɅȌɂȅɇȏɃȄDŽȇljƎŃĎōĂÅ-|{|~I}żô}ȯⳛ~}|ۅڃن؂ׄ ӇҊцІχ΃̈́Ά͆̈́̈ͅ·τΊφЄׅ҇ޅ߄߅|}~G恏||θ~ĝd|}~Ҿ8ǸBżò҈ф҅чЂшЌу҄ё҄ӈ҆ш҅텗킏őԈՂԅՅ֊ՃԄՉԒՈԉՅևֆՆԄӆԐօՅՅԍӍԚՋԋӋԂՊԎՆքՈ֔׉֏ՈԊՇԄӄ҉ӚK􋠷灎Ļ÷ҾчΔςЄχ +ЋυЊϊΌ̜͊ˈʃɅƌņĆʍ-ۀ뀊?¸ʻϵ깠߆ +چم؉ׄֆՈԂӄԆӆ҆ӄ҄ԉ ԊՄք׈؆ +ކ߂G牠򁉑Ⱥ־ʣ +DꀌĄÂąðׂ~~~2|}~?~}}|}û~˹}ΐ̍ˌ̂̈́̔Έ͋̋ͅ󇙬킎ĘۖۢφЂъВςЄόЌφЅх҉шЍϔЌςЅύΆςΆϘЌ͈ΘόІцЇ҄ьҊяЈσΈςЇυΆ͒΄ψK聏ƿ˿̸͋ɚʅ ˋʅˊʄɌȐǖƈłĆT~}}¸|˼ӺǢ ~}ۄڃهׄքҊцІψΆ͈͆̂̄͆ΏσΊςІш҇ ׅޅ߉ }~C􂉑Ⱥªܭ >򆕣}̈́ 迈0{|}~>~~}||{ľ|¹}ɷ|ʈˌʆɈʎ˄̃ːʐˈ򆘫끍—ٔΐ͌Έϒ΂͙΅͉ΆϋІϊΉ͏΄υ΃͋΃͊̄͂Έ͋ΈχΈ͈̉ +̈́΂͆ΙϕЊϒΈ͊·̂ͅˇ̛I󌠶怍󁈐Ž~ɽʷ˄ǐȏɄȖɄȄɂʊɋȇLjƠŋĂÆV~}|~~~|{ɺѹ~š ~} ||| څق؆ׄքԄӂҊчІΆ͏ʍˆ̊͆΅͉ΆτЅхֆׂ؅݉ޅ߉|||}~I򀈐ĿǹڬC󀇎|ˆ搽ĔˆÈ0Ɵ?оԄх҈шЈш҂ђ҈ӄэ҈􆒟ɜԈԄՇ֒ՂԘՆԊՅ֋׆֊ՉԏՄքՄԉՅԋӍԐՈֆՈԋӇՊԆՙ֔׋֏ՈԊՆԅӄ҇ӉӐIĻķѽҋΔσІϋЂτЊχτЄτ΄Έ͐̅̌ˈʂɆƍņĆщ'(ǽٿ̦ ߂އ܄ ؆׊Յԇӆ҂ӆЍц҇ӆԄӊԄՅևׇ ܄KǮⱘ >҇ďð~~~Ѓ<Ȍ|}~<}~|ſĺ̉̈́̈ˈ͇̕΄͂·͉̈́̐}􆑛}ΆφΈόЂѶЂφІђҊюϚЃχΒІч҄щІϊΖόАц҈ҍэЉτ΅΄ϊ΄͠L~턒ž̹Ȋɍʅ˂ʝˇʊˊʌɄȆǂȈƄLjƈň*ڀ쀋~;}Ƽ³é׫~}}}ׄքՆԂӆ҃чЄφΈ͂̔ɄȄɇʆ˄̈ˈ͇̈΅ύцԄՃքׄمڂۄ܄ݍ߄ +}~F䇞섒~~˴>݄%<Ƌ{|}~;~|}{ľ~¹τ˃̅ˆʂɆʐ˛ʐ˄̆|򅐚|͉͂̕Θϊΐτύ·ωЊцЉςΈφ΄ϔΆ͂̅̈́΄ΆύІψΓ͉͊΍τЂώЄχЈψ΃υΖ͑̋͋̅G}냐ļ˿˷ʈȄNJȞɂʓɃʉɉȎǐƒŊĂÇ+~};~|Ļժ~}|||ׄւՆԃӄ҃цЄφ΄͈̎ʆȆDžȇɄʂˈʇˈ̆͆΃υ΄τ +ԅՄׄ؄څۆ܆ބ߄|}~C↝ꃑ}Ϳ}ɳ <~݆'¿ƉÈ=ΐ<ľƳօӅ҅цЅяҖӄ҂ѐ҅Ӆ聐벀ӖԈ՘֋Ս֒Շ։׊؆׋ ևՃ֔ՄԅӅԂՋԃՇ֌ׄ։ՈԂӎԄՃԉՌք׃֍ׄև׈։Ղք՗ԒӉԍӄI邔􇖤ûƹҾ͍ΌϦЅϏЊό΅̄͐̉ͅˇʈ ĆńĊЊ+򄏛9¸Ǹȭݰ +܄ۄچق؆ׂֈӌэІΆͅ·τЂъЊш҆ӆԌ لڃۄ܄ޅ߂ Eꋢ򇖦􁉑¼ƸѹĞ  ?냒%°~~~ȂЃ?}~|~>~|·~Ʋ̈́̅ˇ̏͂Ά͈΄͂·͇̓̑샒ϊΆφΆψЂф ЇэЋіЇщ҈ӆ҆щЂўЄυ΅ςЌςЇь҃шЊςΚϋЉу҅цҜэЋτ΂ψ΄͂Ά͞E联򆔣}ý¶λ͉ȊɌʦˆʊˊʍɏȎLjƈň Pᄜ񃏛~~ȸʱ~}لׂքՄԆӂ҆уЇτ΃͈ː ȄDžȇɅɅʈˈ̆̈́ΐԄׅ ۆ܉߄}~FЊ}ÿǹվܬ?ꃓ󁉑*?|}{|~8~}{ž}ıЅ̃ˉʇ˂̆ˍ͎̐ˉ̇ꂑ͇̈́̔ΚτΘϋ·υфЌъАφΆψΈσΊ͉΂͆·ϏЈφΒ͖ΎτЂώЄφЈφΆτΔ͔̊͌G怓|»͹˄ƆǂȄdžȚ +ʄɃʋɆʎɆȋǑƉňĄÇ O􁈐}~~}ȾƷ~ɯ췙~~~}}}|Ԇӂ҄уЇσΆ̈ͅ˄ʄɆȄɊȂLjƄdžȄɈȄɆʈˆ̇̓΅̓΅ф҃Ӆֆ؄كڍۂ܄݂ބ|}~GΉ|󁈐~Ƹӽڪ >邒񀈐,¾ŊÈ@2žǼ˷ׅӂ҄фІяҘӄ҂ѐ҄ӆ򆖩ԈӔԇՙֈ՘֋Շօ׌؊אֆՆֈՇքՋԈՂԆՈ֎׈ֆՒԌՂԉՍքׂ֎ׄֆ׈ևՅփՕԄҐӇԏG򀈏»ȻΆ͋΍ϨЂϐЊώΏ͎̇ˈʈ Ćńĉю'爠#żͽе󽞅 + ބ܂ۄڄم؂ׇւՄԇӃ҈фЄυ΅ϊ΂͈̄͆΄χ΅φЇч҆ӌԄׄ؂ل܄݄DՎ恏;ëᰖ + +nƆ¯~~~ςЈ I}}5}üƼƲ҄͆̌Ώ͊΄̘̓ͅ΋ӄόΑωжцЈцҐӉ҉ъЉчЄшЅυЂьЂъ҂ӈ҅щЋϝЊъҤфЅхЎς΅͆̉͏΋Fނ~|Ź}ѾɇȊɌʒˈ̉̌ˆ̌ˈʖɊȈdžƆŊĄÂ„M鋢~}~~~}ú~ͽѸȡ~}߄݅Ԇӄ҂фЈ͌ʆɂȊDŽȈnjƇdžȆDžȉɆʃˆ̂̈́̊͆΄ςЄԉ +نڅ݄߅}~<}푣~|ȲÛ  넕}~|||}I빾|~|~9~~|º~ź~ıˆ̆˄̅ˉ̂̈́̔ˋ̎ь͈͂̐΍ψЄςІЄσЄЌςΈτЊъҌтЈυΝϋΉςΆψЋхЉυ͚ΏϏЂψІτЂτБχ΄Ή̓̏ˎ͏B݁􇕣}Ŀ{ķ|ϼȆǂƈNJȍɠʇɊʐɊȐLJƈńĆ̂M犡}|}}~~~}|¸}˼Ϸ~Ơ~}}}|||߅݆܄҆υ ̆ˇʂɅȄǐƃŇƆńĂńDŽƄłƈdžȆɄʇ˄ф҄ӈ֊ل݄ޅ|}<~~~|쐡}̾{ư  郔|}{{{ÿ ~|ޕ…Ä„ÂĒÂĆL=˷҆ъ҄ӍҍӘ҇ӎ،ԃӏԉՌօׅւ׆ׄւגւՈք׉؋ٌ؂׈ֆ՘֌ՉւՆֈ׋؅׈ֆՆԜՍ֏׃ևׇքבևՎԂӆ҃чҞB䆛􁈐˾ïυ΅͊ΊύГфЄщЈяЅϕΊ͈̆ˆʊɄȂDŽƉŇă˄Ȇ (/ɿóֽͥ + +ن؄Ո҆хυ΄̈́̂ˊ̃ˇ̆˅˄̈́̄˂̈͆ΆσЋф҂цو +ކ>ŷͶȟ  +w񈙫¾曅„ƒï~~~~ІR뎐}~3}ļɽ~¯|΅̌͂Ύ͊΄̖̈́ͅΏϏΑωВт҆Ғт҄тЈх҉ӄԂӄԋӃ҈цЊфІяЉтІцҌӆ҇цЇϟЋъҦтІшЌς΅͇̌͋΍>􊘦~~ɼ¯}ʆɈȊɌʋː̇˂̋ˉ̋ˇʔɅȇDžƆŋĄVꀌ|}~~}ż³׾ש~}}ߌ܄ӆ҄ω̌ȅNJƃljƊŇƃljƅNJȅɃʆ˂̄ˋ̅ ф҅Ӈ֊م݅ބ߂}~@ТǹӼ߭ F焔~|}~~7~}||̉O鍏|~}~3~|ºǼ}{̈́ʂˇ̂˅̅ˉ̂̈́̒ˌ̑͂Ώ͂̅̓΅͋ΌϱЇυЈѐ҈фЇσΞφΒσБцЉϏ΄ς΄υΐώЃψЇ БψΉ͂̐˞B򉗥}¿}ǻ|ȐNJȌɎʂ˞ʐɊȄdžȎǃƇńĆ͂Z􁉐{|}~~}|Ļռը~~~}||߅ޅ݄܄цЂτΈˆʄDŽƓĄŇĄ ƄŋƃdžȃɌʆ˄̂̈́Єч ֆׅڄۂ܆|}@~~Ρ󁈎~ŷҺݬ  + L惓~}{|}~~}~7}|{ÿ~{¾ˊÆĎĆS񒔗4÷ȴӅӆ҄ӌҍӕҊӑԂՏԃӄԃՆԊՌ֛֍ֆ׋օ׈ؐو؄׆ք՞ևՒփב؆׈֔ՂքՂֈՏ֍ׅևׇ בֈՍԂӄ҅чғӃ҈>½dzχ͌ΊϋЕфЄшЊѐЉϑΆ͆̅ˆʋɄƉŇĂÅ„ɝ%񄐜4¸Ƿéܭ ؆ԉц ̈́̆˂ʊ +ˆʆ˄ʈ˄ʂˋ̃͆΃ϋЌфքׅ؇ۊޅBզ̾屔 H툘􃌕7½Ҋï~~~~ЇW}|}1~|ȽϺΊ͂΄͂̆͊ῌ΂͆Μτ΋ϕІт҄Ѩ҄Ӎ҇ӅԃՄԈՄԄӄҐ҄хЛу҉ӅԂՇԄӄ҈ъЙуВц҄ф҂хҟщЄχΓ͆Ε>㕽~dz̉Ʉȏɍʈˍ̄̃ͅˏ͇̓ˎʊɄȆǃƉŅ „ S􅑞||ǿƷê峘 +~~} +܉؄Ԅӂ҄̆˃ʆȅřňĆ…ÒƅŇDžȌɄʉˆ΄φЅцԈׅڄ݄ބ}B~~~ǚӄǰǟ?}}|}~A~~||~ډZ|~{~|~/}{ǻ͸ˑ̆ˇ̂͆̈˘̐Η͘ΉϐЍтЎтІЈшҐӄ҆хЅυЎσЍυЇ҇҄уЋτΈςЌςДϚЄφИτ΅ͅ˄̇˗̂˄̂ˈ8ᔻ}˿Ų~ʄǃȉǂȄDŽnjȅɉʇ˖ʌˆʐɔȅƇŅĊÄ„ +Tބ򄐝~{{ƽĵ䲗 +.~~~}}}|||߄ކۈڄل ӄЄ̇ˆȄĄÄšÃˆ’ÍƇljȊɉʅ͇΅φ҅ӄԄՂֆۅ |C}}}~~~ƙ҃̾Ư~Ş ?||{|}~A}}{{þ}؆…ÈĂËĈX3Ǿ¶Կӆ҄ӊҎӈ҈ӄҌөԗՉ֐ם؂׆׈؈ّڃن؄ׇׄքׅփՆւ׏օׇٍڂل؂׌քՉ׌ւה֚ׄֆחևՆԄӊҋ҈ӄ҈8Ź̸ъ΂͐ΌυЌц҆тЎш҆ѓЍχ΃͆̄ˈʅƈŅĆ̅ʈ– W戡ĺ˼Ȯ뷜 +" ݄ل؂ׄ ҇ц΄ʄɅȕɆȊDŽȒɇ͉̇ΊψІӄԇՄօو܄ 8͞وŷ͵̣  @〔􃍗A½߆¯~~~~Ї]}}~.}Ļƺİ}ώ͂̅͋Ύ͂Ά͎΅ΡϒЌю҄҉ӂҋӃҋӅԒՂԆӃҏцЙф􂋔ԅӃ҈шЖтҚф҄ьҟшЃφΔ͇Ε̈́΅3Ԃԟրĸ͹ɄȈɂȐɍʇˌ̆͆̂ˎ̈͆̔ˌʃɅʄɂȅ… V񏨾|ʺ~ǯ򽛎 $~~~}}} ߇ۇڄلՄԂӄ҂фˇʃɆDžĖÄĊˍ¡ŅĆƅǍȄɎʆ͇΄φ +ӄԄՂֆ +܄݄ +}~,Ӳ~ǹԼ純  +6툛~}~G~|þ}ȰԆ _|~~~|}~.|úĸ®|΍̅ˈ̂͆̆˙̩͔ΌύЧҐш҉ӅԄӃ҄ъЂψІΆυЃτЄϊ򁊓ӄ҄фВσЋσІυЄϛЃφЛσ΅̃ͅ˄̅˘̂˄̂ˋ2ҁӞö˸ȇǃȇdžȂDŽnjȅɈʐːʐˊʂɈʄɅȃɋȅDŽʄńP~Ǿ{ȹ}ƭ𻙍~}||ޅ݅وЄτˈʄɅȃdžƂDŽăɆňƉNJȉɆʂ˄̆̈́·шԄ ڄۂ܄ބ|}~)Ұ}}ŸҺ岓  8뇚}~|}~D~}{~|Ư҇…Õć^0˿ɴӄ҄ӉҎӉҘӨԔՌ֍קُ؈يڈم؉׃և׆ւՆքׄւׅֆڄلדւ׌փ׆օ׈֚ׄֆכփՄԅӅ҂ӆҎӃ҆ӄӄҋ6نڤ܃ʽӾ͉΂̈́΂ϊΌτЍц҆тЎь҃ѓЍΆυ΂̈́фƈŅćʆȃŠ……XżϿͳž *߃ބ ؅ք +чЄυ΃͆̂̈́ɄȅǕȇljƄǒȂɄȆˈ̉͊ΉυЂф҆ӄԇׅ؅ۆ +-?ٷ̾ 8󋟵񂌖Dþ͵ن±~~~~Ѕ]|~~}*~ĺ˿ɵЎ͆ͅΈͪΐτΊϋЉт҇цҕӂԈӉԗӇԄՇւ׆ւՅԄӆґфЄуґт҄'Ž̼؅тЌт҆ц҆шщ҆ђ҆хҐуЅуЄσ΄͍̈́̊Ζ̈́Ά,ែÂ}ʽ}˖ɄʆɈʊˉ͈̏͋̏̈ˉ̅2񁂃‡ + J܄􆔡􁉑~̼˱}ȟ +~}݅ +׈҄΄̈́̂ˆʄɄȈDŽƄ Ž„ŒƆǎȃɉʈˆ̈́΂φІ܄#}~(변}ȱФ 3~~~M}½}ſ}}ʄ]{}~}|~+}¹ʽǴψˊ̯͉̂͜΂τΊϏЋт҈ѐ҂ӑ҅щ҅ӄԆՇԃӅ҅шЂφЊφЊϋ+~ĻʻЊБτ΂̈́̄ʉˈ͈̄̄ˑ0ߞ|ȼӾ|ȋDŽȄǖȆɋʉˆ̅ʛˉʂɍʈ' +Jۃ򅓟򀈐ȿ}ʻɰ|ƞ +~}||| ߄܄ ՅфЄ̄˃ʆɂȄNjƃŋĄņĄłĆňƈdžȌ˄̂͆΄τل&|}(|ƯΣ6}󃍗~}}J~||ľ|ƿ|ȇƒØćÅ^+ɿķκ֌ҏӅҔӰԉօՉ֏׋؂و؍ڑك؉نڄۆ܇ۄڄم؇׃ֆ׊ֆ׊֋+¸׋ׂ֧֬גԄӄ҂шҊӂԈӎҊӄ,棅ȅöűЕ΋ςΉϊЇщ҃ӆ҄ф҂ђ҈цЊш.DžƇňąÇ‘Æ † !⇟&ƽ²жͣ +܈ׄ ҄фЅς΄͋̂ˌDŽƈŇƇłƆƄőDŽˈʆˉ̇͆ΌфԅՄ$*񸄣Ǹ͵ը:K¼ľƿτ~~~~…O󂅈􀄉~}*ĺ~ƹ|ϺЈ͎ΆͭΉφΊϊЉчҖӍԖӇԄՃֆ׆փՄՅґтЅуґ҅(~ۀ􃌔}®Ǧґу҄Ѡ҇ђ҅хҏхЃф΄͉̈́̉χΔ̈́Ά*嫐֋}dzʘɊʄɈʊˈ̐̈́̄͂̐͋̄ˉ2}†ڂ~¿ + G󐨾逌}ϵΤ~}}}Ԅх̈́ʆɄȄNJą…đŇƊȐ˄̂͆΄τۄ# }~%̮}ǹӼリ +9ი쀊|O}ƿ~¼ȿK񁄇}|~~*~¸}Ÿ{͸τˎ̘̂͒̂̈́̔͂͊ΐώЇ҈ь҈Ӑ҂ъ҆ӄԉՅԄ чЂφЉχЉό+}򂋓|ƥІӜ́̍ˇ̆͌̄ː̇)㪏Չ|˿ŲȌDŽȄǖȆɌʈˉ̞ˍʅ5󄈋|~؁}H񏦼|οͳͣ +~}|| ߅ޅۅ ԈЄτ̄˄ʄɆƊŃċÄĂÈĂÆŊƅǎɅʄ˃͇̄τ؄& |}%˭|ŸѺ +1󀆍{~P~|ľ}ƾÿ…ץÂĈćńƄDžO*ɿ̾տօҐӃҖӐӘԊՂքՊ֎׆؄ل،وڐق؉هڃۊ܅ۄ ؆׃ֆ׊ֆ׊֋+܂თdzׇׂ֢ͪ֯ז Ӆ҂ш҇ӅԈӌ҉Ӈ(바܎Ź̸ϖΖωЈш҈ӊ҂ђҋЄ҅2džƆňąÇ•Ć I󁉑ǾƶԹԨ +օ фЄφ̋˃ʋƆŅąŅŇĄňĂńĆłƆŊƄɄʂɈʂɆˊ͎̅τЄу҅ӄԄ@'ҳ̾Û +:熜򃎙Qžļ~~~~ЃŽE󅌒򀇌}}+~ɾȻ}к͑ͿΈϒЌфҕӑԇՅԐӌֈ¨}چҎч҆уЅх҆*ڂ℗}~®ģ҆шё҂Ӗ҂чъ҂ф҈фІшІςΐ͇ΈϋΜ"歔قƺ~ѽˆʍʋɔʉˇ͈̋Δ̈́̄;||Ć"~ Kሠ}ѷש ~}}}߄ކ݄ՄӆЅφˆʄɆȄÊ„ÂŠÆąŅƂŅƏNJ˅̅͂΄ք6}&~~½~ɲڭ2釜󄏚}~S}ƿƿ}ȾD񄋑||~(}ǽǺ|ιф͍̈̆͂͋̈͂̈̕ͅ΄φ΋χЊъ҂ѐҋӅ҄ю҆ք~|ъЂτЂώЉψ-؁|}¢јЂшАѐЃхЂѐДυ΅̓̇ˉ͇̎̂ˑ̊䫓ׁ~ĸ}лʅɆȇLjǍȅɄȈɊʆˊ͉ ˆˈʄ8{{~!¿~¿O|ƿϵը +~}||| ܈ ք҅τΆ˄ʃɄȉńĆŠ ÆĂňĄňƂņ +Ȅɂʄˆτڄ +0|||}|}}}~Ϳ}Ȱث1熛񃎙~|}M~|ľ~ž|ƼĿ‰ÕĈÈĆņƐǍG)Ĺտ؅ӇԖԆӊԍӅԄӈԅևՋև׊؜ٍل؍ه݂Ǭ؊ׂքׂ֎׉ֈ1߅臛dzɧׂ֔؈אؐ׃؅ׂؐהքՅԃӌ҈ӎԆӄ҈Ӊ 챘߆˿®фЅϊ΄φΖφЊчҐӎ҅=Ƅ śȄdžƃňćȌĉ! L狤耍ƾǷ׼ܭ  ؅ՄԆфЃτΉ˄ʆɄȊŅăÅ‚Ç†ÆŠÌŠÌĄȅǍȃɅʂˈʄˈ̃˅ +΄ςЄхۄ* (ŸƸϷ߱ 2MľĽø~~~~ЃÃćń=~~~-¸ʼ}θϹ΂͒΅ϓЋфҍӃԅӒԈՆԎӈԆ~ڑ}|ð˪Ӆ҈щ҈уІф҆,ކ鈜ь҂ѐҎӎљ҇ѓІςΐ͈ΌφΝ̈́ʿƲͅˈʋʊɔʇˉ͎̌Α̈́<~||} ||Ć3Ȑ}ľ E񅒟􁉑ǿóӸܯ~}}}ބ݂܈Ԅӂ҄υΆ̓˄ʅɆ‹†ÅĆłĄŎƄ ʅ˅τ߄}׿Ǡ +6舟~A}ƿŽ}̿…Åp}}}~Ȼ|̷Έ͍̆͂̅̊͌̆̈́̇ͅͅΈφ΋χѓӊҎӆ҄ь҈}ؐ|{ɩҊϕЉω,݅燛퀊~⾞щЃыЃфДфЂъЄфЄюДτΆ͆̄ˌ͙̏̊쵆ɽıʉɆȅǒȕɋʄˋ̄͋̂˄˄;~}{{| {{-Ə~|½G~򀈏žѷۮ~~~}||| ۈфЄς΄͇ʄɄȆdžƄƆÂćÅĈłĆłƆ Ʌʄ˄ӄل|~սƟ D燞}B~|Ľû|ʾ‰ÔĄÆĆŇƑNjɇʄ@)ȽԽՇԛӃԇӉԎӂԆӈԄՈֆՋև׃ؗقډُڇك؋ىが򅁆ȴЮيׂք֏׊և-䉨DzŤ؉׃؋׃؄ה؄ׂ؊ׄ؄ׄ؍וքՅԃӈ҈ӏԅӂ҄҄ӊĸ˷шІψΆυΕφЊц҆ӂԉӎ҄9 džƃŇćɌÂć1͔ýž IقŽȸؽⴔ ׄԅӆЄτΆ͆̄ɅȅljƄĄÄ„ŠˆŒňƍǂȆɂʈɄʈ˃ʍ τЅԄ6 )Ĭ̤ .BĽºź~~~~‚ŒÇĈŇ<􂋒}|~(~|ĹʼʵЅ΂̈́Ό͜΅ͅύ΄τЂюЇш҅ӖԃՉԊՊӆ&󇨼ѽཝڄ҆ц҄фҒф,㊨༜ӄ҃ӈ҃х҅ӂԆӂԄӆ҂ӈҌӌҊюЊςΉ̓΄͇·χΔ͌䆎}м̐˄ʉɅʄɈʂ˄ʌˊ͈̊ϊΆ<||~ˆ5ż}¼ +IꁎþĴԹ߲ ~~~}}} +ى ҆΄̓̇ɄȄDžƇņĂˆÔĄDŽȇ̅ф+ ̴幗+늡}~D}ǿ~ŽʾŒÇą=򁊑|{}(}{¸Ⱥɴ΍̂ˎ̂͌̄͊̈͆̅͆ΌσΈχЃы҉ӂ҈ӂ҄҉ӂԆӒ(񆧺м޼؆ЂϖЎψ)ቧ􄏙~߻~،ыЊюҎтІф҉ьЉτ΂ϊ΄͚̌͑̊ˊㅍ|κ˄ʍɍȂɈȒɏʅˌ͇̊?|{}Έ4ú|I耍~¼³Ҹݰ~ }}|||׈քτ̂ͅ˄ʆDŽƅŅą ‚ĆƄDŽ˅Є,˳㸖+ꉠ|~}~C~|ž}û~ɽžŒÌĄÈąńƄƄǂƄnjȆɉʉ>(ɾкՋӆҜӂԋӇԆӆԅՋքՈև׃؊يڂىَڂۆڒ(î¢߅׃֕׏ֈ)鍭Ʊߌ؋׊؎َ؂׆؄ى؋׊֐ՄҎӂ҄ӋԑӎҊ늒ьІφΆςΆψЂψЎфҌӄԊӅ?LjƄʂdžÇ5ňOüɹھ嶕  +މ +׆ӄ҂фЇ́̆˄ʆDŽƂńĆŃ„ÉĊņƅDŽƄǎɅȄ ̈́хօ + 5ҹ뾛+򍥽ꀌ=޹õ½~~~~ŒÊĈņƆDžd􂌔}~ùȺů}΄̓Ύ͚΄͆΂ωΆυЂюІш҅ӎԃՆԄՄԋՉӇ)勨񁌔̸ү҅ш҃фҒф҅)莮~ݸ҇Ӎҋӆ ӄ ~Ԉӈ҉яЊσ΄͈͉΂ό΂ͅ΍͏ ⎥̓ˆʇɅʃɅʆ˄ʈˎ͈̎΂υA~򀈏}ˆI¿}}½P扠~~¼ĵպⳓ~}}}ׇքӵ́̃ˆȄDŽƄňĆŒÂ„ÄƄЄ ؄ }}}Ԭ6⅜}󁈑};~|Ⱦ~~ƾÉăņƅb򁋒|~}·Ƹî}͈̉˗̃͊̈͆̄͆΍σ·φЅъҤӂԆӒ)䊧󌠴ʶЮҝЎψ)捬}տ۷ӌыЊю҈}ӄҊшЊϒ΃͙͕̋̊ˌ ͈ʎɌȃɆȓɍʆˎ̎A}|F|ɿ| +P刟}}óӸಒ~}||| + +߄ֈ φ΄͂̄˂ʄɆƄņĈÆ„„„ňτل ||~|ҫ~/|񀇏|~8~}{ƽ}}ŽŽÊĄÈĄńƅƄnjȇɋʆ˅̅8,ɾͿʴ҄ӋҗԋӈԆӅԆՋքՇֆׅ؇٤ڂۇڑ)돬ҽشٜ׏ֈ)½ư⽛ڌ؋׊؎وڄي؈ׇ֑Յԓӂ҄ӊԖӉҎ 蒪ԄьЉςΏϑЎхҌӋBLJƅ˂ȆÇFƺ +H썤過󁉐ʺڿ跗 +܇ۄ Ն҄тЄφ̄ʅɆƄłĄÆ„‰ÉďńƔ +ˈՅ ݄˂ٰ-爠逌8ǿĻǶý~~~~ЈŒÈĂņĈŅƂNj6~}~%}ĶҼψ͆̆ͫ΄ϙІх҇ӌԎԊՅԄ՚'݂℘~Ʊâۑ҄цғф)풳½شӈҐӎ~׿}ӄԆӃ҅њЉϠ΄͐Ά͓͉̆ˈ˘ʕˊ̎͌A~׆ ‡=~}þ~CڃþŵԹ祂~} ۄ +ԇф̄̈́ ȅńĄËƒĄńτڄ}~~~-܁}5~ļĺͻ‘ÈăńƋ3}|}~%~|ôл̈́̌˦͉̋Ότ΄υЉц҄ӂҫ҄ӊ҄'܁}İ ٥Ђώ*둱~쁌տײфҖш҂ӈ҇}󈓚վ|ӈ҆фЄύ΃ώΊͨ̄̈́̈ʉ ˄ʄɂȐɅȅɂȄɄʇɇʌˌ̂̈́̄@󂒜}Շ!ވ9~}|}̿ɾ  C؂􆔡½óӸ夁~}|%Ԅӂ҆̅ džĄÅ……ÃĄ ̈́ Մ؄ل |~~}}~~~)ۀ󁉑|8~}û¹~˺ͿËćÅąŎƈnjȌɂʆɈʄ˂̋̈́3%ǼɻԄӆ҂хҥӄԂӅԉՈքՄօ׉؆ٶچل'ㅢ臜˶ɦׂք։*݃􆑞»Ư޹؄ٖ؅مڈهĚڄن؄ׄ֎Ղ֎ՅԩӄԃӉ҈҇хІτЎςЅτяЇш҆ӂҋB݆ LJƄńĂą„ÊŠĉ捍<þƷż D߆þʺھ%ۄه҄ ͆ʄɄȃDžƂDŽƄ†ÅĂņŏăńȆɃʄ ҄. )⅜9ɿſʂ~~~~ЉÌĂņĈŅƃNJȈ`}}~~}ǽ}ͿDZ}͆̋͘ͅΆϚЄц҈ӅՆԚՄԂ՝'뎬տصӑ҃хҍт҄х)݃~ԯӈҎӐԂӄ}ضĔ~ԆӃ҄ѠЅϯΆ͐͑̆ˈʂˎʂ˅ʖ˅̐ͅA|- @}ý~´οB~¾Ĵ˒~}& ڄԄӂ҆τ˅ DžƂńąÃ‹ ÄĄ˄؄ل +}}}~)򅑟}4~}¸λ~Ļ‘ÈĂńƂDžƅdž0~|~|}~&~}|Ƽ|˽Ű|̆˞̂͆̊̈́΂τΈτ΄τЊц҄ӂҪӂ҄ӆ҅'鍫󍡶~Ӿ׳фЂѮ&܂󅑞ƿԾ}ҮބфҔц҇Ӈ҆|״“}҆фЄό΄ϐ΋̛̈͝ͅ˄ʅȒȍɄʅɌʍˌD{( +8~|}; + B}􁈏óɑ~},||߄ۄӵ́ɇ ƅń ‚Å΄ׄ؄|||}~~G󁉒|~2}|Ǿ̹}º‚ËÅĆōƇnjȉʆɈʅ˂͇̋΄Y򂒞쀊øĵ̶Ӆ҅хңӊԄՂքՇօՄքׇ؆ٙچۙڅم'Ů޹؄ׂخ*㇝ƿŮڴ؄ٔ؆وچن܀޻ɘن؃ׅ֌Մ֏ՋԢӈԄӈш҉хІτЂυЇτЂτЄыЇю҆҆A)ƉŅĂą‚ÌŒ 8»ǹĻ B؁ĿɹЖ' ߄ل؂׆χ ̅ʄɄȄǂƆłƄ ÂŠÃądžȃɄ&ޅ + +F2ŽǽԂ~~~~Ї‚ĈÐĎņƌǃȋɆU~~}|}~}}}ƸѺΉ̈̈́Β̈́΃ͅΆϖхҎӋԟՅԂ՘&~ᄙ}θɦٕ҇ј&|䇝~ƾֿϪׄԕӆԊՆԄ%򂋓ݿԦ҄эІѐАϖ΄ςΈτΏ̈́̂͊̂˄̎˂ʄ˅ʛˇ̕=񂍕~|}~~~,~~}|ٔ=~ƾ~˹}ʼ + I샐󀇏ݹ~}}'߂ބ݄фτ ȇƄńĂŇ +  ‚Ä̈́ׄ}}}~~~ >爡ꁎ󁊓}3|ż}·±~ϾƒÅËĄŌƂǐU}}|{|}||~~|ĶϹ̇ʆˊ̂ˉ̄ˋ̅͆΄χϋτЈъҍӆԆԑӅ҂Ӌ҄'}߃|ͷǥ׉Ѫ&{↜}żԽͩֈ҈юҎӆ(۽~ҤІ΋υ·ϊ΋͇̒͂Έ̖͆ˏʛɆʂɑʉ˅̅˅@쁐}{|}~}}~~.~}}|{Rؓ}ļ}ɸ|Ȼ +I󏤻ꂏܸ~~~}0||ބ݄܄Єς΅ͅȄDŽąÃ„Ä ̆Є +|||}}}~~'懠耍񀉒|~4~{û|~}μƒÎÇĆňƆǂȄLjȎɐʆ˄̄͂̄͆ΌUǽ˽ֿӇц҉ӑ҄ӂ҄ӆԆՂ֔ք׈؉َچۅڇےڂنډل'燝ԽΪމ؍֜&ހꊡꁎ÷Ĭկ݈و؎َچ(Ģڪׅ։ՊֆՆօՋԈӒԂՈԆӕҏіφцБѐD􅕣0ҡߊߘ:üо + + J򆔢俆քԆӄ΄̈́ ɄȄLJ +„ ĄDž҅܄ + (팥5¹Ǽȶº ~~~~‚Ä…ÑčŇƌǂȌɄʅQ󄎗|ù|̽¬Ά͂̊̈́̚΄Ϙх҉ӅӋԈՂ֕ՅԂ՘&犩󎤺ǰ߹҈ј&ꊡꁎսʥ~ԄԕӆԋՅԄ)DzЧьЇщчБωΘυΏ͉̈́̂̃˄̔˅ʌ̆ˇ̅Ί:~}<~}X˹2聎셙~} ݄܄Є΅ͅ Dž ąÃ… + „̄ք !}}~~~ ;|}7}úź~Ѽ„ÄŒÌĄŌƂǕW񃌖{{ʼʇˇ̒˄̂˄͇̄·ς΄ωτЈъҎӆԆԒӂ҇Ӊ҄&剨񍣹~ÿů޸ЂьЂϋЃю%~艠耍ӼȤ}҈ю҄ӂԉӅ)펬󍡶󃌕ưΦљςΈϋΏ͂̒̓Έ͆̍˖ʔɘʊˉ>󄓧}|}<~}|¿̄8ƾɸҿ +2틡怍~ꃗ~~}|'݅܂ۄڄτ΂̈́̅ɄȂDŽƂDŽŃ„ ˆՄ +!||}}~~~ ;~{|~7~|~ø}ϻӿƒÑĈňƆǂȄDŽȑɏʇ˅̄͆ΏτQ􃓥􀆌ȿôDZӅщ҄ӎ҄ӂ҄ӅԆՇքՂ։ք׈؊َڇۃڈۜڇم&펭ƾ̵澛ׂ،ׂ֋׃؎%ტǹêϩم؎لڂۉڅ)ͷ֬؄ւՒփՈ֊ՏԃӒԂՉԅӏх҉тЅі Ѝщ҈ӄ;삍9ňĄÏ‚‰XŽоźF򈜂.ՄԂӄ҅τ΂̈́̂̈́ȄDžƇłĄÈ „ÃĄƅȄ х% + >ڂ怍5ȿʿƺ~~~~„ÐĄłĉŊƅljȇɌʉɄO큋ú³ȱͤ̅ϋЅчЂч҅ӎԊ֞ՈԂՍ&ރúֿΩՓ҈ђ*ރ񎦾ŷԼĞԗӅԎՅ+鋩򍢷͹ҰьЊфЈхЕυΌσЅσЄψ΄͍̈ˊ̍˅ʆˋ̄ˈ͇̆7􇕩뀋}G~}}"8ÿ}ż­U鉟~~~~}}}"؅ Ԅ΄ +ɄȅǂƅńĂĆ„ Մ}}~~~ 7鋣탑}}~0~}ɽѻɸ –ÊĊŊƃLjɎȇU뀊~ưʈˌʄ˅͉̂ΖςЈьҊӌԤӋ/܂􅑝¹ԽͨќЂцІ%܂õӺÝ҅ю҈ӄԅӆ(犨̷Ѯѥω͌΍͓΅͍̂ˆʆ˂ʄɐʄɂʌɗʄ˅̆7򆔧|~G~}|ÿ~|ۿh¾|ĻԿS爞~}~}}}|||*ل؂ׄԄɅȃDž +Ąӄ߅ +||}}~ 7牢낏||}1}ȿ|Ǽ~Ϲ~Ƕ†ÇĎŇƋDŽȆɂʈɄʂɄʍˆ͇̉ΑχQ󄏙ȿǸͶ҆фҘф҆ԉՖւ׈،يڐۥڊ/䇝ĬԮ؎֍ׂ؆׆%䆦ʼʢم؎هچۄچ(ӾشإֈՂԌՏԑՄԍӃҍцЎэЂφЖф҅ӄ9񃏙BÿńČʊƒlŽȱŹ >샐.݅Մ υ΃ͅ +Ʉ ńăǃ …Ƅ"ڄ  +6􇕣񁉓<ƽ÷μł~~~~‰ÈĂńĈłĄŌƇljȈɍʉɈJ뀊|ŷ̶י̅ˆ̆ϊЍІф҆ӍԊՊ֝ՇԃՎ%񎤼삏Żζ彗фҒю*݅ȹӺ迖ԖӆԎՇ)⇥|ԾٵыЌЋцІφВφχЄό΂͎̈ˌ̎˂ʆ˖̃ͅ4~~J~}ÿ~m~þżƯԿ +C懜~}~~~}.ׄք҄ȄdžƂŅĂĄ7}}~~~ 0|~2}ĸվǴ•ÉċŅƈLjȅɍȆƄI󇖨{ƿõ~˴Ոʂ˙ʃ˅͆ΎςЉσЇфҎӆՊԦӉ/߅ꁎĺ~͵㼖ѝцІ%ۄǸѹ潕ޝ҈ӅԅӅ'슟{~ҽ~״ЦϘΊ͔Ά͌̂ˍʅɆʄˇʋɓʇ:쁑~}}N}|}m}½ĺĮӾD䆛}|}}}|#ՄԃӄȄņ„҄ׄއ߄ ||}}}~ +1{󁊓}4~|ȿ¶Ӽ~ƳąÇĔŅņƅljȅʄɈʂɄʈˆ͇̊Αψ΅K򄎘􀆌ƾʼҺܤу҄ԇՖփׇ؄ِڇۂ܊ۦډ/扩򆓠Ի›؋֍؆׆%≫ξٿĚهڇۄڄ(芩逋Įߺצ֗ՌԓՆԋӃҌчЏьЂυЕф҆1􅖪킎OĎțsþ˴ķ D싡遏󀇍 /܄ۄ Ԅ΄ˆȅ ŅĄÂ‡   ń83倍+Ƽɽê̹Ȃ~~~~…ÉĚńƋLJȌɔʅȅC큋~ǸآҊ˂̒˄̄υЋх҅у҄ӊԌՇ~֜ՇԅՆԂӄ&ۂ}ƻŭ~Ӭԉқъ҄%ވ̼Ҹ⹌׉ԂӔԐ*݂ꉟ}Ů໙ךтЌњЊψщϊ΂͇̍ˑ̏˄̂͋̄2􆐛~|T~þ~ÿ}雄3}~|~G~~}}ŭɷ$㆛}}}},߄ӆ҂ф ʅńăÆ + *Єք ݅ }}}~ +\݄聏~~ǭȳ +ÈăÈćňƉNjȂɒȍC뀊}ľŷ֡Єʄɇʂɔ˄̂̈́ΈϓЃц҈Ӎ}ՄԚӂҊӊ+ف|Źī}ѪцτЅЄςЈυЇ'܇~~ʺзซ֜҉ӈԂӄ(܁舞|í޹РτІφ΂ψ΃υΆ͆Άύ΃͈̆˅ʄɈʈˋʄɆʈˇʃˆ/򅏚}{~T~}½}~|皅0|}{}}~7}}||ſʿìǶ$ᅙ|ގ||| 4цЄ Ȅć +  F߄||} +~~~~܃瀎}~}ȿ˿ƫƲ +‰ÂċłƄŔƆDžȉɘʆˊ̇͌ΗϏD􄏙ž̽ަщЄхІхЇԅՋ֓׃؅ٍڍ삇܄ۡۄڊ*ᆝ耎˲ذ؆ׄוֆ׆'䌯؂邑׽辏ݚًڈ.ㆥ逌ºʳנք׆ֆՂֈՃքՇԇՅ֍ՂԉӅ҅ьЊф҈ъЅхҊу҅/XĿ範2<ƻʲμ6鉟瀎擔ք ΄ɄȆLJņĄÈ…ÅՄۄ +㈡󂋔5żŹͱ͸~~~~ƒ…ËęŅƉLJȎɕʉɂȋ;瀎󃍘¿׌٠˄̄υЊє҂ӌԈՅꍲ~~¤ۙՊԄՆԂӅ%܁Ǻռމқщ҄%؂邑ϽжܳӖԏ)~凞}ý˴؛тЌњЊψЂцЄω΃͆̎ˈ͈̂̎˄͉̂1~}|~]}}~}~ʁ}~~|ľ~·ӻҺp|Җ}}Є Ʉ ć + + R}}~ +G苤􂋕~*}ʾպҼ ŒÂĄÒŊƆǎȄɌȍDŽ?񂌖~~ՋʈɄʄɓ˄̂̈́΄ϊЄэЂфҏӇ茱}}لԙӂҊӋ)ۀ팣ŸӺ迖цКυІ)ދց灐ͼδڱӘҌӈ.}㆜|¼ɳ忝~ПυІφ΃φ΅τΆ͆Άύ΃͈̆˄ʊɉʉ˔ʈˆ2}|{}a~|ſ|Ŀ}Ŀ|ɀ~|~~}}{ü}Ѻйjރ{Е||Ѕς΄ DŽ„  + :ڄ݄ ||} ~~~D抢򁊓}+~|ȿɼӹк +ˆÂĉŅƂŌƇǃƄDŽȌɎʂˈʆˆ͉̉Νϔ;탒þǞݐތЂђЈԄՄֆׄ؍ׂ؄ٍډȩۙڂيڋ)ℤ̿ƛ؆ךօ׆*援݅ôֻ⸅ږٍڈ.싢遍øйƢןօ׆ֆՂֈՄքՆԆՆ֍ՂԉӅ҅ьЊхҋтЊф҈4ꁍ񀆎\½ŊŠÆ„;Ѕ;üȼ׿!懝怍ؚ 4ֆ̈́ȅƇĆÄ + †8 + D(ƽöڿ ~~~~Ђˆ‚ÆčŃƅőƂnjȆɡʚ7󅕧}ʠˈ̂̈́΂τЄѐ҆ӄԒ~喬ǴҰۄ֒՞$掰ׁƸ̲֮}҄т҇Бщ҅'Ᏼ݅ҿγ֪ՄԂӚԇՃօ(~ĻѺǣҧцЂѓЅϋЌυΆ͇̑ˋ͎̃̅ˏ+~~e}»ƿ|¼~ſEĐ}}B}ļ~é~׾ ނˆ.ͅ ĄӅن +'}}}~~~d|}}¹ʽβƯ ˆÂąÚăŊƆǑȊɆȎdžȆ4񄔦|ЄɅʅɂʎɊʄ΅ϐЌтҎӆ}㔪ƲЯنԒӛ%䌯ր~Ŷ~ʰլ|ЌςЄϊЅ'܄텔о̲ԩӊ҈ӂҌӋ)ބ}úиŢ׆АςЉφАυΆϑ΅φΉ͆̇˅ʇɈʊ˖ʄˈ+~}~}g~|~ľ{~}þAÏ||~~<~}|»}˿§}ֽ!݁ʅ ߄Մф ˅ …҄ۄ܂݅߂||} +~~~g||~|Ȼ̱Į„ÄĄŇƂNjƐǂȆɌʅ˃ʒ˂̌̈́ΚτІϛ3쀋נЊ +Մ֐׌؂َچ뚱͹صېڊلډ%쑵݅냑̽ѷܲ׌ւׄ֊ׅ'瓹㉢ŵӸܯڊٖڌ(扠過׿̧߆םքאօՆ֊ԆևՈԆӅ҇ьЎфҘт҈+ꂍ`ž҄ĆŊąɔºƺɭñ 䆜Љ;ׄ +хŅąÄ DŽȄ؅ޅ +( UǾµӷ˳~~~~~…‚ÅčŅƃŒƂnjȄɤʕɅȆ+ꁏ~ʟˈ̂̈́΂τЅяҊӅԇ"}אꊙҾཝ֒՞'}댥󇗧ŵÓ҆Ҙъ҅'㒸㉢˰~ϟՍԂՑԇՃօ&ꑳڂ~¶ͨچңтЄфЄчэχЋχΆ͇̑ˌ͝-~|򀇎}Z~ƿ˿~I~~}~,}ȿ}Ǻɭ}ֽ +݂ĉ"ф +ˆ„҄؅ ކ}}~ +h|~}}~|Ļʽɯۿ ˆÄăÐăŇăŋƄnjȂɄȋɆȅȌȆǂƅ-耎큋}ȟɈʅ ΅ύЎуҎ|Տ艘н޻ՆԐӐӇ%|鋣񆕦ô׍ЌόЄ'ᐶሡ󈙫ҿʯ}ΝބӊҗӉ)鐲ف}־̧ىЎσЋσГςΆύ΃ψΈ͇̇ˊʆɈʄʅ˖ʇˀ}{|~}ž~ɽ}I}}|}4~|ƾ|Ź~ǫ|Ի!ہÈ1ԄʅɄ %օڄ߆$||}}}~~~e{}~||}{¹ɼǮٽ„ÃąŃƇDžƕǂȄɎʆ˂ʒ˂̋ͅΔτЂτІϖ΄͆+ϞЇхՆ֌׎؂ُݔï¡܅ېڏچ%ဠʺǬȗބֈב֌ׄ'蕽錦Ƶѵգډٗڋ(聏ǻŬӬ׏ւ׌փדւՆ֑ՂֈՉԆӅ҇ьЎфҘрꁏ瀌žĻŐćʄƅI-żα +!⅛½ɍ,фЅĆÄ + ńƂDŽׄ݅  3Ԁ恐󂌕)µδį~~~~~Ј”ÄăŇƃŇƂņƃDžƄNjȄɕʄˌʑɄȍ$~~藦֍ʂ˄ʊ˂̆ˆ̄̓ΆχЄѐ҂ӄ-֌܀ɴʨׅ֎ՆԆӓ&߈Ӏ灐±Ѷ٭ҕуЍц҄$ᔼ茦}~}°ȭȑׄՅԇՖԊ&ክ}˽ƭԭۊҭҒЄІύ·͆̂˄̄˄̄ˌ̂ˌ̄͂̄(򇗫|~F~|}žɊF}~+}ȿ˾ȬӺ~ ل"Ȅ $  Є݆ބ } +~~~ J~|~~~}ƽͿʯ~ֹ„ÏĂńĐŋƅDžɆȗɓȈLjƄ*}}斥ȆɂȅȊɎʄ˃͉̆΂ψЎъ!~ՋdzȧօԐӔ҂ӆ(݇倏ϵثІτАώЅ%ߒ拥|}~~|ǬǐֆӂҔ҆ӂԅ%߉~|ɻĬ~ҬڌЄςЄτІσЅςЄόЋφ΄ς΋͋̇˗ʅˏʆ̇)~{|D}{ƿ|ü~̿ÅJ|}*~~|ƾɼǪѹ +~}݄ ׄ ΄ LJƅ„ +   ʄ΄ӄڄۅ܅ | }}}~~J}~{}~~~}}}|Ļ˽ɭ}ո ňƐǔȄɃʈʈʇ˄̃˅̊̈́ΒϐІτ΂Ϗ΃͍$끎܅ςІϋЄхЅӇԈՂֈ׎؋!䂦ܐℒιϬ݆ۏڎلچ(匰ك텔Ƕ׻ׇ߱փא֎ׄ&䁑ǵβΕ݆ٛڂمڄۄ%玱ڃ灏µ˲ڲ׋ׄք׆փ׋֌׎ֆՄւՊԌӄҌтЎтҒь)GžûŽȉljƇŇČØ‡J,żöΰؿ +!Ʊބ͆̅ȄDŽ + 'Є  Lׁ郒¹Ķгܾ ~~~~~ЄȔÅăřƄǂƄnjȄɒʇˋʄɂʊɇȇǂƅƄ~}ɍʂ˅ʉ˂̆˄̄̈́ΈχЇь҂ӄ҇'⎩Ծ״؄֎ՆԄӕ%얼拤ϾƫĎԖуЎх҄$폪】}~ðŪԅՃԈ՗Ԉ&ۃ}ŷ̳۳݋ҩтӌҍчІϏ΅͌̂ˈ̂ˌ̂ˋ̇'}}=}üʿ}ĊÇŒA}||@}ż̿~Ũɱ0~~}}}}}ׄLJƄ   'ʄքۅ܅} ~T~䀏򂋔}}}~´ί~׼‡„ÄăŇăńĎŌƅDžțɒȉLJƋ 􄏙}|džȃɄȄȊɎʂ˄͉̄΄χЍц&쌯~~ҽ~ֲօԏӝ'땺䉢􉙫ν~ĩÍЈςАώІ#ߕ뎨|}¯~Ĩ쾄ӆҊ%ق|Ķ˱ٱێύЄτЄυюЈφ΅΋͋̈˗ʄˏʆ+~||~;~|ºǿɽ|ȆŒ=|󀇎{{~@~|Ļ˽}çǰ1~~~}}||||| +օƆŅ     Ʉ̈́؄چۄ "|||}}~~R}|||Ǿ}̮}ֺ ŇƇǂȇǔȅɂʙ˅˄̍̈́ΒϐЇσ΄ψ΄͑܀ΎϊІуЅӈԈՄև׍؆,蒮Įݸێڔڈ'쎨IJ˯ɒ׈ב֎ׅ$鄕ɵˮňڅي%怏˼Ҹḏׄ֌ׄքׄօ؆؆׉ֆՄւՊԌӅқтҒч(킑遍>ŽĹɊȆnjƆňċ؇><ĶʬζE +܄̆˅  τӄ  T؁ꄓżǹӴ~~~~~~Њ–ÅąŘƆǐȃɏʋˇʂɆʅɉȈNJƅ򃍘ȊɆʈ˂ʈ˄̂͆ΈόЅчӉ҅ӄ&}ɳ濜ڇքՄԄՙӄ$ځ}胓}~}ֺ̺۪шЈтЉ҅ф҅$胕İ~¦ԐՄՄԅՌԄ&|̾ӹ⸏ވ҂ц҇ѕ҈ 郌ӅԂӅщ҉фЊχ΅̂͘˗cꁎ~~}~}˾~ƇŃć͎<􀊕}~=|ɿ˽׻*~~~} ӄɅ +  +#ʄ Є ؄لڂۄ%}}}~ L}䀏󂋔ºǹӷݾ‚„ÆċčŅƆǂƆDŽȗɅʆɐȄNJƐń􅔤ЄnjȐɌ̇͌ΆψЈуЄф*|~DZ供ՇԄ҈Ӆ҂ӓ(ـ|悒|}|ʸԸ٨НωЄ'悓~¯}ӆԜӄ҉%{˽ѷ෎ݡЃъ炋ׇ҄эЂτЄφΊ͇̌˅ʆˈʂˇʋb킒耍~}~~~}~~~|}Ǿ|ɽ}ŅăÆ‹?}}~=~~{Ǿɻչݾ*~~~}}}| ф ȅ +Å    5Ȅׅۄ܂ބ߅+|||}}}~I|񁊓ŷѶ۽…¡ŃƎǖȅɅʆ˂̄˂̇ˉ̅̓·̓ΊϔЂфЎφΉ͇̊˄׌ΆϐЊт҅ӈԉՆֈ׈؃ׄ؄+ـθŠ܆ۏړ%Ӂҿܿ։ׄ'ɵǪڇۛڄى%䀏Ĵپ轓׃؊އل؍ׂք׃ֆՋԄӎ҆фҖфb񅒟ƿżõˇʃɆȎǎƈŋĆ΃Œ>󁉑=Ż´ŭ1 +؄΅ Ʌ =Մ ݄ބ#M׀ꄓȿ̾ؼë ~~~~~Љ…ËăÉąņƂǐƆDžȃɇȃɊʙˇʂɆʅɉȈNJƆDžȝȎɅʆ˄ʇ˄̂͆ΈόІѐ҄ӆ&舦~ӽ̦݇փՄԄ՘Ԅ&ލሢ~~ǴʭĆчЈБу҄)톘}}İ}ܾݥ֍ԆՌ)閾錥ƶپ龓҄щ҃ьӉ҅ၛ}ˤӕ҄хЉυΉ͇͙̅̃\􆖪󁈐|Ļ}ȼ̄ƌńćΎ5~􀆎~8}Ǹ˫ʰ*~~~} фȄDŽÅ6Ȅ τׄ߆"} ~H』󂋔Ž};«(‰ʅÆĊłČłƋƅDŽȘɆʅɏȅNJƒņƜƆDžȂDžȐɋ̉͋ΆψЈтІц(懥}һʥՆԄҏӓ%݌߇}}ƲȬ…ωЄ'녗||¯|ڽܣӈԚӄ҉%畼狤Ĵؽ罒ѠЄю߀|ɣ~҄ЅшЅυΊ͇̖ːʈ]󅕨삏񀇎ƿ{ù|ǺŋĆŋ5}}8|ȿŷɪȯ-~~}"|||݄ЄDž +„  +,Dž ̈́ Մքڄ݄ބ|}}~F񁊓Ļ|˽ܿ…¡ŃƍDžȋɃȉɅʆ̈ˈ̅͆΄̈́΄ςЄϔЂхЍφΊ͆̊˅̆͌͡ΆψЂφЊт҅ӈԉՆֈ׈؂ׅ؇(삍ªѫ܆۔ړ%䑻猧͹ϲɊՖ։ׄ'󊝲􀅇ɵĦڈۚڄى%̻ĩ×ؠׄ؋煟၍Щلׅ؈ׄֆՉԅӏ҄цҔф_ƾˌʄɇȎǎƈŌąÇ‚„Œ5򁊒*ƻ̽аϴ / +քͅĄ  + 6ͅ#߄ L郒ºĵƧǯ~~~~~ЅŒ ʼnȅɃȉɆʈˆʏ˅ʅȆɌȆDŽƆDŽȄ ̈́ʉɉʂɆʊ͈ΊψЉы҇-ށ戞}ýǯٲ׆֊ՂԇՋԊ%鄕~ڽۣێуИт҄%~򊜲~įغՕՉ֒Ւ$܍ሡν~ĪĖ҂Ӎ޺ؐӆ҈фЇυ΋̓Ύ͕V܂󁈏}ùϿȅDžƉňĈˏ5}󂋔})}ɿ׸ֵ0 ~~~}} +τ̄".Ą ̄ԅ ܅1}}~~K~񁊓ŷ̮ͳ  ňąŃƑLJȒɂʎɈȑljƌň ˅ǜȆɇʅˆ̈͆ΌϊІы-݀䇜|¼Ůױԕ҄Ӊ*烔}~ػ١ڣф#}~}®ֹӔՏԒ҇(ی߇󈙫̻}èÕџЍхܹ׏ч҈ Ή͈ˊ̎ːʄTہ탐񀇎ſ|¸ͽDŽƆňĈȄ7|񁊓􀇏|~)~|ǽ~οնԳ $~~~}5|ۄ ҄̂ͅ˄D%„ф҄G|}}}~~E}žĵ˭̲„ÄąŃƄNjʈ͑ΆύЄϑЄϓΉ͆̃ˇ̄̈́ ҄̓΄φΑχІф҆ӉԅՌ֊׆؋.䄡싢遍¹̴߷ۙډ*dz¥؄#сɴ޿ڙܐۑڂي(␻猦°ʮʚ؟׍؅ޔ؈ه ՉԄҊӎҐфU↚ƿɾķ̅ͅˉʈɈȄǖƇŋĉͅŒ9쀊xĺƶܽ۹ +фƄ Ȅ ل 5F傑Ž˼ҳӸ   ~~~~~Ѕ‹ϩԆ*}Ȑɇʋˆʏ˄ʆɂȅɂȄɊȐDŽȅɋʉɉʂɆʊ˄͉̃ΈψЉыҍ'ۂ|ǾѸ潕։ՃԇՅՅԊ(؄څ|лͯ}ЊфИт҄$Ѐ|~îԶʄՍ֎Ւ$ց׃򈙬|~~IJʯʚ҂ӄ҂ӄ싩ПܜԉӅ҈фЈτ +͆΍͉ˊLӁ􏜪ſƻϾʄɅȆDŽƉʼnĈȄ2}~}&}ƻƷ~߿ܻ$ +~}} ߄ۄ˅3 +,Ƅ +̄ +҄ۅ2}}}~~N苣}Ϳ۾⽣ ;ͧ|ˊDžȒɂʎɈȒNjƈʼnƊǜȈɆʄˇ̇͆ΌϋЅэ,ف{żϷ伓Ԛӈ҃ф#փ؄{~~ιˮ|ф"{}­ӵ~Ƀԑ҅)Ԁւ{}}ðɮəўБꊨϞۛ҆фЄ̈́΄͎̎ːʄMҀ򎛩~þ~ĺͼȇǃƇňĈȄ3|}|~N~|ĺŶ}ݽڹ"~~~}}}|| +ڄ̄' 0ل4|||}}~~O扢~|̽ٽ໢  ƒÅăŅƂNJȄ ԭڅ)ґΆόІϐЄϔΉ͏̄ͅ·ψΊςΆωЃф҇ӉԄՌ֋ׅ؍,ᆝ怍÷׽™ۛڈق؄#݇ҴŁ؄"Մ퀅ɳڻЈۍم)ۄ݇ʷдО؞ב֣م؄ׄ ԓӎҒNلſôυ΃͆̅ˈʉɈȄǖƇŋĊ̔̼ĦῨ"%ׄ҄ „ %½ƒ‚ÄĿ )DŽׄ*Oĵå§  ¦~~~~~Ѕ +Ä4|þɉʆˊʄˇˆʔɎȄDŽȈǒȌʅɄʂɆʉ˅̆ͅΆϊІы҇Ԇӄ(芪}ȼ©ɝ֊ՅԃՈԂՑ-脖~~ɴ~ݿڙцЖу҅"ԃ~íвֆՌԄӄ$~~̸дў҄ьэҏ 䃟懜ԩ|ӄ҈эЃτ΂ό΅͑̄˄Bݞ|ÿ|˅ʅɃȉdžƇŋĊƏ-񆒤}5~~˻ŧ⾧H~~}}}߄ م Ɔ +  + Ņ̈́̂ˆ ɉȂɄ̆<ýQ؄1}~@蚸񇗨}ǹгβ 4~{¼̈́ȧɊȐǠƂNJƎǒȈɆʈ͍΅ώЅэ&物|􇕣ƻǛՅԓӃ҅ӏ#ߓ폫烕}}Dz}ؘܾҠτ,҂}~~ΰԌӎ&}솗}~ʷϳϝѝВ ₞冚~Ҩ{фЌψΌ͋̍ˑCܝ{{ʿɉȂdžƇŊĊɇ/|~5}ɿ}ɹåསG~~}|||ބ#ʄ +Ą + + +ɆʆɆȂDŽƈƅ ˄ʅ/¼  DŽׅ̄/|}A~~~晷|Ʒαͱ 忉ĄŅȅɂȄ3ýΉϋІϐϏΙ͆̒͋ΌωЄш҄ӂԍՅ֎׃؏&ՀǭΡ܆ۚڏ$򁆈ϹĦ՟ք,نၔ򂇊Ȳֶیڎ&ӂҽֹ֢؝׉؅ل ꇤ튠ڮ؄ׇՄֈӈԊӄ҄хҒC򀇍ƻƷІτ΄͉̅ˇʋɊȆǓƅŎĈΊ-Gƻʫë7ޅЄ ʅ „ +Іω΂̆̓̄ͅ фЄІń ݄̈́1A񁊒;շӶ ň~~~~~†Ä~|}~~:~~}}¾φˉʄˎʄɂʎɏNJȈdžȂNJȎɄʂɊʇ˃̇̈́΅ϋЅь҆ӂԆӅ&򇕥Ƹ̲Ԩ֋ՅԃՈԂՑ3ӂ}ϱЖф҄"ׅ߀«̭܇ՊքՂԄՊԄӄ#ꅗӿ׺ע҄чэҍ,}܂̷~҈фъ΅ω΄͒̅ˇ6ܣɾ̻͒ɂȆNJƇŋĊʏp􁉑}|Ĺͽǩ澤~~}}ބ/ą ʄː̂ˆ̈ˆʄɃȒ Έ͈# DŽ̅ׄۄ'}=~~~~ʋ³}ħŪ*~臻 }{|}}~~:~~}}||ΟɊȑǟƂNjƋǒȉɅʈ˄͍̂΄ϊфЅю'ހ쌤ķʰӧԘ҅ӏ$с|ͯΟτЄ$Մ퀄~ʫ۔Ԍӎ&脕~ҾոաќЊц&|ځ큌ʵ}׆тЈςΈτΌ͋̃˄ʆ˕7ڢފǽʹ̈džȄDžƉŊĊɈ+򀈐|~(~{·̼ƨ佣H~~}}||ք Æ($ʍ˄ʄ̅˃ʅɃȆdžȂDŽ +ˇ̄̈́̂ͅƾƄ˄Յ3||}~~~}ȊĄÿ~|æĨ *}繺ąńƄǃȅɂȄ;ÿƺՈІχЄЄϑΖ͇̓͌΂τΌϊЃч҄ӃԍՄ։؄ׅ؎'兤˽ѷڭ۞ڊ*؅DZն՟ׄ$݉儗ǰѲیڍ&񉛰Űܿݦ؜׊؆&‚⅛ѼƘކ؂׈ւՅքՌԊӄ҆фҌтЈ6⨓換Ĺӈ΄φ΂͊̆ˇʋɊȇǏƅŌĊ̋pɾ²ͮèlɆ +0Јц ҅уЄσ·̓ΆΆ ҄ӄ҂ӅĿ0̄ф܄'Ϗ˄ Ǹʬʮ + +~~~~~ˆ}ٕ@~žôʆ˖ʔɊDžȊǚȒɌ˄̆̓΅ϊЄю҇Ӎ'∠²պుՅԄՄԎՐ'օ捪脗󀄇й֍ЅтАфЈх'ڇブǨՄֆՊֈՎ%؉荩僕|}Ʋ~ݿަӆ҃јҊ&쌫킎¬ڶنҊтЄцЄτ΂χΆ͒̌˅-ؕ񗢠ȽɹͅɂȄɄɋȃnjƌŇďǂ„U􊘭킍󁉑}~źνŦຠC~~~}}}Ԅ" +#ɉ̆͆ +͊΂͆̆ʅ ʄ˄͂΄φΈφ ч$ü +ȅԄׄ$E}}~~~|;׼ݹ,}|ؔI}ýʅɛȑǗƂǍƊǘȉɃʄˆ̄͊΄όЊь(턓Թ߰מӐ"Մ䌨惖η޿ՌυЅ!؆႕󂅇־ŧߖԋ*ֈ挨䂓{|Ű}۾ܥѓЂцЍф'ꋪ끍ٵшВχΎ̈́̄ˇˈʃɈ-֔~Ǽȷ˓ljƆŋĈƇ†q󉗫끌񀈐|~}Ĺ̼ĥ޸}$||߄ۄЄ" ƆȆ ˇ̂̄̉ͅɄʈɂȅ Ή̈́΃͆ Ї» 4ƆЄՄք"E||}}}{˼ֻܷ<~|ĆńƆLjɀߚ@ĽȹՊЕς΄ώΏ͉̖̈́ω΋ψ҆ӄԋՄ֋׉،ل%苤Ƿ涅ޞڊقڄ"܈푮վƧܑքׅ!ꆚŮ̬盄ܘۊ*ލ솙񀅇̷ŧؓ׃؅׌؅'􆒝¾ǰ໚؈גևՉӄԄӄҌт҈цІ-ݙøϾҍΊ̈́̌ˋʇɏȆDŽƅDŽƈňĈ̎ ++􅑜nó˫澤 ل:  „͇υч҂Ӆ҄ҊхτЇσ΅ ԉӄԆ և  ̆ل,Gÿô㽣 +-~~~~~‡&韮C~ûŶˆɍʂɄʎɇȂDžȊǚȓɋ΅ϋЄю҆ӌԄ%ꌮցꃓ̻}è콇هԂՄԎՐ&ޗ}~ǰѱІтАфЈш$݉煙|־¢ԆՄևՍևՇ*݈}θŨӠ҈'싢ꁎþ~ηġ׆ҕшЂόΆ͆ˍ̌˂̅%|΅~ɿ˺ʊɒȄNjƍņĐ΄(聓耋}~~}źͼ~ٴ~}}}Є& +$ʄˆʂɄˆ̄υ΄Ίς΄͂̆˄̇ΌτЃφ҆ӄ҅ǿ ĄDŽфՄք1}7񖠥ɺжִ7򂉓|̺"蝭߆F¿}ĵəȄDžȇǖƄnjƊDŽȂǓȈɃʄ˅̅͊΄όЊы҅(苬Հ肒ʺ|§꼆ҚӐ#ܖ|}ůϰܣυЅ!ۈ儘{Խ҅Ԏ&ۇ|̶æ҅ёЄхЌ*ނꊡ耍¼}̶ ՉГχΎ̈́̄ˇʈˈʅɉ#{̃}ǽʹ̆ȒnjƆŎ௅†)怒󁉒|}"}|ù˺}ݿײD~~}|||ބ$˄*Ȉɂʅʈ˅̋ ΅̆ ˇʅɅʄ̂͌΂τфх҅Ž +/ÄŅфԄ$ |7𕟣ǹϴղ @{˹ĆńƇLJ%𣳵Cÿ˻КϐΌ̖͊͒Ίψ҆ӄԋՄ֋׉؋ن(܅񇗨ɭŠٚڐ#ρ򁈊̵ֶօׅ&㍫쀈ìǧډܙۍ&㋨愖񀆈ӽʬمؑׄ؅׋؄'憤򏧿񅒟úԼɥ܉דևՉԄӅҌт҈чЃх(ԈĹѿϏ΋̋ͅˌʆɐȎDŽƉŇĊʎ]ʿŦ޸`ф*˄ΎτІхҋ҆ЄшЅυЄ҂ӌԂՄՅׅ؅ׅ؅þ,Ʉ˅ڄۄ15οֻܸ 8ҿ˂~~~~~Єˆ%¾|}~=~}|þ|Ⱦ~ǹϓʐɄȆǜȂɆȈɃȄɈʇ̈́΂χЂшЅы҇ӇԊ%偑ų̰ƑމԒՊԅ%݉儗~սЂтЄфЈтІъ#눝~ԼݼՈքՑ֊Մ"т~}}վʬӞҋ)ބ怍ë~ӮҎфЊшЅχ΅͇̂ː̆˄ʄ˅Ḝѿ~ˈɄʈɃȇdžȈǃƍŇēʄ}瀋|}~~|øʹָЮ~~}}ՄԂӄ +̄˂ʄ:ʌ͆̈˅̅˄ύЄφЄЄΎ͆̄͂΄ЅтЉфӅ҆ӄԂӄԄՂԄՄĽ& ‚Ä ͆х-.}}ŷ˰}Ϯ H}~&{|}~~D~~}|{{ƽ}ŸȋɏȄǓƏǃƝLJɄʂ˅̂ͅ΅σ·ωЌцҋ%ށ【ò˯ŏ݆ҝӉ#ۈブ󁅆}Լ߿ρσЅ)ߊ醛}Һ~ۻ՛ԍ$ρ}||ӽɫҏыА.܃~ǿª}ѬτЙυΆ̅ͅˋʈˉʏ߷ɿϽ}ȄljȑǐƆŌĆя|{|}~~}{~ȷշ~ά~~}}||Ԅф;Å˄ˇʄʆΆφ̈́̉˄ ̄τЃωЄт҄ӆ ӄҊӂԅü4̅Є,.||~~Ķ~ɯ|έG|}ĆʼnƃLj*ô:þĺ̾ԎЄφ΂ω ̊΅͂Ί̈́΃͍΂̈́Έχ҅ԆՄփՈ։׈؇ً%慦녕ʸҵ̔ٞڈ#㌪쇜ëƦօՔփׄ*揮򋡺񂉋ܔۃ܅ی%ׅၔ񁆉Įбَ؋א.䈠탑ƻɰٲքטօՆԅӆҌфҊё潠ƻĴχ΄ω͈͇̇̃ˍʆɔȊDŽƎņĈʂˆ倓탏ȾϾܽղڄ؅Nȅ̈́ щЄ ІԇՅӄ҉ф ҄ՄւՊքׂ؄؅؄ق؊ل! +.ƈ҆օ-H˼еԳI􀇍 ~~~~~†;򡣥}~;~ý̻΋ʆʉɅȅǑȂɊȃɅȂɆȄɃȄɈʆ̈́䄑Іщ҉Ӈԋ%鍧}~}ϼոӚԒՉԆ/ֈ˳ѱцшІъ#㍬ҹ}׶ՉփՑ֍$ڏ~ůб~Ԅӂ҅Ӗҋ(ᆧ}}µз优ҏфЊфІτ΄͊̂ː̆˄ʄˇъ}ǶʍɄʈɃȆ LjȇDŽƇŇē˃~ꁍ|~~~}ɿ}ų̯Ť~~}}}Ԅф- ͌ +͊̈́̄ˆЇх +ф Έ̈́΄΅҄щ҄ӂԄԅՄԋՃքׅŽ2̆τz}}ᓟ}ô}ǭʪU񀇏?~𠢣|}~<~}ɾ˹ȉɏȄǐƒǂƞLJȃɈ̄΄ハЈψЉч҉ӄ$狦~|}|ͺӷљއҕӊ$ԇ󌡺ʲϯӋσΓσЄф!ጪ퉞~Ѹ|ֵلՖՅԇ&َ􌠸}~íϰ}ҎчА*߅||ζ⺗СυΆ̈́̆ˋʆˋʎЉ|ŴȊNJȐǒƄōĆэ}而~{}}~}|Ⱦ|ò˭ģ~~}}|||ޅӄЄ +ʄĄ ̅˃ʄˆ̆ˈʆ˄ʅυІτ΅τ΄͊̂̈́̂˄̄̈́υЂψЄӄч҄ӂ҄ӄԂӈքļ& +ʆ΅-Q||ߒ||ŬȩE~} ĊņƄdž5;»źӈ΅υΕ̈́΂̈́Ά͈ͅ΂̈́ΈφЄт҄Մꇔ׈ֈ׉ +وڅ$悓۽ٞٗڊ$یѸ׵ڋփՓփׄ؄&鑱ؾݻܔۄ܊ۅ&ʳֶَ؇א*犬Հ灏ǺּסօՅԅӅҍфҊэІ׍̻Ѝ΄ψ΂͈̉͆̄ˇʇɓȊDŽƆłƆņĈ̉⁓񅑞źʸҳʨք̈́)&҄хЃч҆шЅхЅՆֆՄԄ Ԅӊ҂ӄ҂ф҄׆ֆلل؄ىۅ܄8ćԅ-R痤ȹ̲ϯ<􂐚£~~~~~ЅE|~9}»¶ij~ˉʈɘȈɆȊɃȍɊʄυՇ˪҅ш҆ӂԆՄԆՆ$狱܆~ű~ݤԂӇԉՆԑ!ߝӄ⃗}ЂϐЅщ"揮󌣽󁆈~жѰՆ՛)ꐮ}˴ַ}ԍӂ҇ӌ҇'ꌥêˣҡхЅτ΃̂ͅ˕̇ˈʆ +݂}ʈɄȐɍȃǎȅNjƄŎĆЊၒ򅒟ĺϾ}۵~~}}̈́̄Ä(ʄЅύ΅͂΄͂΄̈́Ά +Є҂Ӆ҉Ԅ τЋφщԅՄՄԈ +֊ׂ؄ׂօӄ ȄɄ̄\êɪ\~񁊒ȺF킃{}~7~|~ò}ɍȍDŽƳNjȄ +̈́ӆɩψЈщ҆ӈ$抯څ~}ð}ܿۢґӅ҉ц"ݛу|ؿ࿟ϊΎф#䎭񋡼񀅇}εЯӫ$~菭툝|ʳԵ|~ӆҘтЊ*苤󈗧˿©ɢУφ΅̓̄ˠʋہ|ȓNJȊǘƆ +ĆЄ߀􂋓¹μ|۾ٴ~~~}||؄˅(͈̄͆̂ˇ̂͆̂˄ +҄фЂτЃчψ΄τ΂͆ЅӆԅՂԄԄӇԊՆՉՄ ǿƄǂȄ6$~Ϳ©ǩ"?}~˄DŽ…ÅĂÈĂňƄF6ǻʸЉυ΂̈́ΐ͏΄͋΂͎Ήτ Ԅۋѯׄև׈؈لڂنڈ$폵≤ʶƨْچو؆"ه膛뀇Ʈť֌Ս؄"쓳ջ׵$܂ѹܼŃچ٘؂׉+ƸɯѨףօՆԂӄҜъЄτ ㅉЈ΂͌΄φΘ̋ͅ˄ʍɇȍdžƆńĐÌ愖òŦ๞фńՅ ҄ӆ҂ӈ҂ц҂ӆ҂ф +؄ׄւՄلՈԄՄԂӆօنڄڄو܆ۊ܂݄܂ۄ؄ +̄͂΄ф ݄HƷȯί A҅ο£~~~~~ІE۷}~|~ 5ƽ~ȻųʊɂȄɖȉɅȋȎɊʄ }͹~׵}ш҆ӃԅՅԅՇ)򉜱}~κȫӈԂՄԂՅԓ 珮򌢻~϶Я和ЂϑЅш葰}̳˪څՈ՜%݉膚}~Һ~ܼŁՄԌ҉Ӌ҅(؃οжܱҡхЄτ΃͛̈ˋʉɂʆɂȆɄȐɊȆǏȆLJƄŎĆш-ꇚ~VǾ~ǶͰǦ~~~}}ل˄(ӄԄ Јφ΂ψ +φ΂̈́ +ԄӊՄфЄь҄ՆֆׂքՅ֊׆ׅ׆ԆӅŽ"ńȄ˄Pݚɩ\󄕦󃍗ՄUڵ|}{}~4~ļ}ƺıɈȎưnjȄɂʄ|˸}ֳ|чЇъ҅ӊ#~~|}̸ǩҋӅҊц$厬}ʹήΈϋ΍ψ搯􍤿􂅄|˱ɩ؄$ۈ煙|}и}ںÀӆҘтЉ*އׂ셔̽ϴڰФφ΅͂̅ˉʅˍʊɄȈșNjȈǚƍńĆ΅"醙}pż}Ŵ˯ť~~}}}|ɄӍ΄Έ͂̄͂̄̈́̅̄ фӄ҄тЅт҄Ј·ςΊςЈт҄ԅӄԂӆՅփׅփׄւՆӈĻ"Ą ʄ Մ PۘٿǨ `񃓤񂌖ÿӹ†ÂĆÆĆŇO5º˸ІϋΑ͋΂͜ΈυӾݹ؇׆؊نڊ#ェԂԿίٍڄي؆+퓳ջִ֏Պֈ"Ҹѯ$㍬퀇ؿʄچ٘؂׉*挳އĴֻⶐףևՅԂӄҊтҐъЈψЇ͆΂͗Μ͆̆˄ʎɆȐljƅŅĐÆ |遏ú̻ҵ̪ބτƄ„ ׄىԇӂ҄ӂ҄ӄ҅҄ل؄ׂքڅֈքԋ؄ۆ܂ۄڂۆڄۊ܆݂܄݄܄ۄڂن؄>ʄ ЄZ㞰Ƭέc½ڿ£~~~~~Ѕϼ}~}|~~Ǻ~мʋɕȪɆʄ!؅Øׇï依ԇ҄ӂԋӋԋ$놙~­вՔԗ$׌~ށ|êᾞЄіЄц꒲|||ɯģՈ։Շ%ۓ΂႖|ؿʂևԎӊӄ*悒̻}¨ҞюЄτ΅̎̈́̅ˌʇɂȍɋȗɇȆLjɉȂDŽȊǂƊŊăՂ񅓡}ǿνټٳ~}҄M ՄւՄֆՄօԄ҅фЄςъφЂцЂυՄօՂԇՄ +҄ф҆ӆ҃Ӈ؄لي׊؆ل؉ՅՄŽ„˄T}ʩ_逊}||}}|þ}ͦͺ|}|{}}~Ÿ}ϻȕljƍǂȆLjȄdžȃDžȄɄքՆ~­⽜҆Ѕщ҂щ҇ӈ$ꕿ酘}ϰԝ҄ф҆#Ջ}܀{߽~·τ ΍χ葱{{{ǮâԄե"ڒ́߁{~׾࿠ȁԇҥ)䁑ʺ|쿖ІτЂϊЎψ΅̓̍̊˃ʊɇȋLJȈǂƈȇDŽȃǑƉǐƅŅĊÄ’ +|ƽͼ׺ر~}}%ՔԃӄфЄτύΊσΆՆԄ +ՆԆτҌӄՄԄՂֆׅքՄ֊ׅ؃ׄՆւՆ ҅ ļ;e|ȧc~|{{||{¼|̥빹Äĉ^0ǽ̿ϐΐͤ΂τ΅τ"މȜ݋ɳġنׄؔهډ$򊝳Dzַیقڏل؅(ܐ́䄙뀈ȯĢՇքՂֈՍֆڀ瀈δʨۆ܊ܘ"Ԇ熚ꀇŭƦυ܄ڃ٥)셖Ȭƛ׆քׂև׊ֈՄԃӗ҄ъЈϘ΅͛·̈́̉͂Έ͂̄͊̂ˊʊɃȕǂƊŅČč񁉒ϱ߷.dž$ ڄۇڄۄڂلׄքՄԂՄԂՍԋՂԆ ۅڄڄ +ׄք؋׃؄ څ݄ +ފ܊݆ބ݈܂ۆل؄7Džhϭ4gþӪ~~~~~Ђh|}~󀃇|~,}}}Ǿ̿ӾʋɐȪɅʄ$ل쉕͸ȤӅ҄ӂԌӊԍ#߆ኦ䃕~˴|عāօԂӈԜ#ۉ퉠񁆈~ѷάڄЄѕЄц씴~}ūཛྷ~ڎւՅֈՈ$ׁ~ŭťфֈԎӆ҇.އ}|ȶгѤ~ҜѐЅτΗ͂̆ˌʈɂȐɇȘɆȆljȂɓȇǂƇƄ<྄釞遏žòũэ}}˄#ׄւׇփׅփՄӅ҄фЂьЄт҆тІքׄփՇք؆քӄԂӄ҄ ԉօل؄ׄ؊ن ׆؂׆ +ԄӅǽ( ȄɄX}~~5n逌}~~|~ܺh{|}{}~-|||ƽ˽ѽȐljƋǒȃǎȅ(׃눔̶ǣЄы҃ш҅ӄӄ#݅߉⁔}ɳ{ַ~€Ԝ҅у҇ ߠو눞}ϵͫك ΐχ꒳}|ê߼}Ԇբ"Հ}ìĤσԈҤ&܆އ|{ǴβУ}фІτЂϊЊψΆ̈́̊˄̇˃ʆɈȌLJȏDŽȊǎƐǂƄNJƂŌĄ!􂈉޼熜耎Ľ±ħϋ|| +τ-֌ԉӄ҄фІІτ΄ωЃφՄ +օԊ҄тӆ҂ф҈քՄւׅ؆ׇֈ׊؄ׂֆԄԅӅ҆Ƽ|~}}}~~h~~|}~~~}{ľ}žۄÈĄŀĺķðόΏ͔·χ΄τ΄τЄ$߇‹󍙢ӽΩׄ،؈وڊ$劶玫ꆚй޾Ʌڛل؄ه"፭󍤿ּԱՈ Տև݁ꁈʰáۇ܉ܗ"܅߂˲˪ևۈ٤&㋶挧⁒λոש؄׆քׂ֊׈֎ՆԄӔ҄фЍχ΂͈΂ψ΂͛·̈́̉̈́Γˆʂ˄%üɷ˭֐ ՄJ܎܅ۄڄ؄ׄֆևՋւՆ ܅ۄڄ܆ۄ +քن؂ׄڄ܄ۄބ݄܄݊ކ ܆݂܄څم؅Q¾ŅE:4샖7ſž⿿~~~~~ЃŽx}}~}~}Ǿ̾~ϹЊɌȉʄɖʃɅʄˇ%ڃ薱􅐚}Ҫ҄ӄԎӈԊ)҂~|Ӽ˄ԢӅ"~}Ī޻ՔЎш ٶ핅ֆמ#可􍤿󂇈}˲ʩَ׋Ԡ%}~}¯}㳇ӄҝъЄφІυ΋̅˄ʈɅʄɅȇɊʆɆʐDŽȄLjȓɇ4~~Ľþი􂊓ƿ}ȷڀ~)3 ӆׇׅ؂ل؅քՄԄӅ +ӆҎӂԄֆׇ +׈ ՅԈՄԄ׈؄كڄۇڄى܋ی ׅֈú ńƀ}}~~D퇚􁉑|~9~}ſº}ù̈́|||}~|}~~|żʽ}͸ȝǎȂɒȄɇ)ق敯򄏙ֿ|Щщ҃ф҂х҄Ӌ#Ё~}{Ѻ߿ʃ։Ң }|©ݺӄςΈτΎϊ씴~}ڿ~׵ԉՑԆՉ!䎭򌣽񁅇|ɰɨ׍֎ҕт҆*|}~||ܿᲆІτЂχЌϕ΄̊ͅʅɆȃLJȎǎȂǎȋǍƌDŽȄǃȍ1}}Ä ߂~󁉑ľ|Ƶ}Wׄ֎ׅӄԃӅ҄фЉь҂цՄւ׈քׄӄԃӄ҆ӄԆӆև ؇׆؆ل +؆׉Ղԅӂԉ¹ Ąŀ||}}~~2놘򀈐{}=}~~|Ľ~|¸̸ŽËĈŃƄǎxúöԾ֊΄͈ΠσЈ'Ʈׯ؄ڄك؄ق؄لڌ#؆ₖ􂇊ťш݉٢"ނ끈ɯօքՎ֊߂킉Ƭ߻ۊܐۈ܈!쓴зЮߒݏٔ؂ن*πȴũ鸋׆քׂև׋֖ՄԄӐ҆ЄφΆφ΂͈ΌτΊόΈ͔̈́̈΄O… 憜ꂐžͼ2 ׆܆݂܄݂ބ݅مڃل؄ׄւ؄׌ل܅݄܆ نڂلچوڅه܈߄߄މ݊څ3ȿ ʄ4P3󋞵=ĽȾӾ~~~~~ЄŠ„Ä_}~}ǿŸڻ֓ɂȉɟʂˉ'}߄}ɱڱӆԎӈԊ(ìǧՏيӄҐӈ ֎̂燝ѶʨЌъۀ ׼үۂֆדփ׆$ۖՇ눟зϮޒڎԝ&ۆ䋧䃕~лͰÓфҝъ ݅ЄτΊ͆̄˄ʉɄʃɈȆɌʄɉʈɉȄLjȈɃʄ9~~}}~~~}|۶❛~ځ}󁉑~⣸  +Ջل؄قڄن؂ׄՅԃӄԄӂԆӏՄׄ؂و؆لڂل؇ւՅֆՄֆՆ؉܋ څ ۄ܂ۄچىֆՂֈļĄŀ}}~~~z퉜怍񀉑|~~|Ľ}¶~½b|~}|ƾ~ķغȚǏȅɏȆɆ)|݃|ǰدӄӆ҂ф҂ц҈ӈ)􌡺~«Ŧӎҝ(Սˁ兛~ϵɧφτΌό핶~պЭځԊՎԉՇ!ڕӆ針~ϵάܐؐ҈ф҇ф҄+څ⊦⁔~}κ̯’ІτЂχЍψ섇ۆ΅̈́̉ʆɄȆdžȆǂƆLjȂɊȃɇȇǎƊǎ6}}||}~~~~}}|{ٵ}ƿ +ـ|񀇐}ࡶ &ՄԆ։׎؂׆ ԅӂ҆ф҄ч҄ӂ҄֊؄ׂلքԆӆՆԂӄԄՂֈ׃؄مڂل؆لڂۈڅقڄ׈ւՆԈ û„À||}}~~ w눛{~}}{û|ȿ}ŠÈĄŎƋńƈDŽȄ_ļ˽۞΢τЉ&ရ刞϶ඏڄقڅق؄ق؄لڍ*󂈋ɱ̫ۓٝ&ܒ҆튡׻ЭՂֈՌ֌ ᄚ׳ی܄܅ۍ܆"ۊ񌣾ּղڏم؅ن؈,ቷꏬ놙ӵɗ׆քׂև׌։􈌃ՄԄӎхЄχΆυ΄͇Ός΍ϋΈ͍̈́̃΄ς΄8Ỉ衠¾怎Ŀ觽ă .ڋބ݄ނ߄ބ݄څۃڄك؅؈ق؆܄݂ވ݄څچنڄۆچ݇ކ߆߆މۆڂۈ󌠸샑ºƽ!Ǻ¿~~~~~Ѓ„ņƆO}}~ĿɭɄȌɄʆɆɗʉ˅'ۃ~ǿѸ㷏օӐԌ$ۂ卫퉞~˳έߓӌ҃х҉Ӆ҆} é۷씕Ћъ݁뀆ҷʧ֋׈֋ք!ׂ~კ뀅ֻԲۅՒԂӊԄ+}ȳ}ܽաхҎфҊщ惜~ŽІΉ̈́̅˅ʏɊȇɐʂˈʄɓȉB~0|»~Ŀ |񀈏" +քׅ؃ه +ۄڇمׄ +Մԉ Ն لڃمڄۄهՄ֊ׂ؆ׂքلڅފڄ +ދۅ܂ۅ܄ۆ؊ׇԄ"Žf}2~+䅘䀍~>}º}Ż}̽}ĿƒÄĉN||}ýǬ܉ǢȄɈȎɉ(ق}Žзᵎ՛҈ӄԅ"ځ㌪눝}ɱ̫ݒ؉ьЌщޣߍ| ٵ꓎ΐϊ!ۀ~еȥԠ%Ձ}߂ԺҰهӔ҃ӌ$~|Dz|ڻԟԓύЊ傚}؅΄˄̄˄ʄɆȄDŽȊDŽƅLjȃɄȈɈȉdžDŽƅlj=~~}'~{}½j{Ʉ4ԄՂքׄ؄چ؅ׇԄҌӄԄӏ ه؇ن׆օՅօՄ ք +لۇ ۆ܆ۄڂۆօՂֆ0ļ f|2}~~~+ㄗ}>~||ú|˻|ýĄÊčŇÅăŅƆDŽʆˇS󁋓ľϲ͈ΈφΚτЅ(ᆝ過Ĺ׽鼓ܛوڅۄ"ᅵ둰􍢼иӲ߉،׌؉璳耈ȮἚՎ֊$ㅛ򄊌ؼϫۄ܂ݔ݇܄!܅ǁ燝򃉌ڷڄلڌلڋ$тθ¤ۥۓ֍׊쇠₍ǒՄӅ҄хЄφ΄φΈ͈ΏυЇτΒ͈C &Ŀ!i߃䀎τ4 ۄ܅݃އ +߆ކ ڄڄوڄنچ ބ߄ބ߄އڄے܂ۅބ߅߄ +ۆ܇-¼ fbꈜ냑>ȿ·~~~~~Ѓ +„ņƇǃƆC~ɆȅɎɛʊ˄.ׁɾڿ뽒ӄԂӔԊ$Ӆ䄙}~ҹԲ҅цӅ҇ ߃퀆~еƣەЉщ!ނ큆~̲چ֌֌քꓴ~~~ٶۆՖԃՋ$ڃ卪뇛󀄆ʬ鲃Ӎ҆хҊч~}ÏЄςΈ̈́̅˅ʇʈɉȇɚʄɎL}(˼0Ƽǽ}Gք؄لڈ܅܅چ քԈՈքՆֆۅڄڇքיڄۂڄۄ߄݄ۄ݅߅ނ݄݄܂݆ۆ؆ׂ؈Ԅƾ}}~~~C}6~úĹ}Ǻ~ʿ‚ÄĒC}퀈NJȂɍɅȅɆȐɆ)Հ~Ƚؾ黑ԙ҉Ԉ"ф⃘|}зұ߅яЌцЄ ݂}γġό΍ϊ"݁뀅}˰~؅Ԡ$蒳}}ٿ}״وӄ҆Ӊ҅Ӆ'؂㌩醚Ծɫ谂ѠЋ}|͈̄˄ʄɅȄDžȌƅNJȂɄȈɈȗn|~¿Ɉ2¿źŻy~|~߰ՄJ"ׄֆׂ؆لۅڂى؈ׅӆӅӄօ؄قڈنڅ؆׆Մ׆ք ׄڄم܅ ڄۂڄ܅݆܄ۂ܈ۄ +׋ՄӄЅĽ||}}}~~B򎥾|~6}~ø|Ź}ȾÓĂńĆÅăņƄDŽȂɄʆˈ̂˅E΄ͅέϓЅ)݅냑ĶŪ–ܙوڄۆ"وꈝ큈ؾڷ؏׌؆ׄ凝󄊌պ˧Ջ։#䆝󄊌ҷǣ܄ݓ܃݆$݂쁈Ŭ߻ڃنڅ'둯񋟷ůбؠ׋恘ۀȓӅ҄хЄφ΄χ·͈ΐσЈυ΋͈A󃎖'5¼倎nۄ܂݄ބ߇߆ ۄٌڄچۅ߄߇ۄ܅܉݂܅߄߄݆݉ڄل½C7ȿʿ̿¾Ђ~~~~~Ђ…ʼnƈǃȅɄ2󁋔|ɘʂ˄ʂˋʏˇʅ˄'銪恐Ⱥ~ƫՅԆӐԄՂԅՅ!ߎٿڸҌц҄ӆ҇ԏІ }ձۂьЈч҅߃ƬݹՄ֏ׂևׅۗ׉ūݺԇՈԔ*ʀͶ|عŏӎҖф񍢷ЀςΆ̆ͅ˃ʗȕɂʓɄA􆏛}~,~}.}ʼ~Ǽ݁~Cυي܅݂ބ߂ބ݂܏ڄق؄ څ܄݈܄ ݇ هۄڄ܄݆ߋ߄ ݄ވ݅څل؆ Յ҄ǿ}}~~郑􃍗}}Ž}ɽϽȾ ċ +Lj2񀉓{ȈǂȌɂȲɆ)物~䀏ǹ}ĪԗҔ#ݍ~~׾~ضєЈхІ#ӎ΄슢ڿ|ӯفЅφ΋ωІ݂쀅ūܷ쓇ԝՅ ٖՈêܸڅԤ%~~˵{׷~Î҄цЂюЎ􃌔̅ͅˇ +LJȎLjȂǘȎ>򅎙|}~1~~}|¿/~|ſȻ}ƻ܀}~˄**ن؂نڂۅ݄܃ۏքՄքՆֆׄلچ݆ۈ؄و؎ل܄ۄ܄߆މދ܄݆܆ڄ؄ׂ؈Յ҅ӄ!Ž +||}}~~[ށ炐򂌖|~|Ļ|ǻλƽ‹‡ÒĂÉĆņƃDžʈˎ·5ϊΔυЊϒЂχЄ*؃텔ο˰Ɨڋلچٔ#იĬཛؔ׈؅ׅ$ړ։Ƭ۶ׅֆՋ։׆ 凞􄊌̱供܄ۆ܃ݕ܅ ݍʰ保ڃۖڂۄڂۅ%σ⃗һ޾ʓل؆ׂ؎׎քԄӄ҆хЂωϓωΆϓ΃̈́?-2ㅛ肐ǿ҄*ԅފ߄ނ݄ۄ݄߅ އ߄߅ބ݆ۅý}憛¹¶®~~~~~Ѓ…ʼnƎǂȔ%򃋖}ɔʄˊʐˈʄ˄̄(䆦}胓ó̰’ԆӒՋ'}搯Ŭཛҍѐ҉!味~̲応҆ьЈц҆}԰؀Յ֍׃ֆ׆$׃懞򁅈}ɯ⾜ԧ#䎬~ìƧٞՆӋҘ"傝凝΅͆̆˂ʭɂʓ/򃎚|~A~}煼BϜ}º|ɼ +tㅛ灏Ç˄ń3 фچۆ݅߅ݐلׄل؅ۄ݄ވ݄ ވ ڇۆ݄ކ߂߇ޅ݂ބۄڅԄՄԂӄž}}~~~wㅜ񇖦}~ƺѹŽ ĊʼnƆlj+|~ȄǂȌɂȳɄʄ'Ⅴ|悑±ʮӋӈҕ!|䎭󁆇ê޻ІцЇޥ㐲~~}˰㾛ԄІτΊω%ރ쀅ڿ|ӯԛՅ ւ~农|ǭ༚ӄԔӊ&⌫퉞}~Ŧםӄ҄цЂэЏ 䁛䆜첂͆̄ˇʃɑȋLjȂnjȄ8쁉{}?~}|廆Λ0|{ѿǺ +~ᄚ倎†Ą3фׄ؈كڅ݄ ډۄلׅփׄ ֆۄۄ܂ۄކ݇لڈَڄ݄܄݄ފ߈ߋ݄ކ݈ۄل؄׆ +Ԅӆý|}}}~tᄛ~|~~Ǿ}Ÿ~Ϸļ +ˆÂŠÌăÉĈņƃDžʈˉ͉χ%ΆςЌόЂφЂϑЃψЄ*ꊪӁɸѵǖڊلچٕ!݁쓴ʱ ׆؆ׇ땸݂ҷšۄׅօՊ։%懞Ƭڵރ۝܄ ݆Ȃ틢δàڄ۔ڌ$ꑱȱ̬ߣڄل؆ׂ؍׏놡싢܅Ӆ҆хЂψ΂ϒ΂ύ΃ϓ9􆎝 +1ՠ/ȿƲ鈟턓ɋ4ׄ߆ބ܄ބ݂ބ݅ ߇߈܅لڃل»Lg鉡񂌗,Ž̿׾» +~~~~~Ђ†ÄăŅƌDŽȂǜ􂋔ޅɅȉɈʂˋʅ˄ʄˈʇˋʇ˃̅&Ⴁ鄕̺Ѵ}œքӤ#ӆ뉠񁆈}˱Ÿы҄юҊ}凝򂇈ؽΪ҄шЈш҄#ᄚպ˧Սւז#ꔶہ뀆~Ͳ~Յ֌ՆքՉ*~ށ}иԴӇҊцҍ$ׁӼΖӄ΄͆̄˔ɄʎɆʍ4󅐜󀇎~E~}~͉ƅKᓗ¸DZZ늠ρ1Ȅ/Ӆ ݆ކ߆݆ބڄلڂٌڅ݅އ߅߆݇߉߄ڈۂچׄֈՂօ&ӄ0}p~~ᅝ򈘩~~ƽȻǰùĊŎƆǂƊǂƉ~򁊓ȊljȇɈȨɂȈɂʅ*߁烔ʹϲ|Òӟ҄ӄ!҅鈟|ɯ~ЂѠ|ㅜֻͩЌόЄф߃쀅ӸʦԊՈԃՇ"蓵ـ}˱}ӆԂӞ%ތ}܀|ζӲ~҇їЅυ$Հѻ̕ч̂ˆʉɘȂǒȄdž2񄏛}E~}|~}ˈĄKߒ¿~ŰԿꉟ΁. ,؄ڇ݄܅݄݅ ٌ؃ل؂ل؂ل݇ ݈߈߆ ܄ې܄ކ߆߇߂ފ݄܃ۇڄقچق؅ׂօӄľ'҄/|m}}񇗧}}}ļǺů¸ŒÈĂÄĆʼnƅdžȄɂʅˋ̖ ̈́񂉓΃͉ΆφЊωϊЂϋЇψЄф)熥ҿ׹ʗڍلڎلڄ!يжǣׂؐ؏€늢¨ԯׄւՆ֌ׄ؄爟ۿѬېۄ܆"ᄛ񄉌ӷǣڦ%ɂ䅚ֽڹهؗ׆ք$݄ªӚ؆Ӄ҆фИόΈύ4􃎚Pÿҍ˄K痛½ǽ̶Ż񍤽Յ%ńBׄ؄ ߄ބ߂ކޅ߅ ߈߆܄ېļ&ׄ0r爡¹̵Ⱦ~~~~~Ѓ…ÄăŅƈǣȋԇɅȉɈˌʅ˂ʉ˅ʈˈʉ˃̄̈́(~酗}~~}ָǓӖԃӉԄ ۇ}쀅еţ҃ю҂чՒӈ|ȭݸ鐆҅цЉш҄"ᄛ~γ}ե#ڒՉ}жŢՆւՄօՓ"ތ񌣽Ĭƌ߄Ԃӊ҅ъ҉&ㄡ󇕢~͵㼚Ӆ΄͆̄˔ʎɆʈ6~~}~V~}½~}|ՄU~ſɽԺ~~~•FԄ ׄڄފ߄ۄڌۄڂۄ߆߇߇߂߄ބ݆܄ۂ܆ۆ؄Մքԅĸ&Äŀ}}}~؀}~.}Ļ}İȹ ƒÄĊŎƅLJƆDŽƈdžӏNJȆɉȍɄʠɂʆ)}焖|}}|Զ~őӟ҃Ӆ*چ|ނ~δĢѐяԐ҇{Ƭܶ珈ЋύЄф߃}̲|֍ԉՑ"ّԈ|~ϴġӥ"܋ëῠċ݅҆ёЂч,ჟ򆓡ľ}˳ẘч̃ˆʊ ɌȆNjȇ6}}|}~_}|~¾}|{ӺW}þǼҸվ~}}}~*?҄ۆ܆݆ކބ ڌلڈ ݈܂݆ވܑ݄݅߆ ߉ރ݄یڃم؂ׄ Մö&τm|||}~~솖|}~.~|¹|ͿïƸ†ÄąʼnƆDžȄɃʄˈ̞Ή̈́΃τڇ΄͉·τЊϢψЃх)₟dz۽̖ڎقڏلڅ)À燞󄉌ֺ˨ؐ؏ەٌ耇Ͳ余׋֍ׄ؄爟􄊌ԸǢ݌ۊ܉ۃ܄"ۍ遈ֻ˦ڦ"䐰ʱƦːهׂؐ؇ׄ(臥ŽҺ؇ӂ҆щГύ·ψ.삎]½ڄſ¶ٿźvǘÄل߄ߌ߂  +݄ڄۄɼbރŷɵ;~~~~~~Ѓ…ÄĄńƇǫȊɂʄ ȕɄʂɐʔ˂̑˅̆͆(퐬醙ȴ}ٻÍԄӆԈӂԍ 摲~~Թʧ҄ӎ%瓶ہ~ҷƢҖх҆퀆ƭݸ菨!~~舠􂇉ԹɥՎւՕ!ۄނ}~ѸϮݜԄӇ҆ч҃ӈ)ކȾŬ}ϩυΈ̈́̐ˈʅɋȄɈȀ~|}}}~}|Ŀ}¼}~}ƅ|}~~}~}ſ}ŸӸ~ȶc}}DŽ Άт҄ׄۅ߆݈܆ބ߂ކ݄܇ք}}~~K傒퀊}}}~úʻе}Ʒ„ÄĆņƂLjƂǐƃdžƄǏɓNjɈȎɆʅʄɏʉ˄&돫腗~~Ʋ|ع҃ѐ"䐰}}ӸɥыЌфЂц撴ـ}~жġ؅ЊώІф햹߃ū۶掌Օ }}懞򁆈~ҷǣӥ"ك܁|}϶ͬܛ҇ьЍ+܅섒Ǽī|Ψ͌̃ˈʑɉȖ'ߚ}{|g{½||Ŀ~}|ĺ퀕{|}~~~}|~}|ľ|ķѶ}Ƶ~~~}|͇Ԅ߄ +ކ߂߂ބڄۊ܆܄݄߅߅ބ߂ކ ނ݇܆ۆڄׄՅ <Єр|}}}~~け|~||}Ⱥ ϴ|Ŷ ÂĆŇDžȄɄʄˆ̡Ήφ΄ +͔ΆΏϋЅцЂъЂфЈш҅%͹ȑكؐ"앷ہ쁈ڿЫ؋׌؄׃؅ᄜ񂉌ؼ˦߅׊֎׆؄爟󄉋̲㽙ۆ܄ۉܐ$ہāپΩڋۂܔ'䅜큇׽ճڅه؄ֆ׎+䊣ö˱ծԋӄ҇ѐЈυ·͇,jĿ¼Ż+Ž˽ٽͻkӆւׄ܄   ߆݄ۄƼK놖󃎙ȿֺ˼~~~~~~Є„ÅĄŅƆǬȜɂȐɄʂɐʊ˄̊ˈ͈̈&됸玫醚ιܼԄӄԛ чؽΪԑ҆ӆ҂ӄ!Ӏ~艠򁆈}ԯ}х҈햺ٿ|ҭ|ւՅ擵ہ뀆ֻ̨ՈւՔ!ӈ󂆈ī޻؅ԅӆ҇х҅ӈ&ށ悑׼滗}ш΄͉̎ˈʄəgƿƻ҈ 4Ϗ~}}~¹Ķܾɵ~}}?6ӄ҂ӄ& +ބ߆ޅ ߇އ݆܄ڄقڄ؂لׄƿ4Єр}}~~~݄}}}|úɺǮ +…ÃĆŇƃdžƄǐƄDŽƅDŽLjȘNjɄȎɆ̅ɔʇˈ$ꏶ捩腙~~̷~ۻߑ҅х҅,φ׼ͩшЖх}爟ڿ|ҭ|ЊώІф땹ރ~׽{Ѭ{ 䑴ـԺʦӌԂ՘!҇틢񁅇ªܹև҇ыЏ(܀偐ջ井|͎̅ˉʏɇȅDŽƋl콛~ÿŽĺ3Ύ}||~~}~´۽dz~~~}||8  ҈Յ +چ߄ߋ߄ۄޅ܆݅ރ߄߆ ߂އۄ؇׃ք ԅž|}}}~~~Cۃ|||{¸Ǹ~ŬͷŠÃĆņƄDŽȅɄʄˆ̡͂ΉͭΆςΎϊІшЎъ҈$Ծ¢Ǒل؅ك؉%֋©ԯ؈ז؅؃āƬڳ؀׊֎׆؄懞򃉋īزրۄ܆ܔ 엺ᅜ򄉌Ҭڋۄ܉ۂ܈ۄ"ٌɰچه؄ֆ׏(ㄤ텕Ǹ§ԍӄ҈ѐЇτ΋͂΋gĠ½ĽʅDžĄÂ…ԒǾɻįιw؇$    ߄ބ܆ý>Մր㇡ɿο̲ ~~~~~~„ŅƆǐȆɖȉɋȊɂȎɖʊ܌̈ˎ̆͂Έ̈́$励〈釛ӽ߾ܚӃҋ ׃|䆞ҭ͂ԈҙӅؓӈ|ʱ⼘Ӛш҄ 땹߃~}ѷȣՆ֎Ղ֍ ِφ|ؾϪֈՅօב&앶ڀ~~жɧljԆӊч҃ӆ%苰ވ}óγѧӇω΋̋ͅˇʅɛJГ쐙}ʼ̈́ƄŇĈŠ􀆍~|Ļɺ|ֿܿv~~~}}ԆՅքمه݄߃ + + ߅܄ۂ܄ډۂڄ؄֊ƽ$DŽ$\}}~덨䂓Ļ}ʻ~īʴÅĆŊƐƝDŽƞLJȋɂȆɂʅɄ +ۋ͓ʉ˅̂ˆ&㉰煚ѻݼ~ۓҍф҄$ւ{⅜ڿЫ́Р!֒ч{ɯຖЅςІφЂϊЅ锸݂}|϶ƢߙԂӆԅ؎ͅ{׼ͩԂӇԉՄԌ!ꓵ}}ϵǥňۈ҅эЏ%抯܆|±̱Ϧ҉͈̌˅ʍɆȇǏƇKΒꏗ~ȿ|ɺ~DŽƂńĄÌ;~}~~~{úǸ{ڽս~~}}}||6ԄӂԈԅ܅߄ކ݄ + ބ߄ނ݄܄ نڂل؂ׄżMe||}~ꋦ⁒쀊¹|ɺ}êȲ ŒÂĄņƊDŽʄˆ̏͊Ύ͔΄͟Ηϊ⏯хЏч҄Ӄ҆%덶萮¬ãĊٍ؄ل ݆늢ƫرӆڜه!ݗٌеׅւ׆ֆׂ֊ׅ凝׼ͨ!ߓՊ耇éկۛ!ֻΫ̍م؍׏%䋧‑ɸԸ֫ىԈӋ҅ьІχΘJ՗򔝢ƾ҄˄ʇɈȂNJĄÄ„;ϿĬñ7ڇ ޅ܄ ߈߄݄ۊ M[ꆗɯϸ ~~~~~~„ńƆǏȋɎȎɇljȉɂȎɖʊ娃Ƹ}Ա}τː̆̈́Ά̈́&߅܉釜~ྞ~ەӇҊ'䑴؀é~հӄҝ 擷܂~ӹɤш҄蔸݂}Ȱ㽙צ 凞|ҭ~։Մֆ׌%݉ł늢󂆈©~״ߙԇӎя%IJĨ黔Њψ΋͆̊ˆʄɌȄǏ9Ԩ~ʿ̅˄ʇɅDŽƃŇĈŠ;}~}}}ǷвĮ~~}}. ؄Մօׄڅۂچބ߄ ߂ޅ݆ۆ܂ۄڂلׄֆý)DŽȀ}􃍗ļˮư ÅĄŇƳDžƝdžȌɄʄ㦂ķ|Ұ|Έʉˎ(݄ڈ熛}ֿ޽}ِҎу҆ ␲~}Ӯуӓт҅у҉咵ځ}~ѸǣЅςІφЂϊЅ擶܁|ǮỘӈӋԆӂԄ㆝ؾ{Ь}ԂӇԊԍ!ۈā鉠񁅇}ղݗӈ҇яЊ$솘°~ç蹓ֈ΄͈̍˅ʋɆȈǏƅ7ӧ}Ǿ~Ƚ̅ʅɃȈĈÈ<|}|~~|ǿ|ƶΰ­~~}}||-Վ؄ׄ܅߄ނ߆ބ + ߄߄܄ +څۂڄ ֎P\|솗򂌖»ξɭŮ  ŇÂąŅƉDŽʅ˅̋͌·΄͐ΐ͙Ηϊ꬇˽ڶЌш҆ӂ҆ӄ$剰⍬Ʈâَ؄م ꕸރȮ۴هڋ؂ن؂ل؄ى헼⅜پϩׅւ׆ֆׂ֊ׅ䆜퀇ε܊ڎۂچ"싣ūزԁۛ"ʅǭݹڇو؎׊$ɷʭ݄ՈԈӌ҄ьІσ΍̐7ڭżĶ҄фЄφ΅̄˄ʆɈLJƄłĄÄ„񀈐񁋔ƻͼֶɲoۄڂۇ܄߅߆  ߂ބۉ $ʄ$[􋝯ŵг˴~~~~~~Ї~˄ƃDŽȄȗɊȐɆȇǐȆɈʄɊɇʇ᧎ֈƱ㽜ˊ͎̊΂υ#Ն臜}ëྜྷ~، +Ҏ$ߐΆūױՄӄҊӄԑԀ}鉠~ְׅч҇咶ہ~ױ܊ԉՂԘ܎}}ԯ҄׌Յօ׈ֈ#܎}~~ͳԉӄ҂Ӊы%ނօ߀}}¯׺ҤҊЃχΆ͈̆ˈʅɍȈLj.Ԧƿ~ĸ|ˌ̇ˇʇƄňĆĂ~򁈑~Ͼַì~}}Z}؈׆؄݇߅  + +߄އ ܄ۂڄք׈ ºطüǷ͵ +}~!~ŅƎdždžȝǎƒǠ঍ԇį⼚ʏˈ̄̈́̄,~Ӆ憛|ª޼}хғт҉ݏ̅Ī~հӃӊђ҂ч |爟~ؿ}ԯՄЈωЂψЈ㑴ڀ􀂃}־~հډӄԌޜۍ~|ٿ|ӮуՄӋԗ ڍ|}}̲保ՄҍъЂф&܁Մ|~~|ָУЋ΅͆̎˄ʊɃȆǠ,ӥŽ}¶{ˍʆɈȄńąÈ…}󃎙~}ȾͽԵ«~}|[||ք Մׄمڂۅ ܄߅߄߄ޅ݂܅ۄڈքՆ $Äx׵ƶԸ˴ +Є˂̄͐΂τ΂ϊ΄͒Ά͇̍Πχ竒܌˵ օю҆ӂԇӃԄ$ჩۊɰáْ݊؂ىӊ˰ݶۈڊؒق؇ ڄĀ􂇉ƭ݈ܵ׉ֈׂև׉떻ᅛŭݶ⍑ډیⒶ܃쁇ƭڴ؇܍ۘ!⒴ف킈Ӹƣ܅؄ٌ؊ׂ؄&䅬܉愗ȴݿة׊ՄԈӌ҅чІφΌ̈́̊,ګĻɽЍшЅψ˄ʈɆȄǂƆĆźòܼȰ\#݈݄ ݄  ߄ +܇ ƿɄx޻ºͼܾҺ ~~~~~~Ў}2~ſ}˄ɂʋɉȐɆȊǎȉɃʆɆʆɆʄՈզꐝӼȣ҄̍ͅ΂ψ΂υ%΃憝~ŭ߼ֆԄӆҎ$凟񁆈Ƭٳքӆ҈ӄԌ#۔ЇȰ⼘֖ч҈ᐳـϷ˦ԄՆԗׇā©ױՅ׍Ւֆ ㆝񂆈پϫȇۅԉӄӏ$卷ꑯ~̮츐֍Єψ΄͌̆ˇʅɇȊDŽȇЍڃ~ʊˋ̈ˇʇƄňĆă-􂑝}󂊓~N}ĺնᾧ~~}mڄۃڅهلކ + + + ݄܈ل׆  Älڷÿ˯ + + }3}þ|ǎȝNJńDŽƌǠ!ԇӤ菛~ѻǢʉˈ̍̈́΄"̂䅛}ë޻ԇғтҊ~㆞ūױՃӎэ҂ш ٓφ􎦿~ƮທЄόЂχЈߏ~ͶɥҕӃԌՆ€싢~~կԄՅӄԂӆԈՂԊ ~ᅜ׽ͪƆنҎщ)㌵萭}~Ӿʭ귎ԉυ΅͈̊ˆʈɄȆǣΌ؂˾}˅ȄɄɐʇɈȄŅĄÇ‡ +.򁐛|񁉒}2~|¸пӴ߽r~~}}|ڋֆ څۂ܅ۆ܂݄߂ +߆݆ބ܂ۊ׆֊ ƿص􃌔Ͽɮܿ +Xſ΄τ΂ω΄͐Ά͉̎͆ΉτΒτۋڪ𔡧ªΧэ҇ӆԂӄԄՄ"ԇ튡ʲۈْ؂ي܃실̱߸܈ڊ؛ ֊εׅ֋ׂև׈甸߄ԼЪڅۋ݊ɄǮܶۈ܅ڄۂچ۔ 銡é԰َ͋؉0됻ŰҳֆՆԆӈ҉чІυ΍͈͇̈ՑŸϊЌщІχ +ʈɆȄǂƅłĆ/뀌ɿŴڻë# + ߄߄܅ބ  +ބ܂݊ Ľ&DŽȀ߼Ŀƶдů +~~~~~~Ѕ&};}¼ùɇȍɆȈǂƍǍȆɂȄɄȆɈ#Ӂ~􅑝ȯҪҍ͆Ώτ%ƀ䆜ƭ޺ׄԉӆҒ؀~ǭڴ،؇ҌӇԄӂԅ⑵ځζȣҍх҆"܎~|~~ů徚ՈԏՅԅ!甸ރ|ªزیՈԈՑߍɅ||ɯݸԋӌ҂ӆ)݁}ѼѡхЂфЉχ΄̈́̄˄̅˅ʅɆȡȇɇʉ˂̌ˆʆɄȄǃƅŃĉŃ+}}}ĹϽ̭Ѵ~~} +܆݈܂ۆڂم܅ + ߆މه؅ׅ¸n}̼èԹ 򼉵#|~<|¸~ȖdžƍńʼnƛNJ&р}򄐜ƭ~Ш̄ˊ̎ͅ΅$ㅛ~Ĭܸӄҟ!ގ}Ƭس֋фЉѓـ~̵ƢЄψІۍ}{}}ĭ㽙ܖӂԍ哶܂{~ֱڋ҈҇ӍԆތȃ{{ǭ۶҅тЊтЇ$~|к޾ϟ~Ѕυ΄̈́̂ˎʄɆȅǍƄŎƇȉDŽȈɈʅɅȄǃƄŅĄÅ‰ ||~~|øλʬϲ~}}|F܄لۆ߇ ݄݅܈ن׈քׂ؄ p|ʻ~§ӷ ~𻈳!Eɾ͍·͖̉͒΂̈́Ί#؅ʹخ؈҅ӎԅՅ$˃뉡񃈋˲俜ڄٟ%擷ބͲ๔ޏ׉ؓ蕺ӻͨׄֈ׆⑵܂󀂂˴ğڄی혽䇞퀆ǯ޷ِڌۇψ耇γ㽙؄ل؂׊؂ׇ#̂ㄙ󁅇ŦץօՉ +҅ЈфЅυΆ͒͊ ό΅ϋЅыЄφ΄̈́̄˄ʃɉȄDŽƄłĄ ʿ°Ѳָ8 ߂ޅ  +އ݅܅ƼÄp²ȭڽ ~~~~~~(ΜGĻ~ɈȄDŽƂdžƊǙȅɈ&ր~ƿҷڮҊ͈ΎσЅ$䎿|⅜Ƭ۶ԊӄҕގɄǮ۴܏ӈҋԋ凜~~Ҽ}ӮՊҌц҅؋}ѻײޖֆԐՄԄے͆~}ªٳݐӌՄԆՆޏ؀뀅Ӹš}օԌӉ҅Ӆ%~ֈ쉟ͶԳԄцЂфЊχ΃ͅ 녊˅ʄɅȡDŽƄņƂdžȇɇʈ˂̌ˆʅɅȄǃƆŃĉă (򃔣|~~}ǵݽݼ~~}} ߄މ݂܅ ݆ +   ߂ބۇه؄قڇ Ƽɹ}γ %򁆋}ԉ,͛H¾~ú}̾ljƖʼnƏƅlj+}Žжحˉ̏͆Ά&⍽{~īٵߙҝ&܍ȃ󀄇ƬٳڎЌё~䅛}}к|ҭӉЂτЂψІ ֊|Ϻ~ֱܔԓӃԌ ّ̅󎥿}|ײۏ҇Ӄ҈ӎ!܎~ѷà|ԉ҆тБ#}ԇꈞ˵Ҳ쵊҈υ΅ ˇ 鄉ɆȄLjƅŇƉŇąŃƉDŽȌɇʊɇȄǃƅŅĄÅ‰  (~􃌖{}}~~|ʿƳܻܻ~~}}|| ۅ݄ڄن܆  + + ބ߈݈چ؂ׄօׅ ĻnǸ|ܾ̲!4񀅊|ӉtԠŵΈ̅ͅˋ̙ͅΉ*܄聏Ļؼ್ҊӎԆՆ&Ā艠򃈌˱ỗٜ'χͳṕ׋ؒڂ슠ٳڎֈ׆ ݏـݷێڅۋ Ӊǯ߸وڂوڋۅ䓷ބ񃉋پʦ܎م؂ב#߁܌򍤼һٸهքՊԄӂ҇ ЄυΆ̄͟˃ʆ˃̆͆ΈψЃьЅφ΄̈́̃ˆʃɈȅǃƄłĄ ꂏƻͺ¤>    +ވ݄ނ߇ ξŪ&ډ΂~~~~~~/}~~C~}ýȽʻǛƋǃȆLJȃɊ)Ԁ肑õۿ߰͑ΈτЈ$ሷīײғԢ㆞ǭ۴܏لӂҞڑɃ޹ٌ҃я҆҈DzʦȃֆՈւՅ֊ }䆜|ڴӉԂӈԋ"}删򂆈©}ӮɇۇԊӊҋ"ބ璲}񀄆ǰƦќ׍хЊχΆ胙ʆɆȐǓƅńƅDŽȄɈʌˌʆɄȆǂƄńĊ + }}~~~|ùλŦ~}}}2܄߇߄ + + +܆ۋڈ +¹v~Ʒ|ܿϳ8Ɗ9|}}~F~}|Ƽ~ȺĈŌĈŒƇDŽȅ)灐ٽݮЇ̄̈́̊̈́Ί$߇ރ~é~ձђҎц҈&~⅜~ŬٳڎҔц҂ц ؐȂӾܷІђІߙЇ􍢸űɤǂԂӔԇ|⅚~~{տسޑє҄ӄԂӄ |㇞|Ѭdžӊ҄фЈт҅+܃呱|ƯĤϛΆψΌ悘~ȆdžƞŐĂņƄLjȘɆȄDŽƄńĈÄ„ 󆕣􃌖||}~}}{·̹ĥ~~~}|||3߈܈ۆ݄ކ + ߈ۆڂه}Ŷ{ھͱ8~ĉ:@¼·̚ˋ̄̅ͅΉ(ڄȺĨ嵏ׇӄԆӉԃՊ!狼懟򃈋ʯݷؗي؉م؄#݂ꊢ򂈊̲Ṕٔ؆؇ φů侙׆ؒ׆،̷Ъ·ܕ܆ۆہꊠƯ๕ؔلڄڅ ހ실ȭس΋ڎم؃׈؂م)䈲햷ۀ͵̪֡քՄֆՎԂӅނφΆ͐̄˂̍˅ʈˆ̄̓ΈύЎυ΃͆̂˄ʄɊ ć +ɾʪƩ  + ǽw̼ŪԷ'7ˍ~~~~~~Q|}~2}ſ}ǻ˺΋ƉŊƐLJȃɊʅ,ӀŨⰉωΈτЊ"݄ꕷ݃¨|ҬňԢڌ~ŬڴێٍҋӅٌ}ïÞ}҄̅񌠴μ⽙ւՔևԊ|}|Կ۵܅ӆԈӆԋ݉Ă|˲໗ԉӌ҇$䋻ᄛ}۸ﳇѐА"〕~|ҐɄȊǔƉƄŃƆɊʈˎʆɄȆǂƉŃĊ„탗}øнǨ~$   ݄ڈ Ƽw㖘}¨ҵ.󁊓džN{|}~6~|ľ|ƺʸ̈ŐċŌƇdž3슪톖Ϳçᯈ̅̓̆Ί*ۃ蔶ہ~{ЫÇ҄ь҆'؋}􀃄ëٲٍғцш؋||ѐІ!˄ͻ໘ՊՑԅ҈{|{ӾٳєҊ$܈Á{ʰ޹ӊ҇хЅ'㉹߃|~׿~ٷф΅χ΍}{ЏȆDžƏńĂŇňÉĆńƂLjȎɐȄDžƄŃĈÄ„ 삕󇖥|λƦ}"ޖ݆݇ބ߆  ܆ۂډ'Ļᕗ|д +1񀉒~ƅ R0ŽѿӋˉʊː̆̈́Ίτ*لŶʭ鵍ӄԅӆՋ"∳㆞񃈌ǭױʌك؎ل؈!ۂ˱ดْ؏ߐڀȴȣؐ׆҉®܆ۄ܈ۂ܆$ڍ؀Įẕؔل*ʆѷڋ؅ׅ؄&爟퀇ƮὛ֊ՃևՎ郙ۂ쀉ה΅͏̔ˈ˅̃̈́ΉϋЍφ΄̂ͅˉʃɊDŽć +'󆛭yȽ®ͬƨ   +߄)障Ǭ׺<ͷ~~~~~~Ђ}~|}~~~}} ޅŅĂŊĐņƇdžȄɈ&슨р􋝰ʺɫ⯈ѕφЈ#⑴فٿ˦؅ԚӅދ€팣}~ëٲَنԐӍ~镹ނı̨͋ԍӋӄǁ쉜IJӯۜօքז؅懛ѽ۵ߖӉԅ׌}~Ժǣ~ׇԋӎ҄&Ȃ싣~ѹ̪ΘяГ~ɄȄNjƕŊĈŅȅɐʂɊʇɉȂdžƂńćĆ텘~Ⱦͻä᷎$ + +ޅ݄݄܄ĺ}׹k􄐢逊}ýβ|}{|}}~~}||ƿ~ ȼ܄‰Ã„ÈĂÆĆŊƃNjȈ+ꉧ󊜮ɸȪஇ·͋Ήυ ~؀~׽ɥ~׌҃ъ҂щ܊늢|}ױ׌؊҉ы!}男܁ð˧ˊӅт҈шЇ ߒŀꇚ±Үڛ܍ՂԈՇք冚ϻٳъ҉ц҈"Ջ~|}ҹơ}ӆҍІ"Ɓ늢}з˨͗ӆτ΂ψΔ!쁋}ƍŋďÂ…Ë NJȄɔȅDžƄŅăć섗}ƽ̹¢߶8݄ ߆ + + + + +݄چ݄܄ۄ܅ù|ָj򃏠|̆Äƾ öʅɃʉˋʇ˅̇̈́Ώ*ׄпϰ贌ՋԆԅՉք ߂蕹߄Īѫޡ"ǃ򁅅Ȱ߷ޑڈو،لہ䅙ʶҭҏڅ؂و؇ׇ؄̅󌠴ɷٴ܄݈튠­ẖ؊و؆و ݐۃ쁇ٿͧ܄ڈٌ׆"͆׾ҮԜڅօՂֈՓ΄̈́̌˔ʊɇʅ˄̂͆ΝχΈ͂̆˂ʄɇȃdžĄÆ􈜳悑ĺȨ漑" +   ɿݾḮÿӆ~~~~~~Ѕʞ~}¾ڋÏĉłĆńƊDŽȌɊ%燦π}~~}̬߫ݓφЉ$ڎ~պĞօԘӆ|甸ރ}ֿױ֍ډԊӐ܌}熙ij}ֱݟގӉ҇Ӆ}慗ƹŢʼn֋׍ւ׆،}̺ڵӃ҄ӊ#蕹ᅜ}©}Ԯ̊ՆԉӒ(щʱ὚щЄψ·&酟썥򆒝ڼNjƎŒĊńȊɊʂɑʆ}~!~}ľȵو + ߄܆ބ߂ބ݄ނ߅ ż}~h~탏~þԆȝ|~~يƂÊČÅăŊƄǐȅ&冥|}}|ҿʫݩ͇΂͋Ήτ#ٍ~}ӹՋ҂ђ"{哶܂|Ծ~կԌӉ҄ы҆ڋ|兘²|԰۞܄у҈Љ!ލ|儖ŸàÈ֗Ԅ$֋|˸سы҉щ҄攸߄||ҭʉ܅ӅҎъ#Јȯ༙ډτωΐ$脞댤ػƆŋēÊ‡ÅĄłƆnjȂɓ%|}~$}Ѿ󍠹|ýƴ؇"  + ۇ܊݅܉Ļ|~~j}낎}¼~ӯϢ~½ᏖȏɉʂɆʄˉ͉̄Έ2틪Մ߀Ʋұ寈ԆԅՈք$ۃɣڊقؒ#݀혽䇝Ůݵܑڈك؋هĀ튝ʸ۶؄و؂׌؂لŁ퉜̾ʦʍ݉ݕ ސڀҿຖ،ى؇ن牠Ǯڳюۅڅٌ؉#׍϶ž֍Ց$̈́̊ˎʒɉʅ˂̄ͅΝτ󀁂#ļ ûͺߋ +   `が􇓠􁉑ýچ~~~~~~Ѓ!G|~} هĄÄŒÂĆÅăńƄDŽȅɅȈɄ&ㄣ̀܀|Dzͬ٣؆ЂτЄτЋф!щ}}~е㼖ԉӊԄ χ||Ѽ~Ԯґ݆ՉԐ̄³ݹӂԊӍż~ڷ֐ׅׄ݋熙ǶٴӉԋӋڃ늢~ɰẖՉԆӋх#ݏ؀~ҭΗԅЅхЈϏ)݆򇖤׽DžƇŒĆÊĄłƆdžȆ˅3񁆉̅!} + +ꇛ郒¿~! +   +ފ +߆ĺ +n}~~:񆔣񁊓~*~}ǿú~󀆍 +U{}|ɆĉńƎlj'ტ{ű˫ע~֎ΆψЅψ||}δẕӈ҅ҋͅ󎤼{{к}ӭѐۅҎӂԉ˃툚ܸш҈ь҆ވހú}صԜՅۊ兘ŵ~׳҇ьق鉠}ǯ߹ӈ҇фы!ێ}ؿЬ͖ӍσΊ͌$ۅÿռ违~τƃʼnďÖ„ÄąŃƆDž:~ʆ | +膙炑􂊓} +   ބ݌ނ߈ކ߃ ù +|}}~~'}~*~~}|ž¹򓄯ÄĄŇT򀁃߇ɄȄnjȂɆȅɃʄˇ̅͑΅&釧Ӄ̷⃗ӱߧގՆֈׅ׍؁끈պڈل؄ُ!Պڳؕلڂٍڄۈ҈ȸ㾚؈و،م挾慗༘튝ͻ߹ن، 󁆇ε翚ڇو؊!㓷ބƬزԛڍւՊԍ&㉣ƽ¨Ƣ̈́̄ˇʒɆȊɄʂˆ̅͆ЄY¿ ¿Ɓ +    +ɾ()Ľɿ~~~~~~~Ѓ +Äăňƅ0󀇍݇ƄŽÅăʼnƃǐȆɄʆ#ˀ߂˵̪ϛԉЄτЋх$˅|ɯٲϐՆԈԈՅ܆军˷ѫϑ݅ՄԒ"ڌƾ}Ԋӌ"ۃꔶ}ʨћٌ֛ׄ}׳Ԉӌǃ}ζơ}~ՋԆӉ'唸߅~зڄтЇхψ΂̈́(ㄠ톗ҶذȄǃƈŏĆÂ’ÃĄņƄ?~$|υ숆~ƿ党炒򁉐܇    ߊú}~~~Z󃍗~}ûù~~ٿ ƒÎĆ0~ۉ„‚ÄĈņƐdžȆ*ހށ~~ɴʨ͚ψΆϊЅ!Ʉ{Ȯױ͏ӈ҄уҒۅㅚɶϪΐەӈԅ؋󊛫Ľ⿜|Չ҇ц҂ӄ҅ق蓵|ɦϚԝ׋˿|ձӇ҅эߏƂ򎥾|~̵Š|}քӋ҆ю ~㓷݄}εِςΊ͊&ჟ녕ʾе֯Džƃńćц…ÃĆB~}%~{̈́ꇄ}Ž䄙恐~! + ߄߄ބ߄ބ߂߅߄ހ¸|}}~~w턙~񂌖}~~~|~·}̿}ؾ ʼnȇɃʊ˅0ȇǎȅɃʉ˃̅͂Έ͇΄φ&慥Ѓ憛ѺѮԠ֍Յ։׆"Љϴ߷Քڇل؂ٓ⊽늠ѼװՕډۄĶƢË݊م؆نᆶ߁þЬןݑߐƷݷكڇل؇قڄ͇􀄅Լ̦݇ڈه؉ ݂똽刡ּǡւՈԌ(釤󊛬Ŷ׻޵̈́̄ˈʎɆȂǒȃɄʅ˅@Ä&Ԅ򋉆ľ눞 + + + +   Ǿ +$悒1ɾƺĉ~Ă~~~~~~Ѕ } ‡ÅčŅƔ}Ȋ†ÃĆ ƅǑȂɄʂ˄+ㅛͶȥÓьЄ҅у҄ 珿􂅇¨ϨڏԅՅ։ڍ}Ų̧ʏ݉ՅԉՃքۃ瓴||ڷⳊԌӆԊ慜샑}俞ׂ֕؆ފフĺԱԊ~}ѼѬ̌ԄՋԆӇ҄!ڀ홾刡򂆈ƭױјӌцϊ)썯܈ₔƴˮğɄȃDŽƄńĎLj…J}}||}~~~}!|<}ϼ膛넓~ ߄   }}~~a}|}}~Ļʽð}ż | ŽÄĈņƆ|Ҋ…Ä ŒƂDžȈ%~~ᄚ̵Ǥшφ΅ϋ$厾򁄅ͧنӈ҄Ӊԇ،|ñ˦Ɏی҉ӌق味{{ضಉԊ҃цҎ䄚ꂏ|⾝~ؕՆօ&܉႓¹ӯޤӄ҂ӆ҉ Ӊ}|ϺЫʋۍӈ҇ч$똼䇠ū~կϗЄςЄυΉ͉(ꌭۇၓijɭÝDžąÉ‰J||{{|}}~~~}|#{%ޛ|º~慚郒}   u||}}~g|{||~}¹ȼ|ú 󀉍 ąŃƅdžȆɍʅˎ͈ȈNjƉdžȃɆ ˄̑͂΅,₢σ鉟ӻΪȗ؈ֆՅ֋$Ąǭԭ‡څمڊۆ فʷҬГۑڍ헹݀༓踎ۋق؆َ쉠򇕡Ţߏ܍݄釙ڶىچيڎڂױѐڇه؇$쌦̲ܶ֜׉օՊԉ&〈醘˹гʣ΅˄ʄɎȆljƋDžD􀅋*'栝񇗧  + ƻs怕쀋öȵ~~~~~~~Ѓ } ‡ÊĈʼn ƄNjƆ É +†ÃĆ ږ؀}ۺˊȄdžȂɅ˄ʂ˄"}懞~ζßބьЊу҄$실~ӺÝՉԅՇ։釛˾ȣČ܉ՄԉՉ뉕~˼ՅԆӅԓՅւׄւՉ֔׃؆瑺ဎѮݤԂՇ ᑵۂӿܷԅՂԄՆԄӇ"܅닥ռƠێхЄω%ɷ¥ݰ̈ȄņĈLJ;|~G~}}|=ŀ~~}}̻ҿ񇖥 څ   }}} ʾ}}~c僔󄐛}ż}̾}ӾĻ | +ŽÅęŇĄɄ‡ؕ|ڹŐƂDžȉ&|~䆝}̴܇υΆϊЄ"އꊣ}ѸœՐӌԅ~熙ʼƢËچԎӎނ鈔}ʺӒ҉ӂԇӆԇՈԔՊք吹蕾Эۣ҄ +ӆ҉ߐځѽڵԐӆ҇хڄ銤󁅇~ӺğوφΊ*ȵۯʄLJƇ1􄎙{}~F~~}||{=~~}}||ž˺о쉟$| +|| + Ƚ||}~`~ん񃏚~~|ĺ|˽|ѽ~ú 񀊎 ÄĄńƅLJȇɈʉ˒̌˅ ȉ ÿňƄdžȃɆ ބῡЅ̌΅ςЄςЄ"ဟ̓싣ӻȣօՆ֊ׄ"挾ٿɢܐڂۄ܉ǂòͨɏۋډۂ܅懦򍙑ڒىڃۆچۇ܅ە܎݄핿烒׳ًَ畺⅛į⼗ېچه؅&≺ˤ׈ֆՆԆ%ϼȩ㵒щ˄ʅɈȆLjƆŌ6 7@˃žĿ􎥾߅  ùa僘놘ĵö~~~~~~~~~  …ÆČŊƂńƄńĂŅăÄ„†ілЭDŽƇDŽȄɈʇ$~艢̳⼖}׍Іъ҂ӄ"߅홾删}ɱ޷ژԈՄ +ׇ݃⑳~¶ž}܊ւՎ։׈օԇՋԇՌքՈփ׈֎ׅ֐ޓνɠՆԂՄ܃엻℘ԌՄԃӇ!܆ʰ۴әӎцІω'݀΂兛}˷}ٹ}ǞɅȈǂƄňĄÄ‚Зb~}|㔿<|Ǽ̾ø}φ݄  }}}}~}~}~}} ɿ}}~ₔ +~(~ɿ|ȷͽ; ~„ÜĊŃ +ϔκΫƆňƄǃȅȇ%}爠~ʱດ|։ΈωЄх݄옼㇞|ȯܵٗԈӇԏۂ}|ڔԔՄԚӃ҇ӔԊՄԘՄքՂքݒ̼ȟӋҖڂꖺѿ忛׋ӆ҅хڅ쌦􂅇ȯٲї҄ЌχΉ'́ㄙ~~|ɵ|׷|Ɯ̄džƇŃĈÅΖ~W~}|{ᓾ <󖘛{Żʼ|ͅ܄ ||}~}||}}}|}}}||| | +ǽ|}}~~ၒ }(}Ǿ{ƶ~̼˼ 􂋏 „ÃĆŃƅDžȊɌʊ˂ʄ˄ʄɂʅɃȄƅDžƇňƄdž֚ձˆ̇̓Ήφ%ɂ􃇊Ѹ髁݉Ոֈׅ#刳쌤϶伕ۇڇېㆯ蕸݁ȼȣŒܒە܄ۤچۂ܋ۋ܄ۖ܈݄嗴´Ϥډ٘⇵舝ƲƠފڈه؅!⊼еṒ؝׍ֆՈԆ$ュӆ뉟м߾͢ӄ΅͇̂˄ʈɄȄǂƆŌćŅƅz՛¿ĺ=ñȽ݁ԉ  ø腘5źͼ¯¿~ق~~~~~~~~Ѓ „ +ĝʼnĆĊ †察듞~Ϸ㼚ƇDŽȄɈʋ#다񀄇ȯرΖҋІщ҃Ӆ 䔸߄ֿ|ЪŊԅՇ֎ׄȂ醗۱ؓ֕׃֛ԈՎփՈքׇ֎ׂׅ֔֊ }ՔԂՊ#މ熙ʦǎԉՄԃӆ⊹}־ɣێшЈτ%↫ۋ˶Ϯ㱍ʅɄȆdžƄňĄÄ‚ ꓚP|}ʈҵȶþ~ǹʶ~[~}}$  }~~}~}}}} ܅Ƽ}}~~ނ􌟲񃏛|}6~}Ż˹~ǵĺ   +„ÂĈÈċ˄ +㮞鑝}ζ⺙ŇƄDŽȐ&~銣ƭ͕֯τΈϋЃц~Ⓐ݃~Խ{ϨĉކӇԔ"Ɓ煕ڰޡՄԒՄֈՃԍӂԔӆԂՌԋՃԗՅքՂօՅԋ|ԌҌӂ݈҅兘ͿɥōӇ҄х|􁅆~ռǡْφ΋%ڊ󎥼~ɴͬᰌȆdžƇŃĉÄb蒙~{~|ȆдǴ~لڀ½}ŷɵ~}}||@݄ |}~}|}|||||  Ļ||}}~݁򋞱{|4~~}|ù~ɸ}Ƴ~¹ +„ÂćŃƆDŽȆɝʊɅȄljƊ +ĨĄŇƄdž봣򗣧ռˆ̅̈́Έϊ&Ȃͳ޶ԚքՈ֋׃؆꘽刟Ĭ֮ʎڈۇ݈ͅĿᶓ݉܂ێ܈݈܄یڂۓڇۄ܉ۥ܌݆܅ۊیٕ䍿튞ƴЫ̒ڈم؄荾êΧ։Ջ$芯Ᏹлղ鶐Ѕ΅͈̃˄ʈɄȄƆňăÆąŅƅ 𗟢Pφغͺقþ̾ƭϻӄB   䆝1оͺɿ~~~~~~~~~~~~Ѓ ‰ÓÆĈք … ͇Ԛ~ǭȢͅǃȆɆʉ˄ }퍧󁅇©̥~݉Ѝч҅}ێ؀|ʴ~ԆՅ׋瓴턍ўݗ׍؈ׅևՔևՍ֜׋؂׎քՇԂ՘"ꇙɾӯٟՆԊՄԆ"ዽ~􁅆ɲ޷؜ӆцВ)劲瓵ځ󀃅ɲĢ˞ɅȆNJƄ ĄÂ‡VŽ}}|ľ}ľ}„ƻדp|ǿǶ¨Ժd~~} +ބ }~~~~}}~}~}އ Żt}}~ᅝ~'¹}ñ˷~һ +~‹ +%ˆә󆒞}ƫơƇǂȈɃʆɅ!|댥񀃆ˤ}΅·ψЇ|ٍ{Ȳ}؅ӅԆՅւ׆ք߄咳냌ϝ򰜋֑ՓֆնԇֈՈևՐֆԄՆԕӋ҂Ӊ~膘ǽѮםԋӂԇӅ҄&}򀄅Ȱ֛ܵЅχΌ'㉰撴ـȱ¡ɝ~ȅDŽƈņĉ…K||{¼|½~}ʅÄĺ֒u{ŽŴҹ~~}| |}|}~}~~~~~~}~~}}~~}~}|}}|||}||}|}|}| + ބ݄ +ùt|}}~߄}'|°ɶ}Ѻ ĈńƃLjțɈȕDŽƉņ ĨņƄDž ҋڟͲͧ҅̂͆΅ϏЄ#ƁǭҪքՇֈ׆߀ᒶބϹǠڄۇ܄݈ބ扴헹󈑐֢݋܉ކ݃އܴ݅ۇ܄݅܊݅ܒ݊܇۔ڋقډƂ񋞯ôٴߣ܊ڃۈڄل"Ϸ伔ޠىևՒ&뎶ϷɦУυ΄̊ͅ˄ ɄȂdžƇŏćńIǒ灁ýþхĄÄDŽƃŇݖrļ̻Ǭٿf¿    ɿ戢"ɶѼ~~~~~~~~~ЂƒÑĐˈ„ …$쌨恏ȾֹЧτȆɇʇʄˇ 쒿}􁅇Ӻ翗ׇЎц҅ψѽزכօՅ׌؅ 򑣻˽Þׂؓ׏؉ׅ՘ֈՐ֒׆؈׎؃׍֖Շӌܔ~ڷ鯁۔Յԅ ኻ}}Խˤ~݉фЕ$덷䈠}Ůܸ괍˄ʃɆȅNjƄ퇘†&ˋȆLjƄń ‡ۓp~}|~~|¸}°ëȯd~~}} }~~~}}}}}}~}}}~}~}~}~}~~}~} ߄߄ɿ}~؀}}ðŭ³ +ÇՈ +&ꋧ䀎ƼԷΥƇǂȑɇ&ꑾ|퍧򀄆~ҹ彖ΊϊІΆϼװ֙ԄӃԇՅֆׄ𐢺ɻՆ֌Սׇ׉օՠԂӑԆՓֆՑ֋ՆԎӂԅӋӉ~ړޅ}ص讀ٌӃԆӆ҄|~|Ҽɣ}܇ЄτΏ#錶㇟|~Ĭڶ賌ʄɂȆDŽƅʼnć 놗 $ʊƾNjńĉڒ}󂌖|{}~}{|~©Ǯ~}}|c|ۅ  +||}}|}~~~~~}||||}||}}|}|}~}||| + + +  ߅ރ߄ +ȾÄw|}|􄐛ƿ|~ì ĄņƄǃȖɐȋLjƅńŇĄńƆDž'텓÷ܾի͇΅ώЇ%āٿěՊ֊׆%Ջ­޷ݟۇ܄݈ބȢ܈݅ܒ݄ނ݆ވ݄܎ۂܢۆܕ݄܋݂ކ݊܇ۍڂۆڊقڈხ☾抝ž༙ڄۆچلªЩׄքՐ"댤˳⽙ׄ΅͆̊˄󋝝džƈňń"Џż͆̈˄ʄLJƆłĄᖋ/􁊑򀈐ǽȵȯͳB  ĺބ܀ƽȵʲǸ~~~~~~~~~ 􁋏%}(}„‡ +†Å$뉦|£֪υɐʄˇ%쒿}˱ׯȑϊІч҅łñǢՆֈׄ؂ي؈׆؊׆؄ם؇׊֊ՄԊՊքז؈׌؈׈֚ՎԂՅԒ~޾֒ՈԄ}ư߸۟֋фЊχ&쒾|썦Ыҡ˅ʄɃȆDžƊᄘèƒ ƆŊƂDŽƇńÄĂċܓ2򁊓|~|ɿ~͵ʱ~~}* +  }}}}~ ~~~~~~~~}}~~}}} }} ɽՉ퀋ü$ȵƲԼ4򀊎|(~|%鈤{ԩ͔ȃɅʇ ꑽ|󀄆ɯ֭ƐЈΈφЇĀơ~ބӃԊՄֆׅօՠքאֈՆԂӄԒӊԆՐ օՒֈ՛ԇӆ҈ ґ}ܼӊԅӆ҄"ވ틣~~|ŮݶٞτЅςΑ$ꐼ{댥~~տΪП~ʄɄȃdžƅņĆ߃§ÈĆŅąÎ‚ ڑ2󂍖􄏚{~}{Ƚ}Ҿ̳Ȱ~~}}|'||||}~~}~}~}~}~}~~}}~~}||||| ȼӈº~ƴŰһ7'DŽƊLJƊņĉ ĩńƄLJȄ)рǸǨܯΐσЇф āѶݴ͕׈Ոֆׇ%˅ȶͦŒۇ܄ݍކܠݐލ݋ڄےڊۆ܆݈ބ݄܉݄ކ݈ܛۇڅو ٖàڋۇڇ%捾̵彖քׄւՋԄ(ÀƭְإЅτΆ̈́̅ˉ燜ȭǂƌ ąńˆʉ˃̄ˇʄȄɂȄNJƄņ ᖇĹűӺ϶f  +  +ی󄎘,ͺ̷ +~~~~~~~~~~~4􁍒|}<|}Ž} +†É)臤}|ȧשʇɅʄˇ̆!쑿}􁅇ŝϊЅф҈"玼熙ĵ۶Յ։ׄنم؂פ؂٘؈׆։ՌԋՄֆז؈׌،ׅ։֎ՏԂՊԆ 񔘹Ծ׌ՂօՈԄ䉵ꊠ͹ʤфЉφ'쒿~}ӺÝ˄ʅɃȆdžƆ눠戟~† ÇĆŅƆņĉĊܓ􁊚񄑞~}ƻî˯~~}}3 + +} }~~~~}}~}}}}  +·о׹ 򀌑&~{|9{|Ļ|Ä%憢|{;Ǧը̑ȂɆʆ"ꐽ|򀄆׾ĜևΉτЈф卻兘ôٴߤӄԊՄ֋׍ւ׊ւ׌֌ג֊ՂԘӊԄՅօքօՔև՚ԇӇҒӼՆӊԄӋ(∳鉟̷ɣЅς΋̈́!ꑾ}󀄆|ѹφɇȃdžƅņꇟ䇞}څ~‰Êĉ̓ ے򀉙퀉}~|ź­ɮؾ}}||8||}|}~ ~}~}~~}|}|||}|||}}|| || ߅ +􏌥νָҿ + +'=¼ºƇńĊÅ ĆŃƄdžȉ$Ѐ܀ŲάݭӉςΆτІц āŪˢ݈Ոք׈؄튞ʺỖۊ܄ݎމ݅ފ݅އݒދ݉ۓڊۄ܅݉݊ރ݄܈݄މ݇ܚۈڄْڄ ô݆ڊۈڇ(ꌺ񎥽ӾЩׄփՊԅ!ŁȡֆІτ΂͇̅ˆ팤쁋Ɗ ĽÄĆŅƅȇɆʅˆʆɉȄDžƄ ▇ɳдŭ3 +    + +ƻIJݾů~~~~~~~~~~||ǡ¾}ǽķ †Í$冢}܀}~~ɵ˨ҤˌɃʈˆ̄ 둾}󀄆˲ڲ̖ϋҎ割ꕸ݀ſȝ~Յֆ׋؎قڋڊن؂ِ ؆։ՄԄՄԄՂԄ탑و؉׊؅׈؄׃֓ՋԃӓԊ ԌՅԄᆲ옾凜ѿݷޡքтІфЊφ"둿~̳ݵۦˉʆɄȅLj#䂚㈢󇓞~ ~”ÂČÆ„}ܓ邋ꀎ}}Ĺ}Ϻ~ۺ~}}; }}}}}}}~}}}~~~~ ~~~}~}~}~}~~} +ɾτ}}ɸϲ˶~籱;|Ơ>|Ƽ~öƾ ‚Ä*ㅠ||}}dzʧУȈDžȇɄʆ!鐼|ʱٰʕхΈτҋ㈱蔷þƜ}ӆԆՉ֏ׅ؉ׄ؅֌׆փ׆օԜ낐օ׃քՆւ׆ւՅփׄքՂԔӚ҈ӂԒӇԆӇ߅ꗼㅛϽ۵ܠՐ΍#鐽}˲۳ڤˉɅȄDŽƆņ⁙⇠񆒝} +}„ |ے聊󃎘|~~~|÷|ι}ٸ㿨~}||;|||||||}||}~} ~~~}}~~~~~~~~}}~~}~}|}|}}| + +߀Ƚ̓||ȷΰɴ}寰9󀆑̦=þùʼň éąńƃdžȍ$뉦πℙκѭبЋ΄φЈ#Àѷඎњ؆Շքى덷ㄖŻ͡چۅ܈ݑދދߙޅޅ ۘ󆕤Ǹ܇݆މ݄ބ݄ڄێڎِڃېډۆچ状늠İ㼖܏ւՋԄ$āҸ㺒᪅ЄЄυ΄̈́̉#ꆞꌦÁŊ ľĉŅƍǔȂɌȅDŽƉŃą◶ʾΰŮ9  +¹ԇϽշк ~т~~~~~~~~~Ѕ>|}}}~~-~}|ľǼÿ†Ï%₟|ᅛιʥɜӊɈʂˊ!ꐽ}~սŝﮂً҉Ӄ҄ᄩݍǓ}Յֆ؄׆؍مڄمڄن؂َ탐Ĵ۷ՔӇ恏ɩסى؅׎ 낂ׂ֌ՂԄՊԄӐԍՋԌՄ#ނ㓸ނȣЄуЅхЊ&ꏼ}īΦ•ˊʇɅȄDž#؄}ûպ޷ +~“ČÆ„ }ޔ"}}iĺѼ~عܻ~~}  }}~}~~~~~~~}~} + + +Źs}ŵͳƱ +} +~,{|||}}~~.~}|{¼ƻ½ *{߄~~ͷȤȚdžȇɈʄ#菻|~}ӻÜΉσЏ߃ی󊙥Œ|ӅԆՊ֎׌؂׎ؐ׈낏³ٵߓӂ҄ц䀎ǧՠׅՈւ׆遁~քՃԒәҊӄԄӂҊԄӇ܁ᒶ܁ƢЎτ΍ 莻|ê̤цɅȆDŽƇ#׃|Ըݶ}„ +}ܓ#|큋|s¸~Ϻ}׸ڹ~}|||}|}}|}~~~}~}}~~}~}| +ĸރ|Ĵ̲Ű '|숱B󂉒,ý¬ąÄ…éňƂdžȍɄ#膣̀爟ԾЪϠو΅χЉ"€©ʢ߄Ոփ׏燭㑴̗šچۅ܉݉߄ވ߂ߗ󇔟ɹἐ۔ ؋셓έݦ݆ދ݅އ +񆅃ۓڏچًڅېڈۆچ䅯闽䆚ǵΨő׎քՍ ʰԪǙ؅Њφ΄̈́̅#ވۿ伖Ǐ +žĊŅƉƄǓɌȆDŽƈń 㘷䀍ɿ޾⿧  +  ɾ w˺Ӹ˶.~~~~~~~~ԀX ƒ‚ÄĊʼn'݀}扡|ѺĝʄɄʊ˄ 鐼|||ŭ֮ȓӊЄш҈}鲕ӄԄՆ֊׊؍وڃۊڇه؂م͊􋚧޻~׆ՊԌ~옽ܷ⃕؆ט~݅|ۿ׊ԃՇԃӐԄՇևՅ +ԇՆٍ}~سޥ~ёЉτ#㊷~Լ鿗範˅ʍɆ.რ|ȹѳ|̧‹~ˆ‰ÊÆĆ~ޔy烎낒Ƚɴ˫ɪ   }}}}~ +~}  +ɼ +Ѷ˯(򄍙凳 }Hƅ …Ì(|刟{ϸÜϏȉɂʆ菻{{~~{ìխǑъψЈф~|籔҆ӆԉՊ֎׈ٍ؆׃օ׊ˉ򉙦ܹ}ՊӇ҅}ꗻ~ڵא}ۄ{οٽՎӏ҄Ӆ҃ӎԘӈ׌|Ǿ}ֲܣ}ׄω΄σ΋ ቶ􁄆}Ӻ羖它̆ɐȅDŽ&߂{Ʒϲ{ʥ }…Ë…}ܓz悍遑ƻDzɪȩ | |||}|}~~~~~~}| +ǻqοϴɮ*􃍖~䱱 󁈓ڄ>ͅÿ„ˆ ĪƅDŽȄɉʊ#ㄢ̀퍥ֿʢ”֐ϊх򀃃ʲܳΖՅֈׇ؅僣﷙مڅۅ܌ݎކ߈߆߆ނ݇އҎ܋چم؄ނ臙⼖݆އカ㈟ŕĨܑڌلڄكڇۂ܆ۘڈߑہŷ޸䩂֊Չ#鍼ś҆ЈόΆ(燤܀ξ׸ѫDŽƂNj ĄņƅńƄLjƈljȑɆƅÈ +䘸 y톒񆖧¶Ϲаή   + + +ֻд(넷~~~~~~~~~ +~~}|ՅH|~㞒󛚈ĄąňƉ$}썦Ϸ仔㫄ʈɊʂˈ鏻ɳ潖ڈЇц҉ڊӅԄՆ֊׊؄ق؅نǹúڈن؂ل؆܈}ְҗՈԆӂҊڅ~񍡵ƺ๓׏ׇ܏}~ڶ׊ԃ՚ԄՈֆՄԊԇՆÃچŸ~ёЈ!덧򀄅˳ڰКӄˈʒ-썯ڈѾʪ世NjÌ+}ڄ3¾}Źޕx⁏ι}} }}}}}}}}~}}~~}}~}~~} ͽ}~2} }}|{ԊG{}~ᝑ񚙇…Ìċ"~}ꌤ~ζ⹓⪃ˌȊɅʄ玺Dz仕~؆χЅ҄х҄ӇԊՈ֋ׅ򓙙ŷڅ؇׃ք׈ۇ~쉛|ԮіߊӆҌل}ĸ߸ߠՆք׍ڎ|}شߡҍӏ҄ӄ҄ӆԂՆԘӈ؅}҅ϊ΃τ· ޅ藿錦ʱدϙъɈȂLJȅ,ꌭ؇ϽȨⷕ~ +~)|̈́:|ĸ~ݔ rဎǿ̸|| ||||||||}|}|}|} ~~}}~~}}}~~~~} +||˼ 􊐅|}~~~|„~+󁈓ۇF颖„‡ÄɅʋˊ(Ⴀʁ􂇉ս鰈τφЇθš묃ևׅ؄؄مڅۋ܉݌ބ߄̾ȿ߆ނ݆އܵ؛چٌ%˿翗݇ވ⓷݁໖ݑڌلڄكچۃ܆ۙڇȇ¾ȣŔم֊Ո 剳Ѹ്֟؆Іϒ-ߌıϮ꽚ȇNjŇƄƐ)ԅ<ʾ䘸腓ƽԾ  悎끌Ʉ肷~~~~~~~~~~~~~~~~~Ї~dž„‹Â‰Ä(|~ƅˠξٶąńLjƎ!܀~񀃆˲׬̚эɄʆ˄ꑽ팢ʶʣ~҈Јч҅ӂԉӈԅՐօ׌劤ρۣͯۄق؆ن؆䖽懝ŵʢ}}ԃӄԆӄ"܌ƆׁƲ仓ޛֈ׌؆ӌȢ~ڈԆՈԂՆԅՆօՃԊՂֈՅȪڥэЄхЄ+݁ޑ∡}}ʡʓ&핷ރ~~}îϧƇłĆÊ~„q~~~ǿݕ򇜰悓}}~~}}~ }}~~}}}}~}~~~}}~} Ŷɼ}}~}}2ɾ㲲 }ʄ-{}Ͽżɟ̼~׵„ÄċńƂň#}ɱի˘ǏȈɆ 鐻닡ȴȢ}΋υЈ҅ч҈ӇԂՆԆՈւׄ㉢΀̮١ْׄև╼䆜óɡ|}ӌґڋŅՀİ㺒ݚ݉Պ׊ъ~ơ}َӇ҉҇ՄԐӈԈӈƩؤφΊ΄$܀ܐᇠ||ԿɠɈȊ,듶܂}}|⾝ͦƄĄÄˆ }6}}5}ž췶۔y񆛯䁑퀉߀|,|}}||}||}}|||}|}~~}}~~~~~ }}||}}||| + õȻ||}~~||3ƿǼᱱ󁊔̅DŽÃĄńƉNjȂLjȅ(Ɖ˅ȋÆūХí߻Ʌ̇ˏ!⃟ʁѷݱҞև΄ςΆψЄ󐦽лШׄՊօ׈م؆وڇۆ܃ۄ܊덨ՅӴބ݅싡ʺЧڌّ݄̊˷܆݆ވُ݃ƿΧڅينڃۄ܃ۉڍۅڈͯ੄ֆՊֆՄㅫ㕽錥򁅆ƭЦՄЇϔ&䇞ȲţԫˆʂɆȊ ƿńƃņƂDŽƄ66ž♹ +톗ÿ߀¿ɻ」0ƾø酷~~~~~~~~‚Ä„‡Èˆ#̉Ŭ}ѭ}ƔNJ"}􀄆éŜʌɈʆ됻鉝ƶ~ԮК؇Јш҆ӂ҆ӄԊՊՆֈ׈Ҋ⽙~ۅ +ل؇ߎɈڃ˶缓ܗԄӃԇӄӅߕӎ䉣Ѻ缓ڒ؅֊׆؈ȇր;ܳғމԅՄՄ߅݇Ĵĕ֒ՃֈՆԄӅ儓ՄюЃц Љׂ|~}Ͷ亓ߧ؇˂ʈɆȈ#~}}¬ڵ껕ˉƄŃĆÆ *Ѥ}~~3}}|¾빸ߖҔ»酙偒|Ҩ}~}~}~~~~~~~ ~} ȻВ}}}~~􉜵넔}4}~~}}ȿǹͼ~}ˆʈī|Ϭ|čńƂʼn$|~~Ě뱆ʇȂLjȆɆ鎹爜ĵ}ӭΙօΈψЍх҈ӔԅՋЉ༗}ُ׆ֈݍLJ؂ʵ廒ۖцґޔэ∡ϸ滑ؑԇՍֆƆ˼ڲВ҅҇ӆ҈݄ۆòÔԊӉԉӈ҆ +ヒӆφΊφ"ψր{}|˴⹒ݦʅɈȏ&}|쌤|س蹔ʼnĂdž~*Т|}~}&||{鄷ޔВ~焘【{Ч ||}}||}~}|}~}~}}}~~~}~}~ ~}| +Ǻ Lϑ||}}}~T󈛴郓||}}~~~||ƽƸ~˻}迅ÇĂŇȄDŽȄdžȇLjƌņŒÍ"ūҍ˱ֲ˔̊$߀˃ȮˠϊΈ%˻ڳ՞݅Ոֈ׌؅وډۂ܇ۅ܌؎ބ݈΋ѻބ؇ّْꍧ׿ۈܑ͊܄ð⸐חٍچو剴㋤ʹʙۈڏۈډم +뇗چֆՊֆ֍݅һ꿗嫅݇Ѓϕ#ˁȱ๖Љ˄ʃɆȆņ ƅ0ר(ÿ噄ח녖حͿՕ񇘬ꀌ:ĺͿŶ~~~~~~~ŒÆˆÌˆ'~Ĩ鿝LjNJȅ%~ǀ}|з۰̙ɆȄɃȅɄ 鐺兘þܲÈׄψЊъ҃ӅԍՂ֏Մ֊ҋ؀ˤ~ی؆׊}δث҄ԇӋߗ鼑Ԉ՗لӀѼśӎԃӈщ􋚦㳏䡀֌ՂֈՔԂӄ҄і ~~ӫʗ҆ˆʇɋ"˂}}ͧӧϊLjƂŋ¼„Êۈ@ ᖵ+~ļt釛鄔˰ϯ  +}}~~~} + ˽ʋ~}}~~|}~~,ĺɺȹ|Ⱦ‰…%}~æ羜Ǔƌ!}|󀃅{εٯ˘ȑdžȂɄ珹ㄗ¼ڱ‡Մ͂ΊψЊт҆Ӗԅӄԇъžɢ}ڐքՈ|̲֪хҊтЄޖ纐҇ӅԈՇ׃лÚъ҂Ӊψ򊙥ᱎ֓Ԏӌ҄уЉό΄υ!푽}󏦼Ѿ}ѪȕʈɆȄDŽ,~Ɂ|~|տ̦ѦƈŇÉ ~d‰ ߕ+ÿɿ}û x膚烒ʯή ||}~~~~~~~~~}|}}|ʼȊ}||}}􊣺{|}~~}*¸ǹǸ{Ǽ„ÂćŃƆnjȆLjȌLjƈŅĂŊĈÇăņ(ū灎ʬġ͈̕'߁̈́Ҁּᵋҝͅ΂ͅ΅ 뉜÷ⷋɋ܄ԃՉֈ׊؂نږۄڄۇ܅؏ބŷШފ݅܇Ҁӹݰ؅ي؂ׄǪڌڄۉ܆އكʟڅقڈه֍鸓ꦃݔۍڇڄل؃׉֌Մք Ăůٰϛ؆ІυΉ#ტІӀƭӬجԊ̈˂ʋƄņƃDŽɎ@ń 暺-½ƻtѵճ + +Ύ߀遍*ɿϿξ½~~~~~~~$󃋒† ŒÊ‰(}ǽ}ٸ}̤Вȍ ~ɂ~Ø筄ʎȅɃʆ쐸߁ɓ餅ωЇъ҃Ӆ㋖ʿϽؐՅևьބ­دƇ؊׆ܑҏꏬ}ˮƙӆҊӌǩ麎}ԃՄւՈև~ϵתԅӆԆӆ݅쉝ѫʓքՂֆօՊԂՌ҈іㆮ疼䇜ijœ̆ˇʅ+̄Ҁ|ӼɆȈLJƂńĄȍǕŒ‡8/ɗͺᖵ -~øǯѽv }}}~~} ͿǍ~}~ၙ~}~~}ɿƳȯǻ%񂊑†Œ (|솗Ƽ|׷|ʣƆdžƑ$}ǁ}~嫃ƅǂƆDŽȈꎶ햹݀~ǒ裄͈ΉυЈт҅ንȽμӄԈӅԉϋ܃׮ĆڋֆՊېЎ鍫|ʭĘߎфЄуҊх~~Ƨ蹍|҆Ӕ}γթјۄꈜϪɒ֓ԇӂ҈Ӌ҄уЈό΃υᅭ唺↚ñﴊυʄɊȄdž$~˃{Һ辘Ōńć~ƌŔ~71Ȗ˸ߕ %}~Ʈмv|||}~~~~~~~~~~}|  ̾ƌ}|}~~}|}~}|Ƚ$IJƭź!ÄĄŅƅNJȅNjȊLjƈłĆłĄňċ+ƫ³߽ѩΎ͎ ΅ՂǭȝЎ̓΅φ儖ΗԇՉօ׈؂م鏚¬څۆڄۋ֐䈠Dz޴ˊ݅܊דѳ˝؄ׄ؄ى؅ӃͭЁڗӂպݯؕ∹򍢳ÿװЗݔۆىڅل؃׈֌Ղֆ 艳ꊠʸǠцІφΈ%߂҈؄Ş͈̅̆˂ʄɄ邕̙͑njƃLJ65ϛҾ皺>Ƚʹ½v  Ķ̐焝過Ĺ˸ͳ~၉~~~~~~􅍔†ÅĉŅĂŊąÈ…,~àѧ҄ɂȘ~ʃрɰҧ͇LjȆ뎵劗ءͅ·ςІы܀ւ}ޑ։ԄՇ͌ሢҼ源ҊۄքׄևՄ}؆}|Ŧ᱅߄ё҅׆̫跊ԄӏԃՄߛ}ƨ꺎̂ԅԆӄ҄ҍ߅Ƿ̤~݌ՂևՄԃӄԂՄԆӅ҇ѐ·|õز٤Ά̄ˆʄɄȄ!ɃҀζܱ۪·njȃLJ脙}~~ˊ0𦳯~}Ԅӌ҇(}ǹ▶~~ɸ̱}ֽ~}ğ5  + +}~~}}}}&´Č~}}~ـ󍢹聍ƻ˷ؼм򄌓‹Đʄ,쉤}οŸϦВDŽȈ }Ȃ~~Ǯ~ЦŊƆdž鍳㉖נˆ˅̄͆΂ωЈԁ|áՓӇ̋Ѻ丏ЉԉՂԍ|ք|{Ĥఄ݄φЅчЂτՄ~˪綉Ґݙ|~ŧ蹍ʁъ҉ь݄Ŷʢ}ӎԅӇ҄Ӈ҈тЈϐ͆{´~ְأˆʆɄƄ!ǂ̴ڰ٩̄ŋƄň惘|}}‰+~}|ԄӃ҇хЈ)|~Ƹ}ÿĿ}ȶ˯|Ի~}|6  +|~~}||||Ë}||}򌡷瀌ĺʶֺϻ ĄńƃdžȅɉʅɂʊɅȈDŽƍłĆŅŊ.Ǭ݁Ƴɥ͙֬ׄ%χ׃εجŔ͇̈뎛ަ҄ӅԅՂֈ׉⃕܆ʦȕܓچӐ茧쿔׎ۋ܂ۍމ큆˪趈ֆׅ؇ׂք݉Ұṋِц؊ىؑ剠̼Ѩڏۄڇلڈه؂׈֐ԋ؀ɺ޷ߨ҆хЄτ΄̈́!Ά؄ӻⶐᯋӆ̍̈́̆ہȋɇ2ه؅׆+̾皺ſϽҵº2ɣ  ƸɐރѼ~~~~~~~~?򄌖}~~~~}|„‡ é%ꈣ߄}̸ʤϤΏɂʄɅ%̄Ӏ|}˴ݳЛLjȈɂʆ˄̊ͅΈςЈщٔ⃕ʤՎԆߍɊ䋨ʮĘ܎ՉւՍ׎֔~ݻ˛߄Јх҆тЄ汀Ϭ洅،ӆԂӇ։ϐ􁃁ٸ~˜ֆ҆ӂԆӅ}}ӽěԓՇ ˟ՅԊӂ҉юׁ݋ƢÖՉ̅˅+}~Ʈ}ͤěȉǍȄ!烚݄񅑜ĈÆŠÂąōĄĐŋćǃ䗶~Żݾѷ~}~˜}~~~}}}Ŷ‹}~牣䅙ùDz}ɬ̷?|}}~~~%~}}|{4釢݃|˷ȣ͢ȉLJȊ~ʃ{|ɳܱΚDŽƉɆ҄ʋ˄̅ͅΆχЇדȣԋӂ҈ӆތȉ⊧ɬÖۍ؄ԂՅԆӊ֍ԓ}ۺ~ʚ݃ϊІߋ􂅅Ϋ䲄ֆѕԈ͏򀂀׶}ɛՅЃчҌ}|ѼÙՅӋԇӄ~ɝӇ҈тЈϐր܊Ġ~•ˇʆɃȄDž"풾|}~ŭ|̣ÙƅŌƂDŽƅ備ۃɍ’ÄĈͅ +▵􄎙}ú~ӿۼ~ϵ~}|~1 +|}  ~}|||"õ~|}刢℘􆒟ư|ȫʵ>!ɆLJłĊľƂņƉ ȭ%凝ҽϩԨӎ΃υ΄$߂шلй㸎͇֟̉΃υمъ҄ӆԄՆֆ׈ߘ臙ϩđۋڂمڇώꏭгʜۄ܄ۇډݑۘ灈џ凅ׄև׈춄琳ձ칉݆ؕۍԔ߽Р܅׃؈ً܁ҁêʟ܄ڍۆڄ䂡Уڇو؂׈֐݄䏦˦ȚڊцЃτ(ĀӁ̳өɟ͇̎ͅ 퇞㈡ɇȆNJȃɄʌɖʋɇȇǃƄʼn꛻􁉒Ʊëֻ  ɺ{Ǝ패ꈞȾͷϱѻ ~~~~~}~~~~A􄍗ʂ-~º… †Ê&腠剠~Ӿȡ~Ɲ̄ʄɆʊɄځφԀʵ廒ާʆȍɃʄˆ̈̓·χЅш|õͤ~ݙ݆ˆ卭~عΟڄԄԄ Ү泄ЈφЊ綅钷Ѭі񹅳搳Ȧ۪|х҆Ӄ҈܍ʌ捪軐ώԎՉⅮ畸˳ڧԈӆ҉ю؀~~Դ屋ш̅ˇ'捵󀂃|տ뾖鴌ϐǍ%~څၒƿҶňċÕćNJƐňăŃ ~捪}|~~~~|ǽտ˫̱~}}~~~~}}}}~}ǹƿ}~ޙ򅐚½˷ʬؿ A򃌖Ɂ~-ÿ}~ˆ Ĉ%感㈟}~ѼƟ}ě~ʉȃɄȈDŽ؀΅ȳ㹑ݥɑǃȄɊʄˈ̂͌΄ψЄ{ˣ}ۆ҂ӊ҉ۅ㌫}~ָ̞҈Ӈ҈~ދЭ屃Ҍψ΄嵄瑶~Ϫ~ﷄ䏱􂅄~Ƥک{ڇІтҌڋɋ䌨湎΍ߕ唷~~ɲإ҈шЌχ}}Ӳ㰊ϋʈ(䌴{Խ齔粋̈́ńƅŃƄlj*}ل߀Žд쌈Ȇ‚Å‹ÆĆņăÅćȂ }䌩|{}}~~}}{ƻӽɪʯ}|~࿔ |||}~~~}}||||}~}|Ƹľ~|}ܘɶȪ׽rЅſǿdžŅ ƾƄdžȊ&덤ëͥˡфτϊ΄߄ՊڄϺ䫄υ͍΄Ѕх҆ӂԌՄֈׄƅՀȺөكډىnj둱򂅃޾ԣوڇو鱃搵سٕՄ惊װ賃픸ͪᯀׅ؃ٌА푮ǪՑ色홽₏иેه؈׌ևބڹ붏։ф.쑺īÚ︐ԏ̎%偘煖ػʈɋĄȔ +˄̊ˏʈɃȅǂƅ 쑮񀉓¶ĭаѵŘń  ̽Č䝶»мϰó~~~~~}~~~~~@1ÿ}LJ +~„ÄƆLj,䃟덦|ӽ쿗췏ʊɈ ނ҇ð还鯈ȎɃʈˆ̇φЂӋЅш֐䉡}Σ}ӄԄӊ}䎰󂅃~ģצӇԈӄ҄ҕğ̙΋χ輊遇ЪܨКڞڊس츈߆ц҄ӄ҆΁~ݮ֊ԇՉ猻}㾙ԄӊҊьЇ فϊ̄ˈ$ރَ㊣|~̵۰ӤɒNJ*ꉦ~⅘ξήģ堌ňċÔ ƇƄǍƉņĆꁌ||~~|йԸȱ}}” }}~ +~}~}~~} ȹĽ񅀪~¯վƭ +Ǹ@~,½|ņ}ȇņƄ"₝錤{Ѽ꽖붎҄ȄɄȅ%܁ц~澗箆ƎǃȄɊʄˆττΆωԎ∠п|̡|і|⍮򁃂}¢եш҉щє~žʘ̓Έ̄溈瀅Ψڦ섙؝؉􃇆ֱ귇ދЏ̀}~ۭԄҐӆ拹|⼘ӈщЏψ΅ ׀ˊ-܂؍ሢ{~}ʴڮѢȈŌƇ+臤}ͼͭá㟋ĆÌ„ŒÇĐŐĆą逋{{}~~~}{ʿθҶǯ~|~| |}~~~}}||}|}}||}~}|Ƹü}ӽīƶ@¹.Ŀ̊Ƅʼn +DŽȄʮ̈-ꇣêěωΈ ㅦ؋ڃȵĜﴋ͎΂τІф҆քֈՆֈׄۓ덦ưӧؖ݁꒵ɧݪ߉ى؉ؚ̓ɤѝՈԂӄ֮޸󽌵օאԄǨ㳆ۄِچÝڈ؉׏ևՅ +ޅԋфЇ$䆫ߒ鍨񀃃ҺᵍبΒΆ*҂舜óԳɧ뤐ʈɋȓɄʆˍ̍˅ʅɅƄ 倎ƹ־ٽ͵ꂀǘ#̽ŒǴç˱ ̼~Ђ~~~~~~}~~~,}΅>…»ń|غʫȇɄʇ%₝~иܯԥʋɌՈ}ʄȅɃʎ˃̆鏶Ý~ыЊ~}ʱ~̟Ӎ҆ӄ𮀮⎲Ϋ߬Ҋяڤ~㐷⁇}ٲ~Β͂̄ͦԟτ΃φ΄уי̂󄈉~ƓЊы|搲񁄃|߾РӅԄ dž؂ƞӄқхЄψ΄͈̆˄ʅ āˢ~҄DŽȇljȄ/⍮րdzţٲ}ƿƅō âÌĄŃĄŅɈȄɂȉdžƆńĂÄ噶}򄏛Ͷɮӵ~}}ƒ% }~ ~~}2ɼچ}νԸѾֆ+|̇= +~„{ָȪƆǎ$}ζڮӤɊȆDŽ!ނӇ|Ŀ徘ޗƇȆɂʆɂʆ玴}ЄΆ"}|ɰ}ʞ҄уВ̩ݪ׉Ћτآ}⏵|ױ}̖̈́迌̥Ҟΐ̓̄ς՘ʁ񃇈忛}Ē΅ϊЇ{䏰{ݽΟ߉э҄Ņցŝ﯃҄хЄφАσΈ͆̂ˉʆɆ"€~ʡ}ňƄŇƈ1ŲĢװ|ľĈɍˡƈǂƇňąÂ„䘵~톓~ȿ̴ǭҳ}|~|đ|}~~~~}}}~}~~}| ߄ Ⱥ؅|̻ҷϼ􂈏~Դ%򀋓µԄ?Džʄ€޿ϯͅΈτ'腡􁆈ֽⴍکϊΌ凩ی؁ŽŞ͊΂ώЃцȢՅ"Ѐжѣل؃ג蒶ӯވ׌ֆਁꔼ脊߷촂ӗőӫڣӆԄӄևݝцơ˗Յ։ׇڀ씷â֤؍ل̉݅Ǹ̢ل؅ׄֆ׏փՈԇ҈шЃτ Ʉւǯѧƛ؄͇̅̇ͅ/萳܄̸˧߶ě˅ʍȦȋɆʂɅʅΈ̈́΂͈̆ˆʄɂȄĄ띻邔ƹӻγٹ炀ʖ + ſ°ڽ®ۺ~ׂ~~~~~~}~~~LȞ Α&ü~ϔފ̴㓎Ɉʂˍ!~~ƭśʌɋᅦֈ􌛧}ʈȅɃʏ慹~ƢՊЋф܄݉~ѵ}ǘِ҄яލ}ֱ~׊ЇЈʓǀƠǓԄ͖Ï~ɢʕ։Ύ᷊탈ΧӟφІш؊Ӗ者ܸӄҏю猦ë}͢܈Ғф҂фЈτ΃͉̆˄$≭㓻刟ȵ漕汍NJȅLj$ꌤ}~|ɳṖĠȈ Ɔō(~ۄF♷~Żѹͫͤ}œ }~ ~~} ˼нټ쀏#选🶶E~ǝ~ ͍,}͓܉ʲᑍdžȓ }}īÚ﷐ыȅDž߄ԇ򋚦ޫ|ƆȆɂʆɄ䄷}Ġ~τΊυۃۇ}ϳ|Ɨ׏ܚ܌|հ}ֈϋ΄ɒ􄇈ĞŒ̊ˋ}󄇈ǡɔԊˆ̄˅ߵ삇̦Ҟ΋ω։ѕ~ڷ~ԍф҄Ѝ勥|ˡчЊτ ЄςΉ̈́̂ˉʇɆሬᒹ㇞Ƴ亓䰌ͅƂǏƅ&~苢|~}{ȱ߷Þą ĈÉ‹%}مD¿~ÿ􌛮}􅐛ĹϷ˪̣~|Ē + |}~~~~~} |||}}|ɻ쯫ϼػ~C􂌓Σԑ&Ԙ䎒ѹ閑ΈςЌ"惠̱ʠχυΊ戫܌τͅ΂Ϗ쉾̂˦ƗքՊօ∼㌫׺͜ߔ䑶ܶ춂݇֌ՄЗ̄ˤ̗يҐȓɂΦЙۉӃ҄Ӆ҅缍􇌍Ӭ٣Պ։ގٚ̓⽛Ɠȃۍ؄لג퐫ȰӦ؇׊քׄ ׄւՇԅӃ҈цЄ#茲댣κ춐̋̈́̈%䂞ϸ羚ʤ· +ŜˆʍɅ%Dÿ睻~恓׾Ұҩ䂀ʖ +  þ¨򃒞~ׁ~~~~~}~~~/큊Ʌ}ɆĄŌƊńƇĄÈ1ž~Џ怌͛$ၜ|~϶תʛ}˄Ȇ䆥ӄLJȅɈʌ䘾冘›эЇߋƌնÂϔە؊}~ݷ봀և·͊Ҕᐹ䂈~ٰާ̈ˎőƀœ|ˇʈѕ⑹䁈}ٱ͋"ߜݍԯх҂ъٕѷӥٍчІ썯ԩфЇτ΃̆ͅ˄󎡴ŸԬӥ˄ǖ"|}}Ưӫݰˍ ȊĆnӳ¹}}ᚷr~솖逊Ļٽ}Ɩ몽}~~}}}~~}´}~~1}ܮ(쀉DŽ~|Ȉäŋ‰*}ώˆʃˈ˅%{}~ʹթə|ɅȂLJƄⅤуńƈǃȒ◽䅗뮃Љψ΄τ݊ŋ픵ӴϘٔ։|}ܵԆ̓̐Гߏぇ}ׯܦʄɂȊÐ{ɃʄɄȂɆϔ |װިΊ̄̓ΈݛۋҮϒהеѤ~׆τІς· ꌮҨ݅υΆ̓̅˄ʆɅ~񍠲ķ~ҫңņƄLjƆ$~{||ŮҪۯƆłƅ +Ą … Œ'ұF~||x}ꅕú׻~|ĕꩼ|}~ ~}||}}||}}~~Q턔|ÿڬ/󄎔ΉφɃʍˉʅˆɄȈɄ-‘Փ턐қ$無ʀջݯПЅςΆͅ銪ه̈̈́Άώ슝ȟ׉ֈՄք̐ۻœɅ֘ގ߁优򹄜Ԇӊ҂хט甾녌ߵхІʕ˄ȡŏЄτ֙蕾ꅋ߶ՊӅԃՇ㑶ڴ֒ߙ׼٩߆փׇւՇ ڮքՇԃӄ҄шЅȂ˽ڱ٩̘"ゟɀ򀄅̴ٰ㵔Ѝ ŝΊɆ+ٸąFǾӀ睻y偓򊛮…惀ʙ$ǹ5Ⲻ~~~~~~}~~~ 퀋ċřƅǕƂŋ:ƿ}偕Հ|Ƀ~صɦ΅͂̆͂̋⁝}|}}ҺᴌצυȆDž +êƊdžȅɊʌҍĵ源՚щ$ؗɁꁅִ붃јӇԚІ|⻗ﷁԆ̈́̍޸~˄ʎđǁ|㺕~ɍʄɈΘͅ}㺕~̋!벆肇ʥϙ΂ӄВˁצ|ևІы쎷ゐߨІτ΄̈́̅˅ ӄČȃÞ|˜NJȂLj!~©Ğ}şωȊ섖~܈Ć7݌H½⚷؈ǿy넕󁊒~Ǘ}~~~}õ}}~~鄗ꀊ+οȺܶ…ÉīņĎÉ0|〔{ǂ}ִǥ͚ |{||й߲֥ɅȂdžƆ +©ńƇDŽȔЌ߅ó丏ә҇ψΈߔ֖Ȁ耄Բ鵂Ϙ҆ә΅{ẕ˄̃ːݷ}󄇈翚ʇɎÐŀ{Ṕ}ȃɄȄǂȄ͖̄|Ṕ}͋˄͇̂걅瀆ȣ́͘·σІυޙʀ~}ܿե|ԑτ΄ꍶ၎ݧφ΅̓̄˃ʇɅ҃‹ǂ{ƅŒ#}Ü|Þ͑žꃕ}ڇ„¡†ÂĆ3ۋHׇ~ƾs郔񀉑߁}Ŗ줸%|}}|||}}}~ ~}~} |||´||}}􍝲胖4ľ~̽Ǹڵ󄎕ĄŅ ɇʙˆ̔˂ʋ:Ñꄙۄ݀φ޺ΪӍ҂ы 脡ˁπؿ繐ݫЅς΄͆̅ȯŒ͇̅·Ϗؐ犢ʺ쿔۟هֈՈޜτܹ򻇱ً֘ڟՊ܀ه҈ш佐ƁƟЄςΈτɕ̅؀鿙󸁌τ΄ԜӉ݁鿙򸂔ъ҄ӃԆ򷉾ϩԞӅلՆւ׈քфƦݫՏֈ醔Ğ嬅քՅԄӄ҃чЅهɏ·Ȣǜ˄̋̈!Ǯʢʣԍ͇ŝ򇚲⋈ɇ8㐘Lþ螼ތr񈙬慁˛󩽼6 Ⱥ񃎚/Žĵοẻ~ӂ~~~~~}~~~ćŅƃNjȄɉȈǂȋǃȄƄDŽƂDŽȅ }ȄɅ#Ӂ㦑ƴàϧ؊ΐ"₞|̸幑ଇɄȃLjdžȂɅʂˈʏ㊹քι۬фЌ؊ӯߩ؊͍‘Ɓ徘񷁗҄˅ʊɄ˃ޠ؋ހШЙՉɄȋǁ~رޥdžԧœɇʅ˃̅ɔʃ佘񹃣·҆ȧ٧ԓ猸򍠮ݶҖЄτ΄̈́̆˅ʅұ䳏LJȊ$~Ѻᵐ㴐ˆȋ+凝}옡ĢĆƌK앙||~<М㚷þμĿoå߂ʘ)}~}}~~}}~~~ ~}ķ}~爚/ƽ|ҽůÈĄņƔǒňƋŇ +ž|DŽ(~Ҁ⤐IJŸΦ̆ˇ̅#ၝ~{˷㷐ުDžƉŋƅdžȋɆʆ ቸ~Ճ͸٫ϋ·։􃆆Ѯިք̈ˈʄŀ󄇈㼗ﶀЇɉȈɂܟ֊ϧϘȈDŽƃņŀ}ׯܤƌNJҦЊȃɅʅ~ǓȂ󃇈⻗𷂢͈̈́̊Ѕ~~Ǧإ҆΄ς΄ψ拷۵Еυ΂̅ͅˆʄɆаⲍňƆ"閾}~ϸߴ᲏ɌǂȄDžſ㆜|ꗠЅ ÆċKꔗ{{}<ϛᙶ̺þg􌡷톖݁~ɗ존 |}||}}||}~~~}}||߄ +õ|}~~凙튝~ż{мî~􃎖ƆɆʆ˂̋ͅ΂ͅΈ͇͈̄͊̄̄˂̄ͅ Œ̈́΅#ꂗلꪕ˹ɤլޅԄӐ"腢̃Ѐҽ뾕氋΄̓̈ Ş̈́̇͂΅ςІχщ鎾܇Ծ᱄֊ՈގٴӊҋǕ̅ÜׅІωІޏ僊֭֞ڊ΃͇ǔ̅ߵͅ΋٬ǠŠΈφЂцׂΘχœӋԅ؊άهՄֈ퐽㻔ؚֆՂԄӄ҄чЅτ׶긒͇͍"׿纔鸔΄͍΄%ş늢뀊ɦʂˋK򙝝֠螼þĿȪ䅂Ϝ󦹸4 + +$ɻ틞샐/¸òʴ~~~~~~}~~~„ÂĄłƇDŽșɌLJȂDŽȄɇ}Ʉʅ˄#нạׅ̇̄ϊΈ#䃠ʀ⸑ଇȄǂƅLJ 䌯޹˅ʋ˂ʄ~Ҹ˚ݛьχ΄攻ͨљˇ̆˂ʇ㮆徘񶀔ЈɊȆѡ끇~ݵ}LjȄNJ俎ŀ̦ΗϊDŽȉȄޡڍ߀ȡŎՈȄɅʄыߢڍծؠՃщͅ׊򂆆Ϋڥцώ㉶ɻˠфЄυ΄͈̃˄ʆ ܀ȋƈDŽ"ㆧ؋~~ȰѦ̤ȐʅՒĢѰDŽłƍ҇ЃφЂфЅр~֜嚷µ~˹}bǐބ˘5}}}}~~~~}ƹб}}~߁􍢻ǽƴ'|ſÄąńƊǕȂNJDŽƄǎƄDž|Ȇ(򐕑߄μƟˡՄ͏̅₟ඏުDŽƉƅ ⋮ܷʆɆʇɄޗ}ж~ɘۚ̈́Έ͇䓹~˧Ϙ~Ίʎ⬄탇众΅ȊljР逆}۳|ƂńĆ⾍󃆆ʥ̕ŎƉƃܠ،ƠÍƈǃȅɅЊޠ،~ӭןԂЅ̂ˉ̇Չ̩أЗሴ~ȹɟφ΂̈́̆ˆʆɃȅ ƿƆńƈ ᅦ֊ވ}}ƯϥˢΎLj+Ԑ¡Я~ġċϊ΋H}~־՛㙶~}ɸ|̾Ə݃ɗ'||||}}~~}}~~}~~}|ŷΰ||}~݀򌡺턑żų"{Ľ􃏗ĄƅDŽˆ͙̄Ό΋͂̄̈́Άƒφ,ëͥҧԋӈ#ꇤσǴ轕氋͊Ş̄̓̇ 鐴侘фш#́׽ОՉԄ胊ӭ֝ςՈя鲉ÜφΊץ񅋌㺕̊͂̇˅ŒʄҫӛՄ͇̅͊僊ͥʒۇ̈́ΆςЅ׏僊۳ޥۆ׈҉Ӆݎԯԓ鍺ԂХֆՃԄӄ҈фЄυ Ůℋ̊ˈ̄!鉫ޏ捨͵֫Ҩ͐΄"ەɧ׵̄ʄˌ׎ՋHܠꞼǺѾž̓ϛ2 ʽյ䄚·̹$ӽĿ~~~~~~}~~~~c~||ƿؓɊÐ}˄̆(ΰ~~~ӿ񿙁ӄЈτ΄慢́򌟰֣ݖɉ ֖}}سݩʆ˅ʄጿ딵}Ѳ굃Չ·͇󲄸낇Ğ}ɆȂljՙ薾恇㼗}̈́džƄ’Ȃ򂅅忛ƆĆÅ຋~~徛łƆڴ~񃇆ʥ˔ƅńƃDŽȅי閿肈Ğ|˃ٍ̄Ѭ١ߕΉ"܃ЂӻెŒχ΅̄̈́ɅǺLjƂDŽѽʇȌɅ.ڀՑ~ҲΫ~ƣŃƉłƆńLjȈDŽƊńċ$相ƿ˹ǵ}Ƹ~}߄ɛ񠱰 +}~~~~} ɻ~ڀ}ǾŲ}˾B}{~~{ľDŽȅǑ|Ʌˈ%~}}}ѽ쿘リφΈ˄儡ˀԢܕȆLJ ƅńԕ||ֱܧ̅Ɇȅߋ铴~|ϰ鴂~ӊ̆˄񱃶遆|Ȇnjӗ敽倅⺖|ˈŐƁ㾚ōƅ޹}퀃}㽚ÂĄÎس}ɣʓ֊ĂńƆ՘畽恆{Ɏʆߠ׋ϫןݔ͇̍ڂρѺްÑӅ·̓̈DŽ ƈłć$ϻ뾗Ƈnj'쇢Ԑ}ѱ̪}ńĈłƄǃƍņƄłĄÉ„噶~Ľɷų|ŷ~}|ރ~Țڇ|}~~~~~~~~~ }|Ⱥ}ƾ־󁏠|󆔢żı|ھɽc􃐙Ľ݌΄ς΋ȓІх҅%ĬƝĝքՉ҄쉧҅ܨΌƞۛʁݸ㭇ІтЄτŊ׷񺇺ڊӆ҅񅋌ɣĊφΆ͂̉ڝ텊҄̇˃ʆǖΆğ̆Ɇȅ濏ǂߋʅ˅๎ŁЩј˄ʄ˄̄ͅܝɢÊх хߐױߥԉӌᇲֆ涊ʖڄՇԃӊ΅ń̇˃̄ªĝφͅ΂υΆ.ەôط԰˧ʄˉʂˆʄ͖̈̂˅ʂɋힼ􃌖ļѾ̺˽䇂$ΟͿꁋă߃܀ø˷ųþ~~~~~~}~~~>ƴ󁊓ن%ʄɌʅު~ɐ͇̇)~ϸܯ٫ׄІτ΃͇臤΁腓ԘΏ͇ɇт~􍠭}Ч’ʄ˅ʅՉ~ǦКՐ߈͆̉񃇈}޸ȇdžƄ̇ڠ،|~޸ɉńĆńljڌǣ̔҈Ćڲ~հÌăńnjߏ}˧ИŅăńƄ੄킇ױܢׂψʈڏݟ؍}ѬԜԋٌ͋΄|д’՛·ψ·ͥɄ ǺǍ ߃҈؂ïٰ۬хLJȆɅ$}ׁ݊仜ʋƇńƄŃƈɄȇdžȄǃƄŋ 雸~透}ĹƱɱе~~}݄ޅ}~ + ~~}}˽q}ƾտϘ}þ|̸įö c퀌ij񀉒¿¿ҌȄɂȈܩ}Ǐχˉ*ͮ~~~}ηڮשև΄̈́̅憣̀焒ӗ̎ȈDŽ +ƄŅρ}򌞬|ϥɅʊɅ Ԉ}ƥΘԏˋ~~|ܶІƑʆ؞׋{}ݶĎňߡً~Ţʒ‹ذ}~Ӯ샍ŠƋݎ|ʥΗÂĄŇި끆հڡՁ͒Ʌ؎۞֌|ЫӛҊˇ̇͂{ϳӚӉ̅ˤDžŃĄނчցدګЇƈlj#|܉~Հ~⹛ɊŢćłƈLjƄʼnƃŅăʄ皶}|·Űǰγ}}|܃Hʚ򝭭|||}}}~ ~!}}||ʼ}ĽԾ~Η|¼{˷îµ >˹߆!¾ΆςΊχ㮁Δц҈)Ђվⴎ߯݅ՆԄӃ҅ԅڜӓ҇·ƞ͊օ֫ǖЅтЄυЄۍͫ֞۔҆ффׂƃ佗̄͆̆ˆыސဈ彘ΉʄɆʄ̧̍ј׈ȄDž߶쁅۵ȋɄʄ͐哹えѫ֜ʅɃʄ˃̄宇􅋌ݶ݆ІϊЅߓޑဉױڠڏވ҄Ӆԇֹǖ۟ڈԈӇҩ΅ +̾̄̈#凨،ކȴߵᱍ̈ͅΈ#〘㍱ق݅Ћˆʆ˂ʄˇ̂ͅ΄͆̈̈́̂˄ʋ Ą퀋ɾ̶ζչ⇃П c쀊Â՝瀍þҽɴȻ"~ +~~~~~}~~~&}҅6~ɑʌˉз~Ӽ˭φ α!퇢~}|é칓҅Іφ눥ϬˊʇœȄdž捹˽ۢ}Ԕ݉|瀅۹ͅ˃ʇπ‘Ʉ􄇇ϩΓȅƄņćǂ큄ֲ~Ą‚Îѣ~땸}ʩ٠Ԩá͗Ṍ~}}ɧӜĆÂĆ鷌À|ވɂȊ׋ћԋ}ϪϕŃ˄ʅˆ̅Ҕǂ|ƥӟ̌떻Ʉ +ǹŃƇ͎ރŻƠȟ·DžȆ%앻犢ͺܚ˒ljňƆ ̈́ŅÅ윸􇘬~µ~DZĥӽ~~ɢۄϝ󜬫 ބ}}~  ,~~}}}̽}ŽӾ򀄪Ʋе DŽ\|}ǐȆɌʅε}Һʬ̆"놡}|{뽕귒φΈ͂̅ꇤͫɇȄ 匸~ʻ١|ʋɄ܈{ٸ̇ɄȄDŽǃ򃆆Χ̒LJ†Ɓ뀃հ}ÒТ}铷|ȧן󎿆ҧ앷˕߷}||Ȧњ‚Å絋~{܍NJՉϙҊ|Ψ͔ÂӈɄʇВƀ{ĤўӇˋ̄쎴镹߀촃Dž ŸÅĂÄˍ܂úğ~Ǟ̋ƇDž"~ꓺ剡˸ڙʆŅćŒĂń݅ ̅ĉ…꛷򆗫}}Ư¤Ҽ}}ǡÿڃ͜ +|}~ + 1~~}|||˼|ļҼ~Űϴ ń!؅6ΕχЍռѲӄ"͂ȮĚֆՈԂӅԱЉχ Ǡ̈쑾փ¬ŗᧀڅЂьŌᾚӆЄυՄǕΈծԘͅ˄ʆɇŔ͆􄈆ܷɄǂȎרЮߤƌ٭ȥқƅ羐ǂ큄Ϭ٠ȄdžȂɆﻐɄǢÈ΂τ܎ןڏ߀կԙʇυІхטͅ˪٣ڈ҉煔Ĉ΄ +̾ĄʄˆҒ䇛̥Σӆ̇ͅ'䂛펧ӿ➕В̕˅ ̄͂˄ ȅ򠽽~Ǻ͵ɩ©ΦԠ , ·逋ƒ̶ƫպ ̄~Â~~~~~}~~~c¾˄ʆˋ̅.ӓ|ˬƦϲЇ!ꆢ~ìŝ~Ј̆̓̅ˋÝǎ߈уӾ٧ؖۏʦȎцɇȂLJчʖψ􃆅ὙՄńćÄۧ~}̪٠’麋ȫΝ㎭˱ȅƏۋĥӝÅÆē˄ϬמрǎȇуȔ͇˦nj}·Ɇʄۈ|}ԳՅˆ̉䈮斿싟ڲД +ǺƉĂ~ش깕˅ȇdž*~햿쎨|ʵ۳㹕 ȦNjʼnƆXȆŽ|ş~􅙫ǽūڼ}}ǜÿچѝ򜬫}~~~}}ξļлƮWʸ~[ÿ~ΉɌʈ(Ғ|~ɫĤΰ!腡}ªÛ}хΆʆˇʉ›ƂLJއЂѼץʌڎɥǍЅȄDŽІȔ͇򂅄~໘ԆÏڦ헺}|ʩן縉Ǫ̜፬ɯ쵂ǍŎيãқ‰„’Ƀͪ՝ʋƋςǓ̆ɤŋ|ljȂɉه{|ӱ~Ʌʎ⇭䕾ꊞٰΓDž ŸÄĄÁ}ײ踔ɐ,}땽ꍧ{ȳڱḔćƥԄőăńZDž󖚞Ļ{Ğ웸򄘩􉛱ƼĪػ㿩}|ś¾مϜ𛫪|}~ ~~}}|| ̼~»Ϻ󘻣~Ĭɷ%􂐜}󷷸[ýՅЉч)ٗ򑀂ѱ˪նԉ"͂ɱʡě؄Շц҆Ѕȡ̏匷׆è߫ݖᓺЫΒĄΆ͂̇׋ϚԋۄʄɆȅᬄѯߥőƄᅫΰƕӢ꒲ѶĄńċ˒Ᏹʩ١ƄDžȆɗшԱݢփя͇ֆΘӋѪ̐ӆΆτІċ耇ڸڄІы錳򏤴ා֘ +̾ąˉʅ޹Ѕ͆̆̈́'䁚к⸓龙 ͪ̕ˆΊGÿ¹ʣ ÷˰ů̠֡#¶ꂍտ˲Ͻ!񁋖~~~~~~}~~}~~~~"򄏘Յ}ˉŅƃLJȇɋʍ˔͉̅&ҘიšՋІуІ.ꇤ̺Û}ʴ͇̈˄~ۆ対Ǐ؀΄|ѵ̇ʃˉׄ~끆شݡڏDžƅʼnшϙ҉񁃀Ϊәdžˆϐߡ؊ڿ͖ăΖʀª관ʋɒ׆ɶԟކಆҼќՀɁΘІ}շ~هŌ|ā񃆄~ß}ȍ闽}}߿ՈɅʇـؐįӦ~Ȇ +ƺ ԇ~ԪʆLjȂDž.␷勥¬ˢΥŇ􉞸|Ŕ&̂:~ʿ텘쀌׿}ƚÿۇў񜭬 }}~~ ~}о}逊¸͹}%~}"񃎗Ԅ~|ɇÄĄńƉdžȍɋʄˊʅ˃̄,їʾàԊΉχ醣~򏦼˹|ц ɲˊʅ}م㭽ƄDŽƅ̓{гﶅ˄ȊɇՃ}逅ֲ۟؎ƄņĈχ͘ЈͩҘ͏ޠ׉ؽ˕羊‚̔ɼȑՅǵҞ܅߱кϚȀ̗΅|Ե}׉Č{€}ž|ȏ疻||ݽ򵁴LjȈɄ֏푩­ѥ}ƉĄÅ ҆}ҩȇǍ,㊤ɡ̣ſ򈝷{ňą`ʁ}ɾ n넗ս|ř¾نН ||}}~~~~~~}}}|Ͻ|̸~􉣙|􇖧}|"ۈЉʅ˂̈͆ΊώЙфҊ&؜臜ŴʥۏՈևςȟ›؅ и҆шЄÞ̄͂ΈރԈ׺ǑхυЊ݇񄊊޹ߓ̆˄ʉ֋ԝ؍ԯٝ̆džƆԓގĥӛĊÇɇӚЄǯ𹄩ωŽϖ܊ϼ٣Í…淊נۃȇąŇ΄Ԝ֊ۼˆʊ˅ӀɅɤˆ͋̄怈ĠۇΆφ߃ޔɴ٪͇ ̾Ąʂˌًٯ̐,蔼돪ȰѦөš܀ʕc҆½Żj󉜱󄐛ſĤ˞֢  öƽҽ퀍ƅ~~~~~~}~~~􇑘„ÄĆńƆLJȄɄʇˈˌ̇͌̄͋*Ȕ邖لͽޖ҇ц/뇣~틟·߷ߛȢ͇̇ф􎜞塛͕ԓǃ}ãȒΒɇʇל׎~ᾚdžńĆэԛӉ}}ط}|ȱ߾͑ޞтݮۊ~􊖙ŝގĈ՚́±͙Ԃˆʇԛ҅ռɓȈĊ쫁ںŏߒӘӌ􃆄ȤÊֆȉɆÄ钯ʹÔܤɍ ̓ +ÿąlj ⃠ʀπ˹幔껕̊)}倎ŅňƂʼn]~}𞺺Ƽ}}Ǜÿ݈Н򞯭}~~ ~~}}}νꀊ¸̸}~~ ƾ̼ǵϷ򆐖‡ÄĄŅƈǃȆɏʝ˅̆,Ɠ聕׃팣̼ݔ҆Ђϋ+ꆢ}늞ݶݚƠˊЂ򍛝㟚ˈǃƇҒƁ|Ƒ̐ǍȆ֛Ս􂅃}߽ƉDžЌҙ҈||ֶ|ԇ{Ư݆̐ݝρ۬~ٻ}򉕘Ü܊‡Ә̀˘ҁȆҚЄӻȒ‡Êꪀ~عĈńĄݑїъ򂅃~ƣ‰ԄƈLj瑮˲“ۢ~Ǎ ʅĉÊŽ ʷ㷓蹔~ˊ&|ąw~}|źĿ||󂉐|ھ܇Μ񝮬|}~ ~}}}||ͼ~˷|}}~􍣸􆒞!ļʻų͵ƅDŽȄɆʄ˅̇ͅ΃ψЍу҄ь҂ш҄ӆ,͘߈䙟م׃֋+΂󏣶ǽ弗ͦ҇!ׇ륟Έ͂΄ڗ͆쀄ɧΖԕΈφݠݒĞ̆ʄɆאڟٍ޽ƆŅĆĐƀͶďɍӕׅ㲂ȁʡɋ۞ӅǵҝمLjÄĊϊٟ؉ϗ͈ɇ򯅽탆࿛͐˄ُٜΩɎ‰ۆ͇ΈȈҹɘ⨃Έ˾ѓʅ ̊ 熤τՃѾ뾘ъ)š倒섒ʏʉˀ–Հ̟⋇ա  ǼѼ!ü̺Ի~ +~~~~~}~~~Ćń~ }߇͉̌ЈȔ"~Ԅ㕕샐ǟ}ʢلфЌ툤}႒ٌȢ͆̇ΆՁ䝝毈͌ȈÈ~}έԚ֕LjȄdž}~ƢȄƄҌԚ҇ؿ̕|ąܠ݉ңλρɳƻ~ǽ蕼懤˰걀Ćʊ՛Ѓ̺ڥԎƒÄݘ㒵|ϯݢޒׄĉ}ꀅΫ͓ˍىƆDž،}ΰ宀˅ƃʼnЂيĈ!십܌܄ο~Шӫӑ&ޥ܀ź䎌|қńƆŐj~񞻺󂃄ƺ}˼ü~}}ǞއО}}~~~~}}}}}~~}ʅ쀊¸ʷ}~鉞}ɸ~􆑗ÆĄ} |݈ˌ +̈́Ɠ!}҃򐨾ⓔ낏ƞ|ɡ׈ϊ'뇣|߀׊Ǡˊ̅Ԁ✜宇ǎƄ‡}|~ͬҘԓȌƈ|}~Š~†ыҙІ׽˔{Éڟۇѡͺ̀DzŹ}Ƽ画䆢ɮ‰ȈԚ΂ʹأۗ⑳{ήܑۡÑ|ͩˑɌĆň~׊|ͮʎŸ΁؄ˆĩŇ%ꊫڋڃ̾}ϦҪŅ,ſܤĸ㍋{ЏÈĄÓćD~}$򁂃ĸ|ʺ»n셗}||ŝ܆ϝ||}~~~ ~}}|||||}}|Ȅɶ|}~~爝|~ì~ȷ}þ ŅɆ чҊԆ/͘聕وꙙͤЦއ֊'Ё煖ߏͦ҆ ӊۄꡡӌ͈Ȍ‚끆Բڞܙ̈̈́̆遇̦ʼn̈́ȆDŽؐڞ׋ĥҙʀɄń㌦ƸاԄθ̿񁉐¿싨еɇ‡ύ۟ևڎǃȄꖺմ܄ɉ񄉈԰җБ߉˄̇ۃޏԵ별І˂ʉՅߊɈ̄␶∡İ֬ٯّ&š⃗˿둏כʅ˄ʍ˂̄B˿􊜴灁̡㋇բ Έ򃍋Ǽϻ܀ǿ!ʳϽ~~~~~~}~~~~~;~~}͉̇ڠϴɔ΄"уʶ۰۰юЄ ~} Ȣ̈́̊˄܀ԍĞ~֥ˋLjׄ}|Գ۞ڙˇdžƆ։ŏDŽ}}Ȧʐˆ‚Ҏҗ̓ͽߩҽʂ˵ƺەϜ񉕡ܮŐщϘЅ׿˔ȄΔܓٞېѯԘѐĈńŊ|ǦʕٜΑ"ŝąَՏځ㼘ÜΊƉ%ƪ˽}ղäĈņĈńĆďňƆƅńĂÄąÆß򞻺ͷ͸~Ĺ~}S}ԟ}}}~  ~~}}~~}} +}~큊ù˷}}|텓ζʶS}}|ٿʆˎٟγȓ̈́̆!ς~ɵگٯфό}|ơ̄ˊʄӌÜ}դŇƋՃ|홾{Ӳٝ٘ʊʼnԈĎƃ||ǤȎ~ɇЍЖ˂̻ިмȁ튛ɳąڔ͛ڬÇψΗ΄վɓƃ͔ےםُЮӗϏŇÆĆÉ~{Ťɔכ͆Æě󊘟LJĠń׍ӎ؀⻗ŅƅŇ%~ĩʼ|Ӱ¢ÒŋĄÊ†ž𝹹¾̵̷~ø}|ɠއ|Ҟ"||}}~~~~}}||}}|||}}}~~~뀉¸ɶ|}~~{싡냒ƿ͵ȵſ :хҒ६չΘӅ!ׇлᵏ൓؄֌ͦ҆чᄦڑɢܪӹ܈怇ڸч̆ˆۍ˓͈ΪϓЅ Ćב؛ӆª‡υкˆԠⲄʐƄ֍՜ՉŦј͇Ӕߢᔻ״ڜהɈ"ʎă̪Йߠˏ"ʡɅߒۓžȡӔ%傎ě˯®ڷɨđɈʆɈʃɖʉ˅ʂ˅ʄɂȄɅȅDŽƂŅȣ¿ӼӽɾϤ匈٣>  +  󄍌Ƚϼ؀􏧿󈗧ƻԻлž ~~~~~}~~~~WЕ~~̄͑Љـѹ򃇌ԆΉ$Ӹ͹ඐ㵒}ӋЍψ Ȣ~͆˄ʅ܀➜ɯ殀ʓݒ󁄁׵ߡɎąڎĥЖɇЊ̒}庑ԇ悊˶ˑîﷄ}~ѰٝڕĄƒ…ݑ񀃁ٹƒ풼|Ý洿ˢ}ňĆƢʙیʨݲ˅ƅDŽ.锺䈓җͻ̥װ}ĦÅČÅĈ܄݆ƅŅÆ!񁍛~ĽԺ~ֽٺ}Ρኆ}՟}} }}~~~ ~~~~}}~~pƻ͹}}̴}«Yϓ¿}Ϳ}ʄˈ̆!ψи񂆋͇̉ ѷ򏧼˷޴ᴑ|чφ΂̈́·͆ ơ~̈Ʌ᝛ȭɈĂÉߞې񀃀մݠޙDž…ÉޟٌäΕdžͿωˑ|㸐҆䁉ɵɽ󲄸ǿ|}ϮלؔÈܐ׸ą„„둻{~œ䲾ɠ|džġ~ȘًȦ۱ʊĆ%~瓸⇑Ж˺ʤ֮|Ą…Úڅۊ ń„„~}üҹ}Իع~~|T̟|Ӟ󠴼||||}}}~ ~ }||}}~oĺ˸||~~ʳ|ҿ]֙¾ғ֌߃׾مӇԇ!ؽìҾ滔麖ՆֆՇԇ ͦ傌҆Ѕτ΄ყ袠ϳϓ㖼ݺΎɅᒴʪ֛΋Ą֎Җˀ뿕يƿ솎лБȳʼnĉ뀃ֵߡDžƄDž䕺߿˒ȡźЦƙʇɇ˦ԂϝᐟϬ㷔Ѕ˅̄.䂚ꌗؚҪݵʪȅɌȅɈ˅ʅȆǀ¢냑삎÷ڿ¨߿?Ӥ獉ڣoʿѽѹȰƾ~ +~~~~}~~~~~Uވ|ľ~Ķ~܆̂͒%牣߁·ٱω%̀ʽծܯӅЌτ΅Ǣί䶒ʆɆŸ}|ӷﳂDŽņĂņ"ǎDž~ճ۞ږÅ}蓰мњЋѿЁ̍Ĺݕ˓բ֌ΗЇ̭ڟܗÿӁ}}ɧƎʑˆÃą؀ݔ}ώ̝ﳋÈĆƢ ƤȆƊ#ލ݅ցÜLJŅ낓တϘÀƏþƳľ}􋜮큎aû־ϱū~͟㊆~Ԣ}~~~}}~  ~~}}~~񄍐λ}~䕀|ƶŰؼ}ʶU܇~{¼}ô}ۇˇ̍!刡݀ނᾟװՋ&ϲ팢ɻԭڮчΈ͇ơͭ㴑Ʌȅdž|{ѶƐޏƍń}Ӳڝٕ†|撯κϘϊо΀ʌ~„ۓʑ􊡫ԡԋ͕Άʬ؝ږ„р||ǦčȐŅۓ|͍~ʜ˅ġ +ĢLjĄÆ!܌܄Ԁ›Ɔ¥遒͆„QĎ¼Ų½󝄸|򊛭뀍Խΰê~}̞#ቅ}Ӡ|}~}}}|||}~~~~~}||}}~Ŀ͹|~~{ĵîֻ|~ɵP䌍ýʻц҇ӌ"퍧兖ȼ憊ť߶Ԋ&ָӄ²۳ⴒ؇Շ̦Գ뺖φΆǣټʇɂʆ͉̒۸DžȈמ֏ՄёɄїۧƈ‰ېԛ֋Ѳĉń؅遆Ϭ˒ϕLjȂɅ݄ʁՒѢȈɆ˦ ˨Άˊ#䑸䉣ۄȡ̇ʅ񆗮焔ԘȀ˒ý˸¡aèնʯҢ草٥ +  ӿꙄ˻ʴ򁈒л~ ~~~~~~~'}ńƄNjȂɄʅ˔̄͂΄Β#ꏮƷϫഗՄ~䄗ߨ݆׍υ΃̈́ǣ耑ʡ~Ù|̄Ȉƿўؕˆ}~׺~ņÇDԁ}}ͬӗѐԆ𓪺㽺 +䲲  ؄Ҿҽןߚ׋ƅ~Եޢዷ}呱鮊ʤȈÇ슧󏗕ņćŊ'𐩽;}ѠŌ۴Ť։‚ÈTͼþ˾|􎠲򅑜ú|Į~}˝䋈ށ~}}}~ +~}}}~򄎔~ʄ~λ~~̾˷􅑥䁐󁈍)|Ąŋȅɍʋ˃̌ͅ&莬ŵΪ޳~Ԅ*}⃕ݧ܅΄͂΄̈́̇Ţɠ}˜{Džƅϝ֔ʅ|~}ֹ}ÑҀ||˪іϏ҅Ệ ㉰փмѼߍ՝ݙݿ֊Ą~}ҳܠߊ|㐯笉ɣ‡ ꉦ񎖔‘Å ހ̼|ПÇڲâ삋R˺ɼ|󜸸쁏򍞱{ì࿅~}|ɜ⊇~ף܀~~} |||~~  + ~~}|| }}~~}ͺ}}˼ʶ򄏤』񀇌 '򀌖ʄ˄̊φЍх Ӑ*Š̼հ湛ۄтꈛ܎Ԅӆ̨Цɝ΄͈'Ģ֣ޙъ쀃ݿȇلӰ؜֔ŇĄىŠƿ†ꈶވ¯環ǬݣݎȐˈ񂄂ںƄņƅ珼땶𲍥Щ͈ȆɄ ʆɇʉ(儠îפʌḓʨۉǂȈWÿõ􅔬ȿʳƉС鎋ݨ㄃ ӿêѼ넔 ~~~~~~~~~„ńƅǍ݅ω̄͂΄ς΄чЊ&ӛـʺȣЦ蚡٢Տ΄υ΃͆Dƣ۽~Ƹ௅ɚƿӓˇ}~ָ΅„ڙ҉ؽō‡ܐɆϸȻ ;ӊ̷Œȋèמޱꇗ޷Ƴ͖ЛܘޓЕъ|}ڽȋ}|׻Ƣ†℣΂悌Ԙ&⃡퍡Ļ佚ŝϾ%튡ŧN}}}񆜲酕񂊐Ž~~}ɝ匉၀~ }}~  +~~}}}~~􅏔}ͻ}}怏}ºñ|̹} +ÄĄŅLJ܄Ί˄̋Ϗ,љȸƢΥ晠ψסӎڌ͇̅!Ģټ}ŷޮǙƅ ђɆ|}Զ̊٘шֻÌڏȅζǹ ˽щޤ˵~Ɔާ֝ܯ膖ܵIJ˕ލΚڗ߾ܑϔω{|ؼ򳀳Ɗ~|{չŠ…́䁋҅ȆÅ&~댠º⻘Üν!뉟򾷩ĦІN|||ξſ烔~}|Ȝ㋈ ڣ߀~~}||}~ ~~}}|| |}~~򄎓|̹|}~~|{ʸ򁎗Ä ʄ˄̍Ջ҄ӊ֎)ٟ߄пͨժߧړԇӃ҄D˧т̽洉Ξģٗы쀃ܽӋƇ؍¤ʑNjƇƄωսͿ ø؍ҼǐʹȬݣ㵳伦˸Қ撫Ķ՟Ņ֙֎ Ɗą͏ƃ˦Ȃdž舧Ӆ톐٘&臥σ󑦵žʡã%žǪʫƕPƼƼǒΠꏍᨇ愃( ҿ샓゘쀋ǿȶѾ~~~~~~~~P쀍~ĽЅ͐֙̽չ}ш(ɖ녚琳؀ʛӌЄ· ͆0Ť͆瑯ȯ곅ǗžÄώƄ}|ϯӘחDŽׇɿ}ʽüѪ}ƔˁנڄԝՇ¸֜њς踈䱄㓻ʸŷ땮Ԗ࿷ךԊĎȏՕΈ~}ѳ˞󑙗ډԋčהǃɧܴą+ڈ􍣵˵ݹLj…†&󟤛}|~˾ʲú숚~~~}͜ +ݣႁ ~~}}} ~~~}} }}}~}λ}~~↛}ǿų}ʵ +P}¼ΏԘ˼Ը|χ,ǔ鄙叱οɚό͈̃˄ц/Ģ~˅叭ƭ貄ŕĽ͍ă|{ͭї֖ŅՆ쓮Ƚ~|ɼ ºϩ|ēɀ՟قҜӆԛϙ΁緇⯌ᒹɶĶꔬ~տҕ޽ߖ֙҉վƎӔ̆}|ϲߦɝ񐘕وӅÓ֓łȦڲɆ/ه򌡴ɴܷſ#~񞣚||~}ɼɰ뇙}}}|˛ ۢ~ }}|}~~ /~~}}||||}}~ |}̺|}~|žò|ɴſP򃐚œՕ۝ð۾׈(Ι픸ބƳП؎ӄ҄؄҄.ʨ₢Ҋ해ʹ̛ãȅԒˈԴ؜ݛąÇ܋į𷂳… ׯ˘Єݥڢۋǽܠ֞Նl굲нʼ򙲃ƮښĄݞڎŦɒ͓„…ۙԋָТڋɍݘ̇Ϭ⹖χ+£Ѻ㾜̈ƐŋƇƅdžƇLJƄ#ùжȿ򋞳聎恁Ѡ ⧇煄  ) +|ӿ芟瀎Žʸк~~~~~~~~~~O~ᑚ~¿ل΂͐&ң׽潡͖х$胙䎰~ɥӪЅφΉ?ɯŤ̲݁ؒ߆È~}ڗ~󻆺򏦼|~ÎαɀݥስȨĥˏƒѳꊨƘӉʲ򐷪Ǒه٪† Ȼיτ˻ЙۛÄDטӋ}ǧʓӜ~ӍIJ}ȝגÇÉĊƤ‹%Ī}保}„ 򅔍ԓĆ~}}ȥ~Ŀ~п̫˹~}}͝ ܥ₁~~}}}~~ ~}}~~} +}}~~ o}λ}~񆓞½~оϯü O}}ȿז#Тռ张̕Έ悗⍯}ȣѩш΄͉̄~ȭ쾛ã!ۀ֐~ʰ~ž‡}ڿ|ӿٖ}񺹹 +񎥻{}Ͱ쿑ۣ߇Ƨ¤Ɏŧϱ覒ĖшɰƐ׆ةꌿ ƹߖ֘̓ɹΘڙ¸&Ֆъ|ŦȒқ˿ }ь푬°|ǛՑƅň 󛣏Ģń$©|˾㽜| +҉퉈~„}||Ǥ}퀊¾}νʩʸ}}|̜񀄊 +ۤ၀~~}}|*||}}~ + +/~~~}||}}||}}} 􅍕p|ͺ|}~~}μͮ» O򁒜畟Ŀƾޖ$קè¥ҚՄ"꒵ہϩٯ؇ՄԉӅϴŠʨ!ℨޖɂѷȣdžȌÂƣ…΂€ɒԵƖτž猺ͭƃɩГָ̔˜ٍз̕ߋ߯ŇNJͿݞՈ՞Ⱦ(ݜ؏̬ϗ٠ƺDŽ܁ّɷΡܕȆɂȉɊ˨̄NJ$£ɯրŵġDžƈĎńĄŃćĄÃ†ͩꂎþıѯоҡ ⩈腄 )  nӿׂþðԴ ~~~~~~~M~žфΈ͈͂̄%~뎧ꇘ˕ь炗儩ӣۇЉσΈ؏ڞ񈗤Φ̠کɄȆބ҈ʬ֕܉햴ĩמƻԁ͘빹 ե|ތԞ؊ɛ؍־ɢ|򂧤ņ˜ץ̴ЌԯБĦݴǃʴ󸀟ʭԔגЬś餉Ӡȷԕ͈Ӹ찀þ)ۃτվϝ쳋ãڿ†Ä‚Æ‚CހŹ}ұ崘~¦ـ䟔ɏ”|}ԾĠ}~䀓󅑜ºؿ~ڼ̯C~}ϟ􀄅ܨ䃂~}}~ +~~~}}}~~}ͺ}~~Ƶ~ƪ̼ﴴM}ވľ~ļ~Њ̆ˇ'}鍦腗ľ~ʔЍ恖ヨҢنφ΄͈̅׎؝̥˟بdž݃ІȫԔۈ땳è՝ߝĹҀ̗鸷 Ӥ{܊Ҝ։ǚ֌սȠ{Å֣ʲϋҭΐ¥۲łɳȬӓՑΪĚ췊碈핡џǶӔ̇Ѷ.ق΃ӽ͜겊„ ؾۈ‡C쉇÷|Я䲖}쇚➒Ǖ{:|ƾӽŸ~|}򄐛־}ػʭ~}}Ξ򀃄ڦ +~~}} |}}}~ +~}}}| |}}}~~ |̹|}~~}~Ŵ}ĩ˻M捋žüׄӂ҄Ӈ҇&낒ſљ׍텛눮٧ֆՄԇӆޓӫҥଡ଼͆䇮؋бܙƂň⍾ʮݢ˿لӜ񾽽 +ڪ䏫ڢݍįΟޑĢϦʊǝݩѸ֐ڳՕɪ㹐̇йϲژݖְ˟嗀٥μڙӌؽ򵃽Å(ՇĦԢǧēdžȄǂȆǂƆCボ􍌞ʾض친ǫ􋠾߃ꤘΔǘ9Žĸɤꃗűѳԣᬍ + + + Ҿ䃋̺˯!~~~~~~~)ƄɄ ͈̈Έ̓̅͆Ά%¾ꅋڸ𽟅ш؃罀τΈͅ}¶КɇLJ߆ڌՃևø氀ʴưÎ哲Ĭ؛ˠְȇŻޘ×֕͝ƼȊ~̟٣ܩÞ쉷ם钫︂ഭŰゞ|Ӭϸ"܏Ƌ~˕ٝɼ؊͙᪃ȇ戧҅傊ύƒÌ ~فϥċ ݡ넑~ǩ}ϕͅ}ǡ~偔|FԸб훁~}}Тঈ僂~~}~~~   ~~}}}~~~޾}~~쟕~îԸ~}}~|֥0~~Džȇ ʈ˅˄̈τ̅ͅ!~脊ضׄχׂΈ̄ ~|ΙƆŅޅ؋󠝣ƾԂՆ ȳ~Į㒱ë֚򰥥ɟծƆĹݗ~•ޚԓ˜ĻƉ}˞סۨ눵՜瑪޲ îၝ|Ѫη#ێŊ}ӾʔלǺ!։׿˘ߩ処фぉ͌!}쒱׀ޙ~ͤ#۠郐}Ũ|͔˕|Ơ}~󆔫〒{Hҷϰ뚀~}||ϡޥヂ}}|}}~~ ~}}}||}}~~~ yܽ|}~~ꞔ}Ҷ}~||}~{Ԥ)˄΅χ ч҄ӄӊքӆԄ!ރབྷ£ބևއƒԃӈ҄傝πǻ՞ψ̆剳ńąÄۆ܋Ⱦ쵄ŇϹÈ˴Ȓ엷ʱޟХܵ͊ɛ柹ܙҢ͎낃ҤާȢ󍻬ܢ帱ʴ醢ٰս̏ƂŨљߡ΄øގƨҝ篆͇심؈셎ԑǂȋ!ց߅枛ŢԩɄņ"񈕠̮ԙ̀Íͥ넘N뀋¿ٽֶ󟄃զ 媋ꆅ  +  yŒ򣙎ȳټ偎ܩ~~~~~~~~(ӔƪԄЈ4놌ƺ߽Šгϋ 葳͇!憨ُ҂ܩ~Ƅņ߇܍̈Й۠˿Ր恊}ڸ ͒掤ٰ$׭ˊյԒХǢ}迒Տ}‰䴆ݒ؀}Ҟ蝮긄灅緉~~Ȍ}˞⨄Ҡǩϒ곩DŽҿƚ뷫ʂ}ጥĹ}׿ եȠսŒ՝}„£ػ󐤮›~Պդ㌖Ğ+݈ܵ·ַ~ҫ}þ󀇍㢦Ĵ쇙H™~}ѣউ愃 +~} }}~ +} +~~~ }} 鎞ӄi}~胔삍̶}˸ش(~ˆ̂ˈѓĨϊ2酋Ź޻ğα߅͈ 搱υˉ䅧׎Ёڧ}͈ą݆ڋʆϘڟʾӎ|ٷ~ +̑卣د ֬ʉԳҐΤơ|潑ӎ|ⲅۉ|Н札鷃怄嵈}}Nj|~ɝᧅџ~Ũ͑鲨ƃѽę鶄 +ȁ|ߋ¸ީ|ս#ԣǞӻ~ÐӜ|׺񏣬꿚}ԿԣዕÝ(ۇڴ~ն}Ѫ|„􃉐ᡥ~~²󇚴ꆘM~~}|Тޥ䃂 ~~}|||}~~ +  ~|}~~ }| 荝څi|}~悒솚ꁌʵ|ɶײ􃓞ƅ(Ӈؘ҅ˮ֊2񉐗̿žʤշԈ քҊ슬ߓ؅⭁˄ʆ劵␲ҋ֞„ڔ턎ûӖ풩ߴ#ݲюۺٖթͧۀĖۓǍ빉①ރأ񽇺ʂΐ遂У謧ؤ̮Ԗ񸑭̇ĉĚ˞񼯮 υ琪ɿ毀Ç۩Τ£ʖڢDŽńǧƠȟۋƋ۩ꐚʢƇ$㌮ȼܼذȄ„Ä€馪ɹƽ򋞮Jǝ֧媌뇆  ڀ ؄i􊟵򆑚ѻн޸~ +  ~~~~~~K򃍕~Ÿ̎̈́׶運ȯ~έ~׈%ȗơ}ɧψƝ܀~æܲΆ˄펷ĪѻǖܣDžăÄކϾأ }ڶ∧DzәʮՖ󴥤Ѧݶǁʾ܀˚ޔ߁}ѝ㘙う~Лޔ၆ܑ̙ŶəߕƞĊ󱇤򲅽}ݥկ ֒Υ˄巋ΗŸ̍補ʹŒʉƇǷ٬˞LJ7ʨʿꊦ҂늝˺|ֵ Ň ~ɦՄˀ~ûШ|~˻~ྥ恕瘎~}&ӡ~ᨌ焃 ~~}} +}}~ ~}~ ~}ׅi}~~ꇢᄛ}¾°ۼûH}öˈֵ瀊~ƭ}ͬ}τ*ǖĠ|ȥލΆ͇Ŝ}ڰʆɅ덶éйƕۢń܅󟝣ͼ֢몀Ѿ|؉~Ű$јȭӔ򳤣ϥ~۴ƀɽəݓ݀|ϛᖗစ}ΙܓʘېĵȘݔĝÈῖ񰇣񱄼|ܤӭ + ԑͤɃ㵊̖ķʌ硚̳춆ÑɼĆŵثɝžŇޞȦȽ!艥Ё鉜ʸ{ԳÅ }Ǥӏ}ϧ|~˿~}ɹ}޼ɿ䀔旍~}|#Ѡ}ঋ僃 ~}}|| +||}~~~ ~}}|}~~ }|u|}}~膡߃|ٻHʽ҆ݻͳԲ݈%͛˦݁ϫ撠ՅԈ̢℈ȫⶕԆЄʯ͚⨄̄ɄȄ㊵ìݧ߉苫̶؝ϳۚ֫㻏ͅä⃉ў嘤兊ס霝Ŧꅊ֟䘕ŧ腊ҝ㕚ʻϝ噭¢ˣʍƜڳ¸ۖԪч뼏ӛʽё易ӹʖϋˋ̼߱У̇ņƋ7ϬĨ׆򎡲ѿۺǤʆÅ 遑ΪڈЃ֬éŹ셙#إ竏쇆 +   ڀ ܅i爟聍ýǵ~ +~~~~~A򁒛Մʻ¸}ԅˈ̈,܄}߿ְ}ߜ쏫χ΅@卭؇ฑⰌ˪뒰ƫܦ&ÍȺ~Ŏąŭڨ̧ꌽÌ삃}ܯម܀|ў╚Œ糂Ь炆ǒЄ鏏ՙ~ܧ񢯤԰炅쿎}ǎ~Ӧҝ˭ғ~ѫӳ|ѺՄۋЬļ!厫Ľ鶊ϝ~ſ슨π×˂Ɔ#օʧɇ޾Ɣ?ȴ񃅅Ǵ̿ĺw~|͹|ׯ~}դ݆ 㨍腄 +~~~ }}~~~~~~y}}~}}νɪ¹䱲@ӂ~ɺ~|҉ʇˉFڂ|ݾԮ|ݛꎩ~͇䌫ֆ޷஋҄LjEʩ鑯Īۥ~ƹ*}~̈́Ĭا˦~苻ꁁ|ڮߝ{Ϝ􃅁屁Ϋ偅Ƒ΃莎Ә}ڦӯ偄뾍|~ō}Ѥ󬝅Л~ɬВ}~ϪѲ{ϸԃيΪ„萿㍪û絉Μ}ĊꉧɁŇ&Ԅ숙ȥǾ슜ܼąAƲų˽ù~|}~{˷{ծ㿯~}|ԣۅ ᧌愃 ~~~} ||}}~ ~~}}~~~y||}~~ތ||ͻǨⰱCۇǽЈч҈Eᇠၐţܴ堉邍Ԇ둱ދ潕贐ΆHЮ˰Ŀ҃ȑͿ4ƁʒɈʱƍҬ¦Ȑ󆆀ⴅ碄⃉ע陞ǐձƩ͖Ո۝؂ڵ텉Œ΀̒낄٪סѲؗƁȂװظֿۇᏭֱƆ뒰™աʈĄՃțІˇƋ#ī܉Ŀϫ·􏢹˔@͹̹Ķɿ}肑򃌕Ӿܴŵۨ≏ 謐툇 + +  ڂu摧쀆­ήǽ굷~   ~~~~~%󃓜įǸąŅƅهʆˈ +˳҅̈́$鍩수½כч렟|Ά̄儡̄քŸⴉѠDލ֑ĭȿ#؂ݏ蹅ʾ鍀޳ϵ֕ߤ㔵ʲݜЈ§}㿔Ӊşޟҡ疤۞}|Нő݈́䁅긇޴ճ㰀ĮŽ߮~Ñ"Ž遃~ܯ落ѥѫ̥Օ۞؉ܱ #ɖ䊝̤܆؈ǰ„兓үԌʇIϴ|Ǥ儠셑ʱ|׳?}~~ʣp}򈘬~ڻä~~}֥ 㩌腅} }}~~  + +րu}}}}Ʒ}ƨǶ惓쁌̊񂒛íŶ…ÃćȊɆʍɲЈ#셜猨ꇗՙЇ톛Ꞟ {̇ミʃԃöಇϟƄ!~Րì߫~ƽ ցێ渄ɽܲδԔޣᓳɰܛ·쾙~|ὒшÞܞР唣ٜ|{ϛގ~Ð̀܇ 超ܲӲ삄­~ݭ}"耂}ڮУϪʤ&ԓٜ׈۰Ǖ≜ˣۅևŮㄒЮҋɈDβ|ţþミꃐɯ{ղ޿=|~}}ɢ~a|񇗫~־}ٹ£}}|ӄ Ԥᨋ焄~||}}}~~~~ +u||||~ŵ|ŧŵ傒ꀋʉ ɳ̽Ʌʅ˅ψЈ +и׉"򌝪ºݟ׆!򤣪쇀Ӊ뇥҈܈ʽ蹌פ̄Ǭ݂ܕʲ籂̈́#ÿޅ㓲òý万պۙ꘺з֌ǫŞĘٍʣĪإ횩ځ֡擋ʕӄ㋊ꅉ丈۸鵄ɳǒ峂ȕ!ǒⴅשװѩۙލⶅ ΚꎢҨ⊴ތ͵DŽÇ쉗״ِχƆDžDëչ̨ūꈤ򈕟еݸń=ǑЧr䁐ŬȨ۩譏 + +ۃu̼̬̻쇗򅐘э~    ~~~~~~E󄓝}큉þȊɇ~ϻ|ΰن"쐫툋߼ҪӇγĜҹ⷗҄̆Èƴ~ʛ魇ª܃ңļԐө≞籁ۛﴀğӄ̢іФҚи~꽌蕅~ȑȖֆ}ɬΜᔐ}դ𡭍ܜ|ⳄոΕɘׇ۶灃~ೃ랓Ѩ֗~ɝ㖻訚9ꮅÅ҈߶尿Ϻ|廟ɉ핱綇̙ÔłՁ¸ҩѣ„ܖڳ$߸ཝخȻ +~ţ~_㑏~ͷǼ}}~~ྵ~}υ է 歎醅~~}}~~  ـy~󈓓}􌢿䂒􄌓ѿÍB񃒜|뀈lj}ͺ{̯̇"석돪쇊ݺѨ·›иඖ˄ʄEIJ}Ț笆ڂޕѢ» +ҏҨ尀ٚžуˡϕ쀀ϣ웸Йη}輋攅}ƐǕԅ|Ǫ~~̛ߓ|ԣ~ښ{~ಃԷ̔ȗՆٵ怂}޲青ЧԖ}~Ȝᕺ槙;譄ѿ򷥡ч􏑙ݴ~͹{亞Lj씰崆ʘ“āӀѨϢÿڕر~˿%ݷ􋙤޻֭ǹ +徴.}â}pᐎ}˶Ż}|}}޼}|Ӧ +嬍腅 }}|| +}}}~~}񇒒Є]|򋡽⁑򃊒Ͼ~E􄍖Ǿ͊·Եӆ!ĊخՇӷɠؾ輛ׅх!Ӄ˹ϠﲋǯɄ ᇭŵبٔٮ荢ɣوҦך֩מսぇÐ͖Λ܊ΰ邅Ԡ瘔ހ۩׀鸈۽ԙϜ݋ị渇񢄖׭ܜϡ;ȉƨʼn،亱Կ”΍ưѝȘ˅ۅǽخ֧DŽņ¬⚅ෛƇ&彖¢޳ +ź.󁉑ʧ{镓Ҽ߁䁐úګ +챒  ރyꅖķȑ~      ~~~~~~B󃓝ؓ~ùϾǍɆ!怓ݹׇܷᢆ􃇋}%γւ倎۷굒̄ʄށҌ莩ȸϘ„!㔽懔л͢ijȂǸ횚ٷ՟}}̥Ѐ$ܳ~|ܰ☋ʫ}Ң闤~ѯ⸋ށ7쾈ˠؖ޹΄}έ~د󒌅Ӗ}׬ƻ~ܰ}կ|ݴᇰ:ƛӯ߬ҕڟ %֏٬Ʉ!䌵҂ʼ䬊d~Ӆآ|ڶ̨}˷IJ$ķ~ö}z|}̳Ʈǹ郖鶩~}}թ寐넆~}}} +~~  ځ ~j~~셙ͳëȽA򂒜֒~~}·νƄDŽƉ>숥۸ڵߡ򂆉|(ԁٶ賑Ȅ܀Ћ捧Ƿ͖"ޅᓻ䆓Ϲˡñǁ~ŷ뙘׵Ӟ||ˤڲ}{گȩ|Р薣~~~}Ϯ්܀꽇ʟ젲푚וܸ̃|<̬}׮ڿ񐋄ѕ|ի~ÿ~ĺ}گߕ|Ԯ{ܳ߆8ęѮޫѓ~؞㉾Ԏ쐣תȄ!⋴ЁȺ⪉˿}фľ ߂󊌑֠{شʦҾ|󉛯ʵñ$õ}µ|{{|˱ŭŷ炕絨}||Ԩ􌌍㮏鄅8~~}|||}|}}}~~  ؀ }j}}~ꄘ􅎒˲ƼBݗɾË̍Ά!샖㾤⼚܇榊倇%ӷ܆샒ἘфυㄣؐνԜDž!劰싘ֿҧɷ͆Â;󞝬߻ۣƎҪՃḊ灅ⵄ眎ϯ䀄צ𜩬ִ轏Ìѥޛ俓ӇӲ޴ٚݱņいⵄ暄۴䀄义狵9˟ٴń尣ؙςİܓſ߰Ɩτ!ꐺ؅Ƙ갎ňցĦو 憠ަໟѬŇ‗Ѽɶ&ʼȻƀҸ̳̽ﻭ逊ۭ곔 + +  + ߄i󉝺ӸȰ¹~ ~~~~~~~~~~~0ܢŸÄ Ƒ ̼ʄ6ꃛ䋡ʦ廜ј|ψ +΅ڌڄ̟֭˄ 励|ź蜔ߧſ߆Ƹ7ŀѠᴇĎ״ڙįϦΛ}ŏ|~Υ堏ʬ|ݴ啅=~~ְծ҂𥦑ݘǣ}нȊμǮ߂†˻Ȱ߅ކ~Ĉä~反ϐն"}ؙЦɌї~Ö҄8ڭְʠ~Ԛהٳњ߻ گꌔ›Ċ됩~˞ʽ#~ϰۏ˿Č~ّʺ"犩Dzھ>ŭ|~ʽ~~:|ĥ߶㽩~~}}˄񃊌ר +貖퇇~ڃ f}}~̴㿨Ÿɩ.󄓝ڡĶ~ ғCߪ˻邚⊠~ɥ㹛З셚{!틩؋؃լ˞~Ƅ䉯{ø曓ݦľ[݅ĶϟೆÍղٗ­ޭΥ͚|Í{}̣훼㟎ȫ~{ܲ䔅~;}ԯԭсۖŢ|λᆋlj̻ƭ߂ށʹǯ݆܆~}Ç¢}䎌͏Դ~#|֗ΥNjЖ~}у6٬Ԯȟ}ɾҙՓױЙ޹Hخ苓쳊÷鏧˿}ʝɼl}َͯʾË}삈ؐހȹ扨~~ưٽ=ì{}~ȼ}n턕~}{£ݵ⼨~~}}|֧ +簕놆~~}}}~  ؂ ~f}|}~~ʳ⽧ķ􇕣ȧ?ľ˽ˑC񆟾ꏦꂒЫל􉠻߀ӷӄĻܲҤЄ뎵΀˿嬆Ą剩˼1ʃ֤蹋ʒݸɴժ"ӟʓ老ԩ뤓ϰ义똅Dܵ۳؅̧苏Ύ ͳ兇ljδʌɨ듑Քۻσ"ޝիΏלȚ؈Ɩ4ಃܵϤŭڞݘ޷מ忱@Ö񐘕ǟɽŴѢˆ#⁎յAɐߕϿ퍭Ԃ킎Ͷãı;ʲòo烍ɩ廟­ܬ +򊊄 ߆ fѹĬʽϭ~   ~~~~~~~~~~~~=􀍞ō̤ۻ̄耍חȉ΂ψІġ͆メЈڅᴋӡʄ!}Ǝ˿~~ʵ Ԡ񹤢3򳉜֜ŒǛ܍ŏ4ܲӭ֭}ȬɁ܅ۆި僃хՏʍԵυܜ挟˓ϊ~⻆Ȥх2󘰸۔ڳּܐ}}˴ɠ痳ԑ7㶆|ͦ͂̕歑àޯ~ٜ̌־ӎ}͠ʄ却쌞漖ňCרϫǹ~냐ӯ~ʦ̹􊜞֋>~󄉑ۥ}dحȽ~ǰ}쀈ب벘 +܃~f־牠􇕩}~Ҩ=􅔟Ŀʣٺ˄ 텠퐧Ֆƈ̌ß Յ>႟·؄ǿ߳Ѡ|čʾ@}}ɴҟ﷣4𲈛ԛݿߗ򪕒ƚڌÎڱѫԬ|ǫȀڄمެ쉓ܧ䂂ՄфԎ~Ɍҳቅۚ勝~ɒ̄ͅ}ṅǢ݅ЅR񗮷ٓرԻڏ||ɳǞ喱Ґ=ᵅ{̥ˁʔ嬐Ÿܭ}כˋ볫썬սҌ|˟ɺ-㌳ꋜ井츓ü6֧ͪŷ}쎪邏Ѯ}ȥ˸ 򉚝Ԍ@}񃈐٤|b֬ƻ󌣺}󂈆ů|֧鱗톆 ~ +ڂ~}f􆇇ս~߿戟򆓨|}пЦ=þʎѩǰ҄ ݛ͍ӌԄʤljɦ܄҄醥ՌŸ繏٦τ%ŀ˒Ϻ ٤¿<ܠƞřǐ͠⑫ʓ⷇ٲ۲ατ솇օړБٺԅ퐣З҆ΨօUᘰ߸┩йΤ훷ٕ8黊ӫ҅љɥ㳥ʂߠҐ󹰯úّƼӥυ됹򐢯ʉCݭԯ̽߁񇔚ٴϫѾۊ<ᩱc޲̵򃋎 ݬ􋊉  ᆒcèŴ팤ƻ׬~~~~~~~~~~~ ~~~~~~ؑ}ǻ†‡<~񂉒շٴ}τ<䢪Ւܶ츓}ԧ•†~ϟ\|ɣ}׵ںƒ˱֖ˇֲV᳃ش튨ˍ˺܅܇Ėȣ̈́ˆېʺĄ‹ †Å\ߙ҈|ȓ~˞𘪪}ɦà}}~3㵅ݾՌ֙ا㕓ݪX璬䞔ḩۆ|ᦉǹ̇܅۰ԢƄ9ْ񀋔ЮȤƲ艝øʳ5οķgɽʴǶ腘 ۪ +볙 ݂ ~d}~˷ǰȽCא|źο"}Ӷײ|΄슞̄̈́̄̈́:ށ⠨ԑ~۵뷒|Ҧ}ΞտZ{Ȣ|ִظɯԕɆԱֳ߱뉧5ʌʹۄۆÔƢُ̄~ȹʂ +††ݘч{ǒͅ9}ɝ|ǥŸ||}3~ᴄ۽ԋԘ֦ᓒ۩9呫❓߷م{ߥ셕﵎ƸˆڄگҡŅ߄@בάƣűބ戜·Ȳ>̽¶~cǼɲŵ愗􆘣 ٩ +겘 ܁ }d|}~󌠶ɶƮǼ=ޕƺdžƃLJ<違ۼ޹ÙAꦮۖ⻙ƾڬǙDžգƿϧݺ߿LJжۛЋƤܷė縆޹􎬃4ёѿɚͨ҄ЅʂϿɊȂdžń +ŅĂņƆƈŅȇǃȇDžV،ΗفУΪɤ3麉Ěېܝެ陗㯞햱ķꢘ罭9ኣ竌􊛣Š;ҋ≟żᵎ٧̄扡<ޖֳͩ˶戨ɽϸ5ijɼf´й̻ங +  +⅒cмʹ¸~~~~~~~~~~~~~~Ђ7ڐʺ}ԿDޟδ셢퍨~˭ģƙ̈́Y𺊖׳ͳŀÜڍڂ}өѕLȶЂʗ֗ޱ|ț;~؎֓~}}~ƞ蛼˷㚹Չ܄D߈յǣ݁  >򏳙ߜԉѨǦމ~:ߚЮˏ٢㔵͂Ц;򝙊ʆل齖诉ǹ莶픵|繒BѺϒ廛~°ۃʳߵ~ҹ7}Ǻb򉝲녖~Ͻ༡༪~}}񃉊}ܬ볙񈈊 +   +݂d}Ӽ;げ}5~؏ȹ~|҅=ܝͳ넡댦}ɬ¢ĘYղ˱›߃،؁|ѨГҾNƴρɕԕܰ{ٿǚtޮ}ܾ֍Ւ~}}|}Ĝ暺ʵᘸԈއӳš܀ Rݛ҇ϧƥ}܈}~캓ݙάɎؠᓴѾ~ˁ쁄~Ϥ~𜗉Ʌ׃缕歈ņ"捴듴{帑@ϹΑ㹚}قɱݳ}Ѹ:|~Źc鄔~}ͼ޺߻~}||~|۫겘 +܁~d|~Ѻ˽‑|~8ߔϿŅńA䣦ԹѲɨ˝҆Yݸҷ˃ɡ截ߑٮיͺօЛܛ㵦쩀Ƥ͟洂śޒܗˢѼ ی5ۺ̧ㄙ Qŵ䠐ڌ֭ͫ䌲ճГߦ阺Ũ҆􅈃֪ʃЉ߇Ú̄$@ֿՕǴи庛ؾ:쀋̿c񉚪®Ⱌ + ⅑ eƴõ酖~~~~~~~~ ~~~~~~Ѓ3툜»л@酖}ɹœ~}˲Ěֆٗ~܈>}Ā󍝨ᴎۨ퐵萭ռѽrѰۤ}ȯǀïثĊա晼ɨƓι;ʦ㖱~ + + 騾Ĺ體Ԍȇ΋􈼖򺅮ǧ񙹕篇Ljѷޞӌɢԅ⊘|Ą+‡˓ɸuȄ޵氍˺}}Ͽ}󂉎ɱʦԼ낋ڴ:⩮¿lŷǹ뎨}~²ݮ} +򉉉 䄐c~~ѷ|ҹ燛Ƽ3쇛~Ϻ>焕~|Ƿ}~~|ɰ™ԅؖ}ۇɄȀ|񌜦߳٦쏴揬Ӻ~ϻϯ٢|Ǯ֪É2䘺ȧĒ~͸<ȥ퇌ᕰ} 禼¸фҀ窓ҋƆ͊򇻕񹄬ť孆ņ϶ܜыȡ҄џ~ቖ{¨ɑ􊕚㾙Ƕƃ􌚣ݳ䯌ʸ||򶰯;|퐩񁈍#ȰɥҺ遉ز6ᨭ~탍lõƸ鍦|~}~~ܭ| +볛  ⃏c}}ж{и~冚ź3􋠶샓…?ξǠفзɞۉߛ⋨Ąπ〞ʄ繒ᬇ¿ŝ׵ᨀʹ̃ȴݯɍ3ڥϭ˗ė󺂩Ծ<ϫ隶؁"ɾڐ͋ԏ̫̋׼ِ9ډؤã荜ɮNJЗŞμ͈乔о߀Ėف϶Ы񅎖ฐ8譳낗[ʼ̾Ƿ킊(㲞 + 釓d׼׾ك틟~~~~~~~~~~~~~Ѐ}򁍛ե̽ʺɶʬdz郟报|˶س셄JÛɳጭׯⲋၐѭܪτúóԤ⨤̶ިҿ搸뇻/~~Ç  +ؔЯ޴͊ۋ}}}~ʛߖӾӝ}鵠ƀꗻ ˥Ƃ˘궑ɷ蒽~ѧϠԻ_ꤡ}λԀѾ˧ռЀ풪Ͽ}ٷ>솏~®˭VʺͶм~%ޮ} ) + + 金 e劥煗|}ɲ³|ӣ˻ȸǵɪŲ炞剤{ʵײ~ꄂȀšȲߋ쫤֮ొ쏶Ϭکͽ¸²~ߓҢr᧣ʵܧѽ䏶醺꒤}}†&  +דϮܳ̉ي|}|}ȚݕҼќ|ʾޥ]蕹ɤāʗ赐Ƕ摼}Ц͟ҹ袟~|͹ϽɦӺ둨ξ|ضꅎ!ο}ʬVȸ˵κ}~􃈄%ݬ|ﶝ& +  膐 e䉣儖{|ȱ¾ک¹Ͽλϰ̸펪ѻ޸탘򈇴πȟϸ琱ݴ跏腔ֲ⮉ȿȸ҂٨~譩ƅһ㬆ņĦ씼󘪩сȊ ݘִ乑ӎ÷Ꮉϟ嚽âءÁű𺤞˃*Ѫ˅ƒќĭμ׬Ԥ𨥦ڄïЬՃ󖮼ŷ߼򊓚ƸDzѱYпӻ㲝 d뎩퉛􀆇ǹϷǸ~~~~~~~~~~~~~~~x񃐛ӫŇͻͥ~߁Ǹƅǀšןͺ⸓̸ոş~ᄤςӾһԺ}ߺԌƋᩤ۩b骁}ҕĀ~}}}Óχ֙ۆƿִ4  +)dʇιݨ꿋햧НޒĶ|~ڛƝ՛ԏ̢7꺏֝玩ꫛڳ籉Ѕꃌஊ狧̆Ъʳӹ얻卢|ԺǤũ鐩>􊞰񉖟ƮWķ݅|}~ɷŨ쁇ޯ~ 󊊉 +   腑}e嵊DZɶՃ(~섏NѪÆ˺ˣ}݀Ŷņƀ՞˹ිʶԶĝ}߃΁ѽкҹ|ݹӋĊ ৣ٧b穀|є~}|||’͆Ԙڅž~Գ $)ɆͷRܧ轊앦Ϝܑµ{}ؚ~~ĜοԚӎʡ4鸎՜뽨卨誚ر氇΄肋ެ劦ʅΩȲ~Ѹꕹ㋡{~ҹƣ~ç珨>򉜯ĭZµۄ쉛~{|}ȶæ龤ꀆܮ}򉉉 + +  + 煐|e䴉ƿůǵӂ􈏓(܃􉔚Kٰʋҩ聙兡̽̀ƞݣҿ轗Ѽ۽ˣƛ燨ՅĄڿē俭ڏˏ¸筩୘a﯄ؙʃȗՋܝŲ۸$   + dϋӽ”ď󚫡֡䖲ɼߟˡƯ۟ړѦ5ܡí풮𰟫ตƵՈ沎Ƴ폫Ҋկϸؾ됧ڿͩʭ˲ɻ㈣􎡭ϼʬĩ񄊌㳠&     ဆe뺎ƻ̵λۆ~~~~~~~~~~~~~~~~~~~y}τʼɴæѺ탟䆟|}־۵~Ňƀ̍鐫ˮΥ~ʬþκ̀³놖تƧٗOǏΙ۵ʐށΐ˹ڍ󸹸$~Ӧ ~}}}$}~ ĉģʽߕ|؉~ڙ쁢괇~죛멍ˆʑǀ}סᑴǒϝޤ經ȳތ~ԯަͣډ܉ɼ|ʸԴӳꜽ݉ý׸ҿ񂍖緰}GƲ̶}䄔ݲ~& +  퇑 }"ȅ@΁⿤턘׉չ̫w|̓ȻȲſϹ˾낞⅞{|ռٴ}΅Ąŀˌ~玩ʬ̤􆋏}ɫ½̹酕֨ĦؖOŎ̘ٴɏ܀͏ʷ،򷷷$}ҥ &~~~}}||%߄ 4|}~~ ˆ¢~ɼޔ{ֈ}ٗ뀡貆}뢚ꨌɐ󥟞|ՠ뵝ߏőΜ +ܣ嵑DZ݋헹}ҮܥˢوڈǺ{ȷӲҲ蛼ۈ»շCѾ嶮|U򶇏İ˴|⃓¿􂆇ܱ~󊉉$  + 놐 }¿Ìལ냖ֈރԷʩxԈϸƾƷȫֿůꊤõẕわʇˀ̼ё炝ѳԩбӿфǷŠ񉚡ޮ˫ߛx啙̓ƅӝẾϓㄹԔѾߑت- Ȍȧ噬ތƅ󧟥򭑉NjЕ̃āݥ)畹̖ա㩐η䐺がٴҧ⌨Ͻڹٷ㌡´ݽƵX˷ѺЀꇘⷥ¥-  +󊔪ဇńIӄĨ󈜳݌戚۾Ѱш~~~~~}}~~~~~~~~~~~~~~ÄkɄΧ}~ôӫꈣǺÈćŀ̽׬ꈯۉ怈ң᳋펱܆Ù}؟ɰ䤚҂ʖؔӣk݋њՎꇧؼ愄ΚϑЍ͓ ~=}˅„Ą̄Ԅ ܄)}~˅󸳵՗ţ͍㜌ւإ}ꧠ}ߴИ麥񬦥wʑ~}˞ɭф㤢}ֹʠƫ̙˪ܵꋜǬť˶}陯ր၎®͵ũ} }ߴ +(   }ѻ<ᄏÿï𼮬|߾ȹmǃ̦|}³Ѫ釢Ƹ‹ÀĜʻժ臭ڈѢ߲덯څ|֞Ȯ⢙Ё~ɕ֓ѢmۊИԍ醥׻僃͙ΐό󲦥̒,~~}}}|߄τʄɂȇƄ ÈЄӅׄ |}}}~ʄ񷲳Ӗâ̌ᚋߟԁ֤|챂覟|ݳΗ繤앾﫥Ȑ}~|ؾɝȫЃᣡ|ԷɟĪʘɨڴ芛ūĤ~ʵ}~痮߀˳ħ| |ݲ~( +  퉑}!~Ϻ<߃®{ݽǷȄ·ӬƾPЂɹذ񌨸ͿȈɇʀ´ݰ፯샌ا縏⊢ȝĽݣϵꨞ؆Лݘاk㏨מےđ툇ԞԕՑҗ)ЅƄň Ȅ +˄Ԇ݄/ Јڛʨґ蟐܆ީ񫥤Ӏ幌՝←ϕťѣαׇ騦ܾФ˰ѝЮ⺣̱ʩк偐؂ۄ焒ȳӹʭ‡ +퀆严è) + 〇ֿE爓Ĵɴ³̀ͽ~ ~~~~}}~~~~~~~~~~~~~pֆĶˮƭʸĠ}ȅKĄ~Ǭˡ}ŲӴ̷ކļۨՅΦؼǂլ˨̌ˎқќј}윾Ձۈʲ4Ŏ~ͅE  Ƅ ҄򵍇~ɇ󧠢̙𮯱ϐԑƍ冸ˑ|ɖאǚËΑ$ڧ}}ɡdzт¦߉|Ш׹҆~٭~Ȩχډț߂ۼ㬍໴Z䁓Ѯ~}̹~݂؆}㵠(  ~)~ΰ8Š̄}ǸʯrՅõɭŬ슟ȷÞ|€}ƫɟ􂁄|ı꾑ѳʵ܅º٧ӄͤ׻Ł􇊻ԫʧʋɌ򐡀КߖЛϗߛ|뛼ԀهȰ빷č~}̄K  ń фׄ؀񴌆}~Ȇ񦟡˘͏쎯ҐČ䅷ʐ{~ǕՏř;̐󏞩ئ||ǟƱρ݈{Χոхދ}׬}ǧ͆؇ǚ݂ٺᫌ޹t‑Э}|˸}ہօ~|ⳟ$  퉒 })}̯8ğʃ|ƶɮ~܊Oʻг̲􏥱нʤͅȀɇЁͱХ˷ŖƬعѼۈԪ̆§۱ōѬѐБן֠֜Ӂڄ϶򿽺ŕʒ҈M +1+ՆրΊѝԔڕˑ늽ѕʀAϚܔ̞ȏӕ଀Υ͸օǪ區լݾ؊搬޲άԊΟ䆓鰐忸 ~ꄖֲҾ邛㆕މ鹤ī%  䁈)Ҵ8°˥҈ۀͽд ~~~~~~~}~~~~}}}~~}~~~~~~~~~~~~~׈߮뜷ø˲}׿ĊلƑۯ环댭𻶶ûĤĒܸ܉ץ᱄؜՜~牺~Զm~}  +% ղLJ띞hΎٮ۽̥|~}ᯄ~ط՚㲛}փ䣘UģΥ|Զܰä}̲ùÖփú®Ǻ Ҵ~䵢«}  +񋔨 +U~Ҵ~~~~} |Շޭƿ隵샊ʰ|վÉ׃Őٮ卭~~鋬߸~£Ñ۶ڈդ֛߰ӛ}戹}򤞍ҵm}~|(Ա~ņ핎霝h͍~حٻʤ{}|߭}ֵӘᱚ|Ղ㡗U¢ȿͣ봦{ҵۮ£󲴔|˱m¸򵻱•Ԃ~¸Źѳ~~ⳡ|   +~Y}ѳ}}}}| {܋泴􈏝Ƚѷ䁕ɍ߇܀̕ᴍ풳澃ɩʖ⼥ܪ綈ݠ۠팿要ٺ  + "ٶˋŝ񠢣Ӓ޲O쁢À糇ĉ†߂޼۞鷟ȁ܇꧛oɧƳԩ󺫩ڻⴈȨ􄇉ѶǾ\ș܇邌ȿDz̿׸鹥ǯ%  䂊Q׸ŋ悇Ǹ +~ +~~~~}~~}}}~~}~~~~~~~~~~~~~~~~׉ĽꜞȆǼ}ج翿댗۸쓘}ڿ͟倡񩀯ζЋۭҴ˂왽Ҫűňڀٝ끞ܞۏ馡ˣ~갰 ~ʼn狋ڤªΦ~@}󌶃݁ٮ͒Ȇ~϶Ⱄ㐫mٲ큅Կęطʋތʜ璉廗Ԇ Ѕ˄z|}}~㶣Ư~"  󌕩Q~Ƨǫı}}~~}~} ՈI»蛜ƅ~ƻ|֪~兾~鋖ٶ둗|پ̞~燐̴ω٬вʁ꘼~ЩįÇޙ؜逝ڜڎ礠ɢ}鯯9 }Ĉ~劊أ̥}@|񋴂ۀ~ج̑ƅ~}ʹ௓Ꮹkر뀄Ҿ˜׶Ȋ܋ț㹖х҅фυʄz~{||~~ⴢŭ}" 񋔨 ~M}Ŧƪ¯|}| ܌𠢢͊¼ް냎ȃ򐛟Ἑ󖜡Ŵӣ냥Ӻ֎ᲇ׸Ѕ炍دōʵʌćƛߡᓨϧﳳ  +  ʌ򊁃펎ÑgߨǯԫŠㅒ߳Җ͊ջƖ絘锯h߷󅉭İɝ޼Ϗ䐡Ϡׅ؅ׄՅԀź¸ĕ〈 +麧˳ 䂊K˫̯ɶ ~~~~}}~~~}~~}}}~~}~~~~~~~ ~~~~~~~~Ѕ։}ܷѠ~􃆂⼽ɿ싚ӗ扥ƹ붯Đ~̬޾|͂|~βݨņҠ~}ݛֺُԖ輻ߦN~䛓Ѩۘ 2)F  ĉ筜}~򡣥ပݏԍ۸Ԙϛٵ؟ੋꔨƽ~~~}嚿ëہ ԦքԄӄԄӅ҃цх҄цoψڻ~~~菴~}㴢}Ȱ~  󋗪 P}}}}}~ }}Ո|ڶϟ}~򂅁໼Ⱦꊙξі䈤Ÿ鵮Ï}ʫܽ{́{}̱ۦ뺛Å~킊~П}|ۚ؍Ըҕ滺ޥN~}㚒ϧٗ @MÈ嬛|~񠢣ߔ܎~Ҍ~ٷҗΚ~״֝ާ蓧Żߟ~~}}}|~㙽팝ڀҥՈӄ҂ӆ҂фЈςЄ Іυk͇ٹ~}}}玳~}~|~~᳡|ǯ}6  򊖩 ~P~|||||}||܍⼡֤ٶŮ󏟬Ŗ؛썪̾񻳱ɔԂѱïЀӅӷʊפߒۿٚ嫦ŗM韗լ /OɌ베百㓂ڑ򂇅ὔڜ՟ߺޣ歏È·椂8ȯᄡ٪ڄۇل؂ن؂ׄֈՂք ֆՅkӌĺ߿퓸߂踦ʹ +3 䂊R ~~~} ~~}}}~~~}~~}}}~~}~~}~~}}~~~~~~~~}~~~~}~~~~~~ЅՊ˴ǡ~ĸוͽ~·ޱɃܿх˸ݮ}ǩܘ̇􃄄ڷ򲐂~چ߁ΐݪרa}Əе񏨦І~~}~~+ ąĿ +G}~}~~ĉƤ~덎ĚɆ}ʓҖΒ̆磰ͭʓƕk嘲}ӺʜΑ冐ݜŸ~ɓׄօׇӈԂӅ҄ +҄ӄ҆qω¿󎣵}工~˰!  ⁈Q}}}}~|} |ԉɳƠ~}~öՓ킓̼}߿ݯǂھЄʷ۬|Ũۗʆ򂂃~ض𰏁}؅ӿހ̏ۨէQ~}Ŏϴυ }~}}~ ĄÅýg~~~}}}~~}ˆտţ}~錍ÙDž|ȒЕ͑˄墯̬ȒĔj㗱|ѸȚ̐ㅏ~ۛ}Ȓ։քՄӄ҄ӄ҅уІЅф҄фЄυjÿ񍢴|~䶤}ʯ~ Q~||||}~{|{ۍй̥󧂺ɼܘ炎ȼƢ䵯Άıŗ׉ѽ㲀̭ы༞߉Ƨ儧Ӕ×⭫ܬdʓչՈJɄȅºȌʨ񐑓ɞΉЗיԖ҉Ӳϗ˙뜷ٿœZӕ는蜂⠳ǣΖ܅ۅۄ؄ل؅׃ֆօׄ؃ׅքՅiļ뻩 д   焋a~~~~} ~~}}}~~~}~~}|}}||}}|}}|}~~}~~}~~}~~~~~~~~~}~~~~~~ԉȤ€ӣ~|๿Ǽʥ凔|}ij섑ȱ}ۇ|ΟևꕬĪݫ𶟲ِλЍҖ~Ωl󻜛~~}הɣЄ ۅ+ͅÅŊᾤײـᐎ}~~񶶙ތƪӠء~甦õ沋ʦLjќˤ}̛֋؅׆ +ׄ֌Ӊ҃ӇԃӆpЊ~~鼨ϴ   +䂋i}}~ӈ~ǣѡ}{߸ƺȤ㆓{|²󵭽ꃐư|ن{͞Ԇ蔪é۪؏ͺ힫Όѕ~̧񺜛~}}}֓Ȣلڅ (̆„ÄÉ߽ձߏ|}~ﵴ󢯭݋ĩџ֠}哤³䰊ȥƇЛɣ |˚ևׄքׄֈՊ҈ф҄фІjΉ¿~}~躧~ͳ    ⁊N~||}~ڍ󂃃ͨǃ٧ϩ님ɸ󈕗ͶዞԤۋʯߔƇՑיӭm¿ܖͦ +Ԅ߅$ц ˄DŽĶ*$Ɏ¨ܶ哒启B˯٤ݥ혪ɺ췏Ϫ̌נĞШў܉܈ۋ؈ׄ؄ׄֆrԍŽžၑ Ӹ + 酎R~~~}}}~~} ~~}}}~~~}|}~~}|}}}~~}~~}~~}~~}~~~~~~~~~}~~~~~~'ӊ~Ѱ鹷}㫁ѷꀃ}Ұֱۈ˿ۏʺ郢ڕ۝Ʌ~Ū@򧇅~Հ݅IͣՄւԈӃԅԅ +ՆۄԅӀɱǍ੎Ҙܾꟙnå晩}ÔǑܜτũ΃ԨҔɉӄՄو؄ׄ؄ل؈ׇՄԈӊԄӄ҆rЌ~~ 쾪η + } +䁍d}}~҉}~~ϯ緶|⪁϶􈋋~|엜ѯ԰هɾハڎɹ~炡ٜؔDŽ}ĩB񦆅}݅=ˣ +(Ԅ҄ Ӆ҅DӅҀȰŌߨї۽鞘~r¤䘧|Ɛڛ̓çﷆ̂ӦѓȈӄԂՋֆ +քՄԂՆ҈у҉ӂ҆xϋ~}}~ 꽨Ͷ + } +がh~||}ٍ򁂂ֵᄐ갅ּصܶጢĬŏᓫࡶ͈ʮ?ڃއ1Ч߄  +&ۆ؇׃؅ق؄ +ن1½߅؅׀͵ˑ歐כtɪ읭Ș̕ԇʭӇ¾ڬטΌڄی݄܅݃ބ݇ۆڄق؈׃؉ق؆qՐŽ􆔟îӼ + Ҁꅐc~~~~~}~~} ~}}}~~~}|}~~~}|}}}~~}~~}~~}~~}~~~~~~}~~~~~~Ѕ҈}~~~)胿岸ީǦ~˖񂆂ώʼnĝ¹Ň}Āț¿~}ꓨ㌒}Ճ߆=ͤ Ԇ ՇԈՅ7˱܄݄܀ѫ~Ŏߜ~~ͅ荫֞}j񧱰ܯΰ}؄ž۬ܗ툔À΋҄ +؊ن؄و؊ׄւՈԅ ԅJя~ }}~ι  } 炍f}ч|}}~~}悾Ϳ㱶~ܧť}ɕ΍Ĉƿœ퓢Ć|~Ǚ~>}}蒧⋑¿|ӂޅ݄̣Ʉ$ ֆӆ҂ӄԊӈֆ5ʰ܇=Ъ}čޛ}~˄猪ԝ|聆ڮͯ|փĽ٫ۖ~'쇓€̊ф؈ׂք׃؄ք׈քՄԈӂ҄ӈԂӆ҂хE¿~~}|}탐~̸ | 恌_|׋񀁁뷽䭴̪ЙՒˌɢǿʋ͞ò?珕¿Հڅѧ΄( ܆؆ ه؈8ϵկʑ埀҇ۡlⴎ–Եއĺ⛃󋗳ȃҏքڄ݉ކ݄އވ݉܄ۃڈىڂن؂ׅEƿ􆔟 ƳӾ Ҁ텐g~~~}~~} ~}||~~~|}~~}|}}}~~}~~}~~}~}~}~~ ~}~~~~}~~~~~~Ѕш}}~~-}ۄո}}ӗ𕢢憻򅏡ȁ}ꇗҎ릌}~~ٓ󂹵 }Ղ߇Υʇ ؆ՅքՅֆ8˱܄݂ބCخŊ⶚͐~~}~~~֍Ѓƥ樳􌾫憌؉(ۧ΋Ԅ؍ څ +و؄ׄֈՂԄՇփՅԃӄjѐļ~~~}}}񃐛 ñм π 背S~Ї||}~~~|كӷ~||쾈і䅺쭶ǀ|膖Ѝ餋~}}¿G~}ג񁸴~}Ԃޅ̤Ʉ# +؇ ӅԆӈԆ6ʰۄ܆ۀ׭ĉᵙˏ~}}}~~~}}~}}Ԍ΂~Ťh姲󋽩克ֈ厖ڦ͊ф ׉؆ׄڄ،ׅքՉԅӄԄՄԂӆ҄jЏ»~~}}}|}~ °λ   悋a}~׌0۽ñČٛ̈́גၐޗрڅҨ΄- ܇مڄمڅ܆˅δܲſʍ躝ҒڐՅʨi쭷ï튐Ǡ݌뒛᫱ӎׄ +݌ބ߄ބ݂ކ݅܄ۉڄلڄۄڂن؄F֔(ȶ ԃ톏f~~}~~}~~}| }~}||~~~|}~~}|}}}~~}~~}~~}|}~}~}~~}~}~~}~~~~}}~}~~~~~~щ}}}~~~|ɽ}ըαι~冑֘艘ةөѰԔѰ΀ݏ֭ܘ~~ً~IĒٌ}~~փ߆Τ˄" ֆՈ +ׄ׈Ȅ˰݄ނ߄ ׯф +ʉɀlj̩ſ}͍~}ܨ뱱 ;㱴΋ӄԂքًۈ܂یچ؅ׂքׅֈׅօpғƾ~~}򄐛ij +Ӿ  Ҁ ꃌP~ψ|||}}~~}{ǻ~|Ԧ̰͸}ㅐ՗戗֧Ѩϯғϯ̀ێԬ鞿ڗ}}ÿ؊}I¿Ñ،~|~~~Ղކ2ͣ܄ ׅԅ3DŽʯ܄݄֭ʄɉȀƈ˧þ}ˌ}}ۦ鰰 ;ⰳ͊҄׆؇م؂لڄۂڈهևՂֆՆքՃԆKђĽ~~}}񃏚² +Ҽ   肋`~}~֍¤۬ӶԾ聇늕ܜޭخֵژ׵Ӏ㓝۲ƅ✮ޏK½ɖޏ΂܆ҧτ$ +݄چو +ۄۈʅϳ ۳Մ Ί̍Ьlё⬸񵵶;赸ӏ؄ۄ܂݄ފ߄߇݄܄ۃ܆ۆ܅ۃڅmח÷ȷ†( ׃ g~~}~}~~| }~|||~~~|{|}~~}|}}}~~}~~}~~} +|||}|}~|}}|}}}}~~}~}~~~~}~~~~~~Ћ}}~ѫ}ݻԷš}ۄžܢɕ˰ՖĔ␤ٻ~Kڴ}~¿҂߄DΣ} نֆՈօօׅƄ˰ׯʈlj̨؅DŽV쎩΍㞴~~ը}~~}~~~G屵ϋԄهچۅڂۄ܅݂܋ۈڅ؄׃؆׆؅ׂֆLӖ~}􄐛Ų վ + ւ 背S}ϊ||}~󨍋Ъ|ۺҶà|كۡ~翟Ȕʯ~ԕÓԾغ~}¿J~ٳ|}~тޅ:͢} ؄Նԇ +քՂևńʯބ֮ɉƈ˧ք ƄN덨͌ᝳ}~ԧ݆}W}~~㰴͋҄ӂՄؐلڂۄ܂ۄڊن؂׋փՋփՆLҕǿ~~}}󃐚ð Ӽ  + Ձ 悋P~}~ ֏װڼʥӀᇛǢ⦤Ƥϙѵƀۚɘ蔩èI޸¿̂؅Ҧτ + +ކچوڅچۅʄϳ۳τ̆̍Ь݄˄OĿ񑭤ӏ袹ڬ䄀_괹ӏۄވ߃݈ ݅܂ۆMؚŸ ɶ†   ۅ P ~~}~|~~|{ }~|{{}~{}~~}}}~~}~~}~~}~}|}}|}~~}|}~~~~}~~~~~~Ќ|}~=򡣊ڮ䣻ﻴ뀃ע֘䆞~œʽב쌙١ɖ†ñү~︶t}֕ľ}ԂϤ̄˄߄ + ڄ׆օׇׄ؅dž̯ޅװ̈́ȆɊͨمDŽƀٹ~~鞶¾ͨ֬~}1籵ύ؄قڄۏ ބ݆܆ۃڋل؆ن؆ׄHԙ~}?}Ǵ +־   ف +煏P}~΋|}=𠡉٬쥜⡺աԗㅝ}~򏤠ɻՐꋘנǔ°Ѯ}}Քý룢~} +ҁ߄Σ˄ʄބ"ل Մֈք׃ֆƇ3ˮ֯̄džlj˧ׄ˄Džŀ׸}}蝴̧ի~}8水Όمۄ܇݂܊ۄچل؂ׄ؊ׂ؆׀Ә~}||Ƴ +ս   ؀ 儎O|} Տ=ݦۜꉢǠ‘ܕ򏝢ߥΙNJȵسtژ󨥤ʀمӧЄ ކۆڂلچۅۆ܆ˇϲܴЄ̆ΎЬބ̄ʀ޼Ҭܯ8ԑ߅ߌބ݆ކRٝƻ̸ † ބ 툒P +~}~}|}~|~}{ }~|{{}}{}~~}|}}}~~}~~}~~}~~}}|~~|}~~~~}~~~~~~ύ}߭˝՝˥겋ϻ͓牧|~὘΂}~䟥ܖ槖ރҮɼ̦}ő勉~ÿ~쩦c윖}փϤ̄˂ʄ߄ ڄ Մֈ؇Ȇ̮߄ذ̈́ȅȍͨڅDŽܹϺɨԍ򁌐}貵 Ўۄ܈ ߃އ݆܃ۋډقچR՛~}} +˷ ֿ   +  + ؁酑P~͌|ޫʜӜɣ谊ι̒刦{}߻꨾́|}㞤ڕ䦕~~ÿ܂ѬȻʥ|Đ䊈}¾}ꨥcꛕ􊎍|ՂΣ~˄ބ  نֆՂԄՆօ ׆Ɔ˭݄ׯ̄Džnj̧ل˄Džڸ~ιȧӌ񀌏}籴΍ׄ +܊ۄ܂݅ރ݊܄ۅڅِ؄׆oӚ~}|| +ʶ ս  + +  ր焐O} ԑѢڡѩ𷏹æӗ퍬œżӆ꣪⛍쫚ŬزѪ½ʕ덌񬩧J򟘓ȀۅӧЄ "߄لڌ ܅ˇбܴф̆͑ѬЄ̄ʀἻҽέڏ2Ԓ݄ ߂ބߎ݆LٟƼмÇ  +݄ P +~~~}~}|~|{~}{ }~|{{}}{}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~Ύ񷥤ˌ𼓵~ȠⳭ謲Й}☠|څġǶ̸벹Ø~ƛ}뢐¿Ɉ雓<맲~~҂У̇  ܈؄ֈ +چهׄńƂDŽ̯د͆˃ɅʀȎͩ۹ǽͪԒW~곶Џ܄ݍބ߂߆ބ݄܂ۄډۅڅN֝·~}!}ɸ +   + ׂ 텐 };̍ ﵣʋ}ǟಬ櫱Θ|{ل Ƶ˷鱸}Ś}ꡏȇ盓-馱}'}сϢˈ߄ (لՄփՈ؇ĄłƄˮ׮̆ʄȄĄ̌̄ˀڸƼ̩ӑ=}鲵ώ؄܈݂܄߄߆ކۊډقچRԜ}}!}ȷ +ؿ  +ց 널P|Ӓ +ЏďΤ踲՞߀蜤ɥͻļǓѼ񷾼ǜĽ˞¿𥔷¿͌X񪴳π؅ԦЈ&  څۆކ݈Ʉгܳх΄̈́͒ѭфЀἻҮڔ<𷺻Ւބ߆߄OڡǼ' +μŇ & +܅ 򈔜_~~~}~}|||}~|{|~{~}{ }~|{{}~{|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~͎𶥤ŧ~巉ջ㵃Ќێ}~񙻤ܹٮߕ娦ޱ}ˀŖ׎þ؜ż矙ޔM~ӁТ  ܄ ؈ׄ؂لۄۆńȄ4̱ٱɆʀǎܹͩԬP~쳷яڄގ߄ނ݆܉ۂ܆w֠~~~ɹ &ق }Bˍæ첺}볦㵈Ӻᴂ푞ߋ~΋ٍ|}ڷ׭ݔ㧥ܰ|؀Õ֍½כĻ枘ݓ~&}сϡˇ  + ۈ Յ؄ن؇ĄDŽ˰ׯȆɀƍ̨۸ӫ`}겵ώ݄ބ݄ ކ݃܊ێڄمN՟}}}ȷ ؿ  +؁ 톐},Ғīʫ뻍麆炛Րᒮύ޲ꬪ㶽πɚûۑޞȿ򁄃—▖ ԁ؄ԥЇ  +߄ +܅ۄ܂݄ +ބ߄Ʉʂ˄дݵцτ̈́΀̒ѭ⼻ٱP񷺼Ւ߄߅yۤƻ +νŇ  ޅ !+ +~~~~}}~~}~}|}|}~|{|~{~}{| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~ˏ ŧ򻿎~Œ䦧ݧ秅ր}ߡțΖی~бзȕ~o}񎱬ſ؜̓-}Ԃѡ̄  ކׅڄ܌ɈͲٯͅ˅ǎΨ̄ˀܹխ1~촷Ґׄ ބ ߈ލ݅܄ۀס~~}}~~ʺ" ف R}ʎ Ħ𹽍}Ñ⤦ۥ妄|ޠǚً͕~}ϰϵǔ}|Lſľ؛ʒZ|ҁϡ ݉քׂֆلۄڂنȈ̱خ̅ʅōͧ˄ʀڸӬ9~곶Џڄۂ܄݂ގ߄ނ݄܂݆܆ۇu֟ȿ~}}}|}~ +ɹ# ׁ #|:~އВ īʫđʖꪬ㫗܃奪͞Ӛնջ½͘MÃĺ¿۠З򨨉AӀمԤ &ۄ܃݄߂ʆѵݳхφ̒ҬЄπἼڲBľ񸻽֓ sܥƻ򀉗 +Ͼ ƈ +ބ + , +~~~~}~~}~}~}|}|}|~{|~{~}{{| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}}}~}}}~~~~~~ˏ ŧʣӗޛÜВأ뿘±ƒGѳ׎Ŀ̻ᴕˊ  ˔便)~ԂѢ~˄܇ ׄۄ܅ۄɇβڭ˄ʄȍΩ̄ݹլ~쵸Ғ܄݂ބ߂߆ކ݇uء~~}}}~}ͽ Ņ + + + ۂ 򇒛Q}~ +߇Ɏ쵅ĦɢҖܚϑ֢꽗ĐHв믭쓎Սþ˺೔ɉ~ʓ}҂С~ʄ˄  +ۆքیȇͱج̅ʄɄƌͨ˅۸ӫ~~봷ёׄ܄ߎ߄߂ވݍ܆wנȿ~~}}||}}|~˼ Ą +  ف"}:~ކГ󺄩 ūʫЧٛȡ֖ާÜǵæʕGֶ򴱪ۑϾ䷗ύИ󨨉 +Ӂمե΄Є + ߄߇߄͈Ҷޱхυ͑ҭЄπ⼼ڰ2ľ򹼽ו݄sݥŻ񀉘 + ʈ$ + + #, ~~~}~~}~~}~}~~}|}|}|{|~{|~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~}}}~~~~~~ː춄Ũ߂Ĺ¿ǭ޲?¼ӟЕčۍ~̕ ~ӂBҤ݈ڋقڄۂ܄݄܂݆ɇβڮΆ͂̈ˎ ˄ʀݹ~Ӭ}FӓބO٢ɿ~} +Ͼ Dž + ݃ +􈒛!~}+~ +݆ɏ굤 ħ~ށ¸Ŭݰ¿Fߌ~ҟϕČڌ}~˔쥥 }т"ѣ~̅ +/܄ٍۄ܋Ɉͱ"٭Ɇʍ ʄɀܸ}Ҫ~}~0뵸Ғׄބ݂އ݉Pؠǽ~~}|~ +ͽ ƅ +ۂ +򇑚P~|}~߄ +܄Д򺩪ĬʬȾ˱Œľ@双ƿƑ٢ӘǏޏĽ2љ򨨈 ҁ؅?֧ 6߈ބ߄ Έҵ"߲ΆБ τ㼼ذ½򺽾ؖ߄Pަĺ Œ +̉ + ↘b~~}~~}~~}~~}|~~}|}~~|}|{|}{|~{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~ʒ붦ŨĿɽ}ԕ凅ō~~~Cەܚʡŋ╕̖ Ӄ?Ӥ݆ۈڄۉ܆Ʉγۭ΅͂̈̑Ϫ˄DŽ޹~խ~ԕلۂ܄ނ߄ ߂ߊrڢɿ~~~}}Ͽ dž  )ڂ 􈓛#}+~ +݄ɑ鵥ħ~þǼ~|Ӕ䆄Ì~}}}?їÿڔۙɡċᔔ.~˕쥥~҂Bѣ(܈ڄوچ +ۅلȅͲڬ͆̂ˈʐ ʄܸ}ӫ~}~뵸ӓ؄ ߄ߍ܄RءȽ~~}}~ξ ƅ   +؂ 򇒚a~|}~ۄϖ񺪪ìʬÿŭłŨژꉈɐB֚úͤȍ旗ž.њ񨨈҂؆5ק +߉ ͆ҷ߱҆тЈє τ㽼ڱý򺽾٘ބsަĹč ̉ ߆ +^~~}~~}}|~}|~|}~~|{|}|{|}{|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~ڄɕ궦ũľȽč}ɿ}ĉژC~ӓꢍӹ߿Ȍᔔ4̕ +.Մӥ̈́ *ބۄ܋݄ޅ7ϴ6۬̑Ϫ˄DŽƀ߹~խ~<ՖOڢ~~~}Ͼ +ņ  ڃR}~ބ܅ۅل%Ȕ赥è¼ƼŒ|Ⱦ|Èٗ>}ђ題Ѹ޾nj~˔쥥 +~Ԅ8ҥ +݄ڇۖɅγګ̈́ˆʐͩʄƄŀ޸}Ӭ~~(붹ԕم߂ߊr١Ⱦ~~~}~}|ν +ąق!~|,}~܆ۅڂم%Ι𺪫íʭ¾ƱȐèɌߚAÍחؼ¥ˎ䖖¾Ŀљ򨨉 + +ӂۇJש߄߄΅8Ӹ߰҄ІєҮτ˄彄ڲ¾򻾿ڙ߄ rߦŸ쁊Í ʉ   !,~~}~~}}}|~}{~~|{}~~{}|{z|}{z|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~ڄɘ 鶧ũĽ¯ǾĘȷ˷ćĹMҪʑԠʎߓ2~Ε簾 + рԄԦ΄ф$ ۄۆ݌ۄ˄ѷܭφ˄̎ ˄DŽߺ~Ԯ֖}ۅsۢ~}~~ѿ +Ć  ل }-~݄܆ۂڅل&Ǘ赦Ĩ¼ƽØǶʶ†Hѩɐҟɍޒ~̔ -ӃӥЅڄۋ܄݂܄ʄ϶ګ·ʍ ʄƄŀݹ~Ӭ~~?춹Օ|߈߄vڡȿ~~~}}}}Ͻ…  ؃􉓛Q~|}~ۆچΜ ﺫ­ʭ½dz¹ɜ̻ϺȊǼE֮Δ٢ĥ͐╖ҙ󨨈 -ՃهةՄτԺఐӇВҭτ˄佄™ٲþۚ OŹÍ ȉ  ߇R~~}~~}|~}{~~|z|~~{z{}|z|}{z|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~ل(ɚ趧ǪüðļÕЉ瘳ʽIʭǒսѣ͍ᓓ͖簾RрӃԧ ܉ۂ܇ބ߄Rҷܭφ΃͇͎DŽݺӭח~ Oܣ~~~ +Ć ڃm~~چلׄ%Ǚ給ũ»¯úΈ嗲ɼ澄Dɬƒӽѣ̍~̔ +тӦ΄% نڂی݃ޅ8Ѷ۬·̓̇ˍ ʄܹѫ~췺Ֆ} Rڡȿ}}}ѿ +Å ؂e􊔛}}~لڂنބ(Ξ ­ˮȵȘŨՌ뛷ĈEͱ˖ԦЏ䕖ҙՃ؆تӄ9ֻ౑Ӈ҂шґ τ˄㽽™رýۛ sźōɉ߆ V~~}~~}|~ }||{{{~~|{zz|~~{z{}|z|}{z|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~؄&ɛ趧ƪ}üIJ¹‘;΅藵֗ӆEƬȖңϊ㓔¾̔簾 сօ"ը҄ ߄ޑ9ҷݭφ΄͆ʌ*ۺ-`Ҭﹼח܄Rܣ5~Š Ȇ +ۄh􊖝~}~ۄچ,ǚ浦 ũ|»°̽̄疴Ֆ҅IŪǕѣΊⓓ~˓ +ЀՄԧф߄ۄۄ܆݄ނ݄ބ8ѶܬΆ̈́̆ȋ ʄɄƄٹ-lѫ~֖ ۡǾ~~~ ƅ ڃf󉕜}}}؄ق؇+Ο ®ˮɶƽǔ¨ӈ훹ŷÆڙ׈Eɯ̚զҌ疖èј󨨈 +-Մۈ٫ք ߄5ֻᱏӆ҃чϐ τ˄ཽÚױýܛ±uĻ +Ǝ +̉  + +d߄߇~~}~~}|~ }||{{{~~|{|~~{zyz{}|z|}{z|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~Є'ȝ綨ƫ}üIJÎʼ́}䝺ǻÆڝ󁅑B̪Șѣ̆└ÿ~Ζ +сم֩҄  އކ߆͈̄ҶݭЅ΄̈́ʍϩȄܺҬﹼؘPݢɿ Ë Ƈ  +܅ R~}~ׄم؆ׄ+ǜ嵦ũ|»±̿~ɻˀ}㜹ƺ~…؜󀅑>˩ǗТˆᓓ¾~̕ +ЁׄBԨ܈ۂ݆ބߊ̈˄ѵܬυ΂̈́̄ȌɄDŽ۹~ѫ~$ז VۡǾ~~ņ ۄc}|}օ׈+͡ ˯ȷŻǑу衿ʾȉޟCϭ̜ӥΈ喖ĩҚ򨨈 +Յއ8ڬ шЄֺⱐԅӂ҄хϐ τ˅†⽽þÚر¼ݛ²RĻǎ ˊ ሙe݅ވ݂܄~~}~~}|~ }||{{{~~|{}~~{zzyyz{}|z|}{z|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~/ɠ涨 ƫ}üIJ~Ĺ㜸·}†ט􂇕E˫Ƙپϣˇߔ~'ΗЂم֨ӄ" މ݄ߋ#͆ӸޮЅ̄ɍϩȅܺӭ𹼾ٗ + VݢɿË Ƈ + + څ R}~քׂ؈+Ǟ嵧 +Ī|»±˿}øᛷ|֗󂇔Bʪŗ׾΢ʇޔ<}͖쥥ρׄէф҄ ݇݅ވ߈̇˄ҷܬυȌɄDžڹ¾~Ѭ︻ז +RܡȾ~ ~ ņ +   ل S~|}ՅօՆ/Τ컬 ¯˯ȷĻŐȼЂ砽ƺNJۛHήʛѥΉ▖ƫӛ򨨈Յވګׄ  чЄ׻ⱑԅ҄фΐ΄̂˄†ώ•Ěرݛ +yĺǎ +ˊ +߈e܅݈܇~~}~~}|~}|{~~|{}~~{zzzyyz{}|z|}{z|~zzz{{{|{{{z{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~,ɢ嶨ƫ~üĴ坸ȾٕAåʘغʢ͍§ ͖便 +сׅ/ת߈߅ψ̈́Թޭ҅ ̄ɍϨɄȄܺ~ԭ}}𺽾٘ vޢ~ËLJ + +ۅb}ӇՄ +ӄ*Ƞ䵧 Ī}»ò̿䜶ǽؔA¤ȗֹɢ̌ߔ~˕ Ѐօ֩Ԅ  މ݂ކ߄Έ̄-Ӹݬτ˄njΧDžڹ¿~Ҭ}|ﹼؖVݡȿ~~~ŠƆ ل U~}Ӊԉ,Φ뻬 +¯˰ɸĻƐŻт꠼ċޗDƩ͛ݼͥЏ㗖ǫњ󨨉ք݈8ۭӈфؼⱐԄЄΐӬ΄̅†ώŗśٱ¾ޛź񁎜Ǐ +̊  Rنچۆڃ~~}~~}}}|~}|{~~|{|~~{zyz{}|z|}{z|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~Ԅ'ɡ嶨 +Ǭ~üijĎ÷砾Ƽٔ@ʙظƢƊ╔ħ.˔便сԄتԄք߆߅ψ̈́ԺޭхΈȍϦȄߺ˜~ӭ}}𺽿ٙZޢ}5~Č +LJ ڃd~}ӅԆՉAȟ¿㵧ū}»±̿¶柽ŻؓAɘַšŊᔔ¦ʓ +Ѐ҃֩ӄՅ +ވޅ߆Έ̄Ӹݬц͈ƌΥDŽݹ~ҫ}}ؘQݠ|5~~‹ +Ɔ +قf}|~ҋل'Υ뻬 ¯̰ȷŻɑǻ҂ʿݗ2ìΜݺɤɌ儗ɫЗ +Մهܭ؄ڄ "ӈф+ؽⱐՅЄ͐Ӫ̅Æ佽ƙƛٱ½ޝzƻ󂍛ȏ ̊ + ߆ ցR׆نډ~~}~~}}}|~}|{~~|{|~~{zyz{}|z|}{z|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~ӄ&ɝ䶩 Ǭ~ļijŏķ颽żՕMǛٶšᕕĨ͔сфةׄ +χ̈́չޮ̈́ȎЦ˄ຆÖØԮ~𺾿ژ{ߢ¶}Ì Ň +ۄ}V}Ґ,ǜ¿ⵧ ƫ}»²Îö~衼Ļ븂Ԕ􄉓@ƚصġ~¾ç̓ЀЃרԈ ߈އ˅̄ӸݭЄ̄ǍϥɄ޹—~Ҭ~ﹼؗޠ}~ ~‹ Ć ك|]|~҄+Ρ껭 ð̱ɸŻɑȺҁɿڗRį˞߸Ǥ䗗ɬ6Ҙ󨨉Մׇ.ܬІټⲑՄ҄͑Ԫ΄Å澽ȚǛٲ¼ޜyǻ􂎛ȏ +ʊ   րV׆؂ى~~}~~}}}|~}|{~~|{|~~{zyz{}|z|}{z|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~+Ȝ䶩 ƭ~ļijĸ΀졿żՕ􃇑?Ǚڴáᖕèϖ簾Ёфبք +φ̈́ո߭҆ͅnjХ˄Ʉ߻ר֭}𻾿ږTߣ¶Ō +Ƈ + څU}х҂ӄ҅,ƛ⵨ ū}»ñ÷̀꠾Ļ컂ԕ󂆐,Ƙٳ ~͔πσקԄӂՄ +$߄ނ߆·̄Էݬх ̄ƋϤɄȄ޺˜~Ԭ}~ؕtޢ~Ë Ć +؄W|~ЇЇ؄&͠黭 +°˱ɷżŒȻӃɿ٘Q˜þරƣ䘗Ȭәԅևܫڄ +Ӈфټ㱐օ ф̏ԩ΄Å徽ȚǛ۲ޚPǻ􄏜ɏ ʊ  ߈ق]؄ׅ~~}~~}}}|~}|{~~|{|~~{zyz{}|z|}{z|~zzz{{{|{{z{{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~ӄȝ㶩 +ƭ~Ľô¹Ǻυżۘ@¥×ľ۲àᖖľ7ϗ𦦅т΄٩ׄم + + + ΄պ߮҅ψ2ɌЧ߻Řę~֭}ڗ +O·}񂍙ÌȈ +  Մ׀X~}Іт҄+Ɯᵨ Ĭ}û²ƹ΄Ļڗ0–½ڱŸ ü5Ζ便Ё̃"ר؆ ̈́Թޭц̄2Njϥݺר~Ԭ~}~ﺽٖUޢ~|‹Ƈ +ԃj}|~τЂχ+͡黭 +˱ȸƽĔ˾ԇɿŨ<ǚᴷŢ䘘ì5ӛՅӆݬۄڂۄ݄ + ҄фٽ㲐օф͐Ԫ΄Æ徾ʛț۲'ߛXǻ6ȏ ̋  + ڇi܃Շ~~}~~}}}|~ }||{{{~~|{|~~{zyz{}|z|}{z|~zzz{{{|{{zz{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~+Ȟ㶩 +ǭ~ľ³ĺ~ȼч}Ƽޙĩ8ޯğ~ᖖ6И𦦅Ҁτ٩؄ + 1ֺ߯ӄψȍШ˅߻ǚƙװ~ڙV·~}󃎚Č +Ȉ + ׄj׀~}}ЄтІф$Ɲᵨ Ŭ}½¹}ǻχ}Żݙ@èĿܯß~þ8ϗ復̓بքׄ̈́3չޮфΈ2njϧݺŘŘ~֮}~𺽿 ٗ uߢ}}񂍙Ë +LJ +   +Ճj}|}~ΆςЄ؄$͢軭 ˱þƷȾĕ̿֊㜜DǬė䱶Ǣ䘘ľ8՜փԆ4ݭ ҄ھ䳑ׄӈ͐Ԭ΄Ç忾̝ʜܴߜTƼɏ ͋  ܇j܃ՄւՆ~~}~~}|~ }|||{{~~|{|~~{zyz{}|z|}{z|~zzz{{{|{{{z{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~фǞⶩ ǭ~Ŀƽʾъ}᠜BħⰸɟᖖþQЗ𦦈рЄڪلυֺ఍Ӆχ3njЩ߼ɛǙڲ}ۘ s¸~򂍚Ì Ĉ + لj׀}}~΅ψ,Ɲ൨Ŭ}þżɽЉ}ȿߟ æ௷Ȟ(½ 5ϖ簾σ٩؄ + Άչޮӆ·ƋϧɄ޻ǚƙ~ٱ}~ڗTߢ~}‹ Ç + ׃jՀ||}͇΄̢軭 ̱þƶŗ©׍ļÉ壟BǪ粺̡䘘 7՛ՃՇޭ݅ ӆ۾䴑ׅԈ̐Ԭ̈́Ç忿Ο˜½ +xǼȏɋއj܄ӄԈ~~}~~}|~}|{~~|{|~~{zyz{}|z|}{z|~zzz{{{|{{{z{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~Ǟⶩ +ǭ~ſ²ǿҌü奣~ŧ᰺˟▖Ŀ:ϖ񦦈р҅ڪڄۆ& + фЂτ׺ఎӄφ4njШἻɜǙ۳}ۙ ·򃍚Ì Ĉ + لk׀}}~ΆτŜ൨Ŭ}þƾы»䤢}~"Ħ߯˞ ᕕþv͕簾Є٩م؄ +Є΅0չ߯҄·4ŋΧ໺ǚƙٲ}~ژߣ~񂌙‹ Ç ؃j||}͇̅ք̢续 ̱ĿǷûƙũ׏Ëꨦ ȫ粼Ρ嘘¾vӚՃ׈߭ބ߅ ՄӅ۾䴒ׄӇ̏Ӭ΄̈́ÈΠ˜ý VǼȏɌ އk܃Ӆԇ~~}~~}|~}|{~~|{|~~{zyz{}|z|}{z|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~Ǟ ⷩǭ~—;ϼ&΋ߔʟ 㖕:Ε񦦆Ԇ۪ڈ + ,׻ఎφ5ȋϨ༻ǝə޵~}ܙ p񂎛Œ +Ɖڃ׀}}~ ̆̈́ŝ൨Ŭ}˽~λ͊ޓ>§޵ɞ╔I̔𥦅 ~Ӆ<٩  ΄պ ߯Ά2NJΦ޻ƜǙܳ~|~ۘrߢʿ +ň؂||} Ʉ˄ˢ +续̱ĸŹǚ¨ԂԿҍ▓Ǭ<͡昗ſIҙ+ւى߮ވ ӄ۾䴑ӄ5͎ӫÈ̡͜¿᝺oƺǏ ˌ߆j܃х҅~~}~~}|~}|{~~|{|~~{z{}|zzyyz|}{z|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~Ɲ ᫄ ~~~ýĝǚȚþļ~뽈ܩŒ㖕%З򦦅~Շ۩ۄقڄ.׻౏υ3Njϧ߼ǝəݵݙ p񃎛ÌƉڃ\}}~˄̃ͅŜ ߩ~}}}¼Ûřƙ~᭿»;~}꼇ۨԿ╔Mϖ񥦄~Ԇڨڄ؂و <ֺ ߰΄4ƊΦ޻Ŝș۴~ۘqɿ~ň؂~||} ʅ˄ˡ 篅ǡ¿ɡ̞͞úœø8ଛàŎ昗L՛%Ձۊ߭߄݂ބ7ۿ嵒ӄҀ̏ӫÈ̡͜U¿❹ oźǏ +ˌ߆ۂ Єу҅~~~}~~|~~}|}~~||{|}|{zz|}{z|~zzz{{{|{|}~|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~Ɵ¿ ᷨȲₙ}ǜȍ}˼}½썥5篬òФ>Ҙ򥦅ֈ۩܆ۈ)Єτ ׻౏τƎЀོȞɚڴCݙq􄏛ÌƉ܄ ~T}~~ńʅŞބටlj|ƛƌ|Õ~|ꌤ宫ñϤЗ~ԇکۊڄ τֺ'߰Ōπ޼ǝșس~C~ۘp򃎚‹Ĉڃ}\|}~ɆˣI缬ͷ煝ÿ̠̑ɚ𐩑Ǵ ӧªo֜ւۋ୎߈Ԅۿ'嵓ˑԀÇ͢͜߹C❸pƻȏ +ʌ*ሚځTʄυ~~~}}}~~~}|}}}|}|~{|~{|~~| }~|||~~|}~~}}}~~}~~}~~}~~}~}|~~|}~~~~}~~~~~~ƣ¿ɾ·†&}~}}݂}e¾񻼷潚􀖂~~π؇ܪ܅ۇ2׺)ᯏŌЀ½޵ɞ޴B~楧Ȗ}τЂц +q¶Ōʼnن ~T}~ĄɆ˄Ģބ+Ǽ&|}|ÿ}ہ|ſiﺼ廙}}ֆ۩ۆڈ $τֹ߮ċϦݴȝnܳ}~䤦ǔ|΅҄p~􄏚ċÈ +ׅ }T|}~ÄȄ ˧,ǼìÅ&ĿİþⅧDŽĿeӃ݊୑߇ ۾峒ʏԫ̀丷Ϣ/ÿ쩫̙ԅ؄ pǻɐɌ މځTɄΆЄ~}~}|~{~}{ }~|{{~~{|{|}~~}}}~~}~~}~~}~~}~}|~~|||}~~~~}~~~~~~Ť3Dž҆рл}w}߁̲ܭ~Ǹˁۈݩ܈  5ػ>⯐ǼŊζ٤ԏՀ~~ʡخ~c櫾򼽼%KD~郑Ō +ĉ؄ ~i~}}ģ߄8ńЄ$κ̄ɀ|Ŀ}݀þʱp۬}Ʒ󮼽ʀهۨ܅# Kֺஏ΅ƻĉ͵ף]Ҏ~~}~~Ƞ֭}Ԅb䩽񻼻2ɿᄩ]~}肐ċ Èփ }e}||~˄ʨ5̅ׄրƾŚ䄥ѶᲺʽτᬑ Pܿ泓Ӆ,ʎҺާ`ؒڂϥݲĕڄZý¿Ř Çnƻ议ʐɌ݇ +ہi~~}~~}|~~|{ }~|{{}~{|}~~}}}~~}~~}~~}|}~}}}|}~}~~~~~}~~~~~~˾J￰|}ҳý~~~}¿Z䲮~ﷸτҦȄ ̈́߅ ߆ބ߂އ݄͆ń̿Ōߥו햒5ɯ}}~Y  ~~~}}}}PȿÿČ +ĉ + ؃ ~i~~ÿɽ߄'օ&|б¼~}}|ĿⱭ}¿B~~΄ѥLJ݄  ބ܅̅Ä˾Ëݤ֕앑퀄6Ǯ||~; ~ }}}||||Pǽ~Ë +È +  + ׂ }i}}~½ç)݆$ĵ׷Ŵ`궳ÿӄ ֩ Ʌ  +х;úɏ䨏ݙ󚖵γŵ OĽ pĺɐ Ɍ   +݆ +فiÿ~~~~}~}}}~~|}~}}}~~}~~}~~}~~~~~~~~~~~~ʾ~}}~~}~  î΄߱~~~}~}|½~~fŤĕ~ſ~娥 +* + }~ьӣz}ιȾ̴߄܆ۅ Մ҆ф҃фυ΄̓̄r~~񁃇ƍĉ +ك U~}¾3ɽ}||}}|}~ ~ ­̃ݯ~~~}~}}|}|{˿}}sãÓ~}ľ}䧤2 |}ϋ򪧨Ѣ|Jǿ͸ Ƽʳ܄؄Մ ЄτЂτ̄yƾ~}~ČÈ +ׂ +i}|~ç"ȳӈ嵻ƿ¿°¼zʨɘׁꫨ& !ů֏اZŶԾüѸ܄ ׄքօӄ҃фtŻʐ +Ɍ  +ކ +i~~~}~}}}~~}~~~~~~~~~ߥ}|}~ +ưш 殴~~~~~}}|^}Љ꾿}3¿}~~璏~~4οȸ}||}}~ }˽܂״~~~~~}  +~ƍÉ + ؃~d}~ݤ|{|}~~ +ůχ嬲~}}~~}}}||{οÿ~}ψ齾|¿|}~}~呎}}~ͽƷ|{{||}~ |ɼہ~~ղ~~~}~}}~}}| +ǿ}~Ōˆ  ւ}d|}媦̵ׄ žzՌÄ핓ͽ½ⅅܸ߅ƻː +Ȍ  + ݆rف퀆~~}}~~~~~~~~ } ȳՄ 쮴 +ڂ ~~}|}}|>̶ƄID~}}}|ЄŇąĆÄƅF}~~ Ƭͨ||}}~~ιۄξ刈ܴ∆~}}||~}}~ɍÉׂ +~i|}}~~~ 짢| ƱӋꭲ~ +Ͼ؁ ~~~}}|{||{ 7ʵü>?~~}|||{χ DžĆ„V|}~}~ ū̧{{||}~}}}~~ͷلͽ㇇ڳƿ~}||{{~}}|}njˆՂw}~{||}}}~~~ʀͷۋ򳸺ž߅Cѻ˄]³Eʇe ˱ҬӾÿ댌⹶芉źۂ񀁇͐Ȍ܆ځ~~ꀊ~~~~~~ ɰ؏𰶶Կ¿ぁ~ +}} ٳل Ӈ҄̈́ɅĄ$ +  ń ̈́΃υŭ´ +~Ӻ቉ѿꌌߵ犅 +ƾ܅~~~}}~}~ȍÉ +Ղa}~}~~}}~򧡣~ +ǯ֎ Ҿބက~~~} +|| ױօ҄4   +ń ˄΄ë +}~~~~~Ҹ߈Ͼ苋ݴ扄Ľڄ~~~}}}||~|}njˆ ԁa|}|}}~||}~̃ εݓ  ľ厎Ŀ腄  +߷߄ل΅Ʉ ˄ +҄Մ +ބLʱƸԂ پ獄Ŀ𐐐庸펊úለm͐Ȍۅwـꀊ~~~~~~ ǂɮّ󱷸 ㊏ ~}~}|} + ׅ ҄Іхυ΅͉˅ʆ˄̂̈́΂ͅ΄ф҄ԅل |}|}~~ | +~уٽ䅌 ҽ쎎߶ꍞǾለk~~}}¿~񂆇ĊӁg}}}}~}}~ ƀ ǭ؈ 񯵶վ⊎ +쉈~}|}|{| ܄Մӄ҄Ўς΄̆ͅˈʆɂȄˊ +υфӅل +߄{|}~}~ {}Ђ׼⅋ мꍍ޵茒ƽ߇k~~~}}||~}~É + !ҁg||||}||}~~ ̅γ߉ ſ銓 􍍆 ڄم׍ւՄԅӆ҈хЃτЄҊ؄قڄقڄ + ׇ ꆐ¿򒄑廸𑐐 +ú焋 ɍ ؅iۀꀊ~~~~~~~~Ђ ǂȯل 󰶸듎~} | }~ ԉ񍎄ѽꅍߴ藌ǍǾ≉v~~}}}|~Ċӂr~~}~~|}}}~~ƁǮ׈ +񯴶 ۿ钍󎍍~}| {|}~ӈ м腌ݲ昋ƽ~~~}}|||{}~~É + + сo}}|}~~{|||}}~̅ʹ߉ + ſ񗍖Ŀ  ڌ  ¿丸ú荌xɍ  ؅[܀ꀊ~~~~Ї Ȃɍ Ȱ؏ 񰵷 +~ +}֋п苋ݲ戊 +Ž℉~i}}||덫Æ +rՂ}~}}~ Ɓ +ǯ֎﮴~} +ÿ|~~ +Ԋ ξ抉ܰ䗉 +ļ~~~}h|||{ꌪ… uԁ|}||}}}~ ͅε݉ +‡ +Ŀ ܏ 㶷뚎¹荍 +j񐰩Ȋ sڅ݁݀者ۀꀊ~~~~Ї ȁ +DZג ﮴剉ܳ䈆 +ƾ℉~}m|݉ +nՃ}~~}}~~ ƀ ƯՌ ~󌔏 ξ㇈ڲ⇆ +Ľ~}|m{¿~~܈~ +qԂ|}~~||}}~  ̵ͅݑ +†̓ 댐 +Ḷꌔù荍m⌰ +sچ܁݀者ۀꀊ~~~~~~~~Ѕ ƁȮؓ ͑䄈 žቇx~~~}}|勏~~荬   n}}׃}~}}~~ ŀƭք +묲̐ οↇ Ľx~~}}}||{䊎~}挪~ n||Ղ}}||}}~ ˅ɐ +ͳݐ +󲸺̕ꆋ +ù熌z뎒푰o܆܁ꀊ~~~~~~І Ɓ}퀓 뮴 + +Ͼㅇ ž뉆~~}w}􀀇 v؂~~}}}~~ ŀ| +ꬲ ͽᅆ üꈆ~~~}}|w~| vׁ}}|||}}~˄󃔏 +򲸺 ÿ銋 ¹򅌆 +t݅~~~~Ѓ ǁ ꯴Δ̓ν⌆ Ž~~}}}|~ }ր||}}}~~~~ŀ +譳~˓˒ͻ ļ~~~~}}|||{} w}~~{|}}}~~~ ô̄ 𳹺Ϙ̗芉 +¸ق¿ sۃ~~Ї 駧ƀ 갵Ĕٕ왆 ƾ~~~}|~} Ձ!}~~ 禦 +诳~œžꙅ Žއ~~}}}|{}~~| +Ӂ|}}~~~ 﫬˃𵹺ɘϙ򉉉 +ù兌ǁ {څ~~~ + ̃ Ǿ߆~}|~} )Ȅj}~Ղ|}~ 󩧬~ ˂ڔŽ݆~}|m{~Ԅ| ~|}ԁ{|}~ ɂ҆ù兌m¿؅ ۅ ƀ~~~~€Ѓ  Ƚ~~~}|~}~}퉘}~ 󩧮~ Ƽވ~~~}}}|{~}|}~~ӄr|~숗|}~ Ȃ ¸卄񁂇 ڄr󌛦̀Ȁ~~~ŀЈ +󗬖˕ ~~}y|~~}ۄ񀂆ׄu~|}~ 󧥭~ǖ}~}|{}}|}~{|}~ Ȃʙ ̀π~~ʀЃ ̀ƕ~}}}|}݄|}|}}}~ 򖩕~}|||{~}ۄ~ +|~|}~ ҄!}~~ˀЉ +}|}~}}~}!񁂅 +$~z}~~|}}}~ |{|~~}||~}|%$~z|}}~~{|||}~ +$v~~͎̀嗏~}}|~*򁃆}~|}~斆~}||{~}*~|}{|}~ܛ- ~~π~~~}}|:~~}}~1|}~– ~~~}}}|||:~}} |}}~1{|}~< + 0€~~Ԁ~~~}}|C~}~ +}}}~}~~~~}}}||{~~}|߄"}|||}~7|}~‘@ + Ā~~׀ +~}|%~}݄}}}E|}}}~~}|{~}|ۅ}||~E{|||}~Ɛ$À~~݀Ѝ~}"~~}ބ݅ }}~M|}}}~~}|&~~}}|܄!~&|}}~|}~' Lπ~~߀Љ~}}}+~~}}*}~ }~+|}~~}|||Y~}}|||}|}~+{|}~*& *Ӏ~~Ї~}}}||5~}}ބ߂%}~~e|}}}~~}|||{{<~}||ކ݄  +%ބ |}~+{|||}~6 -*׀~~Ј~}G~} $܄}}~,|}}~⊖~}|?~}|߄ $څهۀ|}}~;{||}~ՎH$$߄.ۀ~~Ѕ‹“~};~~}4 ڄր}}~X||}}~~~~}|F~~}|7؄ـ|}}~~P{{||}}}~~~ŎO4*߄߄F݀~~Ћ~}D~}} ߄ =~}׆߆}}~~<|}~~ ~}|4~~}}|, $~}}ބڅր||}~~~R{|}}~~~@  ,܅݀S~~Ћ~}}N~~~}}ބF~߅ހ}~~c|}~~~~}||C~}}}||܆ޅ ڄ} + +~߄݄܂݄ۀ|}}~^{|||}~C/ Z~~Ћ~}||;~}}߅ ք(~ +?}܉݂܄݀}~Y}}}~ +~}|{C~~}}| ݆8} + ~|'ڌۂڄۂ܄݀|}~~S|||}~ \ ۄ! CR~~~Њ~}~~~}}݅}5~~~~~݆ +}}~~~\|}}}~~~~}|\~}}}||݄ Մ؅4|}}}~}߄ ݄܅އ߀||}}}~^{|||}}}~_ڄބ'(e~~~Ѕ~}| U~~~}ԄԄ ք&߄ 3 + }}~~<|}}}~~~~}|{ O~~~}}}|ՄԂӆ҈Մ ؄E5 ||}}~<{|||}}}~ߑxللۆW05 8~~~ލ~}|v~}}؆քԄՆ>܄*݄}}~ 2|}~~~݌~}|{>2~}}|ׅ.ۅڅڄ ܄ل6߄߄||}}}~:{|}}}~~~34݆ۄلچB  2~~~Д錕~}8H~~}}܅ډڅڇ ؅ق؆ Ԅ3ׇ؂نކ  +} ~~~D|}}}~ҋ~}|84~~}}}| ڄچن؄؄؅ׂ؆ӄцԄΈ݄ׄބ߂ |||}~~~D{|||}~0߄ކ߄߈ނ߆ ݆ۇڄք ܇އ  !~~~Г~}7~~~}!߂އۄڂمۃڄֆԇ҄ӄ҃ф܄}~J}}}~~}|7(~~}}}|||ސ݄څ ل؆ل ӄԆӄ҂ӆфЄш ք|}~M|||}}}~: +ޅ߄ۄׄ؄׃ք؄܄3A~~~Ї‹~}}}| 0~}  ބ݄܅ۄڅمڂ܄ބ}~@||}~ƓɊ~}t|||{I~}| + +߅܆ۂڎI|}~@{{|}~ǘ+/ +߆ކ 7~~~}|$~}  |~+x|}~~}|{/ ~}|މߏ|}~}}~&|}~⎤<  Bw~~ЉƊÓ~}(|%~~}  }}}~~}}~~~*|}~ȉ~}|{ b>~}~}|  |||}~ ;c{|}~L1~~ЌŊē~}$|] +~} |}}|}}~&|}~ljđ~}|{ a& + ~~}| ||| +|||}~7j{|}~Ӑ#c +$ +"i~~~~ЇŠ~}|"~}}~~}|}}}~/|}~Ό~}|{z<~}||}}}|||||}~2{|}~ l* +~~Ќፃ~}V* +m|}~㌂~}|T# ~~  G{|}~j + (kⓂ(~~~}}}||W  }||}~ے~o}}}|||{{% )˄фF{{|}~ޗ   _؄DЃŎⓂ~}| |}~ے~}|6{ڄF P̈́P{|}~ߗkÄ! +Ј؎~} ք, +  /)Մ$|}~~}|h    +0ل{|}~ EDŽ +Љ~}s| + +|}}}~~}|{"ք&!*Մ6 |}~ +%^*ЉȎŔ~}6ԄÄ +\!|}~ Í~}|hĄ v|}~Ē(>Ȅ!Z Љ؏ ~}||^ + G|}~ߎÓ~}|h{{ń^"{|}~ɒ  ĄR Љ~}|2˄)?߄ +|}~~}|e{Ʉ =߄ {|}~bЅƄ +ÄR)Еҍ~},|4̄& Ą4|}~Ԍ~}|{݄ ք˄   E{|}~‘^ńɄ؄ В~}U|Ԅτ"  ńɄ0|||}~Ï~}| {$Ԅ"Ą + ƄԄ {{{|}~Dۄ1ń„ +ń ʄ"ۄ +鎄~}|.)ЄĄÂ„ …ƄɄ4 +|}~폎~}|{ >Ƅ +ńɄ\ +{|}~ƒSۄ +Մ̄ɄȂDŽăƒÄDŽ˄= €Ї~},||,Ӆ ̈́ɄȂDŽƄѡĂ„ƅɄ̈́O|}~~}| {{4фńĄÃ…ńƂDŽʄ҄ք4 +{|}~"݄؄Є̄˄ʃɄȄƄŅ „ÄĂŅ ˄҄ ل>ŀЇ̑~}*||.Ԅ +΄ʄɂȅǃƄń…†ÂĄȄ˄Մބ +|}~󐋏Ύ~}| {{!ׄӄ +̈́̂˄ʄȂDžƄłąÄ‚Ä̈́> |}~򕋔"ڄτ΂̃ͅ˄ʄDžƄĄÃ…‚ÄăńƂDžȂɄͅԄN ƀЈ璙~}|݄Є̈́̄ɅƄń„„ ȄɅ̄Є؄ۄ +||}~~}|{  ׄ˄ʄɂȅńĄÄƒ DŽȄτ Մلڄ +{{|}~ E҄ф΅͂̄˃ʄDŽƇ …‡ÃćłƄDŽΆфԄՂքʀЉ䒒ې~} | ܄ۂڄ΄̈́̂˄ʄDŽƄŃąÆ‚ÅąȄɂʄ˄΄ф҄ׄ؂ل܄݄ ||}~ב󏘐~}|{ ۄԄӂ҄тЄ̈́ ɅƄŅ…„ɆЄ؄كڄۄބ +{|}~ז ل؂ׄԄӂ҄тІ̄˄ʃɄȇŅɊ†ÃĆŅƄǃȄɅ τЄт҄ +ׄ߄̀Б~} | ߄ނ݄܂ۄЄτ΄̈́̄˄ʄɄȄDŽƄńˆ…ÅąņƂDŽ˄ Єӄ +؄܆߄|}~ԑ~}| {݄܂ۄڄ҄΄̈́̄˄ʂɆȄDŽƃŅĆ„†ÄąDŽȂɄ ΄҄ۆ܃݄ {|}~Ԗ +%ބ +لքՃԄӄ҄уЄτ΄̈́̄˄ʄLjƄň௄ÂĈʼnƄdžȄɅʆ˂̄ЄфՄلڂۄ ŀЀВ~}|  ߂ބք҄уЅσ΅͂̆˄ʄɄȄdžńąÇ‰ŠÄĆņƅDŽʄ˂̄ фՄւׄۄ܂݄ޅ߃ |}~ňܕ~}|{ +܄ۅ؄фЃυ΄̈́̃˅ʃɅȄDŽƄńĄÃˆ†ÅąņƂDŽ˄ӆ܆߄ {|}~؄ׂօՄԃӄ҂цЄυ΃̈́̆ʄɅȆLjƅŇĄÈ††ÉĉłƉDžȄɆʆ˄̄̈́΂τф҃ӄڅ ǀԀЕԔᓘ ~}| ߄؄ׂօՃԄӄ҄фЄτ΄̅ͅ˅ɄȄDŽƆ ĆȄ…ÇćŇƊDžȈɄʅ˃̄υЄф ׄ؄قڅ݄ބ߄|}~̒~}|{ +݄ ׄԄӄ҂цЄτ΄̈́̄ˆʄɇȃDŽƄņĉlj ‰ÆĊŅƉDŽȆ˄̂̈́ΆфՅք؅ل܅݄߄ {|}~Ԙބۄڄق؆ׄփՄԄӃ҇уЈς΄̈́̄ˆɊȈǃƉňĄÄ…Å +ˆ…ÉċňƅDžȇɇʇˊ͈̄΅τЄԄՆ؄݆߄ +̀ۀЏڔ~} ||| + +݄ׅԅӄ҅фЃυΆ̆ͅ˄ʄɄȄNJƊňăɎˆÆĄňƇLJȊɄʉ˅̄τц҄ӄ نڂۄ܆߅ +|}~Օԓ”~}|{  ߄܄ل؄ׂօՃԄӄ҄фЄτ΄͇̃ˈʄɄȄDžƉňĉƆÇćňƉDžȈɅʅ˄̂̈́΂υЅф ׄ؄قچ݅ބ߂ +{|}~՘ ߄ނ݆܂ۄڄل؄ׄքՄԆӄ҄цЅσ΄̉ͅˊʈɃȉŊƂńƊńĈ ðˆÄĆŊƉLjȆɄʈˆ͉̈΄ψЅх օׅ؄ ޅ߄ + +ՌЀހЉܖ͔~} +܆ۄل؃׆քՅԅӅ҂хЉςΆ̈́̆ˉʅɈȊǂƆłƆņƃŌċÄœ‚…ËĉʼnƃNJȈɅʅˋ̇͆΅υЅфԄՅք؆ބ߄ +|}~~}|߄ބۄڅׄօՅԆӄ҇фЃφΈ̈́̃˅ʈɆȌDŽƈÒȇ‹ÊĄņƆNJȄɌʇˆ͇̆΄φӆԄՂօ ۄ܄݅ޅ߂{|}~ܚИ ބ݅܄ۇڃه؄׃օՈԄӃ҅цЉυ΅͉̂ˆʂˆʆ˃ʌɋȄDŽƂǝDŽƇǂƅDžȋɉʉ˃̉͆·υЊш҆ӆԆՄֆچޅրܖƔՒ~}|ކ݅ۄڄل؄׈ֆՄԄӄ҉уІςΆ͈̇ˉʈɄȆǂȆDŽȅNjƋŅĨÄĆÆĆŋƇDŽȄɊʉ˄͈̉·χЄх҅Ӆօׅڅ݄ބ߃ ||}~ԓ~}|{܆ۄم؂׆քՈԆӄ҃хЉτ΃̅ͅˊʈɆȉǂƄőƄŃĄŃĄÂĆÉ„„„†ÊĈŊƄLjȈɇʅˋ̇͆ΆφЄцՆ؅ۄ܆݂ބ߅{|}~ך  ߃ޅ݈܄ۆڅق؅׈փՅԄӆ҈цЈω΃͆̂͆̄̋ͅˋʅɨȄɆȆɆʊˇ̄̈́ΉωЄц҆ӇԆՄօׄ؆܆݄ۀЃږҕʓÖ~}|| ۆن؆ׄֆՆԄӄ҄фЋϊΊ̆ͅ˂̍ˌʅɋȡǂȄ +džȈɈʄˌ̈͋ΈυЊч҆ӄօ׈؄څ݄ނ߅}~މє~}|{{ ߄ބ ن؇ׅևՆӄ҅тЅψΉ͋̆ːɅʆɊȊǶƉLJɌʇˉ͈̄ΈψЈфԅՇօ؅كڄ݅ޅ߄|}~舉ښЙÚ ߆ކ݇܅ۆڄم؂ׅֈՇԋӈҍхЂцЌχ΋͉͇͆̂̈́̂̈́̅̆ΉσЌчҌӄԈՉև׈؄ ܈݅ ЃҕȔۓŖ~} ||݄܄ۇڅو؅׆քՅԃӄ҈щЋφΖ͆̊ˎʶɉʆˇ̂͑ΈτЉш҈ӇԅՂք׃؇هۄ܄||}~Ԕ~}|{{ + ߅ۄڄو؆׆օՇԄӄ҃хЊϊΈ͐̌ˌʆɎȅǂȈǂȄȊDŽdžȈɈʄˌ̈͌ΈτЊш҇Մք׈؄قڅ ބ߆{|}~ҙߗŚ + + +߅ޅ݆܆ۄڄك؅׊ֆՌԅ҄ӄ҂Ӌ҇цЋϵ·χЈуҎӆԌՈք׊؈ه݄އ߆Л֕ߕۖ~} +|| +߄ޅ݈܇ۄچن؄ׅւՇԇӍҎъЊώ΄͙̈́̄̉ˋ͇̉·φЈъ҉ӉԃՊֈׄ؇كڄۂ܄݈ރ߅||}~Ք۔~}| +{{߂ބ݆܄ۆچن؄ׇքՅԂӊ҈чЃφЈωΎ͋̐˅ʈ˓ʂ˅ʅˋ̆͆ΉϊЉщ҅ӊԉՅօ׃؅كڄۆ܄݅{{|}~ՙܙښ߅ކ݄܄چو؇ׄօׇ։ՈӆԊӌҊ҉тАцҊӆԆՊ։׉؉مڈۉ܆݅ބ߄֍Л˔ϖ~}|߄އ݆܅ۅڇل؅օՊԊӄ҅Ӈ҈ѐЋϑ΄͉ΐ̈́΅͆ΊυЈщ҉ӉԈՆ֊׉؅نڂۅ܃݄ކ߄||}~֔ޔʓ~}|{߆ބ݆܅ۇڅم؆ׄքՆԆӌґщІώ΄΄͙̈́̅̉ˌ̎͂ΆφЌч҇ӊՇ։׆؄لڂۆ܄݅ޅ{{|}~֙ΘϚ߃ބ݃܇ۅڌّ؉׆֎ՈԇӃԈҎӋҎӌԂՊֆ׌؆وڊۂ܊݈ވҍЙ핂~}||߃ވ݆܅ۄڃي؂הֈՄԌәцҮы҃ӎԇՇ։ׅ؊يڈۈ܂݄ބ߆||}~ĊǓ~}|{߇ޅ݃܉ۆڄلׄֆՖԌӅҏэыАσЇυЉψ ъҋӄԌՄ֋׈؅يڄۂ܅݃ވ{{|}~ᙐ ߈ބ݅܇܎ۉڅي؍؋אփׇք׊ֈ ؉وڄۋ܅݋ވ߅Й~}|| ߋބ݄܄لڄنؐ׎փՑԐӂԊӌ҄Ӆ҇ӄ҈ӂԄӄԊՊօ׊؅ٌڇۇ܊݄ނ߄}~Ŋ~}|{{߄ޅ݊܄ۅڃي؂׊օՂ֋ՉԊӍ҄ъ҂фҲъҊӈԆՉև׆؈لڍۅޅ߇|}~߂ތ܅݌܊ۊڌل؊ق؅ٱ؊ىڈۇ܈݇ޅߌ~}|ބ݃܇ۋڄي؎פքՔ֋Տ֋ׅ؊وڄۄ܎݇ބߋ|||}~~}|{߂ކ݆܄ۆچي؊׊֐ՔԄդԂӒԆՊ։׈؅لڎۅ܅݌އ{{{|}~߉ކݔ܏ۊܴۄ܌݇ކߊ ŕ~}||߄ޅ݆܊ۉډِ؄ׂؔׄؤׄ֐׊؆وډۅ܄ݍޅ߆||}~͕~}|{{߅݄܆ۆډى؇ה֍ՍֈՃ֪Ճ֍ׇ؆نڃۋ܇݇ކ߆{|}~ + ߎދ݅܄݂܎݈܄݂܄ݒ܅݅܅݌ޅ߉Џ~}|||߉ވ݋ܐێڂۄڂۜڈوڄڄڌۆ܅݉އ߉|||}~䔇͕~}|{{ ކ݉܋ۈڑي،ل؂٦ב؊نڅۇ܊݆ފ߆{{|}~ߜ߆߃Ѕɖ~}||߈ދݒ܊ۆܛۈډ ڇی܆݄ވ߉|}~㔍וѕ~}|{{߆ވ݌܊ېڇٌَڰوڈۄ܈݉ދ߆{|}~˚ËЄߕߖ~}|߫ނ݋ތ݄ܕ݂܅ݍވ߄||}~ĕ˕~}|{߄ޏ݈܂ݪ܌ڜۋ܉݄އ߇{{|}~ߙ‹Ѓߕ~}|߆އߊފݒ݅ލ߉||}~䔄ʕ~}|{ߊ޺݌܂ۛ܌݉ބߌ{|}~ߙЇ╆~}|||߆ߕ|}~ ޔ~}|{{{ߊނ߆݉ބݖބ߄ߋ{|}~ᙄЇЕƈ~}||||}~ޔ~}|{{߅߂߂ވ߄ލ߄{|}~ߙЇ旂ň~}||||}~ە•Ƈ~}|{{{|}~曃Ѕߖ򗂖閬~}||}~ڕ֖Ƈ~}|{ +{|}~ߚ񛂚Ì~}|||}~ҕᕈ~}|{{{|}~򛂚Κˀ֗~}||}~Ôڕ~}|{{|}~ ֛ܚрЂȕ͗ؖ~~}|||}~̕~}~}|{{{|}~Й͛ךʎڀЃΗ֖~}|||}~ ĕ~}|{{{|}~ʘƛ֚Ǝ߀ІʗȖ~}|||}~씄͕~~}|{{|}~虯ʛɚЌŎЇʗȖ~}|||}~씰̕~~}|{{{|}~噴ʛȚ茗ƎÀЅƕƖĕ~}| |}~Ԗǔ ~}|{ {|}~ωĚ™ÎЀЅ +Ɩ•~}||}~늎~}|{{|}~ω +ƚÙŽԀІƔ•~}||}~~ߊ˓Ɠ͖Ք~}|{{|}~~}~~才Ƙ™Œ +Ј˔Õ~}||}~ފ͓Ǔ͖”~}|{{|}~才ʘƘš™ČЉƔʔȗʕ~}~}|||}~犑͖ʔ~}|{{{|}~Ǜə̌ЀЉԗ̕~}||||||}~~}}}~Ζؔ~}|{{{{{{|}}||}~ԛ˙ـГ֕~}||}|}~ږٔ~}|{{|{|}~֙Гڕ~}~}~}~}~}~}~}}~󓏒ۖҔ~}|}|}|}|||}}}|}~ޙ߀З错ԕ~}}~~}~~~~}||}}|}~}~}~ȘԙŒʁ򍟎߀Йɔڕ~~~~~~~}~}~~}}~}~}~~ڛÌނ߀Л痖‰~~ɒǖÈ~~~~}~}~盖߀М旖ÉɒĈ~~~Ǘ曖č̂߀НЗ󉤈ʀ˒Җ󈥇~~~ɗЛȍ߀НƓЗ򉦈‰̒і 񈦇ΈʗЛɍރ߀М͓җ 􉪈ȁ̉ޖ󈬇ȀψϗқÅ䍒߀МΓ䗄Ȃˉ֖ۓ􈬇ȁˆ̛㍑߀СƉ⁧ޒі͓ +ň䀦ޗ٘Іፓ߀СٔƉ ْЖГ ňݗ٘І߀УݓܔуƒʖЂƗ΅߀ǓԃƒʖӂƗ߀Љ̓̉ǒ ƖȈ؈ȗчĈ߀Љ˓͗Ӊ̈·˛؇톦߀ЫÓωք…ے̈փ„ٗ퍂ҌΌ߀Ы“ړ̉Ԅڒˈԃ肠ٗ臈ЌՌ߀ЭǓĈ䍐ό֌߀ЮĄ섶ȃЃ +鈚ևЌ׌߀Ѓē†ރ䈄Ԍ߀Ѓ“Њȉ慖†ĉˆ҈NJ߀ЃגɊȉ텃ćÈ򕒔̑ɉɈ섂͇舌Κʖ̈Ȉ猫߀ЃϖԒȊȉʈ򕒔ɉɈŇϚΌ߀ЅŒȊƉц̅ˈˆˑΕ‘ʼnňЅˇȇ˖獂ĉ߀Ѕ͒ĊƉ톇…߅̈ΕÑʼnLjօĄ℟̇ȇњÖ捄߀ЉÒ֖ÒˋʅĈđĈ؄Ƈ햬Қ–䍂ԉ߀ЋԒӖÒˋ܆È푰ȔمƇ얰Ѝ䌆č߀БВǓɋ׆ˆ􉷈ʑ蔢ˊօɖōЊԍ߀ВϒȓNj톇ن +Ñ锞ʊׅÇ–֙ԍЊ֍߀ЕŒ镚ߊ ̆ᆂŐ݅􅆆ڊЊˌʍ߀ЕƒĆĐ̅ʅ숆ڊˌˍ߀Еڕڊ‰чȒ҉ˆȗލ߀Е͓يÉ͇܇ЇȒ”Ӊˆ͆ӆ׈ȗ߀Г͓ȑيˇ釚扄̒ˆԆ˗Ǝ芐ڍ߀Гӓ؊󇞈ډΒǏӉ͆󆘇䈄͗ƔŽڊ獂Ō߀ГԊ򇂆߇҉ĉ҉҈⍂񍘌߀ГԊԇȈщؐ ĉ򆃅ȇшԕՍ߀Гڔ͊ʊɉ؇ψ͉ŠؐۓƉʈۆԆ̇̈ؕԘ׍ō̋ÍӍ߀ДՔȊɉӇЈˉŊؐ㓅Ɖʈ܆ӆЇ̈‰ٕƔ‘؍΍̋ҍԍҌ߀ИҐЊƉƈȊޓԏʼnƈԆɈژđ͋Ӎ߀Г䔂Ӑъʼn􇄈ƈȊƉƈđڍʍ΋Ӎ߀Џ֑␄ΊɈŠԐ͉†Ƈѕƍċۍ߀ЎבᐄΊŠԐΉŇՕōċӍ߀ЉƎڊ臂֊؉ݐݒωܕܗ’ō؋Nj̍߀ЉŎ܊戂臂֊׉ݐԒщ凃Ӊوܕӗ’֋ʋʍ߀Љޓꐂ͊؈܇ljҒ䇄膈ˉֈїȒÍɋˋǍ͍߀ЉГꐂԊڈڇˆƉ䇄↉ˉLjЗȒˋǍ߀ЋÑ̓󈃇ӇҐ꒴懄߆􉄈ҕ ȍ߀ЏÑē󈂇ɇҐВ񇔆ӆ􉄈ΕЗ퍑߀ЋĒΊLjĊ܊ΐʒ‘ɇȕʗ–쌰Ӎ߀ЋĒ’ΊÈÊ̐ĒƏȉȇƕė苃ҍ߀ЊÒȐȊƈՊƐ’ĉƇƉ扂ĕ—΋ьĎЍ߀ЉɒȐȊƊЈֈ֊Ɛ’ĉĉɇÕ—͋ӌĎ߀Ћᒤē󐥏ȊԈϏʉƈƉ퇂͎҇ΌƋˎ߀Ћޒ“󐥏ʊ‰ш鈂ފ֏ÈƉ臆ч񇵈˔͎ŽΌˌƋ̎߀Лސ∏ʈ֊ԏ䇊ȇχ׉͎̔̌Ƌю߀Лؐሏ֊ӏ䇌ȇ·׉Ĕ͎̌ÌƋю߀Йې݈ƈߊ̏ᇍ +⇄ƍڌŋՌ֎߀ИܐЋLjƈኂ⇌̍،ȌԌ߀ЕÐƐыƈ䈊ƊԊĊΊ̇ćԍߌ߀ЕÐƐыLjƊԊϊ͇ȇҍό⌝⎅߀ГڐЋŊԊЊЇȉ׉ ̍όÌ⌺߀Вېыĉӊ ЊЇĐ̍όŒ⌺߀ЍŒבܐ؋̈׊ʋАڑÏƊ扄ÐՍ߀ЌΌ푥ܐًو‰̋ʏŊ݇䉃Ð鎊߀Јڐ؋ŠՈ퉈͊ɏˑƊڇ̔ʖɒۍ Œ߀Јؐ؋Š ҈̊ʑȊ‰ևϔؕȖДȒƍŒ߀Їۑƒސċˉˈ􉮊Ǐ֐đÊ̈ԇ؉ϔϕǒ߀ЇΐƒߐʋƉˉ􉮊ȋ֋ԏ֐ߏĊˈч؉ϔЕǒ߀Їϐؑ̋Êlj򉄊Nj‹Ջ +ʏՐߏĉȈˇĐ˔ҕ‘̌ڍ߀І׌ϐؑÊȉʈ򉰊ȋËՋˏِߏĉȈˇ쉽Đ̔˕‘ ̌ڍ߀Ѓ֌Ӑᐌ勽Ŋ񉂈։ʈ󉳊ɋċԋяܐ኱lj숊̇󈴉ŠÊǔɕ + + Î݌ލ߀Ѓ֌Ґᐌ͐勽։ʈ󉵊NjŋӋې䊠ʉ숉ˇ󈵉Ê֕ Ȏ ፐ߀Ѓؐᐈ̋ȉƈ܉ًҋېƊΉȇ∄ÊϐϕߎΌ쌂񍑎ꎂ߀Ѓؐᐆ̋݊ɉň݉؋ϐې⏉ʊЉȇ݈ĉÊɐ͕ߎΌ쌂掇߀Ѓόސڊ͊쉪Љˆ܉֋Ӌďː܉̉ˈƈLJʐɕӎnj؍ŽɎ߀Ҍސي剮lj݉֋ӋÏʐЉȈƈƇƉʐɕҎ͍ƌ؍ŽƎ߀УÐސʏ܊Ɖ׉ʊ͋Ȑ슎Ή؉Ԉȇʉ֐”ȕ㌂Ս莄Ŏ߀Тʑבސ̏܊׉̊͋ȐŎ߉҈LJʉҊ֐”ƕ򎄏߀ХڋމȊƋ؊㉇ψćވ؉ފАÔÎҍ߀Ф򑄐萐ڋኌˆމي≇ć߈؉ѐȍҍ߀ЗސЏ鋢Ï݈ɇƍ包߀Зݐ搯苢ǐÏ߉艞܈񈯉ĕЍ㌇󌻍߀НƐۊ։ސƏ܉ވȕߎ΍ʌٌ߀ЛƐ܊Š≂ԉݐŏ݉ˈ߈ֈ͉ǕݎЍȌٌ쎶߀Ј؍֑ې̐ڊщŏِ݉ψ݈ӈƔ + +•ڎ֎ڍČ܌ȍ쎸߀Ї؍֑ܐȐڊ⌆揊ۏ⏪܉Ԉ݈ԈƔڎ͎Ï߀␨ܑي‰҉䏋ǐ܏؏ۉމވɉ˔ՔҏꎌƎ썖Œ߀␺ؑي҉Ê 䏐Ȑ͏ۉډ߈ȈʉʔՔҏꎌŎ퍶Ꮅ߀ލː葋ёᐂۊ֊Ċ苩̏̏܉։LjƉ򊥋̔ӏĎߎ߀ލː瑋БÐۊՊ퉝苩茒͏ΐ̏܉׉ Ɖꑑ˔ҏĎߎ߀Єߍܐԑӑӊ؉҉ĊߌЏЏʏى҉ህ̉ኯ鑑 甈Տ玊썱ÌϏ߀Ѕސّӑӊω։ +Ӊ܋ϏяʏƊΉ׈֑̉הՏ莊덲ݎЏ߀Ѕ荛ǐĐ +ȋ׊ӉՉċЌÏҏNJщˉЈԈʉ䊳ˑ”Ҕ莈ݎ߀ІǐŐɋ׊щ׉ċьÏϏȊɉʉшވȉ”Ҕ؎ύݎ߀Јō֋ڊ߉Əŏӊ݈숃Ɖ”Ŕ֎čގ߀Ј֑ċيЏƏԊ툂ʼnŔčގ߀Љᐂ쐅⑧ċΏԏŠ҈툠ʔΎčގϏ߀Љ쐆㑭ċ񉂊ЏÊ҈∠ٔčƍюӏ߀ЇݐݐˑNjʼn݉NJ숂∘Ҕ +čĎ߀Їݐݐˑ܋ʼn܉NJވєÍĎ߀Ћސܐꑩ݋ȉʌꏞޏ܊ňވĊōƍ܎߀ЋސܐꑬދÉˌ菟ݏ܊Ȉވʊޔčƍ܎߀Ѓ㐸葮ۉҌ܏Ő֊鈆߈ōێ߀Ѓԍ␸葮ډÐ׊߈ɉՊݔƍڎ߀Ѓ鍃͐Ցˑ⑧ŠۉЉ댂͏ΐɐÐ鋡߈ʉՊΔʍč؎߀Ѓ荃̐ӑ⑂④錠ȋىЉŌΏʐʐ苢ʉ ̍֍Վ߀אȑ쑂ۉЉnjА͐狚ֈΕʕčÎ߀Вאȑ쑂ىЉŠ ƌڐڐ狚ֈѕ͕č߀АΐϑҊ҉Ԍؐ싆ĉՈňۈ늺ꕅҕ܍ +߀Аΐ БӊՌǐ싆ʼnƈ눰ꊼƕ֍ō߀Бʐّۑ֊׉ƊތɐƉƈ؈։Ћ둂ɕƍꍈߏ߀БĐؑۑ׊ ؉NJ֐׉؈Չыē˕ȐǍꍎ߀бƏۊىԊ،ĎӐމ҉ۋˑȓ͕ƍ̎돳߀бƏ܊ӊ،Ǝѐ剑҉ڋđ ɓ͕яƍҎ͐߀вǏؑč܊牂׊܌ɎԐىህ׉ۋÑԕЍƎޏ͐߀гǏÐܑƍ݊؊܌ŌǏސ쐈܉ህ숂ىڋÑԕЍƎޏ͐߀еŐڑÊ扔艐ߊ܋ЌƏސ 萄񊂉܉ʈ숉ÉߊЋ Ĕߕ蕄ɏՍȍɎ͐߀пƐڑƊ剓艐ۋҌƏߐ琂 爒߈ĉڊϋđĔߕ畄΍ȍȍɎ͐߀пΐϑ̌銩܉ًԌŒ͏␆֐ȋ퉄‰ÉيӋÑʔ•֕Đȍˍ̍ȎԐ߀пΐ‘Α⍌犩؉ً֌Ώ搆ʐ̋‰‰܈؊ԋőݔȔ•֕Đȍۍ̍ŎԐ߀пؐʑɍÉ֋ό֏𐓑ː茎ĉňÈԊڔ앇֕ǐčՍލܐ߀п̍֐ȑ΍׋ߊ׋ߌ֏Аː猏ʼnňˆъ‘ٔ”֕ҍލŽސ߀ЙʍԐȑЍ؋ߊÉÊԋ⌰ԏˏϐϐ挶򊉉߉ˈ≄ΊԔ͔Ε̕㍜Ď߀ЕэԐǒȑ̍򋄊ފŠފ؋⌰ԏˏϐ̐挶򊊉߉ˈމ͊捜Ŏ߀Еۍː䍌ڊȊ֊ыጮʋމƉԉҊꍚǎ߀Е؍ǐ䍌׊ȊԊҋnjȐʋމljԉҊŒ߀Їƍȑ׊̊ ՊϋƎꐤ茖扚ʈԉҊ╅瑤厍܎߀ЅՍŏȑ؊̊‰ϋٌȎ쐣牚ʈԉԊŕ‘ǎێ߀Ѕ֍Ǐ͐Ƒڍ抖‰ĉՋیǎ쌎߈ňڊÑÕΌ߀ЅՍȏ͐ƑڍՊ񉂈ĉًڌƎ􏃐ڌ߈ƈĕ̌؎߀ЅӍ쐄ӑ +މƉߋ،֐҉ň߈ƈފ⎆ŽՎ߀Іԍ됃ґ틑މʼnߋ͌،ՐĊ剅݊ϑՎ߀Љ؍ɏˑَ݉؍񑂐֒ҏ֎߀ЮƏ̑Ď݉׍֒ӏ֎߀ď됂摚Ύ勏މ틝ƐύÉވኔőŕВʏŽ쌝؎ ߀ʏꐂؑЎ勏މ􋜌ǐύ䊑 ‰ꊔƕΒȏŽ挂َ߀З獄ܐ׎ً􉽈ȌΐӍފȑ敆ɏ̍Όَ߀З̐֎؋􉾈ӍԊȉߊȑʏ̍ˌێ߀ИˍҎ̌Ջ؉ċ،Ѝ؊‰ֈ‰Šȑ“ߎՍʌӎ߀ЙˍюԋËԉċ،Ѝ؊‰ՈɊʑ敂Ώߎ׍ɌΎ߀Ӎ瑃ΎӋ̋҉ċՌ͍ኞĊۉЈ‰ߑڏ ێۍƌ߀Ӎ썓둆Ύ܋ы̊ËՌ܊ŊۉЈ‰Ƒڏ܎ɍƌ߀Н̍⑌Ў֋Nj͊‹Ռŏ׊ډȉŠԏގێэʌЎ߀О鍒ɑЎԋŋъ‹ՌŏŏэՊ≊ʉŠΏގڎЍnjώ߀ЍőǎЋދԊҊ ŒĐǍӊމԉ’Õߎʍ߀ЌǎŒЋۋԊҊĐƍҊ‰މԉĒ•ƏʍЎ߀Ѝ쐈Î΋Ȋ͊Ĉ +̍Њ̉ΉӇܒ•厃ɍČʌЎĎ߀Ѝ΋̊ՍʍΊΉܒюɍʌώŎ߀Аܐ ̋ЊٍؐōʊىՒו΍ʎ̎߀Бېבɋ׊؍֐Ȋډ凙֒ϕ֕΍Ԏ߀Ў֑̍ʋъ܈‹ٍȌʊˆۇ֒Ȏč߀Џ֑͍ɋ‹ۈɋ؍ʌʊ≝؇ђ掴Í߀Г +͍ȋ㋍ڈӍΐӐ֌ʊ牞Š܇Ԓ͕̔ҕȏ⎴ώ߀ГґŽ΍ȋ䋌ڈЌӍߏҐ֌ъ㊍̑ђʔҕȏߎҎ߀ЙԎӑŎ‹Ȋ拶ۈӍᏃҐɍÌŠ艕NJއÉʑ̒Ȕѕ‘ďю֎߀ЛҎґƎȊ拶ۈ͌ ҍ㏄Ґ΍Ì؉鉓Ɗ߇ʼnǑ˒ +ʔ󕳔‘ďЎՎ߀Пǎӑ֎֊ɋ܈Œ͍ӏҐ׍ՉȊђϔҕƑҎ͎߀ЍƎ琏Ƒَ֊ȋˆȍҏҐٍ։Ȋ͔͒ҕƑ׎̎߀Ћʎ搉ڎ̍݊΋čʐÐƍˌЉˊŒɕÕȑᎫێ߀Ћʍ搉ÍNJЋčʐÐǍʌΉˊɕÕᎪӎ߀Ћ䐌򎶍􋬊ΐݍ􊬉lj͕̐֎ю߀Ћ同Œΐލʼn􊬉͕ՎЎ߀Ћ荋搈ÊČϏ䐅󊩉ƏЎ߀Ћ捋搈 ŒЏ␌􊪉╌Ǐώ߀Щ㍏𐆑䌊ΏӐэĊljő̒̔ҕǒҏ͎߀Щ⍍㌉ΏҐҍĊđ̔ҕȒꏠˎ߀ж草񐄑 Ǝ슂䌆Íҍőʒ돠ǎ߀з􍈎ɐю슂ƌ匆ȏՍ ȑ”ʒ쏠Ǝ߀йŋŌ댂А׍ꉎŊёЕ߀йБ +ȋ +͌Ґ֍鉎ƊБ쎂Ž߀йґЎ؋㌂ɍ鉌Ɋ͑ƎÌǎ߀ۍӑʎČۋ㌂ٍ牋ي瑨ŒƎ߀э +ō؎ϋ挻ۍҋЊ味ǎ߀э +َӌЋۍҋĉډъޑ꒳ƍ玅Ž߀Ћƍێ֌銋 +ً鍫nj҉؊АĒَ߀ЋǍێ䌛ꊍ؋Œ鍪ŌË҉يʐĒێᎊ߀Ќ׍Žڎی؋ČЋŌ덦‰ڊъɐƒێǍ⎌ˏ߀׍Žڎڌ׋ƌҋ֌덦يËҊȐڎ܍䎌͏߀Ѓ䍤Ҏ܎Ќ֋ˌʋ܌ڍՊƋҊޑ؎ڍގ׏߀Є䍣ݎČċ̌ʋ܌⍯ԊʋԊߑ͍ߎ֏߀Ѝ⍨܎ҋ͌΋׌ލҊȋƊ䑂唷ˍގՏ߀Ѝ⍥ݎыΌ͋ċ֌⌢揺ڍЊȋŊޑ‘ʍގ֏߀Ѝ䍢΍Ő܎ϋΌ̋ʋ̌化 ďߏ؍Ԋŋ̊ˊ葅ƑݍԏƏ߀Ѝ䍢΍Őݎϋ͌ˋʋ̌؍ӊŋŊʊ鑄픆Ǒ܍ӏƏ߀Ї덓ȍȐʍՋɌʋ܌䌂荫Š̉֊Ȋדȓ˒Ƒԏ߀Ї썒䍅ΐŽʍ֋njʋތ䌂⏎񍬌ƌŠlj֊͒ד۔͓˒⑑׏Ï߀ЈÍ򍖎 㐑 ÌƍŽ܏ˍČ܉Ԋđ̒Ǔڔʒҏ߀Еč򍖎Ώ ƌō ܏̍Ō׊ωőВٔʒҏ߀ЅŠ̌􌊍ߏÉƋђ֔𑂐ҎƋ߀Ѕ +Šی‰틚̋ԑюNj߀Ѕ񍌎팞򌈍܏ꋡċ͒Ցɏ߀Ѕ򍌎Ўߐ򌈍֏΍ފꋡ̒ː߀ЅԐދ팣Ќ΍É싢 ˒֐߀ЅҐ͊쌤Ќދˌ΍닢߀Ѕፃΐގዽȋ茦쌄 ΍ފʊ㋢܋㐌ȑ߀Ѕݎɋ挡쌅ڋЌŒފȊ⋠ۋ܊吇ɑ͏͏߀Ѕčȋ挛ًnjnjˍ +܊ߊ܋̊Ȑ̑ȒҏĎޏ؏߀І ƍˎދ܋ڋ̍ +܊ۊԋ̊̑̓̒͑ЏƎݏ؏߀Ўތ񍆎Ɏ ߋ슅܋،싊዗؎ȍފڊՋЋ􊅋Ñʎ؏߀Ўʎ늅܋֌싉싗׎ފۊՋ‘ԓҎُᏂ߀Љ茣勆ًԌȌ싋򌆍ۊыƋ񊆋ΐ摊͓󑤐͎ԏ߀Љ茣勄ԌȌˋ񋒌򌆍䊆ڊыƋ򊆋א Ύ؏߀ЉÍ׏؍ƋьČ̋͌Ď܎挂ߊЋ ҐꑂʓߑЏӎُ؏߀Љ錔ۏ؍̋틵Ќˋ܋ˌĎ܎挂ˊ͋Ґᑂ ߑя ӎُُ߀ЋڌŏԏӍ̌‹ƋȌꎃӎʌ쌗ʋؐʑ̏Ҏ߀ЋٌƏӏӍ̌‹Ћʌ،ʋאȑ̏Ҏ䏂߀бԌڍҏՍߋԌċыꋄ̌֌ԊҋƏ֐ƏՎڏŽ߀ӌ ڍǏԍ܋֌Ëы鋄͌֌Ҋ̋ݐ꓉䑄֏߀Їʏэ̋ӋՌیꋘ쎈Ԍ֌ӌ񉅊ˊËڐĒ摃؏܏߀ЈǏэՋ̋ӋьیꋘꎊՌҌʊ ސ葃ȓĒ㑆ُ܏߀Ј鏇ύЋϋ늆ˋŋƍȊ 琂葇Ɠ’ޑ߀Ј友Ѝϋ݋ʋƋҎƍNJNJĐ葈Ɠ’Ǐ߀ЈŒ㏏ˋ֋Njڌċōǎъي艚ԋNJ瑈ēĒ߀ЈÌӏˋˋˌċȍƎЊӊNj瑈ēג󑃒ɏ߀ЅˌŏێċϋȌŋٌ΍͊Ҋ +Ƌ葄ђߑ뎄Ďʏ߀Є ď̋Ȍƌ͍؊ +߉Ƌ葃Ғߑ率Ď߀ЅƍɎƏҍы݊ʌˋČՍ䌠̊뉅ȋ 䐆ޑ +Ӓ +͐⎈Ď߀ЅƍэЋߊʌˋČꍛՍƋ̊ꉆȋ䐆ݑՒ֑ːߎĎ߀Ѕ ҌÌ΋͊ČË̊扐Ɗ‘đǐˏԎǎ߀Ѕ㍆Ìԋ̊Čċ̊։ƊՐđȑȐʏԎǎ߀ЂŒЌ֋Ɗ؋Ƌ덂̋̊ʉҊÐԑǑʐƏЎώ珋߀ŒҌՋƊڋNjꍂ͋̊ʉԊ抃ʑؑƏЎԎ珳߀ЉČ鎂ÌЋƊ⋇심΍ŒҋʊЉ؊Ç䊂݊ƒڐď܎ُߏȏ߀ЇČ玊ŒЋÊ䋅鍂΍ƋʊЉڊĊƒڐ܎ُȏ߀АČ莊ŽÌɋˊϋڍЍɋȊ͉Šć슂ސƒڐ ݏČ߀Џ뎇㎉ƎÌɋˊ׍Ѝ ڋȊ̉ć슃ъɐʒِ܏ÌÏ߀Ћ܎펅ĎΌČʋʊ̋܍ߍыɊˉƊ܊̊̒ڐގڏƌ߀Ћ܎ÎʋɊ‰ދ ̋ڋ؍ፇҋʊʉƊВܐ􎂏ڏnj߀ЖŒˌ܎͋Ċˉ̋׋ы܍ʊȉъĈƇɒ搎֏ȌЏŎ߀ЗnjɌȋ݋̉勈׋ˋ׍ˊȉЊÈȇɒ搈֏ɌՎ߀ЗČnj׎ +Ë􋚊܋΋퍂NJ؇ƊۏǑ㐃Žʏʌ߀З򌄋Ɍ؎Ž +Ë􋶊Ћ΋ڍƊ̇ۏʑŏʌ߀Ж +׎Ì҉̋֋ҍÊňӏ ՑՎǎ͏ʌ߀ЗˎꎂÌ҉Ѝň􊄉ԏۑҎƎ͏ ʌ߀НތΎŽŒӉNJ􋔊̍ŒƉڏ ő됂ȏ匙Î߀НȌɎÍŌČԉȊ򋕊͍ ŒƉƉ슂ڏʏތŎ߀КȌɎˍԉڊȋċȍˌĊʼn㊟؉늍珄͐’ԏ̌ގ߀ЂɌ Ɏċ募ԉۊ ċȍĉኟމ늍珄ߐΒՏʎŎ̌ގĎ߀ЂًȎ݋ԉ스Ƌʍۊֈ䉚吂鑒̏ĎȎˌ䎂Ď߀Ђ̋Ɏ͋܋׉슠ʍڊֈ㉛揂搂ɒȑѐɏ掆ڌ䎃߀΋όڎǎ茊΋拢㊝ȋϊ̋ˍȍ䌜닃ӋЊۊ͈≚늆ڏȑؑؐڏᎌŽ߀΋ΌڎɎЌ΋拢 Êދϊҋˍɍ⌝닄Ջˊ㊘؈≜튄ǑȐِ֑ގŽ߀΋ 􎆏 Ќċ􉆈Ɗ֋ъˋ܌ߍʍތҋЋĊي҈扛呯Β‘̐ԑڐڐ茺Ď߀΋Ќƍ̋ˉȊՋЊˋ܌퍂ʍ‹݌ԋԊيЈ剞򊄉摯Β‘̐ԑܐ茺Ȏ߀͋䍫͎ڍԌ΍􌎋􋂊努ŋϊNjƍɋ֌ČЊ扨֑ؐΒؐґ֐ÍƌƏ߀΋ߍ͎Ŏƌ܍獑⌌ы犩ŋNjōʋ֌͌Њ 牢֑ؐؐאᎿŒǏ߀ЬŒݍŎnjۍɋԌҍȋ茒ˊߐǑݒ’ߐĎȍЌ߀Ыnj܍ƎŽȌ񍆌ɋΌ ȋ拃파ЋĊőܒÒ␎ĎčԌ߀ЫɌ̍Ɏ֌׌ۊ׋ˋȌڍǍ狄܋ȋ̊ӊƑ䑊 ߀ЪɌ̍ʎ،،ōލ֋ɉ֋͋Ȍȍً̊Ҋ˒摂Œ߀Шό펉ɎČ֌̍ь׋ƌҍ֊ȒĐŒΏ߀ЧόӎɎŌ ؊׋Č +׊ՐȒÐƏŒ؎Ώ߀О͎Ì؋܋ČՊ݊đ̒Ր퐄ƏˎϏ߀ОώÌόŒ؋Ì֊݊ɐՑ˒֐ŏ ˎϏ߀УƋ䌐Čȋ݋ĊȋÊϋɋ͊ʼn銉Ȑ͒ƐϐБʎď߀УƋ㌑㌅ʋ򋚊ĊɋƊ͋ɋϊƉ؊ȐƐϐ͑ݎюď߀РċčŽčό⋎҉ӊċĊތŒ‹܊㊗ +ꐄѐΑĎ֏߀МŋȍŽč،⋍ȋԉҊŊƌŌڊŠψꐆҐӑĎُ߀Л͋Ď莉ݍڋ߉ڊ݌؊󈅇Žڏِ蒅鐖ɐُ߀Л΋ڋ݊ŠŌ⌂Ԋ􈄇Žېđݒꐖɐđ؏߀ПǍ拂ފڊ Č⍌䊉수މȊёȐԐȑ⎓׎Տ߀Тō򋎊뉛⊊ڊČ ڍ䊊舙扅܉ԑӒԐđ֎Տ߀Оы劊 +֌Սˋ +㊂Ȋ扆ޑ֑ÐĐđ׏ӎ֎Ǐ߀НčЋ犊׌ʍ⌆ˋ㊂Ȋ牅䑭쑃ĐĐđď̎Í 쎐Ə߀З̍Ō͌닄΋ ۊ猴팠ƋċኂȊۏ䑪ːđ͎č܍ŏ߀З̍ߍČČ鋇̋ۊċ‹䊂 󉃊Ɛ̐Ñ̎ƍŏ߀ЙǍŌԌ匭ɋ؋ NJȑʐΏđʎˍ捄펐Ï߀М䍰Ԍڊ䌫ʋԋ􊊉NJ鏂ȑϐΏȎ̍捄펐߀Щ؍ƌ苅Ћڊی̌ +͊ڏޑѐƐЍፘ߀Ъٍ؍苅ҋ܉ڊیЊʼnڏ⑚Ǒύፗ߀̌Œ捞ȍɌŊыƋ挕҈ӉԏʐȑƐፔڎÏ߀̌Ì̍ȍΌ‹ъNj猒҈Ӊُɑʐލ؎Ǐ߀ތʍٌ򋓊ϊ䋎ыȋ錅ያ⌑􊅉͉폃ΐݍƎ߀пƌċՊ㋓ ҋˋٌ؋⌑Њ +̉ڊ􏆐񑃒Ӑݍ߀Юь̌މ̊ފڋÊ׋֋܌Ŋ݈ɉ݉يďԑ쐆쐂̑Ӎ ߀Ь֌ό͋̊܊ڋ؋֋߈ډيďƐ쐊쐂̑ҍ߀Ч⌇̌ۊ׋ ‹؋ً܋ъۉ׊ՐÑ΍ҍ߀Ч +ˌ݊ы ˋ؋܉ȊАđЍԍʍʎ߀ЃόɌ̌‹䋄̋艅ď͏΍ȍ߀ЂόɌ̊銇㋆ʋ珏΍ҍɍ߀Ї̌Ɍ 뉪苂΋닚ꌂ䊄ŠϐǑđ +ˏߍ߀Ї̌Ɍ􍲌Ћ鉫ꊪċ틃ꋙ猄Šѐؑˏߍ߀Їی񌉍덵щŋ拈؊݌ڈΐʑ߀Їԋ⍂ы슌ȋ拎Ƌ̋ފ܌ЈېԐʑ߀Ѕ㌅Ԍ֋΋ʊˊԊ̋ۋ΋芴Ë܌劈Ҋ󉇈߉ѐϑӍȏ߀ЅӌЌ؋ҋˊኂ튿΋ʋ 銵‹܌抈Љ ϑ䏃ďҍȏ߀Э̌ˊԋ‰̉ΐ +ˑÏΏ߀Э̌ċŠˊԋ‰̉ϐ呂ɐΏ߀ЧЌʍË֊䋘nj֊ېʐďЏ㎓߀Х׌ό򍞌ŋ֊䋘Ȍ͊ߊڐ̑ ʐ 􏂎ҏ􎖍 ߀Ы댈׌錃ԋފˊ䋅؋Ռҋڊܐʐޏԏ֏掛Ď߀Ы׌ꌄꍠԋފʊ㋅ڌҋۊމ̉ܐʐʏ֏֏Ž掚Ȏ߀Ōیڍ䍨΋׊̊ዄ싦‹ӌފݐ搯ΐޏƎ莐Ȏ߀Œ܌ݍ錏͍΋ˊΊዄދԌϋ݊ܐԐ搦אɐꏂ󏍎Ǝ玐ǎ߀ь茗ڌ׋ċڋΊڊЊ܊֊Њڐ֐ȐÐǐ쏄ڏ펑؎Ǝ߀ጃڋ̊؊̊񋖌݊֊׊Ґ͐Ð폄ڏ厑֎ǎ߀ЋȌ׊Š㋅䋂΋‹Ê҉ʉƐǏ֐ΐАϐڐˏ֎߀Ї݌ȌÌ닃䋂͋Š슄Ӊ׉‰̏֐ϐАϐ̏掔߀ЇNjČފ͊Ƌʊŋ䋅튂艅ɉӏϐӐ߀ЇیȌNjnjnj̊ŋˊӋ튂ȉďԐЏϏ߀猂ٌҌŠ׋̊㋄̋‰ʉߊԐѐǐ̏߀猂،ҌҊŠ勄ȋ‰ʉِ̐Ɛˏ܏߀Б䌚ȍŌ̌Ί鋕ʋȋ鋋ʋቆΐŐ͏֏ǎݎÏ߀Б䌙͌ɍŌˌЊΊ鋕ˋʋދʋቄʊ +ΐŐɏՏǎ܎ŏ߀nj֌ʍ쌿Ȍƌ֊ƊԋNjΊ׋ʌ‹ċ֊ىljҊŏ̐؏ď掊ĎɎ߀ɌҌˍōČȌ֊ԋƋ݋׋ʌNjƋ؉ljԊď׏̐̐ސُĎȎ߀Œ匜ό댄ȌˌȌʍό׊ҌËԋ⋬ډԊЋ܏ϐՐѐЏŽǎ ȏ߀Ѓ㌞ьȌʌҍȌˍΌ؊ъԌ΋ҋ̋Ӌ㋩ۉ܊ЋڏÐАՐҐԏюȎۏ߀Ѕތ猂Ό΍ʍ؋Պɋ܋㋉΋‹‹ِՏאʐΎ܎Ɏ߀Ј݌Ό͍؍Ջ؊܋䋉ϋ΋Čؐ֏אʐ͎܎Ȏ߀Э܌䌉ˍߍ茗NJËNJċ苂ԋ勂Œ싅ЌЋՉӏĐʐՐď֎Ў߀Яٌ匋ɍ䌏ŒȊ‹ċNJ‹ԋŒ싄ΌЋ鏪ďꐊԐߐ萐֎Ҏ߀Ƌʌōލ؊܋ϊ݋拄ɋ⋂鋄Ћ󏞐ŐՐ֎Ȏ߀ƋތɌƍъۋϊ݋勖NjƋމ􏝐Ȑאϐ +ߎǎ߀ˋ͍捣̊Êދ݋ߏҐɐ񎄍ꎆŽ߀ҋ茂͍獣؊ŠދڋČߏʏĐҐǐҐԎ߀֌ߍӍՌ芅ዃnjڋኂ揰Đʐ쎍Վ߀ՌꍄǍڌ芄ًӌϋɊ菲ŐĐ֐鎍֎߀ҌЌȋ􋂊Šȋ‹ՋӌċыދɊΏː琓׎߀ʌҌȋĊɋՋЌŋ׋ߋɊӏĐǏʐ莂߀⋂׌Ҍˌ݌݌ˊNj̊͋Ƌ؋쌘Nj̋节󏌐̐؏߀⋆Ō ‹ӌ󌂋ˌ􍑌ƌߌ쌪͊ʊዄ Ë̊̋Ëŋ዆ԋ͉节͐؏ΐ߀ߋ΋֌ŒٌƌNJኈ׊Ë̉ЊېɏȑЏ搂ԐˎԎ߀ߋ֌،Ȍ֍ ÊЋኄ +Ԋۊċڋ򌐋ɉϊ֐搂ϐԎ߀ƋŒԌʍ،ΌꋶƋӋȊҋʋЌҋҋߏ珂ސґʏώ߀󋃌̌ŋ׌ʍ،ҌꋴÊϊҋ㋛ь֋ҋƊߏ揆ґ؏ŽՏ߀닅ŋ򌞋ӌڍ،Ȍ֋ۋˊӊۊڋ⋄ЊƊҏЏ揂񐂏Ïގ鎒Ďۏ߀Б׋ČދҌɌȋ݋ˊʊ ֋⋄ʊÊЏ֏ڐߎ鎓Ɏۏ߀ЋՌҌ댉nj䌳狃ȋڊ犐䋈ꋄʼnӊފÏÏ ҏِꐄЏ뎍׏߀ЉՌ틖 +Ќƌ匲ߋϊꊐ䋞ꋅƉlj݊ď͏搏ҎՎΏ߀І닖ԋӌŒŋ݋Ȋ񊋋把Ӌ֊ʉ؊Џޏ֏ĐƏǎݎϏ߀І싖݋Ҍ‹ًɊኊދފʉ׊Џ܏ґ׏ǏƎˏ߀ЅƋ㌂틝ȋčߌʋɊ֋ҊˋÊފʌ錈ЋҊ䋈ۉኆ̉ӊԏ؏Ƒ쏆ƏɎɏ߀ЅƋ̌ŋčЌ̋ꌵ؊̊΋ъʋĊފ򌉋񊆋⋇䊅҉ʊ菑֏ Əʎȏ߀Ѕ؋ԌˌË錂⌍NJ̊ɋъ֊Ӌԋ틏܋͉Ȋ؏̐ʑҏꐆΐÎ߀ЅƋ֋Ԍ̌܋ ɊʊъÊԋՋ싖ΉNJُƎ͐ʏ琊ϐǎ߀ЅҌ쌄ыيԋҋ׊Ë䊊Ϗݐˎ؎Ə߀ЅЋՊ̌ۍԌ⋅튚։‹ԋ׊Ëފ掌Ϗܐ؎Ǐ߀ЊԊ⌈֋򍦌̋΋؉䊖ٌ̊̊ۏˏ䑮͏ߐߎ܎߀ЋԊԋČ̋΋؉܊܌̊ۏˏ呯ސ̑ގߎ߀ЄҊʋ̌Ҍьˋ⋰ߋ֊ꌃ̋ċ،̊Əۑ됏ێ߀Ѕʋߍό拠芳ۋފ錄̋ʋ׌ʊ抎בڐَ߀ˋÍ׌ŒŒ⋂苓Ɋ򊖋ތϋዷ̌芈ؑːݎ̏߀ʋǍ׌׌挈틌򊈋Ɋƌϋ䊂늅Ƒ͐ᐛ̏Ώ߀ċȌҌ򋄊ꊎϋ݋Êҋҋҋ׋䊂я둂ΐ掋ȏ֏߀ɌȌƌꊎ΋݋ыҋьފꎎÎ׏Ï葄ΐʐ̏ۏՏ߀ЧČЍŒʍΌ؊Ћމ̌njԋމˊǎ +ҏȐڐȏ߀ЦҊÌ׍挗ʍΌ֋މnjی‹ njԋЊǎҏʐ󐇑ސȏ߀С򊶋ɍ̌식ډ򌆋狂֊Ҏȏ͐ݐ揌߀Нߊ󍃌̌ƌ식ĉ슐 茑׊ӎȏُ߀Ѝ +ȊҊɋnj錇䋃ӉډȊЋ鋂拈܊ŎۏƎՎ߀ЍъҊ͌茂܋ӉӉЊЋ֋يŽ揉򑄐ӐۏƎʎ׎߀Ўϊъ升֍󌗋̊ϋщ҉ʌΉΊ͎㎈菅ʐǐĎ莄߀ЎʊÊ ፅ֍͊񋼊щ҉ʌыщĉߎɐǐŎ莄߀ЌϊËݍȍ䊄։򊐉njҌ܎ϐ搃Ïʎ߀ЋЊċڍ͍劂ډ򊄉Ê̌ƌڎڑϐ𐆏ؐ̏ʎ߀ЅڊԌōŋΊ ΌČNJ뉆 ̎ɏĐՑ͐Ï߀Ѕ݊ČΌčƋϋ犈ӌ鉈 ŽՏƐЎ߀эč׋鉑يꉐԉގΏَ̑ڎ߀ՍŒÍ񋇌芒鉐֊NJӊΌꉐՉގڏ󏸐َ͑߀Е⋄ލNj㊤ˊŠЋɉ菟ᐊȐҎ߀Г䋄ˌЍŊΊыŒ +폚ᐊȐЎ߀Ѕʊ쌓܊Ή ߊ܉㎡яߐ Ў߀Ѕ̊쌓؋܊ӉӋߊ܉⎢폵ɑǐԍ߀Љ勂؋Ȍލ֌狆ϊ튄ኈی܋ȋȊ銡щُ󏲐‘ΐˍ߀Њȋ͌ݍی䌶닅ΊыьŋÊߊ牉ωڏ󏲐Ԑ⏂Î߀Џ΋ٌލ댃͋Ċċ،ԋފώԏЏϏُؐ؎ˎ߀Ўŋڌ܍팅ꋄЋÊ،ԋފ͊ЎʏՐď܏쎚Ŏ߀㋢㋫Ռݍ錄ً܋㊪ŠߋÊՊЊ܏ÏΐĐʎҎߎ߀Ӌߋ܍ŋ挄֌Ë܋‹⊑݊􋃌̊֋ҊՊÏ󏵐Ϗ돆ʎ߀ы̋ꌆʍԋ͊􊌉‰ˋΊ􉍊ˎ揇ᐃ͏⏖ʎ߀ыȋĊً댆􋮌ˋԋ͊ˊ܉䊟ϊ牑֎䏇理取ʎ߀ߋꋄÊ􋎌ȋNj䋄勠苂ӊ׊Ӊ򊌋ʊϊ̊⊧É䎎玄Ȏ֏߀ߋ؋Ċߋʋ΋䋄ӊ֊׉݊ƊЊ̊⊩ωʊ厃ю̎֏Ď߀‹򋊊܋ꌼߋՋNjĉ݊Ɋ授ԎӐюЏߎۏ߀܋ϋɋ䊍ފ勇ÊĊɊ⎄׎Đ󐿏ҎяĎߎۏ߀Ӌċ슆⌉ȋЊወ슂ɊъʏÐю߀늋ȋӊË슊슂͊׊ˏ䏂ӏЎَ߀Њ拟ދԊȊԉՊ򊊋׊ډljŠݏҏ􎬏Ž󏉐Ǐԍ߀ϊ􋖊ދЊԉʋ加ߊ։⏇Ȏ⏄ώ߀ÌԊϋꋄƋ򊃋߉؉ڊيŎʏޏ厸߀Н،ߊ؊ꋃ͋׊֊掸߀ՌÊċŒЌ㋄ы‹ʊ֊ː֐Տ؏Ǝ߀֌Ɋ͌ȌՋʉыҊːِ؏ŎЏȐ󏂐ԏ 򎉍߀ߌۋꌂÌ͋݌‹抂׋ً̉܏ҏƎᏴЏɎ߀ʌΌˌ팭 +ϋ܊ˊߋ܏ߏ̏ޏ֎ꎄ߀ċӋϋ܉Ԋ׊܋珌ې鏰Ǐ߀ЋԋՋ֊狖ԐՏ߀ߋތ̋֊א͏͏׏߀،猔ċ􋃊΋񋂊 +犠ʐ򏆐؏􏉎ɏې߀ƌҌԌΌ͌튇ꋂȋ슂ҏ揈׏ +񐎑߀ڌ͌ي銢ʊҊۋӏ珇ېϏ߀،ÌӋ勆׍ЍόËƊ苂ΊꋪՏŐՏÏʐڐ߀׌؋Ȍ䋆֌όҋ䋆؋돎ǏΏʐ߀Ό͍Š΋ԊŠȐҏǐݐϐ߀Ό͍ŒÊ΋ÊӋƋ߀ɊċÐ񐎏Ɛߏ򑇐߀֋؍񋌊ŋÐݏ߀ӌݍƐ߀匢ލߋΌŐ߀ߋߐ߀ \ No newline at end of file diff --git a/bin/library.dat b/bin/DefaultLibrary.imogen similarity index 97% rename from bin/library.dat rename to bin/DefaultLibrary.imogen index 1389847e..5bd474ff 100644 Binary files a/bin/library.dat and b/bin/DefaultLibrary.imogen differ diff --git a/bin/Documentation/Examples/Example_AO.png b/bin/Documentation/Examples/Example_AO.png index 1d4e439c..e4b7aab4 100644 Binary files a/bin/Documentation/Examples/Example_AO.png and b/bin/Documentation/Examples/Example_AO.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Add.png b/bin/Documentation/Examples/Example_Blend_Add.png index 33f063e4..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Add.png and b/bin/Documentation/Examples/Example_Blend_Add.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Average.png b/bin/Documentation/Examples/Example_Blend_Average.png index 986a52e6..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Average.png and b/bin/Documentation/Examples/Example_Blend_Average.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Color_Burn.png b/bin/Documentation/Examples/Example_Blend_Color_Burn.png index 3737afb9..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Color_Burn.png and b/bin/Documentation/Examples/Example_Blend_Color_Burn.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Color_Dodge.png b/bin/Documentation/Examples/Example_Blend_Color_Dodge.png index d7182bf5..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Color_Dodge.png and b/bin/Documentation/Examples/Example_Blend_Color_Dodge.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Darken.png b/bin/Documentation/Examples/Example_Blend_Darken.png index f3b93ca6..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Darken.png and b/bin/Documentation/Examples/Example_Blend_Darken.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Difference.png b/bin/Documentation/Examples/Example_Blend_Difference.png index 93a28c49..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Difference.png and b/bin/Documentation/Examples/Example_Blend_Difference.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Exclusion.png b/bin/Documentation/Examples/Example_Blend_Exclusion.png index ca7c1ed6..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Exclusion.png and b/bin/Documentation/Examples/Example_Blend_Exclusion.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Inverse_Difference.png b/bin/Documentation/Examples/Example_Blend_Inverse_Difference.png index 36b897ea..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Inverse_Difference.png and b/bin/Documentation/Examples/Example_Blend_Inverse_Difference.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Lighten.png b/bin/Documentation/Examples/Example_Blend_Lighten.png index e29d720d..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Lighten.png and b/bin/Documentation/Examples/Example_Blend_Lighten.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Multiply.png b/bin/Documentation/Examples/Example_Blend_Multiply.png index 63296d6c..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Multiply.png and b/bin/Documentation/Examples/Example_Blend_Multiply.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Screen.png b/bin/Documentation/Examples/Example_Blend_Screen.png index f9960804..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Screen.png and b/bin/Documentation/Examples/Example_Blend_Screen.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Soft_Light.png b/bin/Documentation/Examples/Example_Blend_Soft_Light.png index fe333e5f..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Soft_Light.png and b/bin/Documentation/Examples/Example_Blend_Soft_Light.png differ diff --git a/bin/Documentation/Examples/Example_Blend_Subtract.png b/bin/Documentation/Examples/Example_Blend_Subtract.png index 9c9d2ef5..d1c1797c 100644 Binary files a/bin/Documentation/Examples/Example_Blend_Subtract.png and b/bin/Documentation/Examples/Example_Blend_Subtract.png differ diff --git a/bin/Documentation/Examples/Example_Blur.png b/bin/Documentation/Examples/Example_Blur.png index b3b36ceb..aa3a5633 100644 Binary files a/bin/Documentation/Examples/Example_Blur.png and b/bin/Documentation/Examples/Example_Blur.png differ diff --git a/bin/Documentation/Examples/Example_ChannelPacker.png b/bin/Documentation/Examples/Example_ChannelPacker.png index a5c2a1aa..939a0b73 100644 Binary files a/bin/Documentation/Examples/Example_ChannelPacker.png and b/bin/Documentation/Examples/Example_ChannelPacker.png differ diff --git a/bin/Documentation/Examples/Example_Checker.png b/bin/Documentation/Examples/Example_Checker.png index 831d72ee..5924b3c2 100644 Binary files a/bin/Documentation/Examples/Example_Checker.png and b/bin/Documentation/Examples/Example_Checker.png differ diff --git a/bin/Documentation/Examples/Example_Circle.png b/bin/Documentation/Examples/Example_Circle.png index b5bb5439..fae957c5 100644 Binary files a/bin/Documentation/Examples/Example_Circle.png and b/bin/Documentation/Examples/Example_Circle.png differ diff --git a/bin/Documentation/Examples/Example_CircleSplatter.png b/bin/Documentation/Examples/Example_CircleSplatter.png index 2f0787d7..31ffe0d8 100644 Binary files a/bin/Documentation/Examples/Example_CircleSplatter.png and b/bin/Documentation/Examples/Example_CircleSplatter.png differ diff --git a/bin/Documentation/Examples/Example_Clamp.png b/bin/Documentation/Examples/Example_Clamp.png index 2449cf66..63489a17 100644 Binary files a/bin/Documentation/Examples/Example_Clamp.png and b/bin/Documentation/Examples/Example_Clamp.png differ diff --git a/bin/Documentation/Examples/Example_Color.png b/bin/Documentation/Examples/Example_Color.png index 784eb614..4f3c5cfc 100644 Binary files a/bin/Documentation/Examples/Example_Color.png and b/bin/Documentation/Examples/Example_Color.png differ diff --git a/bin/Documentation/Examples/Example_Crop.png b/bin/Documentation/Examples/Example_Crop.png index d29a0e32..d03696c6 100644 Binary files a/bin/Documentation/Examples/Example_Crop.png and b/bin/Documentation/Examples/Example_Crop.png differ diff --git a/bin/Documentation/Examples/Example_CubeRadiance.png b/bin/Documentation/Examples/Example_CubeRadiance.png index fb02c8db..a37943d6 100644 Binary files a/bin/Documentation/Examples/Example_CubeRadiance.png and b/bin/Documentation/Examples/Example_CubeRadiance.png differ diff --git a/bin/Documentation/Examples/Example_CubemapView.png b/bin/Documentation/Examples/Example_CubemapView.png index 9c390a4f..52e01000 100644 Binary files a/bin/Documentation/Examples/Example_CubemapView.png and b/bin/Documentation/Examples/Example_CubemapView.png differ diff --git a/bin/Documentation/Examples/Example_Disolve.png b/bin/Documentation/Examples/Example_Disolve.png index d4ea3e1e..9eb4a61f 100644 Binary files a/bin/Documentation/Examples/Example_Disolve.png and b/bin/Documentation/Examples/Example_Disolve.png differ diff --git a/bin/Documentation/Examples/Example_Distance.png b/bin/Documentation/Examples/Example_Distance.png index 6c4864ff..3006faac 100644 Binary files a/bin/Documentation/Examples/Example_Distance.png and b/bin/Documentation/Examples/Example_Distance.png differ diff --git a/bin/Documentation/Examples/Example_EdgeDetect.png b/bin/Documentation/Examples/Example_EdgeDetect.png index 7dbe36af..568782ae 100644 Binary files a/bin/Documentation/Examples/Example_EdgeDetect.png and b/bin/Documentation/Examples/Example_EdgeDetect.png differ diff --git a/bin/Documentation/Examples/Example_EquirectConverter.png b/bin/Documentation/Examples/Example_EquirectConverter.png index 7963c843..b000005c 100644 Binary files a/bin/Documentation/Examples/Example_EquirectConverter.png and b/bin/Documentation/Examples/Example_EquirectConverter.png differ diff --git a/bin/Documentation/Examples/Example_FurDisplay.png b/bin/Documentation/Examples/Example_FurDisplay.png index 4648ffbb..aa54ca6f 100644 Binary files a/bin/Documentation/Examples/Example_FurDisplay.png and b/bin/Documentation/Examples/Example_FurDisplay.png differ diff --git a/bin/Documentation/Examples/Example_FurGenerator.png b/bin/Documentation/Examples/Example_FurGenerator.png index af09d5e0..48d6c7de 100644 Binary files a/bin/Documentation/Examples/Example_FurGenerator.png and b/bin/Documentation/Examples/Example_FurGenerator.png differ diff --git a/bin/Documentation/Examples/Example_FurIntegrator.png b/bin/Documentation/Examples/Example_FurIntegrator.png index 0382e00d..49a611db 100644 Binary files a/bin/Documentation/Examples/Example_FurIntegrator.png and b/bin/Documentation/Examples/Example_FurIntegrator.png differ diff --git a/bin/Documentation/Examples/Example_GLTFRead.png b/bin/Documentation/Examples/Example_GLTFRead.png index 9e68aa73..9b4ff8c8 100644 Binary files a/bin/Documentation/Examples/Example_GLTFRead.png and b/bin/Documentation/Examples/Example_GLTFRead.png differ diff --git a/bin/Documentation/Examples/Example_GradientBuilder.png b/bin/Documentation/Examples/Example_GradientBuilder.png index 9765fff8..4b01e391 100644 Binary files a/bin/Documentation/Examples/Example_GradientBuilder.png and b/bin/Documentation/Examples/Example_GradientBuilder.png differ diff --git a/bin/Documentation/Examples/Example_Hexagon.png b/bin/Documentation/Examples/Example_Hexagon.png deleted file mode 100644 index 483991c6..00000000 Binary files a/bin/Documentation/Examples/Example_Hexagon.png and /dev/null differ diff --git a/bin/Documentation/Examples/Example_ImageRead.png b/bin/Documentation/Examples/Example_ImageRead.png index 33b42469..086f8d62 100644 Binary files a/bin/Documentation/Examples/Example_ImageRead.png and b/bin/Documentation/Examples/Example_ImageRead.png differ diff --git a/bin/Documentation/Examples/Example_ImageWrite.png b/bin/Documentation/Examples/Example_ImageWrite.png index f07fa500..7d01a1c7 100644 Binary files a/bin/Documentation/Examples/Example_ImageWrite.png and b/bin/Documentation/Examples/Example_ImageWrite.png differ diff --git a/bin/Documentation/Examples/Example_Invert.png b/bin/Documentation/Examples/Example_Invert.png index 48fb7d62..b84869f7 100644 Binary files a/bin/Documentation/Examples/Example_Invert.png and b/bin/Documentation/Examples/Example_Invert.png differ diff --git a/bin/Documentation/Examples/Example_Kaleidoscope.png b/bin/Documentation/Examples/Example_Kaleidoscope.png index d375a851..e413585f 100644 Binary files a/bin/Documentation/Examples/Example_Kaleidoscope.png and b/bin/Documentation/Examples/Example_Kaleidoscope.png differ diff --git a/bin/Documentation/Examples/Example_LambertMaterial.png b/bin/Documentation/Examples/Example_LambertMaterial.png index a5c6c9a3..f51a25c3 100644 Binary files a/bin/Documentation/Examples/Example_LambertMaterial.png and b/bin/Documentation/Examples/Example_LambertMaterial.png differ diff --git a/bin/Documentation/Examples/Example_Lens.png b/bin/Documentation/Examples/Example_Lens.png index 98c0f2c0..3c5749dc 100644 Binary files a/bin/Documentation/Examples/Example_Lens.png and b/bin/Documentation/Examples/Example_Lens.png differ diff --git a/bin/Documentation/Examples/Example_MADD.png b/bin/Documentation/Examples/Example_MADD.png index ead2abae..b62c33b7 100644 Binary files a/bin/Documentation/Examples/Example_MADD.png and b/bin/Documentation/Examples/Example_MADD.png differ diff --git a/bin/Documentation/Examples/Example_Multiplex.png b/bin/Documentation/Examples/Example_Multiplex.png new file mode 100644 index 00000000..30eb2de7 Binary files /dev/null and b/bin/Documentation/Examples/Example_Multiplex.png differ diff --git a/bin/Documentation/Examples/Example_NGon.png b/bin/Documentation/Examples/Example_NGon.png index 61efd23a..18df9518 100644 Binary files a/bin/Documentation/Examples/Example_NGon.png and b/bin/Documentation/Examples/Example_NGon.png differ diff --git a/bin/Documentation/Examples/Example_NormalMap.png b/bin/Documentation/Examples/Example_NormalMap.png index eccfd6f1..ec2ab66f 100644 Binary files a/bin/Documentation/Examples/Example_NormalMap.png and b/bin/Documentation/Examples/Example_NormalMap.png differ diff --git a/bin/Documentation/Examples/Example_NormalMapBlending.png b/bin/Documentation/Examples/Example_NormalMapBlending.png index ec6240d4..e955dee1 100644 Binary files a/bin/Documentation/Examples/Example_NormalMapBlending.png and b/bin/Documentation/Examples/Example_NormalMapBlending.png differ diff --git a/bin/Documentation/Examples/Example_PBR.png b/bin/Documentation/Examples/Example_PBR.png index 843d5858..71d1222e 100644 Binary files a/bin/Documentation/Examples/Example_PBR.png and b/bin/Documentation/Examples/Example_PBR.png differ diff --git a/bin/Documentation/Examples/Example_PBR2.png b/bin/Documentation/Examples/Example_PBR2.png index 9e7bfe02..db56bdf3 100644 Binary files a/bin/Documentation/Examples/Example_PBR2.png and b/bin/Documentation/Examples/Example_PBR2.png differ diff --git a/bin/Documentation/Examples/Example_Paint2D.png b/bin/Documentation/Examples/Example_Paint2D.png index 447a9497..01e15ac7 100644 Binary files a/bin/Documentation/Examples/Example_Paint2D.png and b/bin/Documentation/Examples/Example_Paint2D.png differ diff --git a/bin/Documentation/Examples/Example_Paint3D.png b/bin/Documentation/Examples/Example_Paint3D.png index d9d00afd..2d838b9d 100644 Binary files a/bin/Documentation/Examples/Example_Paint3D.png and b/bin/Documentation/Examples/Example_Paint3D.png differ diff --git a/bin/Documentation/Examples/Example_Palette_C64.png b/bin/Documentation/Examples/Example_Palette_C64.png index 4a57edbe..d44f8c51 100644 Binary files a/bin/Documentation/Examples/Example_Palette_C64.png and b/bin/Documentation/Examples/Example_Palette_C64.png differ diff --git a/bin/Documentation/Examples/Example_Palette_CGA0.png b/bin/Documentation/Examples/Example_Palette_CGA0.png index b9f743c2..d44f8c51 100644 Binary files a/bin/Documentation/Examples/Example_Palette_CGA0.png and b/bin/Documentation/Examples/Example_Palette_CGA0.png differ diff --git a/bin/Documentation/Examples/Example_Palette_CGA1.png b/bin/Documentation/Examples/Example_Palette_CGA1.png index 6a318927..d44f8c51 100644 Binary files a/bin/Documentation/Examples/Example_Palette_CGA1.png and b/bin/Documentation/Examples/Example_Palette_CGA1.png differ diff --git a/bin/Documentation/Examples/Example_Palette_CGA2.png b/bin/Documentation/Examples/Example_Palette_CGA2.png index 7a9bda33..d44f8c51 100644 Binary files a/bin/Documentation/Examples/Example_Palette_CGA2.png and b/bin/Documentation/Examples/Example_Palette_CGA2.png differ diff --git a/bin/Documentation/Examples/Example_Palette_CGA3.png b/bin/Documentation/Examples/Example_Palette_CGA3.png index 14c65c5f..d44f8c51 100644 Binary files a/bin/Documentation/Examples/Example_Palette_CGA3.png and b/bin/Documentation/Examples/Example_Palette_CGA3.png differ diff --git a/bin/Documentation/Examples/Example_Palette_CGA4.png b/bin/Documentation/Examples/Example_Palette_CGA4.png index 4d987cd7..d44f8c51 100644 Binary files a/bin/Documentation/Examples/Example_Palette_CGA4.png and b/bin/Documentation/Examples/Example_Palette_CGA4.png differ diff --git a/bin/Documentation/Examples/Example_Palette_CGA5.png b/bin/Documentation/Examples/Example_Palette_CGA5.png index 7be82199..d44f8c51 100644 Binary files a/bin/Documentation/Examples/Example_Palette_CGA5.png and b/bin/Documentation/Examples/Example_Palette_CGA5.png differ diff --git a/bin/Documentation/Examples/Example_Palette_EGA.png b/bin/Documentation/Examples/Example_Palette_EGA.png index 7ce60e86..d44f8c51 100644 Binary files a/bin/Documentation/Examples/Example_Palette_EGA.png and b/bin/Documentation/Examples/Example_Palette_EGA.png differ diff --git a/bin/Documentation/Examples/Example_Palette_Gameboy(mono).png b/bin/Documentation/Examples/Example_Palette_Gameboy(mono).png index 2125b433..d44f8c51 100644 Binary files a/bin/Documentation/Examples/Example_Palette_Gameboy(mono).png and b/bin/Documentation/Examples/Example_Palette_Gameboy(mono).png differ diff --git a/bin/Documentation/Examples/Example_Palette_PICO-8.png b/bin/Documentation/Examples/Example_Palette_PICO-8.png index 7236c76d..d44f8c51 100644 Binary files a/bin/Documentation/Examples/Example_Palette_PICO-8.png and b/bin/Documentation/Examples/Example_Palette_PICO-8.png differ diff --git a/bin/Documentation/Examples/Example_PathTracer.png b/bin/Documentation/Examples/Example_PathTracer.png index 2c384112..c9797787 100644 Binary files a/bin/Documentation/Examples/Example_PathTracer.png and b/bin/Documentation/Examples/Example_PathTracer.png differ diff --git a/bin/Documentation/Examples/Example_PerlinNoise.png b/bin/Documentation/Examples/Example_PerlinNoise.png index 66d56f6f..d803becc 100644 Binary files a/bin/Documentation/Examples/Example_PerlinNoise.png and b/bin/Documentation/Examples/Example_PerlinNoise.png differ diff --git a/bin/Documentation/Examples/Example_PhysicalSky.png b/bin/Documentation/Examples/Example_PhysicalSky.png index 4f15dbc1..4bdbf77a 100644 Binary files a/bin/Documentation/Examples/Example_PhysicalSky.png and b/bin/Documentation/Examples/Example_PhysicalSky.png differ diff --git a/bin/Documentation/Examples/Example_Pixelize.png b/bin/Documentation/Examples/Example_Pixelize.png index 5433e146..2486fdfe 100644 Binary files a/bin/Documentation/Examples/Example_Pixelize.png and b/bin/Documentation/Examples/Example_Pixelize.png differ diff --git a/bin/Documentation/Examples/Example_PolarCoords.png b/bin/Documentation/Examples/Example_PolarCoords.png index 05cdb941..1cc8444c 100644 Binary files a/bin/Documentation/Examples/Example_PolarCoords.png and b/bin/Documentation/Examples/Example_PolarCoords.png differ diff --git a/bin/Documentation/Examples/Example_Ramp.png b/bin/Documentation/Examples/Example_Ramp.png index c28fbfaa..0f9d6d85 100644 Binary files a/bin/Documentation/Examples/Example_Ramp.png and b/bin/Documentation/Examples/Example_Ramp.png differ diff --git a/bin/Documentation/Examples/Example_ReactionDiffusion.png b/bin/Documentation/Examples/Example_ReactionDiffusion.png index f862820c..c980db67 100644 Binary files a/bin/Documentation/Examples/Example_ReactionDiffusion.png and b/bin/Documentation/Examples/Example_ReactionDiffusion.png differ diff --git a/bin/Documentation/Examples/Example_SVG.png b/bin/Documentation/Examples/Example_SVG.png index 67bb3690..6f556bf8 100644 Binary files a/bin/Documentation/Examples/Example_SVG.png and b/bin/Documentation/Examples/Example_SVG.png differ diff --git a/bin/Documentation/Examples/Example_SceneLoader.png b/bin/Documentation/Examples/Example_SceneLoader.png index be970245..a74f7756 100644 Binary files a/bin/Documentation/Examples/Example_SceneLoader.png and b/bin/Documentation/Examples/Example_SceneLoader.png differ diff --git a/bin/Documentation/Examples/Example_Sine.png b/bin/Documentation/Examples/Example_Sine.png index 206d9819..a9cd6169 100644 Binary files a/bin/Documentation/Examples/Example_Sine.png and b/bin/Documentation/Examples/Example_Sine.png differ diff --git a/bin/Documentation/Examples/Example_SmoothStep.png b/bin/Documentation/Examples/Example_SmoothStep.png index 8b093560..06ad5722 100644 Binary files a/bin/Documentation/Examples/Example_SmoothStep.png and b/bin/Documentation/Examples/Example_SmoothStep.png differ diff --git a/bin/Documentation/Examples/Example_Square.png b/bin/Documentation/Examples/Example_Square.png deleted file mode 100644 index de0f1452..00000000 Binary files a/bin/Documentation/Examples/Example_Square.png and /dev/null differ diff --git a/bin/Documentation/Examples/Example_Swirl.png b/bin/Documentation/Examples/Example_Swirl.png index 509c3b67..0582c0ae 100644 Binary files a/bin/Documentation/Examples/Example_Swirl.png and b/bin/Documentation/Examples/Example_Swirl.png differ diff --git a/bin/Documentation/Examples/Example_TerrainPreview.png b/bin/Documentation/Examples/Example_TerrainPreview.png index 46531f0e..234124ee 100644 Binary files a/bin/Documentation/Examples/Example_TerrainPreview.png and b/bin/Documentation/Examples/Example_TerrainPreview.png differ diff --git a/bin/Documentation/Examples/Example_Thumbnail.png b/bin/Documentation/Examples/Example_Thumbnail.png index e522ce51..9e688d6e 100644 Binary files a/bin/Documentation/Examples/Example_Thumbnail.png and b/bin/Documentation/Examples/Example_Thumbnail.png differ diff --git a/bin/Documentation/Examples/Example_Tile.png b/bin/Documentation/Examples/Example_Tile.png index 9a669a7a..a04c8187 100644 Binary files a/bin/Documentation/Examples/Example_Tile.png and b/bin/Documentation/Examples/Example_Tile.png differ diff --git a/bin/Documentation/Examples/Example_Transform.png b/bin/Documentation/Examples/Example_Transform.png index 2793e5f6..11abe653 100644 Binary files a/bin/Documentation/Examples/Example_Transform.png and b/bin/Documentation/Examples/Example_Transform.png differ diff --git a/bin/Documentation/Examples/Example_Voronoi.png b/bin/Documentation/Examples/Example_Voronoi.png index b7fa09f3..06058a76 100644 Binary files a/bin/Documentation/Examples/Example_Voronoi.png and b/bin/Documentation/Examples/Example_Voronoi.png differ diff --git a/bin/Documentation/Examples/Example_Warp.png b/bin/Documentation/Examples/Example_Warp.png index 0f19096b..85fc1eb8 100644 Binary files a/bin/Documentation/Examples/Example_Warp.png and b/bin/Documentation/Examples/Example_Warp.png differ diff --git a/bin/Documentation/Examples/Example_WorleyNoise.png b/bin/Documentation/Examples/Example_WorleyNoise.png new file mode 100644 index 00000000..eb13a19c Binary files /dev/null and b/bin/Documentation/Examples/Example_WorleyNoise.png differ diff --git a/bin/Documentation/Examples/Example_iqnoise.png b/bin/Documentation/Examples/Example_iqnoise.png index b7908b85..966849db 100644 Binary files a/bin/Documentation/Examples/Example_iqnoise.png and b/bin/Documentation/Examples/Example_iqnoise.png differ diff --git a/bin/Documentation/ImogenUserDocumentation.md b/bin/Documentation/ImogenUserDocumentation.md index 520610f7..89b3b6b9 100644 --- a/bin/Documentation/ImogenUserDocumentation.md +++ b/bin/Documentation/ImogenUserDocumentation.md @@ -7,21 +7,19 @@ # Nodes ## Generator -![node picture](Pictures/Circle.png)|![node picture](Pictures/Square.png)|![node picture](Pictures/Checker.png)|![node picture](Pictures/Sine.png)|![node picture](Pictures/Hexagon.png)|![node picture](Pictures/CircleSplatter.png) +![node picture](Pictures/Circle.png)|![node picture](Pictures/Checker.png)|![node picture](Pictures/Sine.png)|![node picture](Pictures/CircleSplatter.png)|![node picture](Pictures/NGon.png)|![node picture](Pictures/GradientBuilder.png) -|-|-|-|-|- -[Circle](#Circle)|[Square](#Square)|[Checker](#Checker)|[Sine](#Sine)|[Hexagon](#Hexagon)|[CircleSplatter](#CircleSplatter) -![node picture](Pictures/NGon.png)|![node picture](Pictures/GradientBuilder.png)|![node picture](Pictures/ReactionDiffusion.png)|![node picture](Pictures/Disolve.png)|| -[NGon](#NGon)|[GradientBuilder](#GradientBuilder)|[ReactionDiffusion](#ReactionDiffusion)|[Disolve](#Disolve)|| +[Circle](#Circle)|[Checker](#Checker)|[Sine](#Sine)|[CircleSplatter](#CircleSplatter)|[NGon](#NGon)|[GradientBuilder](#GradientBuilder) +![node picture](Pictures/ReactionDiffusion.png)|![node picture](Pictures/Disolve.png)|||| +[ReactionDiffusion](#ReactionDiffusion)|[Disolve](#Disolve)|||| ## Transform -![node picture](Pictures/Transform.png)|![node picture](Pictures/Pixelize.png)|![node picture](Pictures/Tile.png)|![node picture](Pictures/PolarCoords.png)|![node picture](Pictures/Swirl.png)|![node picture](Pictures/Crop.png) +![node picture](Pictures/Transform.png)|![node picture](Pictures/Tile.png)|![node picture](Pictures/PolarCoords.png)|![node picture](Pictures/Swirl.png)|![node picture](Pictures/Crop.png)|![node picture](Pictures/Warp.png) -|-|-|-|-|- -[Transform](#Transform)|[Pixelize](#Pixelize)|[Tile](#Tile)|[PolarCoords](#PolarCoords)|[Swirl](#Swirl)|[Crop](#Crop) -![node picture](Pictures/Warp.png)|![node picture](Pictures/EdgeDetect.png)|![node picture](Pictures/Kaleidoscope.png)|![node picture](Pictures/Palette.png)|![node picture](Pictures/ChannelPacker.png)|![node picture](Pictures/Lens.png) -[Warp](#Warp)|[EdgeDetect](#EdgeDetect)|[Kaleidoscope](#Kaleidoscope)|[Palette](#Palette)|[ChannelPacker](#ChannelPacker)|[Lens](#Lens) -![node picture](Pictures/Distance.png)||||| -[Distance](#Distance)||||| +[Transform](#Transform)|[Tile](#Tile)|[PolarCoords](#PolarCoords)|[Swirl](#Swirl)|[Crop](#Crop)|[Warp](#Warp) +![node picture](Pictures/EdgeDetect.png)|![node picture](Pictures/Kaleidoscope.png)|![node picture](Pictures/Palette.png)|![node picture](Pictures/ChannelPacker.png)|![node picture](Pictures/Lens.png)|![node picture](Pictures/Distance.png) +[EdgeDetect](#EdgeDetect)|[Kaleidoscope](#Kaleidoscope)|[Palette](#Palette)|[ChannelPacker](#ChannelPacker)|[Lens](#Lens)|[Distance](#Distance) ## Filter @@ -33,9 +31,9 @@ ## Material -![node picture](Pictures/LambertMaterial.png)|![node picture](Pictures/PBR.png)|![node picture](Pictures/TerrainPreview.png)|![node picture](Pictures/PathTracer.png)|![node picture](Pictures/PBR2.png) --|-|-|-|- -[LambertMaterial](#LambertMaterial)|[PBR](#PBR)|[TerrainPreview](#TerrainPreview)|[PathTracer](#PathTracer)|[PBR2](#PBR2) +![node picture](Pictures/LambertMaterial.png)|![node picture](Pictures/PBR.png) +-|- +[LambertMaterial](#LambertMaterial)|[PBR](#PBR) ## Blend @@ -51,15 +49,15 @@ ## Noise -![node picture](Pictures/iqnoise.png)|![node picture](Pictures/PerlinNoise.png)|![node picture](Pictures/Voronoi.png) +![node picture](Pictures/Voronoi.png)|![node picture](Pictures/WorleyNoise.png)|![node picture](Pictures/PerlinNoise.png) -|-|- -[iqnoise](#iqnoise)|[PerlinNoise](#PerlinNoise)|[Voronoi](#Voronoi) +[Voronoi](#Voronoi)|[WorleyNoise](#WorleyNoise)|[PerlinNoise](#PerlinNoise) ## File -![node picture](Pictures/ImageRead.png)|![node picture](Pictures/ImageWrite.png)|![node picture](Pictures/Thumbnail.png)|![node picture](Pictures/SVG.png)|![node picture](Pictures/SceneLoader.png)|![node picture](Pictures/GLTFRead.png) --|-|-|-|-|- -[ImageRead](#ImageRead)|[ImageWrite](#ImageWrite)|[Thumbnail](#Thumbnail)|[SVG](#SVG)|[SceneLoader](#SceneLoader)|[GLTFRead](#GLTFRead) +![node picture](Pictures/ImageRead.png)|![node picture](Pictures/ImageWrite.png)|![node picture](Pictures/Thumbnail.png)|![node picture](Pictures/SVG.png)|![node picture](Pictures/GLTFRead.png) +-|-|-|-|- +[ImageRead](#ImageRead)|[ImageWrite](#ImageWrite)|[Thumbnail](#Thumbnail)|[SVG](#SVG)|[GLTFRead](#GLTFRead) ## Paint @@ -74,10 +72,10 @@ [PhysicalSky](#PhysicalSky)|[CubemapView](#CubemapView)|[EquirectConverter](#EquirectConverter)|[CubeRadiance](#CubeRadiance) -## Fur -![node picture](Pictures/FurGenerator.png)|![node picture](Pictures/FurDisplay.png)|![node picture](Pictures/FurIntegrator.png) --|-|- -[FurGenerator](#FurGenerator)|[FurDisplay](#FurDisplay)|[FurIntegrator](#FurIntegrator) +## Tools +![node picture](Pictures/Multiplex.png) +- +[Multiplex](#Multiplex) ## Circle @@ -87,7 +85,7 @@ Category : Generator ### Description Renders a perfect Circle center in the view port. ### Parameters -1. Radius +1. radius Clip-space radius. 1. T Interpolation factor between full white cirle (0.) and height of the hemisphere (1.). @@ -102,29 +100,16 @@ Category : Transform ### Description Transform every source texel using the translation, rotation, scale. ### Parameters -1. Translate +1. translate 2D vector translation. -1. Scale +1. scale 2D vector scale. -1. Rotation +1. rotation Angle in degrees. Center of rotation is the center of the source. ### Example ![node example](Examples/Example_Transform.png) -## Square -![node picture](Pictures/Square.png) - -Category : Generator -### Description -Renders a square centered in the middle of the viewport. Deprecated node. Use the NGon node. -### Parameters -1. Width -Clip-space side width. - -### Example -![node example](Examples/Example_Square.png) - ## Checker ![node picture](Pictures/Checker.png) @@ -144,9 +129,11 @@ Category : Generator ### Description Renders a one directioned sine as a greyscale value. ### Parameters -1. Frequency +1. translation +Translate the sine to adjust its start and end. +1. frequency Basically, the number of bars. -1. Angle +1. angle Angle in degrees of the so called bars. ### Example @@ -159,27 +146,14 @@ Category : Filter ### Description Performs a smoothstep operation. Hermite interpolation between 0 and 1 when Low < x < high. This is useful in cases where a threshold function with a smooth transition is desired. ### Parameters -1. Low +1. low Lower value for the Hermite interpolation. -1. High +1. high Higher value for the Hermite interpolation. Result is undertimined when high value < low value. ### Example ![node example](Examples/Example_SmoothStep.png) -## Pixelize -![node picture](Pictures/Pixelize.png) - -Category : Transform -### Description -Lower the resolution of the image using nearest filter. -### Parameters -1. scale -Number of pixels on a side. - -### Example -![node example](Examples/Example_Pixelize.png) - ## Blur ![node picture](Pictures/Blur.png) @@ -187,7 +161,7 @@ Category : Filter ### Description Performs a Directional of Box blur filter. Directional blur is a gaussian pass with 16 pixels. Box is 16x16. ### Parameters -1. Type +1. type Selection of the Blur type. 1. angle angle in degrees for the directional blur. @@ -208,7 +182,7 @@ Computes a normal map using the Red component of the source as the height. ### Parameters 1. spread The bigger, the stronger the resulting normal will be. -1. Invert +1. invert Change the direction of the XY components of the normal. ### Example @@ -219,7 +193,7 @@ Change the direction of the XY components of the normal. Category : Material ### Description -Experimental node. +simental node. ### Parameters 1. view @@ -234,26 +208,14 @@ Category : Blend ### Description For each source texel, multiply and and a color value. ### Parameters -1. Mul Color +1. mulColor The color to multiply the source with. -1. Add Color +1. addColor The color to add to the source. ### Example ![node example](Examples/Example_MADD.png) -## Hexagon -![node picture](Pictures/Hexagon.png) - -Category : Generator -### Description -Renders an hexagon. This node is deprecated. Use the NGon node instead. -### Parameters -No parameter for this node. - -### Example -![node example](Examples/Example_Hexagon.png) - ## Blend ![node picture](Pictures/Blend.png) @@ -265,7 +227,7 @@ Blends to source together using a built-in operation. Each source can also be ma Color/mask to multiply A source with. 1. B Color/mask to multiply A source with. -1. Operation +1. operation Built-ins operation used for blending. Check the examples below. ![node picture](Examples/Example_Blend_Add.png)|![node picture](Examples/Example_Blend_Multiply.png)|![node picture](Examples/Example_Blend_Darken.png) @@ -300,13 +262,13 @@ Category : Generator ### Description Renders a bunch of circle with interpolated position and scales. For N circles the interpolation coefficient will be between [0/N....N/N]. ### Parameters -1. Distance +1. distance First and Last value to interpolate between for the distance to the center of the viewport. -1. Radius +1. radius First and Last value for the interpolated circle radius. -1. Angle +1. angle First and Last value for the Angle. The circle position is computed using the angle and the distance. -1. Count +1. count The total number of circles to render. ### Example @@ -319,7 +281,7 @@ Category : Filter ### Description Performs a Ramp on the source components. For each source value (X coord on the ramp graph), retrieve an intensity value (Y on the ramp graph). Optionnaly use an image instead of the editable graph. ### Parameters -1. Ramp +1. ramp Graph that can be edited. ### Example @@ -332,14 +294,18 @@ Category : Transform ### Description Generate a tile map of the source image. With optional overlap. An optional Color input can be used to modulate the tiles color. Color is uniform per tile and picked at its center in the output image. ### Parameters -1. Offset 0 -X,Y offset applied to even tiles. Offset in clipspace. -1. Offset 1 -X,Y offset applied to odd tiles. Offset in clipspace. -1. Overlap -Amount of overlap between odd and even tiles. -1. Scale -The number of tiles in X and Y in the output. +1. translation +Translate the noise seeds so you can have virtualy infinite different noise. +1. quincunx +Offset line and/or column. +1. noiseFactor +position noise factor. A value of 0 means the grid cells are more tightly packed and with less size variation. +1. rotationFactor +Rotate sprite randomly. This factor limits the rotation amount. +1. scale +How many cells used per dimension. +1. innerScale +Sprite uniform scale. ### Example ![node example](Examples/Example_Tile.png) @@ -351,7 +317,7 @@ Category : None ### Description Single plain color. ### Parameters -1. Color +1. color Single plain color. ### Example @@ -364,30 +330,51 @@ Category : Blend ### Description Blend two normal maps into a single one. Choose the Technique that gives the best result. ### Parameters -1. Technique +1. mode Different techniques for blending. Check the examples below to see the differences. ### Example ![node example](Examples/Example_NormalMapBlending.png) -## iqnoise -![node picture](Pictures/iqnoise.png) +## Voronoi +![node picture](Pictures/Voronoi.png) Category : Noise ### Description Generate noise based on work by Inigo Quilez. ### Parameters -1. Translation +1. translation Translate the noise seeds so you can have virtualy infinite different noise. -1. Size +1. size -1. U +1. noise Interpolate between centered seed (checker) to jittered random position. -1. V +1. colorInterpolation Interpolation factor between full color to distance-like color per cell. +1. distanceBlend +Distance computation type interpolate between Euclydean distance (0.) and Manhattan Distance (1.) + +### Example +![node example](Examples/Example_Voronoi.png) + +## WorleyNoise +![node picture](Pictures/WorleyNoise.png) + +Category : Noise +### Description +Generate Worley noise with optional Manhattan distance. +### Parameters +1. translation +Translate the noise seeds so you can have virtualy infinite different noise. +1. scale + +1. jitter + +1. manhattan +Mahattan or linear distance. ### Example -![node example](Examples/Example_iqnoise.png) +![node example](Examples/Example_WorleyNoise.png) ## PerlinNoise ![node picture](Pictures/PerlinNoise.png) @@ -396,9 +383,9 @@ Category : Noise ### Description ### Parameters -1. Translation +1. translation Translate the noise seeds so you can have virtualy infinite different noise. -1. Octaves +1. octaves The number of noise with different scale for each. 1. lacunarity Geoemtric scale applied for each octave. @@ -415,11 +402,11 @@ Category : Material ### Description Experimental Node. ### Parameters -1. View +1. view -1. Displacement Factor +1. displacementFactor -1. Geometry +1. geometry ### Example @@ -432,7 +419,7 @@ Category : Transform ### Description Transform the source using polar coordinates. ### Parameters -1. Type +1. type Change to direction of the transformation. ### Example @@ -445,9 +432,9 @@ Category : Filter ### Description Performs a clamp for each component of the source. Basically, sets the min and max of each component. ### Parameters -1. Min +1. minimum The minimal value for each source component. -1. Max +1. maximum The maximal value for each source component. ### Example @@ -460,19 +447,19 @@ Category : File ### Description Imports a file from the disk. Major formats are supported. Cubemaps can be imported using one image for each face of using a cubemap .DDS/.KTX. MP4 movies can be read as well. ### Parameters -1. File name +1. filename Single image frame or DDS/KTX cubemap. -1. +X File name +1. XPosFilename Cubemap image face for +X direction. -1. -X File name +1. XNegFilename Cubemap image face for -X direction. -1. +Y File name +1. YPosFilename Cubemap image face for +Y direction (Top). -1. -Y File name +1. YNegFilename Cubemap image face for -Y direction (Bottom). -1. +Z File name +1. ZPosFilename Cubemap image face for +Z direction. -1. -Z File name +1. ZNegFilename Cubemap image face for -Z direction. ### Example @@ -485,19 +472,19 @@ Category : File ### Description ### Parameters -1. File name +1. filename -1. Format +1. format -1. Quality +1. quality -1. Width +1. width -1. Height +1. height -1. Mode +1. mode -1. Export +1. export ### Example @@ -510,7 +497,7 @@ Category : File ### Description Create a thumbnail picture from the source input and applies it to the thumbnail library view. ### Parameters -1. Make +1. make Force the evaluation without building the graph. ### Example @@ -523,7 +510,7 @@ Category : Paint ### Description Paint in the parameter viewport using the connected brush. Paint picture is saved in the graph. ### Parameters -1. Size +1. size Size of the output in pixels. ### Example @@ -536,7 +523,7 @@ Category : Transform ### Description Performs a rotation on source based on distance to the viewport center. ### Parameters -1. Angles +1. angles Rotation for the inner pixels (closer to the center) and the outter pixels. Angles in degrees. ### Example @@ -549,7 +536,7 @@ Category : Transform ### Description Set the output as a rectangle in the source. ### Parameters -1. Quad +1. quad X/Y Position and width/height of the selection rectangle. ### Example @@ -568,25 +555,25 @@ Ambient aka minimal color within the cubemap. Ambient alpha is used to modulate Light direction vector. 1. Kr Kr component value. -1. rayleigh brightness +1. rayleighBrightness Rayleigh brightness -1. mie brightness +1. mieBrightness Mie brightness factor. -1. spot brightness +1. spotBrightness Spot/sun brightness. -1. scatter strength +1. scatterStrength Scatter strength. -1. rayleigh strength +1. rayleighStrength Rayleigh strength. -1. mie strength +1. mieStrength Mie strength. -1. rayleigh collection power +1. rayleighCollectionPower Rayleigh collection power. -1. mie collection power +1. mieCollectionPower Mie collection power. -1. mie distribution +1. mieDistribution Mie distribution. -1. Size +1. size Size of the cubemap face width in pixels. ### Example @@ -601,7 +588,7 @@ Used to display a cubemap using various techniques. ### Parameters 1. view Used by the Camera technique to rotate the eye direction. -1. Mode +1. mode Techniques for display. See below for examples. 1. LOD Use a particular LOD (mipmap) for display. Radiance cube node can help produce cubemap mipmaps. @@ -616,9 +603,9 @@ Category : Cubemap ### Description Converts an equirect source (one single picture containing all environment) into a cubemap output. The inverse (cubemap -> equirect) can also be performed with this node. ### Parameters -1. Mode +1. mode Select to operation to perform. -1. Size +1. size Size fo the ouput in pixels. ### Example @@ -631,12 +618,14 @@ Category : Generator ### Description Compute N plans and color the texels behind every plan accordingly. Texels in front of any plan will be black. ### Parameters -1. Sides +1. sides Number of uniformly distributed plans. -1. Radius +1. radius Distance from the plan to the center of the viewport. 1. T Interpolation factor between full white color and distance to the nearest plan. +1. startAngle +Angle in degrees of the first vertex. ### Example ![node example](Examples/Example_NGon.png) @@ -648,7 +637,7 @@ Category : Generator ### Description Computes a linear gradient based on key values(position/color). ### Parameters -1. Gradient +1. gradient Double click to add a click. Click and drag a key to move it position. Modify the color for the selected key. ### Example @@ -661,27 +650,14 @@ Category : Transform ### Description Displace each source texel using the Warp input. ### Parameters -1. Strength +1. strength How strong is the displacement. Clip-space value. -1. Mode +1. mode One of 2 modes. XY offset : R and G channels are used for X and Y displacement. Rotation-Distance: R is used as an angle (0..1 -> 0..2pi) and G is the length of the displacement. ### Example ![node example](Examples/Example_Warp.png) -## TerrainPreview -![node picture](Pictures/TerrainPreview.png) - -Category : Material -### Description -Experimental node. -### Parameters -1. Camera - - -### Example -![node example](Examples/Example_TerrainPreview.png) - ## AO ![node picture](Pictures/AO.png) @@ -701,46 +677,6 @@ Radius in clipspace used for the computation. ### Example ![node example](Examples/Example_AO.png) -## FurGenerator -![node picture](Pictures/FurGenerator.png) - -Category : Fur -### Description -Experimental node. -### Parameters -1. Hair count - -1. Length factor - - -### Example -![node example](Examples/Example_FurGenerator.png) - -## FurDisplay -![node picture](Pictures/FurDisplay.png) - -Category : Fur -### Description -Experimental node. -### Parameters -1. Camera - - -### Example -![node example](Examples/Example_FurDisplay.png) - -## FurIntegrator -![node picture](Pictures/FurIntegrator.png) - -Category : Fur -### Description -Experimental node. -### Parameters -No parameter for this node. - -### Example -![node example](Examples/Example_FurIntegrator.png) - ## SVG ![node picture](Pictures/SVG.png) @@ -748,42 +684,14 @@ Category : File ### Description Import an SVG vector graphics image and rasterize it to an image output. ### Parameters -1. File name +1. filename Relative or absolute filepath of the SVG file. -1. DPI +1. dpi Resolution used for rendering the SVG. The higher value, the bigger the image will be. ### Example ![node example](Examples/Example_SVG.png) -## SceneLoader -![node picture](Pictures/SceneLoader.png) - -Category : File -### Description -Experimental node. -### Parameters -1. File name - - -### Example -![node example](Examples/Example_SceneLoader.png) - -## PathTracer -![node picture](Pictures/PathTracer.png) - -Category : Material -### Description -Experimental node. -### Parameters -1. Mode - -1. Camera - - -### Example -![node example](Examples/Example_PathTracer.png) - ## EdgeDetect ![node picture](Pictures/EdgeDetect.png) @@ -791,31 +699,12 @@ Category : Transform ### Description Performs an edge detection on the source. Texels that are close in intensity with the neighbours will be white. Black if the difference is strong. ### Parameters -1. Radius +1. radius The radius size in clipspace used for detection. The higher value, the broader the search is. ### Example ![node example](Examples/Example_EdgeDetect.png) -## Voronoi -![node picture](Pictures/Voronoi.png) - -Category : Noise -### Description -Generates a Voronoi texture based on random seeds. -### Parameters -1. Point Count -The number of seeds. -1. Seed -The seeds random position base value. -1. Distance Blend -Distance computation type interpolate between Euclydean distance (0.) and Manhattan Distance (1.) -1. Square Width -Size of each seed in clipspace size. - -### Example -![node example](Examples/Example_Voronoi.png) - ## Kaleidoscope ![node picture](Pictures/Kaleidoscope.png) @@ -823,13 +712,13 @@ Category : Transform ### Description Duplicates portion of the source using rotation and symetry. Basically, computes N plans and duplicate what's in front of the plane to the other with or without symetry. ### Parameters -1. Center +1. center Center of the operation in clipspace coordinates [0..1] -1. Start Angle +1. startAngle Angle in degrees of the first plan. Total sum of plan angle is 360 deg. -1. Splits +1. splits How many split plans to use. -1. Symetry +1. symetry Enable symetry for even plans. ### Example @@ -842,9 +731,9 @@ Category : Transform ### Description Find the closest color inside the predefined palette for each texel in the source. Using optional dithering. ### Parameters -1. Palette +1. palette Predefined palette. Check examples below for results. -1. Dither Strength +1. ditherStrength Bayer dithering strength (0 = none, 1 = full dither). ![node picture](Examples/Example_Palette_CGA0.png)|![node picture](Examples/Example_Palette_CGA1.png) @@ -875,7 +764,7 @@ Reaction divisor. Component color step. 1. passCount Multiple passes are supported by this node. -1. Size +1. size Size of the output in pixels ### Example @@ -890,13 +779,13 @@ Apply a fluid dynamic-like process on the source image. A noise is computed and ### Parameters 1. passCount Multiple passes are supported by this node. -1. Frequency +1. frequency Noise frequency. The higher, the more noise you'll get. -1. Strength +1. strength Noise strength. -1. Randomization +1. randomization How much randomization is applied. -1. VerticalShift +1. verticalShift How much in clip-space is moved to the top. Somekind of force applied to texels. ### Example @@ -909,9 +798,9 @@ Category : File ### Description Experimental node. ### Parameters -1. File name +1. filename -1. Camera +1. camera ### Example @@ -924,9 +813,9 @@ Category : Paint ### Description Experimental node. ### Parameters -1. Size +1. size -1. Camera +1. camera ### Example @@ -939,31 +828,16 @@ Category : Cubemap ### Description Compute cubemap radiance or irradiance and generate a cubemap with optional mipmaps ### Parameters -1. Mode +1. mode Radiance or Irradiance. -1. Size +1. size Size of the output cubemap face width in pixels. -1. Sample Count +1. sampleCount The samples count used for the blur. The more samplem the higher quality. ### Example ![node example](Examples/Example_CubeRadiance.png) -## PBR2 -![node picture](Pictures/PBR2.png) - -Category : Material -### Description -Experimental node. -### Parameters -1. View - -1. Depth factor - - -### Example -![node example](Examples/Example_PBR2.png) - ## ChannelPacker ![node picture](Pictures/ChannelPacker.png) @@ -990,9 +864,9 @@ Category : Transform ### Description Deforms the source using a lens computation with an optionnal vignette shading. ### Parameters -1. Factor +1. factor Lens factor strength. -1. Vignette +1. vignette Vignette shading: Corners get darker. 0 to disable vignette. ### Example @@ -1011,6 +885,19 @@ Generate a signed distance field from a black and white source image. ### Example ![node example](Examples/Example_Distance.png) +## Multiplex +![node picture](Pictures/Multiplex.png) + +Category : Tools +### Description +Route one input into the output. This choice can be propagated to further nodes. +### Parameters +1. multiplexer +Input selection passed thru the output. + +### Example +![node example](Examples/Example_Multiplex.png) + # Default Hot Keys Action|Description|Hot key @@ -1028,7 +915,6 @@ ToggleLogger|Show or hide Logger window|Ctrl + 3 ToggleSequencer|Show or hide Sequencer window|Ctrl + 4 ToggleParameters|Show or hide Parameters window|Ctrl + 5 MaterialNew|Create a new graph|Ctrl + N -ReloadShaders|Reload them|F7 DeleteSelectedNodes|Delete selected nodes in the current graph|Del AnimationSetKey|Make a new animation key with the current parameters values at the current time|S HotKeyEditor|Open the Hotkey editor window|Ctrl + K @@ -1039,5 +925,6 @@ Copy|Copy the selected nodes|Ctrl + C Cut|Cut the selected nodes|Ctrl + X Paste|Paste previously copy/cut nodes|Ctrl + V BuildMaterial|Build current material|Ctrl + B +CloseLibrary|Close current library|Ctrl + W MouseState|Show Mouse State as a tooltip|Ctrl + M diff --git a/bin/Documentation/Pictures/AO.png b/bin/Documentation/Pictures/AO.png index 29cc152e..77003a6f 100644 Binary files a/bin/Documentation/Pictures/AO.png and b/bin/Documentation/Pictures/AO.png differ diff --git a/bin/Documentation/Pictures/Blend.png b/bin/Documentation/Pictures/Blend.png index c6ef5f17..83e82b25 100644 Binary files a/bin/Documentation/Pictures/Blend.png and b/bin/Documentation/Pictures/Blend.png differ diff --git a/bin/Documentation/Pictures/Blur.png b/bin/Documentation/Pictures/Blur.png index b46f0743..1746157d 100644 Binary files a/bin/Documentation/Pictures/Blur.png and b/bin/Documentation/Pictures/Blur.png differ diff --git a/bin/Documentation/Pictures/ChannelPacker.png b/bin/Documentation/Pictures/ChannelPacker.png index 66574dd9..cd007701 100644 Binary files a/bin/Documentation/Pictures/ChannelPacker.png and b/bin/Documentation/Pictures/ChannelPacker.png differ diff --git a/bin/Documentation/Pictures/Checker.png b/bin/Documentation/Pictures/Checker.png index 831d72ee..0d13814c 100644 Binary files a/bin/Documentation/Pictures/Checker.png and b/bin/Documentation/Pictures/Checker.png differ diff --git a/bin/Documentation/Pictures/Circle.png b/bin/Documentation/Pictures/Circle.png index b5bb5439..fd54c98e 100644 Binary files a/bin/Documentation/Pictures/Circle.png and b/bin/Documentation/Pictures/Circle.png differ diff --git a/bin/Documentation/Pictures/CircleSplatter.png b/bin/Documentation/Pictures/CircleSplatter.png index 2f0787d7..4b928647 100644 Binary files a/bin/Documentation/Pictures/CircleSplatter.png and b/bin/Documentation/Pictures/CircleSplatter.png differ diff --git a/bin/Documentation/Pictures/Clamp.png b/bin/Documentation/Pictures/Clamp.png index de44724a..8804911c 100644 Binary files a/bin/Documentation/Pictures/Clamp.png and b/bin/Documentation/Pictures/Clamp.png differ diff --git a/bin/Documentation/Pictures/Color.png b/bin/Documentation/Pictures/Color.png index 784eb614..33d023e9 100644 Binary files a/bin/Documentation/Pictures/Color.png and b/bin/Documentation/Pictures/Color.png differ diff --git a/bin/Documentation/Pictures/Crop.png b/bin/Documentation/Pictures/Crop.png index 39039e45..d5021d7a 100644 Binary files a/bin/Documentation/Pictures/Crop.png and b/bin/Documentation/Pictures/Crop.png differ diff --git a/bin/Documentation/Pictures/CubeRadiance.png b/bin/Documentation/Pictures/CubeRadiance.png index c7d3c18d..d2102a9d 100644 Binary files a/bin/Documentation/Pictures/CubeRadiance.png and b/bin/Documentation/Pictures/CubeRadiance.png differ diff --git a/bin/Documentation/Pictures/CubemapView.png b/bin/Documentation/Pictures/CubemapView.png index 6afe7229..290eb4dd 100644 Binary files a/bin/Documentation/Pictures/CubemapView.png and b/bin/Documentation/Pictures/CubemapView.png differ diff --git a/bin/Documentation/Pictures/Disolve.png b/bin/Documentation/Pictures/Disolve.png index 0de26624..b858567b 100644 Binary files a/bin/Documentation/Pictures/Disolve.png and b/bin/Documentation/Pictures/Disolve.png differ diff --git a/bin/Documentation/Pictures/Distance.png b/bin/Documentation/Pictures/Distance.png index ecbcfec2..3cd310dd 100644 Binary files a/bin/Documentation/Pictures/Distance.png and b/bin/Documentation/Pictures/Distance.png differ diff --git a/bin/Documentation/Pictures/EdgeDetect.png b/bin/Documentation/Pictures/EdgeDetect.png index 8bc89989..1c20d913 100644 Binary files a/bin/Documentation/Pictures/EdgeDetect.png and b/bin/Documentation/Pictures/EdgeDetect.png differ diff --git a/bin/Documentation/Pictures/EquirectConverter.png b/bin/Documentation/Pictures/EquirectConverter.png index 5fb9d62c..84df66b4 100644 Binary files a/bin/Documentation/Pictures/EquirectConverter.png and b/bin/Documentation/Pictures/EquirectConverter.png differ diff --git a/bin/Documentation/Pictures/FurDisplay.png b/bin/Documentation/Pictures/FurDisplay.png index 4648ffbb..aa54ca6f 100644 Binary files a/bin/Documentation/Pictures/FurDisplay.png and b/bin/Documentation/Pictures/FurDisplay.png differ diff --git a/bin/Documentation/Pictures/FurGenerator.png b/bin/Documentation/Pictures/FurGenerator.png index af09d5e0..48d6c7de 100644 Binary files a/bin/Documentation/Pictures/FurGenerator.png and b/bin/Documentation/Pictures/FurGenerator.png differ diff --git a/bin/Documentation/Pictures/FurIntegrator.png b/bin/Documentation/Pictures/FurIntegrator.png index 0382e00d..49a611db 100644 Binary files a/bin/Documentation/Pictures/FurIntegrator.png and b/bin/Documentation/Pictures/FurIntegrator.png differ diff --git a/bin/Documentation/Pictures/GLTFRead.png b/bin/Documentation/Pictures/GLTFRead.png index 9e68aa73..3096fe67 100644 Binary files a/bin/Documentation/Pictures/GLTFRead.png and b/bin/Documentation/Pictures/GLTFRead.png differ diff --git a/bin/Documentation/Pictures/GradientBuilder.png b/bin/Documentation/Pictures/GradientBuilder.png index 9765fff8..e044eb3b 100644 Binary files a/bin/Documentation/Pictures/GradientBuilder.png and b/bin/Documentation/Pictures/GradientBuilder.png differ diff --git a/bin/Documentation/Pictures/Hexagon.png b/bin/Documentation/Pictures/Hexagon.png deleted file mode 100644 index 483991c6..00000000 Binary files a/bin/Documentation/Pictures/Hexagon.png and /dev/null differ diff --git a/bin/Documentation/Pictures/ImageRead.png b/bin/Documentation/Pictures/ImageRead.png index 33b42469..61ecd0a2 100644 Binary files a/bin/Documentation/Pictures/ImageRead.png and b/bin/Documentation/Pictures/ImageRead.png differ diff --git a/bin/Documentation/Pictures/ImageWrite.png b/bin/Documentation/Pictures/ImageWrite.png index f07fa500..95268a94 100644 Binary files a/bin/Documentation/Pictures/ImageWrite.png and b/bin/Documentation/Pictures/ImageWrite.png differ diff --git a/bin/Documentation/Pictures/Invert.png b/bin/Documentation/Pictures/Invert.png index 37bab1fb..2123fccd 100644 Binary files a/bin/Documentation/Pictures/Invert.png and b/bin/Documentation/Pictures/Invert.png differ diff --git a/bin/Documentation/Pictures/Kaleidoscope.png b/bin/Documentation/Pictures/Kaleidoscope.png index 78031937..616bae86 100644 Binary files a/bin/Documentation/Pictures/Kaleidoscope.png and b/bin/Documentation/Pictures/Kaleidoscope.png differ diff --git a/bin/Documentation/Pictures/LambertMaterial.png b/bin/Documentation/Pictures/LambertMaterial.png index a5c6c9a3..55424df6 100644 Binary files a/bin/Documentation/Pictures/LambertMaterial.png and b/bin/Documentation/Pictures/LambertMaterial.png differ diff --git a/bin/Documentation/Pictures/Lens.png b/bin/Documentation/Pictures/Lens.png index 1df32345..f5c0ebcb 100644 Binary files a/bin/Documentation/Pictures/Lens.png and b/bin/Documentation/Pictures/Lens.png differ diff --git a/bin/Documentation/Pictures/MADD.png b/bin/Documentation/Pictures/MADD.png index e3a47e9d..0e79bc69 100644 Binary files a/bin/Documentation/Pictures/MADD.png and b/bin/Documentation/Pictures/MADD.png differ diff --git a/bin/Documentation/Pictures/Multiplex.png b/bin/Documentation/Pictures/Multiplex.png new file mode 100644 index 00000000..53f15032 Binary files /dev/null and b/bin/Documentation/Pictures/Multiplex.png differ diff --git a/bin/Documentation/Pictures/NGon.png b/bin/Documentation/Pictures/NGon.png index 61efd23a..f953ef1a 100644 Binary files a/bin/Documentation/Pictures/NGon.png and b/bin/Documentation/Pictures/NGon.png differ diff --git a/bin/Documentation/Pictures/NormalMap.png b/bin/Documentation/Pictures/NormalMap.png index 982f3770..1f1a5e4d 100644 Binary files a/bin/Documentation/Pictures/NormalMap.png and b/bin/Documentation/Pictures/NormalMap.png differ diff --git a/bin/Documentation/Pictures/NormalMapBlending.png b/bin/Documentation/Pictures/NormalMapBlending.png index 599ff289..e2f40e1c 100644 Binary files a/bin/Documentation/Pictures/NormalMapBlending.png and b/bin/Documentation/Pictures/NormalMapBlending.png differ diff --git a/bin/Documentation/Pictures/PBR.png b/bin/Documentation/Pictures/PBR.png index 843d5858..9efaacf3 100644 Binary files a/bin/Documentation/Pictures/PBR.png and b/bin/Documentation/Pictures/PBR.png differ diff --git a/bin/Documentation/Pictures/PBR2.png b/bin/Documentation/Pictures/PBR2.png index 9e7bfe02..db56bdf3 100644 Binary files a/bin/Documentation/Pictures/PBR2.png and b/bin/Documentation/Pictures/PBR2.png differ diff --git a/bin/Documentation/Pictures/Paint2D.png b/bin/Documentation/Pictures/Paint2D.png index 447a9497..01e15ac7 100644 Binary files a/bin/Documentation/Pictures/Paint2D.png and b/bin/Documentation/Pictures/Paint2D.png differ diff --git a/bin/Documentation/Pictures/Paint3D.png b/bin/Documentation/Pictures/Paint3D.png index d9d00afd..7e739173 100644 Binary files a/bin/Documentation/Pictures/Paint3D.png and b/bin/Documentation/Pictures/Paint3D.png differ diff --git a/bin/Documentation/Pictures/Palette.png b/bin/Documentation/Pictures/Palette.png index eba5603a..7dff5af2 100644 Binary files a/bin/Documentation/Pictures/Palette.png and b/bin/Documentation/Pictures/Palette.png differ diff --git a/bin/Documentation/Pictures/PathTracer.png b/bin/Documentation/Pictures/PathTracer.png index 2c384112..c9797787 100644 Binary files a/bin/Documentation/Pictures/PathTracer.png and b/bin/Documentation/Pictures/PathTracer.png differ diff --git a/bin/Documentation/Pictures/PerlinNoise.png b/bin/Documentation/Pictures/PerlinNoise.png index 66d56f6f..748c557f 100644 Binary files a/bin/Documentation/Pictures/PerlinNoise.png and b/bin/Documentation/Pictures/PerlinNoise.png differ diff --git a/bin/Documentation/Pictures/PhysicalSky.png b/bin/Documentation/Pictures/PhysicalSky.png index f208271c..55a89324 100644 Binary files a/bin/Documentation/Pictures/PhysicalSky.png and b/bin/Documentation/Pictures/PhysicalSky.png differ diff --git a/bin/Documentation/Pictures/Pixelize.png b/bin/Documentation/Pictures/Pixelize.png index 480dd7af..88cf8136 100644 Binary files a/bin/Documentation/Pictures/Pixelize.png and b/bin/Documentation/Pictures/Pixelize.png differ diff --git a/bin/Documentation/Pictures/PolarCoords.png b/bin/Documentation/Pictures/PolarCoords.png index 8a5fdaf6..cf618248 100644 Binary files a/bin/Documentation/Pictures/PolarCoords.png and b/bin/Documentation/Pictures/PolarCoords.png differ diff --git a/bin/Documentation/Pictures/Ramp.png b/bin/Documentation/Pictures/Ramp.png index 04f7d10f..d0e1a850 100644 Binary files a/bin/Documentation/Pictures/Ramp.png and b/bin/Documentation/Pictures/Ramp.png differ diff --git a/bin/Documentation/Pictures/ReactionDiffusion.png b/bin/Documentation/Pictures/ReactionDiffusion.png index a233309c..952ceab6 100644 Binary files a/bin/Documentation/Pictures/ReactionDiffusion.png and b/bin/Documentation/Pictures/ReactionDiffusion.png differ diff --git a/bin/Documentation/Pictures/SVG.png b/bin/Documentation/Pictures/SVG.png index 67bb3690..c3139514 100644 Binary files a/bin/Documentation/Pictures/SVG.png and b/bin/Documentation/Pictures/SVG.png differ diff --git a/bin/Documentation/Pictures/SceneLoader.png b/bin/Documentation/Pictures/SceneLoader.png index be970245..a74f7756 100644 Binary files a/bin/Documentation/Pictures/SceneLoader.png and b/bin/Documentation/Pictures/SceneLoader.png differ diff --git a/bin/Documentation/Pictures/Sine.png b/bin/Documentation/Pictures/Sine.png index 206d9819..5d79d4a6 100644 Binary files a/bin/Documentation/Pictures/Sine.png and b/bin/Documentation/Pictures/Sine.png differ diff --git a/bin/Documentation/Pictures/SmoothStep.png b/bin/Documentation/Pictures/SmoothStep.png index b37376c1..9e33c2a5 100644 Binary files a/bin/Documentation/Pictures/SmoothStep.png and b/bin/Documentation/Pictures/SmoothStep.png differ diff --git a/bin/Documentation/Pictures/Square.png b/bin/Documentation/Pictures/Square.png deleted file mode 100644 index de0f1452..00000000 Binary files a/bin/Documentation/Pictures/Square.png and /dev/null differ diff --git a/bin/Documentation/Pictures/Swirl.png b/bin/Documentation/Pictures/Swirl.png index 4197e795..ab9e4c8c 100644 Binary files a/bin/Documentation/Pictures/Swirl.png and b/bin/Documentation/Pictures/Swirl.png differ diff --git a/bin/Documentation/Pictures/TerrainPreview.png b/bin/Documentation/Pictures/TerrainPreview.png index 46531f0e..234124ee 100644 Binary files a/bin/Documentation/Pictures/TerrainPreview.png and b/bin/Documentation/Pictures/TerrainPreview.png differ diff --git a/bin/Documentation/Pictures/Thumbnail.png b/bin/Documentation/Pictures/Thumbnail.png index e522ce51..0ff2351c 100644 Binary files a/bin/Documentation/Pictures/Thumbnail.png and b/bin/Documentation/Pictures/Thumbnail.png differ diff --git a/bin/Documentation/Pictures/Tile.png b/bin/Documentation/Pictures/Tile.png index dc04acc3..0041db37 100644 Binary files a/bin/Documentation/Pictures/Tile.png and b/bin/Documentation/Pictures/Tile.png differ diff --git a/bin/Documentation/Pictures/Transform.png b/bin/Documentation/Pictures/Transform.png index 7167d637..982594a5 100644 Binary files a/bin/Documentation/Pictures/Transform.png and b/bin/Documentation/Pictures/Transform.png differ diff --git a/bin/Documentation/Pictures/Voronoi.png b/bin/Documentation/Pictures/Voronoi.png index b7fa09f3..d293b6be 100644 Binary files a/bin/Documentation/Pictures/Voronoi.png and b/bin/Documentation/Pictures/Voronoi.png differ diff --git a/bin/Documentation/Pictures/Warp.png b/bin/Documentation/Pictures/Warp.png index 17a5de7d..139d3883 100644 Binary files a/bin/Documentation/Pictures/Warp.png and b/bin/Documentation/Pictures/Warp.png differ diff --git a/bin/Documentation/Pictures/WorleyNoise.png b/bin/Documentation/Pictures/WorleyNoise.png new file mode 100644 index 00000000..8980b775 Binary files /dev/null and b/bin/Documentation/Pictures/WorleyNoise.png differ diff --git a/bin/Documentation/Pictures/iqnoise.png b/bin/Documentation/Pictures/iqnoise.png index b7908b85..966849db 100644 Binary files a/bin/Documentation/Pictures/iqnoise.png and b/bin/Documentation/Pictures/iqnoise.png differ diff --git a/bin/Imogen.exe b/bin/Imogen.exe index 9754d3f0..62203acf 100644 Binary files a/bin/Imogen.exe and b/bin/Imogen.exe differ diff --git a/bin/Nodes/C/Crop.c b/bin/Nodes/C/Crop.c deleted file mode 100644 index 3770acca..00000000 --- a/bin/Nodes/C/Crop.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "Imogen.h" - -typedef struct Crop_t -{ - float quad[4]; -} Crop; - -int main(Crop *param, Evaluation *evaluation, void *context) -{ - int imageWidth, imageHeight; - int croppedWidth = 256, croppedHeight = 256; - if (GetEvaluationSize(context, evaluation->inputIndices[0], &imageWidth, &imageHeight) == EVAL_OK) - { - croppedWidth = imageWidth * fabsf(param->quad[2] - param->quad[0]); - croppedHeight = imageHeight * fabsf(param->quad[3] - param->quad[1]); - } - //if (croppedWidth<8) { croppedWidth = 8; } - //if (croppedHeight<8) { croppedHeight = 8; } - - if (evaluation->uiPass) - SetEvaluationSize(context, evaluation->targetIndex, imageWidth, imageHeight); - else - SetEvaluationSize(context, evaluation->targetIndex, croppedWidth, croppedHeight); - - return EVAL_OK; -} \ No newline at end of file diff --git a/bin/Nodes/C/CubeRadiance.c b/bin/Nodes/C/CubeRadiance.c deleted file mode 100644 index 3e6948c4..00000000 --- a/bin/Nodes/C/CubeRadiance.c +++ /dev/null @@ -1,34 +0,0 @@ - -#include "Imogen.h" - -typedef struct CubeRadianceParam_t -{ - int mode; // radiance, irradiance - int size; - int sampleCount; -}CubeRadianceParam; - - -int main(CubeRadianceParam *param, Evaluation *evaluation, void *context) -{ - int imgWidth, imgHeight; - int size = 128 << param->size; - int source = evaluation->inputIndices[0]; - if (param->size == 0 && source != -1 && GetEvaluationSize(context, source, &imgWidth, &imgHeight) == EVAL_OK) - { - size = imgWidth; - } - - if (param->mode == 0) - { - // radiance - SetEvaluationCubeSize(context, evaluation->targetIndex, size, 1); - } - else - { - // irradiance - SetEvaluationCubeSize(context, evaluation->targetIndex, size, log2(size)+1); - } - return EVAL_OK; -} - diff --git a/bin/Nodes/C/Distance.c b/bin/Nodes/C/Distance.c deleted file mode 100644 index 5e15cc91..00000000 --- a/bin/Nodes/C/Distance.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "Imogen.h" - -typedef struct Distance_t -{ - int PassCount; -} Distance; - -int main(Distance *param, Evaluation *evaluation, void *context) -{ - int imgWidth, imgHeight; - int source = evaluation->inputIndices[0]; - if (source != -1 && GetEvaluationSize(context, source, &imgWidth, &imgHeight) == EVAL_OK) - { - param->PassCount = log2(imgWidth)+3; - } - return EVAL_OK; -} \ No newline at end of file diff --git a/bin/Nodes/C/EquirectConverter.c b/bin/Nodes/C/EquirectConverter.c deleted file mode 100644 index 0068e0f3..00000000 --- a/bin/Nodes/C/EquirectConverter.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "Imogen.h" - -typedef struct EquirectConverter_t -{ - int mode; - int size; -} EquirectConverter; - - -int main(EquirectConverter *param, Evaluation *evaluation, void *context) -{ - int size = 256 << param->size; - if (param->mode == 0) - { - SetEvaluationCubeSize(context, evaluation->targetIndex, size, 1); - } - else - { - SetEvaluationSize(context, evaluation->targetIndex, size, size); - } - return EVAL_OK; -} diff --git a/bin/Nodes/C/FurDisplay.c b/bin/Nodes/C/FurDisplay.c deleted file mode 100644 index 5df648d6..00000000 --- a/bin/Nodes/C/FurDisplay.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "Imogen.h" - -int main(void *param, Evaluation *evaluation, void *context) -{ - int target = evaluation->targetIndex; - EnableFrameClear(context, target, 1); - EnableDepthBuffer(context, target, 1); - return EVAL_OK; -} \ No newline at end of file diff --git a/bin/Nodes/C/FurGenerator.c b/bin/Nodes/C/FurGenerator.c deleted file mode 100644 index b1a2a42a..00000000 --- a/bin/Nodes/C/FurGenerator.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "Imogen.h" - -typedef struct FurGenerator_t -{ - int hairCount; - float lengthFactor; -} FurGenerator; - -int main(FurGenerator *param, Evaluation *evaluation, void *context) -{ - return AllocateComputeBuffer(context, evaluation->targetIndex, param->hairCount, 15 * 4 *sizeof(float) ); -} \ No newline at end of file diff --git a/bin/Nodes/C/GLTFRead.c b/bin/Nodes/C/GLTFRead.c deleted file mode 100644 index 9956fafa..00000000 --- a/bin/Nodes/C/GLTFRead.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "Imogen.h" - -typedef struct GLTFRead_t -{ - char filename[1024]; -} GLTFRead; - -typedef struct JobData_t -{ - char filename[1024]; - int targetIndex; - void *context; - void *scene; -} JobData; - -int UploadMeshJob(JobData *data) -{ - SetEvaluationScene(data->context, data->targetIndex, data->scene); - SetProcessing(data->context, data->targetIndex, 0); - return EVAL_OK; -} - -int ReadJob(JobData *data) -{ - if (ReadGLTF(data->context, data->filename, &data->scene) == EVAL_OK) - { - JobData dataUp = *data; - JobMain(data->context, UploadMeshJob, &dataUp, sizeof(JobData)); - } - else - { - SetProcessing(data->context, data->targetIndex, 0); - } - return EVAL_OK; -} - -int main(GLTFRead *param, Evaluation *evaluation, void *context) -{ - int i; - int target = evaluation->targetIndex; - EnableDepthBuffer(context, target, 1); - EnableFrameClear(context, target, 1); - SetVertexSpace(context, target, vertexSpace_World); - - if (strlen(param->filename) && strcmp(GetEvaluationSceneName(context, target), param->filename)) - { - SetProcessing(context, target, 1); - JobData data; - strcpy(data.filename, param->filename); - data.targetIndex = target; - data.context = context; - ReadJob(&data); - //Job(context, ReadJob, &data, sizeof(JobData)); - } - - return EVAL_OK; -} \ No newline at end of file diff --git a/bin/Nodes/C/GradientBuilder.c b/bin/Nodes/C/GradientBuilder.c deleted file mode 100644 index 97b550b1..00000000 --- a/bin/Nodes/C/GradientBuilder.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "Imogen.h" - -int main(void *param, Evaluation *evaluation, void *context) -{ - SetEvaluationSize(context, evaluation->targetIndex, 512, 64); - return EVAL_OK; -} \ No newline at end of file diff --git a/bin/Nodes/C/ImageRead.c b/bin/Nodes/C/ImageRead.c deleted file mode 100644 index 858016fb..00000000 --- a/bin/Nodes/C/ImageRead.c +++ /dev/null @@ -1,94 +0,0 @@ -#include "Imogen.h" - -typedef struct ImageRead_t -{ - char filename[1024]; - - char posxfile[1024]; - char negxfile[1024]; - char posyfile[1024]; - char negyfile[1024]; - char poszfile[1024]; - char negzfile[1024]; -} ImageRead; - -typedef struct JobData_t -{ - char filename[1024]; - int targetIndex; - int face; - int isCube; - void *context; - Image image; -} JobData; - -int UploadImageJob(JobData *data) -{ - if (data->isCube) - { - SetEvaluationImageCube(data->context, data->targetIndex, &data->image, data->face); - } - else - { - SetEvaluationImage(data->context, data->targetIndex, &data->image); - } - FreeImage(&data->image); - SetProcessing(data->context, data->targetIndex, 0); - return EVAL_OK; -} - -int ReadJob(JobData *data) -{ - if (ReadImage(data->context, data->filename, &data->image) == EVAL_OK) - { - JobData dataUp = *data; - JobMain(data->context, UploadImageJob, &dataUp, sizeof(JobData)); - } - else - SetProcessing(data->context, data->targetIndex, 0); - return EVAL_OK; -} - -int main(ImageRead *param, Evaluation *evaluation, void *context) -{ - int i; - char *files[6] = {param->posxfile, param->negxfile, param->negyfile, param->posyfile, param->poszfile, param->negzfile}; - - if (!(evaluation->dirtyFlag & DirtyParameter)) - return EVAL_OK; - - if (strlen(param->filename)) - { - SetProcessing(context, evaluation->targetIndex, 1); - JobData data; - strcpy(data.filename, param->filename); - data.targetIndex = evaluation->targetIndex; - data.face = 0; - data.isCube = 0; - data.image.bits = 0; - data.context = context; - Job(context, ReadJob, &data, sizeof(JobData)); - } - else - { - for (i = 0;i<6;i++) - { - if (!strlen(files[i])) - return EVAL_OK; - } - SetProcessing(context, evaluation->targetIndex, 1); - for (i = 0;i<6;i++) - { - JobData data; - strcpy(data.filename, files[i]); - data.targetIndex = evaluation->targetIndex; - data.face = CUBEMAP_POSX + i; - data.isCube = 1; - data.image.bits = 0; - data.context = context; - Job(context, ReadJob, &data, sizeof(JobData)); - } - } - - return EVAL_OK; -} \ No newline at end of file diff --git a/bin/Nodes/C/ImageWrite.c b/bin/Nodes/C/ImageWrite.c deleted file mode 100644 index 256eb2f6..00000000 --- a/bin/Nodes/C/ImageWrite.c +++ /dev/null @@ -1,61 +0,0 @@ - -#include "Imogen.h" - -typedef struct ImageWrite_t -{ - char filename[1024]; - int format; - int quality; - int width, height; - int mode; -}ImageWrite; - -int main(ImageWrite *param, Evaluation *evaluation, void *context) -{ - char *stockImages[8] = {"Stock/jpg-icon.png", "Stock/png-icon.png", "Stock/tga-icon.png", "Stock/bmp-icon.png", "Stock/hdr-icon.png", "Stock/dds-icon.png", "Stock/ktx-icon.png", "Stock/mp4-icon.png"}; - Image image; - int imageWidth, imageHeight; - - image.bits = 0; - // set info stock image - if (ReadImage(context, stockImages[param->format], &image) == EVAL_OK) - { - if (SetEvaluationImage(context, evaluation->targetIndex, &image) == EVAL_OK) - { - FreeImage(&image); - } - } - - if (param->mode && GetEvaluationSize(context, evaluation->inputIndices[0], &imageWidth, &imageHeight) == EVAL_OK) - { - float ratio = (float)imageWidth / (float)imageHeight; - if (param->mode == 1) - { - param->width = imageWidth; - param->height = param->width / ratio; - } - else - { - param->width = param->height * ratio; - param->height = imageHeight; - } - } - - if (!evaluation->forcedDirty) - return EVAL_OK; - - image.bits = 0; - if (Evaluate(context, evaluation->inputIndices[0], param->width, param->height, &image) == EVAL_OK) - { - if (WriteImage(context, param->filename, &image, param->format, param->quality) == EVAL_OK) - { - FreeImage(&image); - Log("Image %s saved.\n", param->filename); - return EVAL_OK; - } - else - Log("Unable to write image : %s\n", param->filename); - } - - return EVAL_ERR; -} \ No newline at end of file diff --git a/bin/Nodes/C/Imogen.h b/bin/Nodes/C/Imogen.h deleted file mode 100644 index 3c156600..00000000 --- a/bin/Nodes/C/Imogen.h +++ /dev/null @@ -1,171 +0,0 @@ -int Log(const char *szFormat, ...); -char * strcpy (char * destination, const char * source); -int strcmp(char *str1, char *str2); -int strlen (const char * str); -float fabsf(float value); -float log2(float); - -typedef struct Image_t -{ - void *decoder; - int width, height; - //int components; - int mDataSize; - unsigned char mNumMips; - unsigned char mNumFaces; - unsigned char mFormat; - void *bits; -} Image; - -int DirtyInput = (1 << 0); -int DirtyParameter = (1 << 1); -int DirtyMouse = (1 << 2); -int DirtyCamera = (1 << 3); -int DirtyTime = (1 << 4); -int DirtySampler = (1 << 5); - - -typedef struct Evaluation_t -{ - float inv_view_rot[16]; - float viewProjection[16]; - float viewInverse[16]; - float model[16]; - float modelViewProjection[16]; - float viewport[4]; - - int targetIndex; - int forcedDirty; - int uiPass; - int passNumber; - float mouse[4]; - int keyModifier[4]; - int inputIndices[8]; - - int frame; - int localFrame; - int vertexSpace; - int dirtyFlag; - - int mipmapNumber; - int mipmapCount; -} Evaluation; - -enum BlendOp -{ - ZERO, - ONE, - SRC_COLOR, - ONE_MINUS_SRC_COLOR, - DST_COLOR, - ONE_MINUS_DST_COLOR, - SRC_ALPHA, - ONE_MINUS_SRC_ALPHA, - DST_ALPHA, - ONE_MINUS_DST_ALPHA, - CONSTANT_COLOR, - ONE_MINUS_CONSTANT_COLOR, - CONSTANT_ALPHA, - ONE_MINUS_CONSTANT_ALPHA, - SRC_ALPHA_SATURATE, - BLEND_LAST -}; - -enum ImageFormat -{ - BGR8, - RGB8, - RGB16, - RGB16F, - RGB32F, - RGBE, - - BGRA8, - RGBA8, - RGBA16, - RGBA16F, - RGBA32F, - - RGBM, - - ImageFormatCount -}; - -enum CubeMapFace -{ - CUBEMAP_POSX, - CUBEMAP_NEGX, - CUBEMAP_POSY, - CUBEMAP_NEGY, - CUBEMAP_POSZ, - CUBEMAP_NEGZ, -}; - -int vertexSpace_UV = 0; -int vertexSpace_World = 1; - -// call FreeImage when done -int ReadImage(void* context, char *filename, Image *image); -// writes an allocated image -int WriteImage(void* context, char *filename, Image *image, int format, int quality); -// call FreeImage when done -int GetEvaluationImage(void* context, int target, Image *image); -// -int SetEvaluationImage(void* context, int target, Image *image); -int SetEvaluationImageCube(void* context, int target, Image *image, int cubeFace); -// call FreeImage when done -// set the bits pointer with an allocated memory -int AllocateImage(Image *image); -int FreeImage(Image *image); -int LoadSVG(const char *filename, Image *image, float dpi); - -// Image resize -// Image thumbnail -int SetThumbnailImage(void *context, Image *image); - -// force evaluation of a target with a specified size -// no guarantee that the resulting Image will have that size. -int Evaluate(void *context, int target, int width, int height, Image *image); - -void SetBlendingMode(void *context, int target, int blendSrc, int blendDst); -void EnableDepthBuffer(void *context, int target, int enable); -void EnableFrameClear(void *context, int target, int enable); - -void SetVertexSpace(void *context, int target, int vertexMode); - -int GetEvaluationSize(void *context, int target, int *imageWidth, int *imageHeight); -int SetEvaluationSize(void *context, int target, int imageWidth, int imageHeight); -int SetEvaluationCubeSize(void *context, int target, int faceWidth, int mipmapCount); - -int OverrideInput(void *context, int target, int inputIndex, int newInputTarget); -int CubemapFilter(Image *image, int faceSize, int lightingModel, int excludeBase, int glossScale, int glossBias); - -int Job(void *context, int(*jobFunction)(void*), void *ptr, unsigned int size); -int JobMain(void *context, int(*jobMainFunction)(void*), void *ptr, unsigned int size); -// processing values: -// 0 : no more processing, display node as normal -// 1 : processing with an animation for node display -// 2 : display node as normal despite it processing -void SetProcessing(void *context, int target, int processing); - -// compute shader memory allocation -int AllocateComputeBuffer(void *context, int target, int elementCount, int elementSize); - -int LoadScene(const char *filename, void **scene); -int SetEvaluationScene(void *context, int target, void *scene); -int GetEvaluationScene(void *context, int target, void **scene); - -int SetEvaluationRTScene(void *context, int target, void *scene); -int GetEvaluationRTScene(void *context, int target, void **scene); - -char* GetEvaluationSceneName(void *context, int target); -int GetEvaluationRenderer(void *context, int target, void **renderer); -int InitRenderer(void *context, int target, int mode, void *scene); -int UpdateRenderer(void *context, int target); - -int ReadGLTF(void *evaluationContext, char *filename, void **scene); - - -#define EVAL_OK 0 -#define EVAL_ERR 1 -#define EVAL_DIRTY 2 diff --git a/bin/Nodes/C/Paint2D.c b/bin/Nodes/C/Paint2D.c deleted file mode 100644 index 20aba3a1..00000000 --- a/bin/Nodes/C/Paint2D.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "Imogen.h" - -typedef struct Paint2D_t -{ - int size; -} Paint2D; - -int main(Paint2D *param, Evaluation *evaluation, void *context) -{ - SetEvaluationSize(context, evaluation->targetIndex, 256<size, 256<size); - SetBlendingMode(context, evaluation->targetIndex, ONE, ONE_MINUS_SRC_ALPHA); - return EVAL_OK; -} \ No newline at end of file diff --git a/bin/Nodes/C/Paint3D.c b/bin/Nodes/C/Paint3D.c deleted file mode 100644 index 6e15c636..00000000 --- a/bin/Nodes/C/Paint3D.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "Imogen.h" - -typedef struct Paint3D_t -{ - int size; -} Paint3D; - -int main(Paint3D *param, Evaluation *evaluation, void *context) -{ - if (evaluation->uiPass == 1) - { - SetBlendingMode(context, evaluation->targetIndex, ONE, ZERO); - OverrideInput(context, evaluation->targetIndex, 0, evaluation->targetIndex); - SetVertexSpace(context, evaluation->targetIndex, vertexSpace_World); - EnableDepthBuffer(context, evaluation->targetIndex, 1); - EnableFrameClear(context, evaluation->targetIndex, 1); - } - else - { - SetBlendingMode(context, evaluation->targetIndex, ONE, ONE_MINUS_SRC_ALPHA); - OverrideInput(context, evaluation->targetIndex, 0, -1); // remove override - SetVertexSpace(context, evaluation->targetIndex, vertexSpace_UV); - EnableDepthBuffer(context, evaluation->targetIndex, 0); - EnableFrameClear(context, evaluation->targetIndex, 0); - } - //SetEvaluationSize(context, evaluation->targetIndex, 256<size, 256<size); - //SetBlendingMode(context, evaluation->targetIndex, ONE, ONE_MINUS_SRC_ALPHA); - - // use scene from input node - void *scene; - if (GetEvaluationScene(context, evaluation->inputIndices[0], &scene) == EVAL_OK) - { - SetEvaluationScene(context, evaluation->targetIndex, scene); - } - return EVAL_OK; -} \ No newline at end of file diff --git a/bin/Nodes/C/PathTracer.c b/bin/Nodes/C/PathTracer.c deleted file mode 100644 index ec085705..00000000 --- a/bin/Nodes/C/PathTracer.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "Imogen.h" - -typedef struct PathTracer_t -{ - int mode; -} PathTracer; - -int main(PathTracer *param, Evaluation *evaluation, void *context) -{ - void *scene; - void *renderer; - if (evaluation->inputIndices[0] == -1) - return EVAL_OK; - if (GetEvaluationRTScene(context, evaluation->inputIndices[0], &scene) != EVAL_OK) - return EVAL_ERR; - if (!scene) - return EVAL_OK; - if (GetEvaluationRenderer(context, evaluation->targetIndex, &renderer) != EVAL_OK) - return EVAL_ERR; - if (!renderer) - { - if (InitRenderer(context, evaluation->targetIndex, 0, scene) != EVAL_OK) - return EVAL_ERR; - } - SetEvaluationSize(context, evaluation->targetIndex, 1024, 1024); - SetProcessing(context, evaluation->targetIndex, 2); - - return UpdateRenderer(context, evaluation->targetIndex); -} \ No newline at end of file diff --git a/bin/Nodes/C/PhysicalSky.c b/bin/Nodes/C/PhysicalSky.c deleted file mode 100644 index 59c0a0a2..00000000 --- a/bin/Nodes/C/PhysicalSky.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "Imogen.h" - -typedef struct PhysicalSky_t -{ - float ambient[4]; - float lightdir[4], Kr[4]; - float rayleigh_brightness, mie_brightness, spot_brightness, scatter_strength, rayleigh_strength, mie_strength; - float rayleigh_collection_power, mie_collection_power, mie_distribution; - int size; -} PhysicalSky; - - -int main(PhysicalSky *param, Evaluation *evaluation, void *context) -{ - int size = 256 << param->size; - SetEvaluationCubeSize(context, evaluation->targetIndex, size, 1); - return EVAL_OK; -} diff --git a/bin/Nodes/C/ReactionDiffusion.c b/bin/Nodes/C/ReactionDiffusion.c deleted file mode 100644 index f98134e7..00000000 --- a/bin/Nodes/C/ReactionDiffusion.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "Imogen.h" - -typedef struct ReactionDiffusion_t -{ - float boost; - float divisor; - float colorStep; - int PassCount; - int size; -} ReactionDiffusion; - -int main(ReactionDiffusion *param, Evaluation *evaluation, void *context) -{ - SetEvaluationSize(context, evaluation->targetIndex, 256<size, 256<size); - return EVAL_OK; -} \ No newline at end of file diff --git a/bin/Nodes/C/SVG.c b/bin/Nodes/C/SVG.c deleted file mode 100644 index 1102b489..00000000 --- a/bin/Nodes/C/SVG.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "Imogen.h" - -typedef struct SVG_t -{ - char filename[1024]; - float dpi; -} SVG; - -int main(SVG *param, Evaluation *evaluation, void *context) -{ - Image image; - image.bits = 0; - if (param->dpi <= 1.f) - param->dpi = 96.f; - - if (strlen(param->filename)) - { - if (LoadSVG(param->filename, &image, param->dpi) == EVAL_OK) - { - SetEvaluationImage(context, evaluation->targetIndex, &image); - } - } - return EVAL_OK; -} \ No newline at end of file diff --git a/bin/Nodes/C/SceneLoader.c b/bin/Nodes/C/SceneLoader.c deleted file mode 100644 index 574442ce..00000000 --- a/bin/Nodes/C/SceneLoader.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "Imogen.h" - -typedef struct SceneLoader_t -{ - char filename[1024]; -} SceneLoader; - -typedef struct JobData_t -{ - char filename[1024]; - int targetIndex; - void *context; -} JobData; - -int ReadSceneJob(JobData *data) -{ - void *scene; - if (LoadScene(data->filename, &scene) == EVAL_OK) - { - SetEvaluationRTScene(data->context, data->targetIndex, scene); - } - SetProcessing(data->context, data->targetIndex, 0); - return EVAL_OK; -} - -int main(SceneLoader *param, Evaluation *evaluation, void *context) -{ - if (strlen(param->filename)) - { - SetProcessing(context, evaluation->targetIndex, 1); - JobData data; - strcpy(data.filename, param->filename); - data.targetIndex = evaluation->targetIndex; - data.context = context; - Job(context, ReadSceneJob, &data, sizeof(JobData)); - } - return EVAL_OK; -} \ No newline at end of file diff --git a/bin/Nodes/C/Thumbnail.c b/bin/Nodes/C/Thumbnail.c deleted file mode 100644 index 4296d3fc..00000000 --- a/bin/Nodes/C/Thumbnail.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "Imogen.h" - -int main(void *param, Evaluation *evaluation, void *context) -{ - Image image; - image.bits = 0; - if (ReadImage(context, "Stock/thumbnail-icon.png", &image) == EVAL_OK) - { - if (SetEvaluationImage(context, evaluation->targetIndex, &image) == EVAL_OK) - { - FreeImage(&image); - } - } - - if (!evaluation->forcedDirty) - return EVAL_OK; - - image.bits = 0; - if (Evaluate(context, evaluation->inputIndices[0], 256, 256, &image) == EVAL_OK) - { - if (SetThumbnailImage(context, &image) == EVAL_OK) - { - FreeImage(&image); - return EVAL_OK; - } - } - - return EVAL_ERR; -} diff --git a/bin/Nodes/GLSL/AO.glsl b/bin/Nodes/GLSL/AO.glsl deleted file mode 100644 index a60c812a..00000000 --- a/bin/Nodes/GLSL/AO.glsl +++ /dev/null @@ -1,96 +0,0 @@ -layout (std140) uniform AOBlock -{ - float total_strength;// = 0.6; - - float area;// = 0.0075; - float falloff;// = 0.00001; - - float radius;// = 0.016; -} AOParam; - - -float hash(vec2 p) // replace this by something better -{ - p = 50.0*fract( p*0.3183099 + vec2(0.71,0.113)); - return -1.0+2.0*fract( p.x*p.y*(p.x+p.y) ); -} - -vec3 normal_from_depth(float depth, vec2 texcoords) { - - vec2 offset1 = dFdy(vUV); - vec2 offset2 = dFdx(vUV); - - float depth1 = texture(Sampler0, texcoords + offset1).x; - float depth2 = texture(Sampler0, texcoords + offset2).x; - - vec3 p1 = vec3(offset1, depth1 - depth); - vec3 p2 = vec3(offset2, depth2 - depth); - - vec3 normal = cross(p1, p2); - - return normalize(normal); -} - - -float AO() -{ - // constants - - int samples = 48; - - vec3 sample_sphere[48]=vec3[48]( - vec3( 0.5381, 0.1856,-0.4319), vec3( 0.1379, 0.2486, 0.4430), - vec3( 0.3371, 0.5679,-0.0057), vec3(-0.6999,-0.0451,-0.0019), - vec3( 0.0689,-0.1598,-0.8547), vec3( 0.0560, 0.0069,-0.1843), - vec3(-0.0146, 0.1402, 0.0762), vec3( 0.0100,-0.1924,-0.0344), - vec3(-0.3577,-0.5301,-0.4358), vec3(-0.3169, 0.1063, 0.0158), - vec3( 0.0103,-0.5869, 0.0046), vec3(-0.0897,-0.4940, 0.3287), - vec3( 0.7119,-0.0154,-0.0918), vec3(-0.0533, 0.0596,-0.5411), - vec3( 0.0352,-0.0631, 0.5460), vec3(-0.4776, 0.2847,-0.0271), - vec3( 0.1482, -0.2644, -0.4988 ),vec3( -0.1400, -0.2298, -0.4256 ), - vec3( -0.1811, 0.4853, -0.2447 ),vec3( 0.3576, -0.3214, 0.4342 ), - vec3( 0.1268, -0.4914, -0.4651 ),vec3( 0.3022, -0.2270, -0.0141 ), - vec3( 0.1402, -0.0520, -0.4085 ),vec3( 0.2906, 0.1609, 0.4733 ), - vec3( 0.3814, -0.4596, 0.0633 ),vec3( 0.4851, -0.2032, -0.4316 ), - vec3( -0.4744, -0.4820, -0.4254 ),vec3( 0.1481, 0.0160, 0.0672 ), - vec3( -0.1199, -0.1149, 0.2206 ),vec3( -0.2901, 0.4013, -0.4735 ), - vec3( 0.4643, 0.0459, 0.3613 ),vec3( 0.4495, -0.1273, 0.1282 ), - vec3( -0.2672, 0.0208, -0.2687 ),vec3( -0.0878, -0.1253, 0.3974 ), - vec3( -0.1237, -0.1445, 0.2443 ),vec3( 0.0879, -0.4289, -0.2810 ), - vec3( 0.3218, -0.0686, 0.1749 ),vec3( -0.2435, 0.1608, -0.4664 ), - vec3( -0.3292, 0.3501, 0.2427 ),vec3( -0.0968, -0.0698, 0.2560 ), - vec3( -0.0343, 0.0098, -0.3571 ),vec3( 0.3354, -0.4162, -0.0135 ), - vec3( 0.0088, 0.0495, 0.3811 ),vec3( 0.2173, -0.1393, -0.4038 ), - vec3( -0.4144, -0.3722, -0.4927 ),vec3( -0.1846, -0.4077, 0.3831 ), - vec3( -0.0111, 0.1529, 0.1266 ),vec3( -0.0739, 0.2930, -0.1468 ) - ); - - - //samples - vec2 uvs = vUV * 3.; - vec3 random = normalize(vec3(hash(uvs),hash(uvs+vec2(1.0)),hash(uvs+vec2(2.0)))); - float depth = texture(Sampler0, vUV).x; - vec3 clipSpaceNormal = normal_from_depth(depth, vUV);//texture2D(normalTexture, vUV).xyz *2.0 - 1.0; - - //clipSpaceNormal.z = -clipSpaceNormal.z; - vec3 position = vec3(vUV, depth); - // occ - float radius_depth = AOParam.radius/(depth+0.01); - float occlusion = 0.0; - for(int i=0; i < samples; i++) - { - vec3 ray = radius_depth * reflect(sample_sphere[i], random); - vec3 hemi_ray = position + sign(dot(ray,clipSpaceNormal)) * ray; - - float occ_depth = texture(Sampler0, clamp(hemi_ray.xy,0.0,1.0)).x; - float difference = occ_depth - depth; - - occlusion += step(AOParam.falloff, difference) * (1.0-smoothstep(AOParam.falloff, AOParam.area, difference)); - } - - - float ao = 1.0 - AOParam.total_strength * occlusion * (1.0 / float(samples)); - - //return vec4(clipSpaceNormal*0.5+0.5, 1.0); - return ao; -} diff --git a/bin/Nodes/GLSL/Blend.glsl b/bin/Nodes/GLSL/Blend.glsl deleted file mode 100644 index 06e8ddd6..00000000 --- a/bin/Nodes/GLSL/Blend.glsl +++ /dev/null @@ -1,42 +0,0 @@ -layout (std140) uniform BlendBlock -{ - vec4 A; - vec4 B; - int op; -} BlendParam; - -vec4 Blend() -{ - vec4 a = texture(Sampler0, vUV) * BlendParam.A; - vec4 b = texture(Sampler1, vUV) * BlendParam.B; - vec4 white = vec4(1,1,1,1); - switch (BlendParam.op) - { - case 0: // Add - return a + b; - case 1: // Multiply - return a * b; - case 2: // Darken - return min(a, b); - case 3: // Lighten - return max(a, b); - case 4: // Average - return (a + b) * 0.5; - case 5: // Screen - return white - ((white - b) * (white - a)); - case 6: // Color Burn - return white - (white - a) / b; - case 7: // Color Dodge - return a / (white - b); - case 8: // Soft Light - return 2.0 * a * b + a * a - 2.0 * a * a * b; - case 9: // Subtract - return a - b; - case 10: // Difference - return abs(b - a); - case 11: // Inverse Difference - return white - abs(white - a - b); - case 12: // Exclusion - return b + a - (2.0 * a * b); - } -} \ No newline at end of file diff --git a/bin/Nodes/GLSL/Blur.glsl b/bin/Nodes/GLSL/Blur.glsl deleted file mode 100644 index d7a4c94f..00000000 --- a/bin/Nodes/GLSL/Blur.glsl +++ /dev/null @@ -1,55 +0,0 @@ -layout (std140) uniform BlurBlock -{ - int type; - float angle; - float strength; - int passCount; -} BlurParam; - -vec4 Blur() -{ - float g[15]; - g[0] = 0.023089; - g[1] = 0.034587; - g[2] = 0.048689; - g[3] = 0.064408; - g[4] = 0.080066; - g[5] = 0.093531; - g[6] = 0.102673; - g[7] = 0.105915; - g[8] = 0.102673; - g[9] = 0.093531; - g[10] = 0.080066; - g[11] = 0.064408; - g[12] = 0.048689; - g[13] = 0.034587; - g[14] = 0.023089; - - vec4 col = vec4(0.0); - if (BlurParam.type == 0) - { - vec2 dir = vec2(cos(BlurParam.angle), sin(BlurParam.angle)); - for(int i = 0;i<15;i++) - { - col += texture(Sampler0, vUV + dir * BlurParam.strength * float(i-7)) * g[i]; - } - } - else - { - // box - float sum = 0.; - for (int j = 0;j<15;j++) - { - for(int i = 0;i<15;i++) - { - float w = g[i] * g[j]; - col += texture(Sampler0, vUV + vec2(float(i-7), float(j-7)) * BlurParam.strength) * w; - sum += w; - } - } - col /= sum; - - } - - return col; -} \ No newline at end of file diff --git a/bin/Nodes/GLSL/ChannelPacker.glsl b/bin/Nodes/GLSL/ChannelPacker.glsl deleted file mode 100644 index 196c5993..00000000 --- a/bin/Nodes/GLSL/ChannelPacker.glsl +++ /dev/null @@ -1,33 +0,0 @@ - -layout (std140) uniform ChannelPackerBlock -{ - int R; - int G; - int B; - int A; -} ChannelPackerParam; - -vec4 ChannelPacker() -{ - vec4 lu[4]; - lu[0]= texture(Sampler0, vUV); - lu[1]= texture(Sampler1, vUV); - lu[2]= texture(Sampler2, vUV); - lu[3]= texture(Sampler3, vUV); - - vec4 res = vec4(lu[(ChannelPackerParam.R>>2)&3][ChannelPackerParam.R&3], - lu[(ChannelPackerParam.G>>2)&3][ChannelPackerParam.G&3], - lu[(ChannelPackerParam.B>>2)&3][ChannelPackerParam.B&3], - lu[(ChannelPackerParam.A>>2)&3][ChannelPackerParam.A&3]); - - if (ChannelPackerParam.R>15) - res.x = 1. - res.x; - if (ChannelPackerParam.G>15) - res.y = 1. - res.y; - if (ChannelPackerParam.B>15) - res.z = 1. - res.z; - if (ChannelPackerParam.A>15) - res.w = 1. - res.w; - - return res; -} diff --git a/bin/Nodes/GLSL/Checker.glsl b/bin/Nodes/GLSL/Checker.glsl deleted file mode 100644 index 7a06cb71..00000000 --- a/bin/Nodes/GLSL/Checker.glsl +++ /dev/null @@ -1,5 +0,0 @@ -float Checker() -{ - vec2 nuv = vUV - vec2(0.5); - return mod(floor(nuv.x)+floor(nuv.y),2.0); -} \ No newline at end of file diff --git a/bin/Nodes/GLSL/Circle.glsl b/bin/Nodes/GLSL/Circle.glsl deleted file mode 100644 index da7ea534..00000000 --- a/bin/Nodes/GLSL/Circle.glsl +++ /dev/null @@ -1,10 +0,0 @@ -layout (std140) uniform CircleBlock -{ - float radius; - float t; -}; - -vec4 Circle() -{ - return vec4(Circle(vUV, radius, t)); -} diff --git a/bin/Nodes/GLSL/CircleSplatter.glsl b/bin/Nodes/GLSL/CircleSplatter.glsl deleted file mode 100644 index 83857bb2..00000000 --- a/bin/Nodes/GLSL/CircleSplatter.glsl +++ /dev/null @@ -1,21 +0,0 @@ -layout (std140) uniform CircleSplatterBlock -{ - vec2 distToCenter; - vec2 radii; - vec2 angles; - float count; -} CircleSplatterParam; - -vec4 CircleSplatter() -{ - vec4 col = vec4(0.0); - for (float i = 0.0 ; i < CircleSplatterParam.count ; i += 1.0) - { - float t = i/(CircleSplatterParam.count-0.0); - vec2 dist = vec2(mix(CircleSplatterParam.distToCenter.x, CircleSplatterParam.distToCenter.y, t), 0.0); - dist = Rotate2D(dist, mix(CircleSplatterParam.angles.x, CircleSplatterParam.angles.y, t)); - float radius = mix(CircleSplatterParam.radii.x, CircleSplatterParam.radii.y, t); - col = max(col, vec4(Circle(vUV-dist, radius, 0.0))); - } - return col; -} \ No newline at end of file diff --git a/bin/Nodes/GLSL/Clamp.glsl b/bin/Nodes/GLSL/Clamp.glsl deleted file mode 100644 index 2f31088a..00000000 --- a/bin/Nodes/GLSL/Clamp.glsl +++ /dev/null @@ -1,11 +0,0 @@ -layout (std140) uniform ClampBlock -{ - vec4 clampMin; - vec4 clampMax; -} ClampParam; - -vec4 Clamp() -{ - vec4 tex = texture(Sampler0, vUV); - return clamp(tex, ClampParam.clampMin, ClampParam.clampMax); -} diff --git a/bin/Nodes/GLSL/Color.glsl b/bin/Nodes/GLSL/Color.glsl deleted file mode 100644 index 3b5b3c91..00000000 --- a/bin/Nodes/GLSL/Color.glsl +++ /dev/null @@ -1,9 +0,0 @@ -layout (std140) uniform ColorBlock -{ - vec4 color; -} ColorParam; - -vec4 Color() -{ - return ColorParam.color; -} diff --git a/bin/Nodes/GLSL/Crop.glsl b/bin/Nodes/GLSL/Crop.glsl deleted file mode 100644 index dc62b47c..00000000 --- a/bin/Nodes/GLSL/Crop.glsl +++ /dev/null @@ -1,23 +0,0 @@ -layout (std140) uniform CropBlock -{ - vec4 quad; -} CropParam; - -vec4 Crop() -{ - if (EvaluationParam.uiPass == 1) - { - vec4 q = vec4(min(CropParam.quad.x, CropParam.quad.z), - min(CropParam.quad.y, CropParam.quad.w), - max(CropParam.quad.x, CropParam.quad.z), - max(CropParam.quad.y, CropParam.quad.w)); - float barx = min(step(q.x, vUV.x), step(vUV.x, q.z)); - float bary = min(step(q.y, vUV.y), step(vUV.y, q.w)); - float colFactor = min(barx, bary); - return texture(Sampler0, vUV) * max(colFactor, 0.5); - } - - vec4 q = CropParam.quad; - vec2 uv = vec2(mix(min(q.x, q.z), max(q.x, q.z), vUV.x), mix(min(q.y, q.w), max(q.y, q.w), vUV.y)); - return texture(Sampler0, uv); -} \ No newline at end of file diff --git a/bin/Nodes/GLSL/CubeRadiance.glsl b/bin/Nodes/GLSL/CubeRadiance.glsl deleted file mode 100644 index bb139d55..00000000 --- a/bin/Nodes/GLSL/CubeRadiance.glsl +++ /dev/null @@ -1,119 +0,0 @@ - -layout (std140) uniform CubeRadianceBlock -{ - int mode; // radiance, irradiance - int size; - int sampleCount; -} CubeRadianceParam; - -vec3 get_world_normal() -{ - vec3 dir = (EvaluationParam.viewRot * vec4(vUV * 2.0 - 1.0, 1.0, 0.0)).xyz; - return normalize(dir); -} -// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/ -float random(vec2 co) -{ - float a = 12.9898; - float b = 78.233; - float c = 43758.5453; - float dt= dot(co.xy ,vec2(a,b)); - float sn= mod(dt,3.14); - return fract(sin(sn) * c); -} - -vec2 hammersley2d(uint i, uint N) -{ - // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html - uint bits = (i << 16u) | (i >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - float rdi = float(bits) * 2.3283064365386963e-10; - return vec2(float(i) /float(N), rdi); -} - -// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf -vec3 importanceSample_GGX(vec2 Xi, float roughness, vec3 normal) -{ - // Maps a 2D point to a hemisphere with spread based on roughness - float alpha = roughness * roughness; - float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1; - float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y)); - float sinTheta = sqrt(1.0 - cosTheta * cosTheta); - vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); - - // Tangent space - vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); - vec3 tangentX = normalize(cross(up, normal)); - vec3 tangentY = normalize(cross(normal, tangentX)); - - // Convert to world Space - return normalize(tangentX * H.x + tangentY * H.y + normal * H.z); -} - -// Normal Distribution function -float D_GGX(float dotNH, float roughness) -{ - float alpha = roughness * roughness; - float alpha2 = alpha * alpha; - float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0; - return (alpha2)/(PI * denom*denom); -} - -vec3 prefilterEnvMap(vec3 R, float roughness) -{ - vec3 N = R; - vec3 V = R; - uint numSamples = uint(CubeRadianceParam.sampleCount); - vec3 color = vec3(0.0); - float totalWeight = float(numSamples); - float envMapDim = float(textureSize(CubeSampler0, EvaluationParam.mipmapNumber).s); - for(uint i = 0u; i < numSamples; i++) { - vec2 Xi = hammersley2d(i, numSamples); - vec3 H = importanceSample_GGX(Xi, roughness, N); - vec3 L = 2.0 * dot(V, H) * H - V; - - color += textureLod(CubeSampler0, L, 0.).rgb;// * dotNL; - /* - float dotNL = clamp(dot(N, L), 0.0, 1.0); - if(dotNL > 0.0) - { - // Filtering based on https://placeholderart.wordpress.com/2015/07/28/implementation-notes-runtime-environment-map-filtering-for-image-based-lighting/ - - float dotNH = clamp(dot(N, H), 0.0, 1.0); - float dotVH = clamp(dot(V, H), 0.0, 1.0); - - // Probability Distribution Function - float pdf = D_GGX(dotNH, roughness) * dotNH / (4.0 * dotVH) + 0.0001; - // Slid angle of current smple - float omegaS = 1.0 / (float(numSamples) * pdf); - // Solid angle of 1 pixel across all cube faces - float omegaP = 4.0 * PI / (6.0 * envMapDim * envMapDim); - // Biased (+1.0) mip level for better result - float mipLevel = roughness == 0.0 ? 0.0 : max(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f); - color += textureLod(CubeSampler0, L, mipLevel).rgb * dotNL; - totalWeight += dotNL; - } - */ - } - return (color / totalWeight); -} - -vec4 CubeRadiance() -{ - vec3 N = get_world_normal(); - N.y = -N.y; - if (CubeRadianceParam.mode == 0) - { - //radiance - return vec4(prefilterEnvMap(N, 0.5), 1.0); - } - else - { - // irradiance - float roughness = float(EvaluationParam.mipmapNumber)/max(float(EvaluationParam.mipmapCount-1), 1.); - return vec4(prefilterEnvMap(N, roughness), 1.0); - } -} diff --git a/bin/Nodes/GLSL/EquirectConverter.glsl b/bin/Nodes/GLSL/EquirectConverter.glsl deleted file mode 100644 index 1bee3542..00000000 --- a/bin/Nodes/GLSL/EquirectConverter.glsl +++ /dev/null @@ -1,33 +0,0 @@ -layout (std140) uniform EquirectConverterBlock -{ - int mode; - int size; -} EquirectConverterParam; - -vec4 EquirectToCubemap() -{ - vec3 dir = (EvaluationParam.viewRot * vec4(vUV * 2.0 - 1.0, 1.0, 0.0)).xyz; - vec2 uv = envMapEquirect(normalize(dir)); - vec4 tex = texture(Sampler0, vec2(uv.x, 1.0-uv.y)); - return tex; -} - -vec4 CubemapToEquirect() -{ - vec2 uv = vUV * 2.0 - 1.0; - vec2 ng = uv * PI * vec2(1.0, 0.5); - vec2 a = cos(ng); - vec2 b = sin(ng); - return texture(CubeSampler0, normalize(vec3(a.x*a.y, -b.y, b.x*a.y))); -} - -vec4 EquirectConverter() -{ - vec4 res; - if (EquirectConverterParam.mode == 0) - res = EquirectToCubemap(); - else - res = CubemapToEquirect(); - res.a = 1.0; - return res; -} diff --git a/bin/Nodes/GLSL/GLTFRead.glsl b/bin/Nodes/GLSL/GLTFRead.glsl deleted file mode 100644 index a3a99d3c..00000000 --- a/bin/Nodes/GLSL/GLTFRead.glsl +++ /dev/null @@ -1,6 +0,0 @@ -vec4 GLTFRead() -{ - vec3 lightdir = normalize(vec3(1.0)); - float dt = max(dot(lightdir, normalize(vWorldNormal)), 0.5); - return vec4(dt, dt, dt, 1.0); -} diff --git a/bin/Nodes/GLSL/Hexagon.glsl b/bin/Nodes/GLSL/Hexagon.glsl deleted file mode 100644 index 14e62635..00000000 --- a/bin/Nodes/GLSL/Hexagon.glsl +++ /dev/null @@ -1,6 +0,0 @@ -float Hexagon() -{ - vec2 V = vec2(.866,.5); - vec2 v = abs ( ((vUV * 2.0)-1.0) * mat2( V, -V.y, V.x) ); - return ceil( 1. - max(v.y, dot( v, V)) *1.15 ); -} diff --git a/bin/Nodes/GLSL/Invert.glsl b/bin/Nodes/GLSL/Invert.glsl deleted file mode 100644 index 9a82e31c..00000000 --- a/bin/Nodes/GLSL/Invert.glsl +++ /dev/null @@ -1,6 +0,0 @@ -vec4 Invert() -{ - vec4 res = vec4(1.0,1.0,1.0,1.0) - texture(Sampler0, vUV); - res.a = 1.0; - return res; -} diff --git a/bin/Nodes/GLSL/Kaleidoscope.glsl b/bin/Nodes/GLSL/Kaleidoscope.glsl deleted file mode 100644 index bc764b2f..00000000 --- a/bin/Nodes/GLSL/Kaleidoscope.glsl +++ /dev/null @@ -1,32 +0,0 @@ -layout (std140) uniform KaleidoscopeBlock -{ - vec2 center; - float startAngle; - int splits; - int sym; -} KaleidoscopeParam; - -vec4 Kaleidoscope() -{ - vec2 center = vec2(0.5); - - vec2 uv = vUV - KaleidoscopeParam.center; - float l = length(uv); - - float ng = atan(uv.y, uv.x) + PI - KaleidoscopeParam.startAngle; - float modulo = (2.* PI) / float(KaleidoscopeParam.splits + 1); - float count = mod((ng / modulo) *2.0, 2.0); - ng = mod(ng, modulo); - if ((KaleidoscopeParam.sym != 0) && (count>1.)) - { - ng = modulo - mod(ng, modulo); - } - else - { - ng = mod(ng, modulo); - } - ng += KaleidoscopeParam.startAngle; - vec2 uv2 = vec2(-cos(-ng), sin(-ng)) * l + KaleidoscopeParam.center; - vec4 tex = texture(Sampler0, uv2); - return tex; -} diff --git a/bin/Nodes/GLSL/Lens.glsl b/bin/Nodes/GLSL/Lens.glsl deleted file mode 100644 index 3ffa74c3..00000000 --- a/bin/Nodes/GLSL/Lens.glsl +++ /dev/null @@ -1,21 +0,0 @@ -layout (std140) uniform LensBlock -{ - float factor; - float vignette; -} LensParam; - -vec3 Distort(vec2 uv) -{ - float distCoeff = LensParam.factor; - uv -= 0.5; - float r2 = dot(uv,uv); - float f = 1.+r2*distCoeff; - f /= 1.+0.5*distCoeff; - return vec3(uv*f+0.5, sqrt(r2)); -} - -vec4 Lens() -{ - vec3 dis = Distort(vUV.xy); - return texture(Sampler0, dis.xy) * mix(1.0, min(1.18-dis.z, 1.0), LensParam.vignette); -} diff --git a/bin/Nodes/GLSL/MADD.glsl b/bin/Nodes/GLSL/MADD.glsl deleted file mode 100644 index 13ac32d5..00000000 --- a/bin/Nodes/GLSL/MADD.glsl +++ /dev/null @@ -1,10 +0,0 @@ -layout (std140) uniform MADDBlock -{ - vec4 color0; - vec4 color1; -} MADDParam; - -vec4 MADD() -{ - return texture(Sampler0, vUV) * MADDParam.color0 + MADDParam.color1; -} diff --git a/bin/Nodes/GLSL/NGon.glsl b/bin/Nodes/GLSL/NGon.glsl deleted file mode 100644 index 04498363..00000000 --- a/bin/Nodes/GLSL/NGon.glsl +++ /dev/null @@ -1,26 +0,0 @@ - -layout (std140) uniform NGonBlock -{ - int sides; - float radius; - float t; -}; - -vec4 NGon() -{ - vec2 p = vUV - vec2(0.5); - - vec2 d = vec2(0.0, 1.0); - float ng = 0.0; - float col = 0.0; - - for(int i = 0;i maxd ) - { - break; - } - - h = Scene( ro + rd * t, localToWorld ); - t += h; - } - - if ( t > maxd ) - { - t = -1.0; - } - - return t; -} - -vec3 SceneNormal( in vec3 pos, mat3 localToWorld ) -{ - vec3 eps = vec3( 0.001, 0.0, 0.0 ); - vec3 nor = vec3( - Scene( pos + eps.xyy, localToWorld ) - Scene( pos - eps.xyy, localToWorld ), - Scene( pos + eps.yxy, localToWorld ) - Scene( pos - eps.yxy, localToWorld ), - Scene( pos + eps.yyx, localToWorld ) - Scene( pos - eps.yyx, localToWorld ) ); - return normalize( nor ); -} - -float SceneAO( vec3 p, vec3 n, mat3 localToWorld ) -{ - float ao = 0.0; - float s = 1.0; - for( int i = 0; i < 6; ++i ) - { - float off = 0.001 + 0.2 * float( i ) / 5.; - float t = Scene( n * off + p, localToWorld ); - ao += ( off - t ) * s; - s *= 0.4; - } - - return Smooth( 1.0 - 12.0 * ao ); -} - -vec4 PBR2() -{ - vec2 p = vUV * 2.0 - 1.0; - - // camera movement - float an = PBR2Param.view.x * PI * 2.0; - float dn = PBR2Param.view.y * PI * 0.5; - float cdn = cos(dn); - - vec3 ro = vec3( 2.0*sin(an)*cdn, camHeight + sin(dn)*2.0, 2.0*cos(an)*cdn ); - vec3 ta = vec3( 0.0, camHeight, 0.0 ); - // camera matrix - vec3 ww = normalize( ta - ro ); - vec3 uu = normalize( cross(ww,vec3(0.0,1.0,0.0) ) ); - vec3 vv = normalize( cross(uu,ww)); - // create view ray - vec3 rd = normalize( p.x*uu + p.y*vv + 1.5*ww ); - - // sphere center - vec3 sc = vec3(0.0,1.0,0.0); - mat3 localToWorld = mat3(vec3(1.0,0.0,0.0), vec3(0.0,1.0,0.0), vec3(0.0,0.0,1.0)); - - - vec3 lightColor = vec3( 2. ); - vec3 lightDir = normalize( vec3( .7, .9, -.2 ) ); - - vec3 col = texture(CubeSampler4, InvertCubeY(rd)).xyz; - float t = CastRay( ro, rd, localToWorld ); - if ( t > 0.0 ) - { - vec3 pos = ro + t * rd; - vec3 normal = SceneNormal( pos, localToWorld ); - vec2 texcoord = boxUV(pos, normal); - - - - mat3 tbn = cotangent_frame( normal, pos, texcoord ); - - vec3 eyeToFragment = (inverse(tbn) * -rd); - - texcoord = ParallaxMapping(Sampler2, texcoord, eyeToFragment, PBR2Param.depthFactor); - - vec3 texNorm = texture(Sampler1, texcoord).xyz * 2.0 - 1.0; - - vec3 worldNormal = normalize(tbn * texNorm); - - //vec3 albedo = cubemap2D(Sampler0, normal).xyz; - vec3 albedo = texture(Sampler0, texcoord).xyz; - //col = albedo * max(dot(worldNormal, normalize(vec3(1.0))), 0.0) ; - - col = albedo; - /* - - vec3 viewDir = -rd; - vec3 refl = reflect( rd, normal ); - - vec3 diffuse = vec3( 0. ); - vec3 specular = vec3( 0. ); - - vec3 baseColor = pow(albedo, vec3( 2.2 ) ); - - float roughness = texture(Sampler3, texcoord).x;//boxmap(Sampler2, pos, normalize(pos), 1.0 ).x; - vec3 diffuseColor = baseColor; - vec3 specularColor = baseColor;// : vec3( 0.02 ); - float roughnessE = roughness * roughness; - float roughnessL = max( .01, roughnessE ); - - vec3 halfVec = normalize( viewDir + lightDir ); - float vdoth = saturate( dot( viewDir, halfVec ) ); - float ndoth = saturate( dot( normal, halfVec ) ); - float ndotv = saturate( dot( normal, viewDir ) ); - float ndotl = saturate( dot( normal, lightDir ) ); - - vec3 envSpecularColor = EnvBRDFApprox( specularColor, roughnessE, ndotv ); - - vec3 env = texture(CubeSampler4, InvertCubeY(refl), roughnessE*12.0).xyz; - - diffuse += diffuseColor * EnvRemap(env); - specular += envSpecularColor * env; - - diffuse += diffuseColor * saturate( dot( normal, lightDir ) ); - - vec3 lightF = FresnelTerm( specularColor, vdoth ); - float lightD = DistributionTerm( roughnessL, ndoth ); - float lightV = VisibilityTerm( roughnessL, ndotv, ndotl ); - specular += lightColor * lightF * ( lightD * lightV * PI * ndotl ); - - float ao = SceneAO( pos, normal, localToWorld ); - diffuse *= ao; - specular *= saturate( pow( ndotv + ao, roughnessE ) - 1. + ao); - - col = diffuse + specular; - */ - } - col = pow( col, vec3( 1. / 2.2 ) ); - return vec4(col,1.0); -} \ No newline at end of file diff --git a/bin/Nodes/GLSL/Paint2D.glsl b/bin/Nodes/GLSL/Paint2D.glsl deleted file mode 100644 index 72fdc520..00000000 --- a/bin/Nodes/GLSL/Paint2D.glsl +++ /dev/null @@ -1,33 +0,0 @@ -layout (std140) uniform Paint2DBlock -{ - int size; // 1<<(size+8) -} Paint2DParam; - -vec4 brushSample(vec2 uv, float radius) -{ - vec2 nuv = (uv) / radius + vec2(0.5); - float alphaMul = min(min(step(0.0, nuv.x), step(nuv.x, 1.0)), min(step(0.0, nuv.y), step(nuv.y, 1.0))); - return texture(Sampler0, nuv) * alphaMul; -} -vec4 Paint2D() -{ - vec4 res = vec4(0.0); - float brushRadius = 0.25; - vec4 brush = brushSample(vUV-EvaluationParam.mouse.xy, brushRadius); - if (EvaluationParam.uiPass == 1) - { - res = brush; - } - // paint pass - if (EvaluationParam.mouse.z > 0.0) - { - res = brush; - } - if (EvaluationParam.mouse.w > 0.0) - { - res = brush; - res.xyz = vec3(0.0); - } - - return vec4(res.xyz*res.w, res.w); -} \ No newline at end of file diff --git a/bin/Nodes/GLSL/Paint3D.glsl b/bin/Nodes/GLSL/Paint3D.glsl deleted file mode 100644 index 79dc8693..00000000 --- a/bin/Nodes/GLSL/Paint3D.glsl +++ /dev/null @@ -1,56 +0,0 @@ -layout (std140) uniform Paint3DBlock -{ - int size; // 1<<(size+8) -} Paint3DParam; - -vec4 brushSample(vec2 uv, float radius) -{ - vec2 nuv = (uv) / radius + vec2(0.5); - float alphaMul = min(min(step(0.0, nuv.x), step(nuv.x, 1.0)), min(step(0.0, nuv.y), step(nuv.y, 1.0))); - return texture(Sampler1, nuv) * alphaMul; -} - -vec4 brushSampleMouse() -{ - vec4 wPos = EvaluationParam.viewProjection * vec4(vWorldPosition, 1.0); - mat4 projMat = mat4( - vec4(1.0, 0.0, 0.0, 0.0), - vec4(0.0, 1.0, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(-(EvaluationParam.mouse.xy * 2.0 - 1.0), 0.0, 1.0)); - - vec4 projUV = projMat * wPos; - return brushSample(projUV.xy/projUV.w, 0.3); -} - -vec4 Paint3D() -{ - if (EvaluationParam.uiPass == 1) - { - vec3 lightdir = normalize(vec3(1.0)); - float dt = max(dot(lightdir, normalize(vWorldNormal)), 0.5); - vec4 tex = texture(Sampler0, vUV) * dt; - - - return vec4(tex.xyz, 1.0) + brushSampleMouse() * vec4(1.0, 0.0, 0.0, 1.0); - } - else - { - vec4 res = vec4(0.0); - if (EvaluationParam.keyModifier.x != 0 || EvaluationParam.keyModifier.y != 0 || EvaluationParam.keyModifier.z != 0) - { - return res; - } - // paint pass - if (EvaluationParam.mouse.z > 0.0) - { - res = brushSampleMouse(); - } - if (EvaluationParam.mouse.w > 0.0) - { - res = brushSampleMouse(); - res.xyz = vec3(0.0); - } - return vec4(res.xyz*res.w, res.w); - } -} \ No newline at end of file diff --git a/bin/Nodes/GLSL/Palette.glsl b/bin/Nodes/GLSL/Palette.glsl deleted file mode 100644 index 7b484b8e..00000000 --- a/bin/Nodes/GLSL/Palette.glsl +++ /dev/null @@ -1,282 +0,0 @@ -layout (std140) uniform PaletteBlock -{ - int paletteIndex; - float ditherStrength; -} PaletteParam; - -float find_closest(int x, int y, float c0) -{ - int dither[64]; - - dither[0] = 0; - dither[1] = 32; - dither[2] = 8; - dither[3] = 40; - dither[4] = 2; - dither[5] = 34; - dither[6] = 10; - dither[7] = 42; - dither[8] = 48; - dither[9] = 16; - - dither[10] = 56; - dither[11] = 24; - dither[12] = 50; - dither[13] = 18; - dither[14] = 58; - dither[15] = 26; - dither[16] = 12; - dither[17] = 44; - dither[18] = 4; - dither[19] = 36; - - dither[20] = 14; - dither[21] = 46; - dither[22] = 6; - dither[23] = 38; - dither[24] = 60; - dither[25] = 28; - dither[26] = 52; - dither[27] = 20; - dither[28] = 62; - dither[29] = 30; - - dither[30] = 54; - dither[31] = 22; - dither[32] = 3; - dither[33] = 35; - dither[34] = 11; - dither[35] = 43; - dither[36] = 1; - dither[37] = 33; - dither[38] = 9; - dither[39] = 41; - - dither[40] = 51; - dither[41] = 19; - dither[42] = 59; - dither[43] = 27; - dither[44] = 49; - dither[45] = 17; - dither[46] = 57; - dither[47] = 25; - dither[48] = 15; - dither[49] = 47; - - dither[50] = 7; - dither[51] = 39; - dither[52] = 13; - dither[53] = 45; - dither[54] = 5; - dither[55] = 37; - dither[56] = 63; - dither[57] = 31; - dither[58] = 55; - dither[59] = 23; - - dither[60] = 61; - dither[61] = 29; - dither[62] = 53; - dither[63] = 21; - - float limit = 0.0; - if(x < 8) - { - limit = float(dither[x*8+y]+1)/64.0; - } - - if(c0 < limit) - return 0.0; - return 1.0; -} - -vec4 hex(int u_color) -{ - float rValue = float((u_color&0xFF0000)>>16); - float gValue = float((u_color&0xFF00)>>8); - float bValue = float(u_color&0xFF); - return vec4(rValue, gValue, bValue, 255.0) / 255.; -} - -vec4 best4(vec4 original, int pal[4]) -{ - int best = 0; - for (int i = 1;i<4;i++) - { - if (length(hex(pal[i]) - original) < length(hex(pal[best]) - original)) - best = i; - } - - return hex(pal[best]); -} - -vec4 best16(vec4 original, int pal[16]) -{ - int best = 0; - for (int i = 1;i<16;i++) - { - if (length(hex(pal[i]) - original) < length(hex(pal[best]) - original)) - best = i; - } - - return hex(pal[best]); -} - -vec4 GetCGA(vec4 original, int index) -{ - int pal[4]; - pal[0] = 0x000000; - switch (index) - { - case 0: - pal[1] = 0x00AAAA; - pal[2] = 0xAA00AA; - pal[3] = 0xAAAAAA; - break; - case 1: - pal[1] = 0x00AAAA; - pal[2] = 0xAA0000; - pal[3] = 0xAAAAAA; - break; - case 2: - pal[1] = 0x00AA00; - pal[2] = 0xAA0000; - pal[3] = 0xAA5500; - break; - case 3: - pal[1] = 0x55FFFF; - pal[2] = 0xFF55FF; - pal[3] = 0xFFFFFF; - break; - case 4: - pal[1] = 0x55FFFF; - pal[2] = 0xFF5555; - pal[3] = 0xFFFFFF; - break; - case 5: - pal[1] = 0x55FF55; - pal[2] = 0xFF5555; - pal[3] = 0xFFFF55; - break; - } - return best4(original, pal); -} - -vec4 GetEGA(vec4 original) -{ - int pal[16]; - pal[0] = 0x000000; - pal[1] = 0x0000AA; - pal[2] = 0x00AA00; - pal[3] = 0x00AAAA; - - pal[4] = 0xAA0000; - pal[5] = 0xAA00AA; - pal[6] = 0xAA5500; - pal[7] = 0xAAAAAA; - - pal[8] = 0x555555; - pal[9] = 0x5555FF; - pal[10] = 0x55FF55; - pal[11] = 0x55FFFF; - - pal[12] = 0xFF5555; - pal[13] = 0xFF55FF; - pal[14] = 0xFFFF55; - pal[15] = 0xFFFFFF; - - return best16(original, pal); -} - -vec4 GetGameBoy(vec4 original) -{ - int pal[4]; - pal[0] = 0x0f380f; - pal[1] = 0x306230; - pal[2] = 0x8bac0f; - pal[3] = 0x9bbc0f; - - return best4(original, pal); -} - -vec4 GetPico8(vec4 original) -{ - int pal[16]; - pal[0] = 0x000000; - pal[1] = 0x5F574F; - pal[2] = 0xC2C3C7; - pal[3] = 0xFFF1E8; - - pal[4] = 0xFFEC27; - pal[5] = 0xFFA300; - pal[6] = 0xFFCCAA; - pal[7] = 0xAB5236; - - pal[8] = 0xFF77A8; - pal[9] = 0xFF004D; - pal[10] = 0x83769C; - pal[11] = 0x7E2553; - - pal[12] = 0x29ADDD; - pal[13] = 0x1D2B53; - pal[14] = 0x008751; - pal[15] = 0x00E436; - - return best16(original, pal); -} - -vec4 GetC64(vec4 original) -{ - int pal[16]; - pal[0] = 0x000000; - pal[1] = 0xFFFFFF; - pal[2] = 0x880000; - pal[3] = 0xAAFFEE; - - pal[4] = 0xCC44CC; - pal[5] = 0x00CC55; - pal[6] = 0x0000AA; - pal[7] = 0xEEEE77; - - pal[8] = 0xDD8855; - pal[9] = 0x664400; - pal[10] = 0xFF7777; - pal[11] = 0x333333; - - pal[12] = 0x777777; - pal[13] = 0xAAFF66; - pal[14] = 0x0088FF; - pal[15] = 0xBBBBBB; - - return best16(original, pal); -} - -vec4 Palette() -{ - vec4 color = texture(Sampler0, vUV); - - vec3 rgb = color.rgb; - vec2 xy = gl_FragCoord.xy; - int x = int(mod(xy.x, 8.)); - int y = int(mod(xy.y, 8.)); - - vec3 ditheredRGB; - ditheredRGB.r = find_closest(x, y, rgb.r); - ditheredRGB.g = find_closest(x, y, rgb.g); - ditheredRGB.b = find_closest(x, y, rgb.b); - float r = 0.25; - color = vec4(mix(color.rgb, ditheredRGB, PaletteParam.ditherStrength), 1.0); - - - if (PaletteParam.paletteIndex < 6) - return GetCGA(color, PaletteParam.paletteIndex); - if (PaletteParam.paletteIndex < 7) - return GetEGA(color); - if (PaletteParam.paletteIndex < 8) - return GetGameBoy(color); - if (PaletteParam.paletteIndex < 9) - return GetPico8(color); - if (PaletteParam.paletteIndex < 10) - return GetC64(color); - -} diff --git a/bin/Nodes/GLSL/Pixelize.glsl b/bin/Nodes/GLSL/Pixelize.glsl deleted file mode 100644 index 63bdb473..00000000 --- a/bin/Nodes/GLSL/Pixelize.glsl +++ /dev/null @@ -1,10 +0,0 @@ -layout (std140) uniform PixelizeBlock -{ - float scale; -} PixelizeParam; - -vec4 Pixelize() -{ - vec4 tex = texture(Sampler0, floor(vUV*PixelizeParam.scale)/PixelizeParam.scale); - return tex; -} diff --git a/bin/Nodes/GLSL/PolarCoords.glsl b/bin/Nodes/GLSL/PolarCoords.glsl deleted file mode 100644 index 7342608b..00000000 --- a/bin/Nodes/GLSL/PolarCoords.glsl +++ /dev/null @@ -1,27 +0,0 @@ -layout (std140) uniform PolarCoordsBlock -{ - int op; -} PolarCoordsParam; - -vec4 PolarCoords() -{ - vec2 uvin = vUV - vec2(0.5,0.5); - vec2 uv; - if (PolarCoordsParam.op == 1) - { - uv.x = cos(uvin.x * PI * 2. + PI / 2.) * (1. - (uvin.y + 0.5)) / 2. + 0.5; - uv.y = sin(uvin.x * PI * 2. + PI / 2.) * (1. - (uvin.y + 0.5)) / 2. + 0.5; - } - else - { - uv.x = atan(uvin.y, uvin.x); - uv.x += PI / 2.; - if (uv.x < 0.) - uv.x += PI * 2.; - uv.x /= PI * 2.; - uv.y = 1. - length(uvin) * 2.; - } - vec4 tex = texture(Sampler0, uv); - - return tex; -} diff --git a/bin/Nodes/GLSL/Ramp.glsl b/bin/Nodes/GLSL/Ramp.glsl deleted file mode 100644 index 7f3f3bfc..00000000 --- a/bin/Nodes/GLSL/Ramp.glsl +++ /dev/null @@ -1,30 +0,0 @@ -float GetRamp(float v, vec2 arr[8]) -{ - for (int i = 0;i<(arr.length()-1);i++) - { - if (v >= arr[i].x && v <= arr[i+1].x) - { - // linear - //float t = (v-arr[i].x)/(arr[i+1].x-arr[i].x); - // smooth - float t = smoothstep(arr[i].x, arr[i+1].x, v); - return mix(arr[i].y, arr[i+1].y, t); - } - } - - return 0.0; -} - -layout (std140) uniform RampBlock -{ - vec2 ramp[8]; -} RampParam; - -vec4 Ramp() -{ - vec4 tex = texture(Sampler0, vUV); - if (EvaluationParam.inputIndices[0].y > -1) - return texture(Sampler1, vec2(tex.x, 0.5)); - else - return tex * GetRamp(tex.x, RampParam.ramp); -} \ No newline at end of file diff --git a/bin/Nodes/GLSL/ReactionDiffusion.glsl b/bin/Nodes/GLSL/ReactionDiffusion.glsl deleted file mode 100644 index 5b68b6db..00000000 --- a/bin/Nodes/GLSL/ReactionDiffusion.glsl +++ /dev/null @@ -1,63 +0,0 @@ -// adapted from https://www.shadertoy.com/view/4sccRj -layout (std140) uniform ReactionDiffusionBlock -{ - float boost; - float divisor; - float colorStep; - int PassCount; - int size; -}; - -vec4 getSample(vec2 offset) -{ - return vec4(texture(Sampler0, (gl_FragCoord.xy + offset) / EvaluationParam.viewport.xy).xyz, 1.0); -} - -vec4 T(float u, float v) -{ - return getSample(vec2(u,v)); -} - -float f(float i) -{ - return exp(-i*i/4.)/sqrt(4.*PI); -} - -#define F(i) (f(i)) - -#define GH(i) T(float(i), 0.)*F(float(i)) -#define GV(i) T(0., float(i))*F(float(i)) -#define BLURH (GH(-4) + GH(-3) + GH(-2) + GH(-1) + GH(0) + GH(1) + GH(2) + GH(3) + GH(4)) -#define BLURV (GV(-4) + GV(-3) + GV(-2) + GV(-1) + GV(0) + GV(1) + GV(2) + GV(3) + GV(4)) - -vec4 pass(vec2 uv) -{ - vec4 col = T(-1., -1.)*0.05 + T( 0., -1.)*0.20 + T( 1., -1.)*0.05 + - T(-1., 0.)*0.20 - T( 0., 0.)*1.00 + T( 1., 0.)*0.20 + - T(-1., 1.)*0.05 + T( 0., 1.)*0.20 + T( 1., 1.)*0.05; - col /= 8.0; - col = T(0., 0.) - col*50.0; - col -= 0.5; - col = col*boost; - col = smoothstep(vec4(-0.5), vec4(0.5), col); - col = mix(col, vec4(length(col.xyz)/sqrt(divisor)), colorStep); - return col; -} - -vec4 ReactionDiffusion() -{ - int ip = EvaluationParam.passNumber%3; - if (ip == 0) - { - vec4 col = BLURH; - col /= col.w; - return col; - } - if (ip == 1) - { - vec4 col = BLURV; - col /= col.w; - return col; - } - return pass(vUV); -} diff --git a/bin/Nodes/GLSL/Shader.glsl b/bin/Nodes/GLSL/Shader.glsl deleted file mode 100644 index 51103914..00000000 --- a/bin/Nodes/GLSL/Shader.glsl +++ /dev/null @@ -1,314 +0,0 @@ -#define PI 3.14159265359 -#define SQRT2 1.414213562373095 - -#define TwoPI (PI*2.0) - - -layout (std140) uniform EvaluationBlock -{ - mat4 viewRot; - mat4 viewProjection; - mat4 viewInverse; - mat4 model; - mat4 modelViewProjection; - vec4 viewport; - - int targetIndex; - int forcedDirty; - int uiPass; - int passNumber; - - vec4 mouse; // x,y, lbut down, rbut down - ivec4 keyModifier; // ctrl, alt, shift - ivec4 inputIndices[2]; - - int frame; - int localFrame; - int mVertexSpace; - int dirtyFlag; - - int mipmapNumber; - int mipmapCount; -} EvaluationParam; - -#ifdef VERTEX_SHADER - -layout(location = 0)in vec2 inUV; -layout(location = 1)in vec4 inColor; -layout(location = 2)in vec3 inPosition; -layout(location = 3)in vec3 inNormal; - -out vec2 vUV; -out vec3 vWorldPosition; -out vec3 vWorldNormal; -out vec4 vColor; -void main() -{ - if (EvaluationParam.mVertexSpace == 1) - { - gl_Position = EvaluationParam.modelViewProjection * vec4(inPosition.xyz, 1.0); - } - else - { - gl_Position = vec4(inUV.xy*2.0-1.0,0.5,1.0); - } - - vUV = inUV; - vColor = inColor; - vWorldNormal = (EvaluationParam.model * vec4(inNormal, 0.0)).xyz; - vWorldPosition = (EvaluationParam.model * vec4(inPosition, 1.0)).xyz; -} - -#endif - - -#ifdef FRAGMENT_SHADER - -struct Camera -{ - vec4 pos; - vec4 dir; - vec4 up; - vec4 lens; -}; - -layout(location=0) out vec4 outPixDiffuse; -in vec2 vUV; -in vec3 vWorldPosition; -in vec3 vWorldNormal; -in vec4 vColor; - -uniform sampler2D Sampler0; -uniform sampler2D Sampler1; -uniform sampler2D Sampler2; -uniform sampler2D Sampler3; -uniform sampler2D Sampler4; -uniform sampler2D Sampler5; -uniform sampler2D Sampler6; -uniform sampler2D Sampler7; -uniform samplerCube CubeSampler0; -uniform samplerCube CubeSampler1; -uniform samplerCube CubeSampler2; -uniform samplerCube CubeSampler3; -uniform samplerCube CubeSampler4; -uniform samplerCube CubeSampler5; -uniform samplerCube CubeSampler6; -uniform samplerCube CubeSampler7; - -vec2 Rotate2D(vec2 v, float a) -{ - float s = sin(a); - float c = cos(a); - mat2 m = mat2(c, -s, s, c); - return m * v; -} -vec3 InvertCubeY(vec3 dir) -{ - return vec3(dir.x, -dir.y, dir.z); -} -float Circle(vec2 uv, float radius, float t) -{ - float r = length(uv-vec2(0.5)); - float h = sin(acos(r/radius)); - return mix(1.0-smoothstep(radius-0.001, radius, length(uv-vec2(0.5))), h, t); -} - -vec4 boxmap( sampler2D sam, in vec3 p, in vec3 n, in float k ) -{ - vec3 m = pow( abs(n), vec3(k) ); - vec4 x = texture( sam, p.yz ); - vec4 y = texture( sam, p.zx ); - vec4 z = texture( sam, p.xy ); - return (x*m.x + y*m.y + z*m.z)/(m.x+m.y+m.z); -} - -vec2 boxUV(vec3 p, vec3 n) -{ - vec2 uv = p.xy; - uv = mix(uv, p.zy*sign(n.x), (abs(n.x)>0.5)?1.0:0.0 ); - uv = mix(uv, p.zx*sign(n.y), (abs(n.y)>0.5)?1.0:0.0 ); - return uv; -} - -vec2 envMapEquirect(vec3 wcNormal, float flipEnvMap) { - //I assume envMap texture has been flipped the WebGL way (pixel 0,0 is a the bottom) - //therefore we flip wcNorma.y as acos(1) = 0 - float phi = acos(-wcNormal.y); - float theta = atan(flipEnvMap * wcNormal.x, wcNormal.z) + PI; - return vec2(theta / TwoPI, 1.0 - phi / PI); -} - -vec2 envMapEquirect(vec3 wcNormal) { - //-1.0 for left handed coordinate system oriented texture (usual case) - return envMapEquirect(wcNormal, -1.0); -} - -float saturate( float x ) -{ - return clamp( x, 0., 1. ); -} - -vec3 saturate( vec3 x ) -{ - return clamp( x, vec3( 0. ), vec3( 1. ) ); -} - -float Smooth( float x ) -{ - return smoothstep( 0., 1., saturate( x ) ); -} - -// distance functions - -float Cylinder( vec3 p, float r, float height ) -{ - float d = length( p.xz ) - r; - d = max( d, abs( p.y ) - height ); - return d; -} - -float Substract( float a, float b ) -{ - return max( a, -b ); -} - -float SubstractRound( float a, float b, float r ) -{ - vec2 u = max( vec2( r + a, r - b ), vec2( 0.0, 0.0 ) ); - return min( -r, max( a, -b ) ) + length( u ); -} - -float Union( float a, float b ) -{ - return min( a, b ); -} - -float Box( vec3 p, vec3 b ) -{ - vec3 d = abs( p ) - b; - return min( max( d.x, max( d.y, d.z ) ), 0.0 ) + length( max( d, 0.0 ) ); -} - -float Sphere( vec3 p, float s ) -{ - return length( p ) - s; -} - -float Torus( vec3 p, float sr, float lr ) -{ - return length( vec2( length( p.xz ) - lr, p.y ) ) - sr; -} - -float Disc( vec3 p, float r, float t ) -{ - float l = length( p.xz ) - r; - return l < 0. ? abs( p.y ) - t : length( vec2( p.y, l ) ) - t; -} - -float UnionRound( float a, float b, float k ) -{ - float h = clamp( 0.5 + 0.5 * ( b - a ) / k, 0.0, 1.0 ); - return mix( b, a, h ) - k * h * ( 1.0 - h ); -} - -float sdRoundBox( vec3 p, vec3 b, float r ) -{ - vec3 d = abs(p) - b; - return length(max(d,0.0)) - r - + min(max(d.x,max(d.y,d.z)),0.0); // remove this line for an only partially signed sdf -} - -mat3 cotangent_frame( vec3 N, vec3 p, vec2 uv ) -{ - // get edge vectors of the pixel triangle - vec3 dp1 = dFdx( p ); - vec3 dp2 = dFdy( p ); - vec2 duv1 = dFdx( uv ); - vec2 duv2 = dFdy( uv ); - - // solve the linear system - vec3 dp2perp = cross( dp2, N ); - vec3 dp1perp = cross( N, dp1 ); - vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; - vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; - - // construct a scale-invariant frame - float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) ); - return mat3( T * invmax, B * invmax, N ); -} - -float GetHeight(sampler2D heightSampler, vec2 texCoords) -{ - return texture(heightSampler, texCoords).r; -} - -//Parallax Occlusion Mapping from: https://learnopengl.com/Advanced-Lighting/Parallax-Mapping -vec2 ParallaxMapping(sampler2D heightSampler, vec2 texCoords, vec3 viewDir, float depthFactor) -{ - float height_scale = depthFactor; - // number of depth layers - float minLayers = 8.0; - float maxLayers = 32.0; - float numLayers = mix(maxLayers, minLayers, min(abs(viewDir.z), 1.0)); - // calculate the size of each layer - float layerDepth = 1.0 / numLayers; - // depth of current layer - float currentLayerDepth = 0.0; - // the amount to shift the texture coordinates per layer (from vector P) - vec2 P = viewDir.xy * height_scale; - vec2 deltaTexCoords = P / numLayers; - - // get initial values - vec2 currentTexCoords = texCoords; - float currentDepthMapValue = GetHeight(heightSampler, currentTexCoords); - - while(currentLayerDepth < currentDepthMapValue) - { - // shift texture coordinates along direction of P - currentTexCoords -= deltaTexCoords; - // get depthmap value at current texture coordinates - currentDepthMapValue = GetHeight(heightSampler, currentTexCoords); - // get depth of next layer - currentLayerDepth += layerDepth; - } - - // get texture coordinates before collision (reverse operations) - vec2 prevTexCoords = currentTexCoords + deltaTexCoords; - - // get depth after and before collision for linear interpolation - float afterDepth = currentDepthMapValue - currentLayerDepth; - float beforeDepth = GetHeight(heightSampler, prevTexCoords) + layerDepth - currentLayerDepth; - - // interpolation of texture coordinates - float weight = afterDepth / (afterDepth - beforeDepth); - vec2 finalTexCoords = mix(currentTexCoords, prevTexCoords, weight); - - return finalTexCoords; -} - -vec4 cubemap2D( sampler2D sam, in vec3 d ) -{ - vec3 n = abs(d); - vec3 s = dFdx(d); - vec3 t = dFdy(d); - if(n.x>n.y && n.x>n.z) {d=d.xyz;s=s.xyz;t=t.xyz;} - else if(n.y>n.x && n.y>n.z) {d=d.yzx;s=s.yzx;t=t.yzx;} - else {d=d.zxy;s=s.zxy;t=t.zxy;} - vec2 q = d.yz/d.x; - return textureGrad( sam, - 0.5*q + 0.5, - 0.5*(s.yz-q*s.x)/d.x, - 0.5*(t.yz-q*t.x)/d.x ); -} - - -__NODE__ - - - -void main() -{ - outPixDiffuse = vec4(__FUNCTION__); -} - -#endif diff --git a/bin/Nodes/GLSL/Sine.glsl b/bin/Nodes/GLSL/Sine.glsl deleted file mode 100644 index c2fafc2a..00000000 --- a/bin/Nodes/GLSL/Sine.glsl +++ /dev/null @@ -1,12 +0,0 @@ -layout (std140) uniform SineBlock -{ - float freq; - float angle; -} SineParam; - -float Sine() -{ - vec2 nuv = vUV - vec2(0.5); - nuv = vec2(cos(SineParam.angle), sin(SineParam.angle)) * (nuv * SineParam.freq * PI * 2.0); - return cos(nuv.x + nuv.y) * 0.5 + 0.5; -} diff --git a/bin/Nodes/GLSL/SmoothStep.glsl b/bin/Nodes/GLSL/SmoothStep.glsl deleted file mode 100644 index e13d5588..00000000 --- a/bin/Nodes/GLSL/SmoothStep.glsl +++ /dev/null @@ -1,11 +0,0 @@ -layout (std140) uniform SmoothStepBlock -{ - float low; - float high; -} SmoothStepParam; - -vec4 SmoothStep() -{ - vec4 tex = texture(Sampler0, vUV); - return smoothstep(SmoothStepParam.low, SmoothStepParam.high, tex); -} diff --git a/bin/Nodes/GLSL/Square.glsl b/bin/Nodes/GLSL/Square.glsl deleted file mode 100644 index a67d211d..00000000 --- a/bin/Nodes/GLSL/Square.glsl +++ /dev/null @@ -1,9 +0,0 @@ -layout (std140) uniform SquareBlock -{ - float width; -} SquareParam; -float Square() -{ - vec2 nuv = vUV - vec2(0.5); - return 1.0-smoothstep(SquareParam.width-0.001, SquareParam.width, max(abs(nuv.x), abs(nuv.y))); -} diff --git a/bin/Nodes/GLSL/Swirl.glsl b/bin/Nodes/GLSL/Swirl.glsl deleted file mode 100644 index 9bcbf67c..00000000 --- a/bin/Nodes/GLSL/Swirl.glsl +++ /dev/null @@ -1,15 +0,0 @@ -layout (std140) uniform SwirlBlock -{ - vec2 angles; -} SwirlParam; - -vec4 Swirl() -{ - vec2 uv = vUV - vec2(0.5); - float len = length(uv) / (SQRT2 * 0.5); - float angle = mix(SwirlParam.angles.x, SwirlParam.angles.y, len); - vec2 nuv = Rotate2D(uv, angle) + vec2(0.5); - vec4 tex = texture(Sampler0, nuv); - - return tex; -} diff --git a/bin/Nodes/GLSL/TerrainPreview.glsl b/bin/Nodes/GLSL/TerrainPreview.glsl deleted file mode 100644 index c1dd3657..00000000 --- a/bin/Nodes/GLSL/TerrainPreview.glsl +++ /dev/null @@ -1,94 +0,0 @@ - -float maxd = 5.0; - -float scene(vec3 p) -{ - float terrainHeight = texture(Sampler0, p.xz).x * 0.5; - return max(p.y-terrainHeight, 0.0)*0.1; -} -/* -float castRay(vec3 ro, vec3 rd ) -{ - float h = 0.5; - float t = 0.0; - - for ( int i = 0; i < 50; ++i ) - { - // - if ( h < 0.0001 || t > maxd ) - { - break; - } - - h = scene(ro + rd * t); - t += h; - } - - return t; -} -*/ -float terrain(vec2 p) -{ - return texture(Sampler0, p).x * 0.5; -} -float castRay(vec3 ro, vec3 rd) -{ - float resT; - - float delt = 0.01f; - float mint = 0.001f; - float maxt = 4.0f; - float lh = 0.0f; - float ly = 0.0f; - for( float t = mint; t < maxt; t += delt ) - { - vec3 p = ro + rd*t; - float h = terrain( p.xz ); - if( p.y < h ) - { - // interpolate the intersection distance - resT = t - delt + delt*(lh-ly)/(p.y-ly-h+lh); - return resT; - } - // allow the error to be proportinal to the distance - delt = 0.003f*t; - lh = h; - ly = p.y; - } - return maxd; -} - - -layout (std140) uniform TerrainPreviewBlock -{ - Camera camera; -} TerrainPreviewParam; - -vec4 TerrainPreview() -{ - vec2 p = vUV * 2.0 - 1.0; - - // camera movement - - vec3 ro = TerrainPreviewParam.camera.pos.xyz;//vec3( 0. ); - vec3 ta = TerrainPreviewParam.camera.pos.xyz + TerrainPreviewParam.camera.dir.xyz; - // camera matrix - vec3 ww = normalize( ta - ro ); - vec3 uu = normalize( cross(ww, TerrainPreviewParam.camera.up.xyz ) ); - vec3 vv = normalize( cross(uu,ww)); - // create view ray - vec3 rd = normalize( p.x*uu + p.y*vv + 1.5*ww ); - - - vec3 col = texture(CubeSampler3, InvertCubeY(rd)).xyz + texture(Sampler0, vec2(0.)).xyz*0.01; - - float d = castRay(ro, rd); - if (d=0. && pos.z>=0. && pos.x<=1.0 && pos.z <= 1.0) - col = texture(Sampler1, pos.xz).xyz; - } - - return vec4( col, 1.0 ); -} diff --git a/bin/Nodes/GLSL/Tile.glsl b/bin/Nodes/GLSL/Tile.glsl deleted file mode 100644 index 7c37ee99..00000000 --- a/bin/Nodes/GLSL/Tile.glsl +++ /dev/null @@ -1,57 +0,0 @@ -layout (std140) uniform TileBlock -{ - vec2 offset0; - vec2 offset1; - vec2 overlap; - float scale; -} TileParam; - -vec4 GetTile0(vec2 uv) -{ - if (uv.x > 1.0 || uv.y > 1.0 || uv.x <0.0 || uv.y<0.0) - return vec4(0.0); - - return texture(Sampler0, uv); -} - -vec2 GetOffset(vec2 uv) -{ - float quincunxY = float(int(floor(uv.y))&1); - float quincunxX = float(int(floor(uv.x))&1); - float oX = mix(TileParam.offset0.x, TileParam.offset1.x, quincunxY); - float oY = mix(TileParam.offset0.y, TileParam.offset1.y, quincunxX); - return vec2(oX,oY); -} - -vec4 GetTile(vec2 uv) -{ - vec2 cellSize = vec2(1.0) - TileParam.overlap; - - vec4 c = vec4(0.0); - - for (int y = -1;y<2;y++) - { - for (int x = -1;x<2;x++) - { - vec2 cell0 = uv - (fract(uv/cellSize) + vec2(float(x), float(y))) * cellSize; - vec2 cell1 = (floor(uv/cellSize) + vec2(float(x), float(y))); - vec2 ofs = GetOffset(cell1); - vec4 multiplier = vec4(1.0); - if (EvaluationParam.inputIndices[0].y > -1) - { - vec2 uvMul = (floor(uv + ofs) + vec2(0.5))/ TileParam.scale - (ofs*vec2(0.5))/ TileParam.scale; - //return vec4(uvMul, 0., 1.); // debug! - multiplier = texture(Sampler1, uvMul); - } - c += GetTile0(uv - cell0 + ofs) * vec4(multiplier.xyz, 1.0); - } - } - - return c; -} - -vec4 Tile() -{ - vec2 nuv = vUV * TileParam.scale; - return GetTile(nuv); -} \ No newline at end of file diff --git a/bin/Nodes/GLSL/Transform.glsl b/bin/Nodes/GLSL/Transform.glsl deleted file mode 100644 index 3ff0f2e9..00000000 --- a/bin/Nodes/GLSL/Transform.glsl +++ /dev/null @@ -1,17 +0,0 @@ -layout (std140) uniform TransformBlock -{ - vec2 translate; - vec2 scale; - float rotate; -}; - -vec4 Transform() -{ - vec2 rs = (vUV+translate) * scale; - rs -= 0.5; - vec2 ro = vec2(rs.x*cos(rotate) - rs.y * sin(rotate), rs.x*sin(rotate) + rs.y * cos(rotate)); - ro += 0.5; - vec2 nuv = ro; - vec4 tex = texture(Sampler0, nuv); - return tex; -} diff --git a/bin/Nodes/GLSL/Voronoi.glsl b/bin/Nodes/GLSL/Voronoi.glsl deleted file mode 100644 index e568c03a..00000000 --- a/bin/Nodes/GLSL/Voronoi.glsl +++ /dev/null @@ -1,44 +0,0 @@ -layout (std140) uniform VoronoiBlock -{ - int pointCount; - float seed; - float distanceBlend; - float squareWidth; -} VoronoiParam; - -float rand(float n){return fract(sin(n) * 43758.5453123);} - -float sdAxisAlignedRect(vec2 uv, vec2 tl, vec2 br) -{ - vec2 d = max(tl-uv, uv-br); - return length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y)); -} - -float sdAxisAlignedRectManhattan(vec2 uv, vec2 tl, vec2 br) -{ - vec2 d = max(tl-uv, uv-br); - vec2 dif = vec2(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y)); - return max(dif.x, dif.y); -} - -float Voronoi() -{ - float col = 1.f; - float minDist = 10.; - for(int i = 0;i 0..2pi) and G is the length of the displacement." }] - }, { - "name": "TerrainPreview", - "category": 2, - "description":"Experimental node.", - "color": [0.5882353186607361, 0.5882353186607361, 0.7843137979507446, 1.0], - "inputs": [{ - "name": "Height", - "type": "Float4" - }, { - "name": "Diffuse", - "type": "Float4" - }, { - "name": "AO", - "type": "Float4" - }, { - "name": "Cubemap", - "type": "Float4" - }], - "outputs": [{ - "name": "", - "type": "Float4" - }], - "parameters": [{ - "name": "Camera", - "type": "Camera", - "default":"", - "description":"" - }] }, { "name": "AO", "category": 4, @@ -1026,63 +1028,6 @@ "default":"0.001", "description":"Radius in clipspace used for the computation." }] - }, { - "name": "FurGenerator", - "category": 9, - "description":"Experimental node.", - "color": [0.7843137979507446, 0.7843137979507446, 0.5882353186607361, 1.0], - "inputs": [{ - "name": "Color", - "type": "Float4" - }, { - "name": "Length", - "type": "Float4" - }], - "outputs": [{ - "name": "", - "type": "Float4" - }], - "parameters": [{ - "name": "Hair count", - "type": "Int", - "description":"" - }, { - "name": "Length factor", - "type": "Float", - "description":"" - }] - }, { - "name": "FurDisplay", - "category": 9, - "description":"Experimental node.", - "color": [0.7843137979507446, 0.7843137979507446, 0.5882353186607361, 1.0], - "inputs": [{ - "name": "", - "type": "Float4" - }], - "outputs": [{ - "name": "", - "type": "Float4" - }], - "parameters": [{ - "name": "Camera", - "type": "Camera", - "default": "", - "description":"" - }] - }, { - "name": "FurIntegrator", - "category": 9, - "description":"Experimental node.", - "color": [0.7843137979507446, 0.7843137979507446, 0.5882353186607361, 1.0], - "inputs": [{ - "name": "", - "type": "Float4" - }], - "outputs": [{ - "name": "", - "type": "Float4" - }] }, { "name": "SVG", "category": 6, @@ -1093,51 +1038,14 @@ "type": "Float4" }], "parameters": [{ - "name": "File name", + "name": "filename", "type": "FilenameRead", "description":"Relative or absolute filepath of the SVG file." }, { - "name": "DPI", + "name": "dpi", "type": "Float", - "description":"Resolution used for rendering the SVG. The higher value, the bigger the image will be." - }] - }, { - "name": "SceneLoader", - "category": 6, - "description":"Experimental node.", - "color": [1.0, 1.0, 1.0, 1.0], - "outputs": [{ - "name": "", - "type": "Float4" - }], - "parameters": [{ - "name": "File name", - "type": "FilenameRead", - "description":"" - }] - }, { - "name": "PathTracer", - "category": 2, - "description":"Experimental node.", - "color": [1.0, 1.0, 1.0, 1.0], - "inputs": [{ - "name": "", - "type": "Float4" - }], - "outputs": [{ - "name": "", - "type": "Float4" - }], - "parameters": [{ - "name": "Mode", - "type": "Enum", - "enum": "Tiled|Progressive|", - "description":"" - }, { - "name" : "Camera", - "type": "Camera", - "default": "", - "description":"" + "description":"Resolution used for rendering the SVG. The higher value, the bigger the image will be.", + "default":"96" }] }, { "name": "EdgeDetect", @@ -1153,39 +1061,11 @@ "type": "Float4" }], "parameters": [{ - "name": "Radius", + "name": "radius", "type": "Float", "default":"0.01", "description":"The radius size in clipspace used for detection. The higher value, the broader the search is." }] - }, { - "name": "Voronoi", - "category": 5, - "description":"Generates a Voronoi texture based on random seeds.", - "color": [0.5882353186607361, 0.9803922176361084, 0.5882353186607361, 1.0], - "outputs": [{ - "name": "", - "type": "Float4" - }], - "parameters": [{ - "name": "Point Count", - "type": "Int", - "default":"20", - "description":"The number of seeds." - },{ - "name": "Seed", - "type": "Float", - "default":"13.37", - "description":"The seeds random position base value." - }, { - "name": "Distance Blend", - "type": "Float", - "description":"Distance computation type interpolate between Euclydean distance (0.) and Manhattan Distance (1.)" - }, { - "name": "Square Width", - "type": "Float", - "description":"Size of each seed in clipspace size." - }] }, { "name": "Kaleidoscope", "category": 0, @@ -1200,21 +1080,21 @@ "type": "Float4" }], "parameters": [{ - "name": "Center", + "name": "center", "type": "Float2", "default":"0.5,0.5", "description":"Center of the operation in clipspace coordinates [0..1]" },{ - "name": "Start Angle", + "name": "startAngle", "type": "Angle", "description":"Angle in degrees of the first plan. Total sum of plan angle is 360 deg." },{ - "name": "Splits", + "name": "splits", "type": "Int", "default": "6", "description":"How many split plans to use." },{ - "name": "Symetry", + "name": "symetry", "type": "Int", "description":"Enable symetry for even plans." }] @@ -1232,13 +1112,13 @@ "type": "Float4" }], "parameters": [{ - "name": "Palette", + "name": "palette", "type": "Enum", "enum": "CGA0|CGA1|CGA2|CGA3|CGA4|CGA5|EGA|Gameboy(mono)|PICO-8|C64|", "description":"Predefined palette. Check examples below for results." }, { - "name": "Dither Strength", + "name": "ditherStrength", "type": "Float", "description":"Bayer dithering strength (0 = none, 1 = full dither)." }] @@ -1278,10 +1158,11 @@ "default":"1002", "description":"Multiple passes are supported by this node." },{ - "name": "Size", + "name": "size", "type": "Enum", "enum": " 256| 512| 1024| 2048| 4096|", - "description":"Size of the output in pixels" + "description":"Size of the output in pixels", + "default":"0" }] }, { @@ -1304,22 +1185,22 @@ "default":"10", "description":"Multiple passes are supported by this node." },{ - "name": "Frequency", + "name": "frequency", "type": "Float", "default":"1.6", "description":"Noise frequency. The higher, the more noise you'll get." },{ - "name": "Strength", + "name": "strength", "type": "Float", "default":"0.25", "description":"Noise strength." },{ - "name": "Randomization", + "name": "randomization", "type": "Float", "default":"40.0", "description":"How much randomization is applied." },{ - "name": "VerticalShift", + "name": "verticalShift", "type": "Float", "default":"0.05", "description":"How much in clip-space is moved to the top. Somekind of force applied to texels." diff --git a/bin/Nodes/SceneNodeDefinitions.json b/bin/Nodes/SceneNodeDefinitions.json index caad183c..99b41a64 100644 --- a/bin/Nodes/SceneNodeDefinitions.json +++ b/bin/Nodes/SceneNodeDefinitions.json @@ -3,18 +3,19 @@ "name": "GLTFRead", "category": 6, "description":"Experimental node.", + "experimental":true, "color": [0.7843137979507446, 0.7843137979507446, 0.5882353186607361, 1.0], "outputs": [{ "name": "", "type": "Float4" }], "parameters": [{ - "name": "File name", + "name": "filename", "type": "FilenameRead", "description":"" }, { - "name": "Camera", + "name": "camera", "type": "Camera", "default":"", "description":"" @@ -23,6 +24,7 @@ "name": "Paint3D", "category": 7, "description":"Experimental node.", + "experimental":true, "color": [0.3921568989753723, 0.9803922176361084, 0.7058823704719544, 1.0], "inputs": [{ "name": "Model", @@ -36,13 +38,13 @@ "type": "Float4" }], "parameters": [{ - "name": "Size", + "name": "size", "type": "Enum", "enum": " 256| 512| 1024| 2048| 4096|", "description":"" }, { - "name": "Camera", + "name": "camera", "type": "Camera", "default":"", "description":"" @@ -51,7 +53,7 @@ "saveTexture": true } ,{ - "name": "CubeRadiance", + "name": "CubeRadiance", "category": 8, "description":"Compute cubemap radiance or irradiance and generate a cubemap with optional mipmaps", "color": [0.5882353186607361, 0.7843137979507446, 0.5882353186607361, 1.0], @@ -64,65 +66,25 @@ "type": "Float4" }], "parameters": [{ - "name": "Mode", + "name": "mode", "type": "Enum", "enum": "Radiance|Irradiance|", "default": "0", "description":"Radiance or Irradiance." },{ - "name": "Size", + "name": "size", "type": "Enum", "enum": "Source| 256| 512| 1024| 2048| 4096|", "default":"0", "description":"Size of the output cubemap face width in pixels." },{ - "name": "Sample Count", + "name": "sampleCount", "type": "Int", "default":"100", "description":"The samples count used for the blur. The more samplem the higher quality." } ] }, { - "name": "PBR2", - "category": 2, - "description":"Experimental node.", - "color": [0.5882353186607361, 0.5882353186607361, 0.7843137979507446, 1.0], - "inputs": [{ - "name": "Albedo", - "type": "Float4" - }, { - "name": "Normal", - "type": "Float4" - }, { - "name": "Depth", - "type": "Float4" - }, { - "name": "Roughness", - "type": "Float4" - }, { - "name": "Cubemap", - "type": "Float4" - }], - "outputs": [{ - "name": "", - "type": "Float4" - }], - "parameters": [{ - "name": "View", - "type": "Float2", - "rangeMinX": 1.0, - "rangeMaxX": 0.0, - "rangeMinY": 0.0, - "rangeMaxY": 1.0, - "relative": true, - "description":"" - },{ - "name": "Depth factor", - "type": "Float", - "default":"0.0", - "description":"" - }] - }, { "name": "ChannelPacker", "category": 0, "description":"Pack channels from 1 to 4 inputs into a new output. This can be used to pack normal/roughness/metallic into a 4 channels image.", @@ -173,8 +135,8 @@ "description":"The source image and its channel used for Alpha in the output." } ] - }, { - "name": "Lens", + }, { + "name": "Lens", "category": 0, "description":"Deforms the source using a lens computation with an optionnal vignette shading.", "color": [0.7843137979507446, 0.7843137979507446, 0.7843137979507446, 1.0], @@ -187,18 +149,18 @@ "type": "Float4" }], "parameters": [{ - "name": "Factor", + "name": "factor", "type": "Float", "default":"0.32", "description":"Lens factor strength." },{ - "name": "Vignette", + "name": "vignette", "type": "Float", "default":"1.0", "description":"Vignette shading: Corners get darker. 0 to disable vignette." }] - }, { - "name": "Distance", + }, { + "name": "Distance", "category": 0, "description":"Generate a signed distance field from a black and white source image.", "color": [0.7843137979507446, 0.7843137979507446, 0.7843137979507446, 1.0], @@ -214,7 +176,51 @@ "name": "passCount", "type": "Int", "default": "1", - "description":"" + "description":"", + "hidden": true + }] + }, { + "name": "Multiplex", + "category": 10, + "description":"Route one input into the output. This choice can be propagated to further nodes.", + "color": [0.7843137979507446, 0.7843137979507446, 0.7843137979507446, 1.0], + "width": 80, + "height": 200, + "thumbnail": false, + "inputs": [{ + "name": "", + "type": "Float4" + },{ + "name": "", + "type": "Float4" + },{ + "name": "", + "type": "Float4" + },{ + "name": "", + "type": "Float4" + },{ + "name": "", + "type": "Float4" + },{ + "name": "", + "type": "Float4" + },{ + "name": "", + "type": "Float4" + },{ + "name": "", + "type": "Float4" + }], + "outputs": [{ + "name": "", + "type": "Float4" + }], + "parameters": [{ + "name": "multiplexer", + "type": "Multiplexer", + "default": "-1", + "description":"Input selection passed thru the output." }] } ] diff --git a/bin/Nodes/Shaders/AO_fs.bin b/bin/Nodes/Shaders/AO_fs.bin new file mode 100644 index 00000000..23c023ac Binary files /dev/null and b/bin/Nodes/Shaders/AO_fs.bin differ diff --git a/bin/Nodes/Shaders/Blend_fs.bin b/bin/Nodes/Shaders/Blend_fs.bin new file mode 100644 index 00000000..c8efc82f Binary files /dev/null and b/bin/Nodes/Shaders/Blend_fs.bin differ diff --git a/bin/Nodes/Shaders/Blit_fs.bin b/bin/Nodes/Shaders/Blit_fs.bin new file mode 100644 index 00000000..53acc70f Binary files /dev/null and b/bin/Nodes/Shaders/Blit_fs.bin differ diff --git a/bin/Nodes/Shaders/Blur_fs.bin b/bin/Nodes/Shaders/Blur_fs.bin new file mode 100644 index 00000000..45140157 Binary files /dev/null and b/bin/Nodes/Shaders/Blur_fs.bin differ diff --git a/bin/Nodes/Shaders/ChannelPacker_fs.bin b/bin/Nodes/Shaders/ChannelPacker_fs.bin new file mode 100644 index 00000000..0d89cdf2 Binary files /dev/null and b/bin/Nodes/Shaders/ChannelPacker_fs.bin differ diff --git a/bin/Nodes/Shaders/Checker_fs.bin b/bin/Nodes/Shaders/Checker_fs.bin new file mode 100644 index 00000000..3452647e Binary files /dev/null and b/bin/Nodes/Shaders/Checker_fs.bin differ diff --git a/bin/Nodes/Shaders/CircleSplatter_fs.bin b/bin/Nodes/Shaders/CircleSplatter_fs.bin new file mode 100644 index 00000000..7821a910 Binary files /dev/null and b/bin/Nodes/Shaders/CircleSplatter_fs.bin differ diff --git a/bin/Nodes/Shaders/Circle_fs.bin b/bin/Nodes/Shaders/Circle_fs.bin new file mode 100644 index 00000000..10158df4 Binary files /dev/null and b/bin/Nodes/Shaders/Circle_fs.bin differ diff --git a/bin/Nodes/Shaders/Clamp_fs.bin b/bin/Nodes/Shaders/Clamp_fs.bin new file mode 100644 index 00000000..48c1fc82 Binary files /dev/null and b/bin/Nodes/Shaders/Clamp_fs.bin differ diff --git a/bin/Nodes/Shaders/Color_fs.bin b/bin/Nodes/Shaders/Color_fs.bin new file mode 100644 index 00000000..7c0b25fb Binary files /dev/null and b/bin/Nodes/Shaders/Color_fs.bin differ diff --git a/bin/Nodes/Shaders/Crop_fs.bin b/bin/Nodes/Shaders/Crop_fs.bin new file mode 100644 index 00000000..9df08602 Binary files /dev/null and b/bin/Nodes/Shaders/Crop_fs.bin differ diff --git a/bin/Nodes/Shaders/CubeRadiance_fs.bin b/bin/Nodes/Shaders/CubeRadiance_fs.bin new file mode 100644 index 00000000..d99bce4f Binary files /dev/null and b/bin/Nodes/Shaders/CubeRadiance_fs.bin differ diff --git a/bin/Nodes/Shaders/CubemapView_fs.bin b/bin/Nodes/Shaders/CubemapView_fs.bin new file mode 100644 index 00000000..eb5bcca2 Binary files /dev/null and b/bin/Nodes/Shaders/CubemapView_fs.bin differ diff --git a/bin/Nodes/Shaders/Disolve_fs.bin b/bin/Nodes/Shaders/Disolve_fs.bin new file mode 100644 index 00000000..872e8cf4 Binary files /dev/null and b/bin/Nodes/Shaders/Disolve_fs.bin differ diff --git a/bin/Nodes/Shaders/DisplayCubemap_fs.bin b/bin/Nodes/Shaders/DisplayCubemap_fs.bin new file mode 100644 index 00000000..84b1b269 Binary files /dev/null and b/bin/Nodes/Shaders/DisplayCubemap_fs.bin differ diff --git a/bin/Nodes/Shaders/Distance_fs.bin b/bin/Nodes/Shaders/Distance_fs.bin new file mode 100644 index 00000000..0b773ef8 Binary files /dev/null and b/bin/Nodes/Shaders/Distance_fs.bin differ diff --git a/bin/Nodes/Shaders/EdgeDetect_fs.bin b/bin/Nodes/Shaders/EdgeDetect_fs.bin new file mode 100644 index 00000000..96ba09dd Binary files /dev/null and b/bin/Nodes/Shaders/EdgeDetect_fs.bin differ diff --git a/bin/Nodes/Shaders/EquirectConverter_fs.bin b/bin/Nodes/Shaders/EquirectConverter_fs.bin new file mode 100644 index 00000000..6f0eed7b Binary files /dev/null and b/bin/Nodes/Shaders/EquirectConverter_fs.bin differ diff --git a/bin/Nodes/Shaders/FurDisplay_fs.bin b/bin/Nodes/Shaders/FurDisplay_fs.bin new file mode 100644 index 00000000..38146eea Binary files /dev/null and b/bin/Nodes/Shaders/FurDisplay_fs.bin differ diff --git a/bin/Nodes/Shaders/FurDisplay_vs.bin b/bin/Nodes/Shaders/FurDisplay_vs.bin new file mode 100644 index 00000000..5f2ec414 Binary files /dev/null and b/bin/Nodes/Shaders/FurDisplay_vs.bin differ diff --git a/bin/Nodes/Shaders/GLTFRead_fs.bin b/bin/Nodes/Shaders/GLTFRead_fs.bin new file mode 100644 index 00000000..25e682c6 Binary files /dev/null and b/bin/Nodes/Shaders/GLTFRead_fs.bin differ diff --git a/bin/Nodes/Shaders/GradientBuilder_fs.bin b/bin/Nodes/Shaders/GradientBuilder_fs.bin new file mode 100644 index 00000000..21431018 Binary files /dev/null and b/bin/Nodes/Shaders/GradientBuilder_fs.bin differ diff --git a/bin/Nodes/Shaders/Invert_fs.bin b/bin/Nodes/Shaders/Invert_fs.bin new file mode 100644 index 00000000..ea6c0774 Binary files /dev/null and b/bin/Nodes/Shaders/Invert_fs.bin differ diff --git a/bin/Nodes/Shaders/Kaleidoscope_fs.bin b/bin/Nodes/Shaders/Kaleidoscope_fs.bin new file mode 100644 index 00000000..1befbb70 Binary files /dev/null and b/bin/Nodes/Shaders/Kaleidoscope_fs.bin differ diff --git a/bin/Nodes/Shaders/LambertMaterial_fs.bin b/bin/Nodes/Shaders/LambertMaterial_fs.bin new file mode 100644 index 00000000..b6676379 Binary files /dev/null and b/bin/Nodes/Shaders/LambertMaterial_fs.bin differ diff --git a/bin/Nodes/Shaders/Lens_fs.bin b/bin/Nodes/Shaders/Lens_fs.bin new file mode 100644 index 00000000..3ad079fe Binary files /dev/null and b/bin/Nodes/Shaders/Lens_fs.bin differ diff --git a/bin/Nodes/Shaders/MADD_fs.bin b/bin/Nodes/Shaders/MADD_fs.bin new file mode 100644 index 00000000..22ad1759 Binary files /dev/null and b/bin/Nodes/Shaders/MADD_fs.bin differ diff --git a/bin/Nodes/Shaders/NGon_fs.bin b/bin/Nodes/Shaders/NGon_fs.bin new file mode 100644 index 00000000..2ca14447 Binary files /dev/null and b/bin/Nodes/Shaders/NGon_fs.bin differ diff --git a/bin/Nodes/Shaders/Node_vs.bin b/bin/Nodes/Shaders/Node_vs.bin new file mode 100644 index 00000000..17e86419 Binary files /dev/null and b/bin/Nodes/Shaders/Node_vs.bin differ diff --git a/bin/Nodes/Shaders/NormalMapBlending_fs.bin b/bin/Nodes/Shaders/NormalMapBlending_fs.bin new file mode 100644 index 00000000..a5cdfc8c Binary files /dev/null and b/bin/Nodes/Shaders/NormalMapBlending_fs.bin differ diff --git a/bin/Nodes/Shaders/NormalMap_fs.bin b/bin/Nodes/Shaders/NormalMap_fs.bin new file mode 100644 index 00000000..8a0acba3 Binary files /dev/null and b/bin/Nodes/Shaders/NormalMap_fs.bin differ diff --git a/bin/Nodes/Shaders/PBR2_fs.bin b/bin/Nodes/Shaders/PBR2_fs.bin new file mode 100644 index 00000000..2cc59555 Binary files /dev/null and b/bin/Nodes/Shaders/PBR2_fs.bin differ diff --git a/bin/Nodes/Shaders/PBR_fs.bin b/bin/Nodes/Shaders/PBR_fs.bin new file mode 100644 index 00000000..63682d51 Binary files /dev/null and b/bin/Nodes/Shaders/PBR_fs.bin differ diff --git a/bin/Nodes/Shaders/Paint2D_fs.bin b/bin/Nodes/Shaders/Paint2D_fs.bin new file mode 100644 index 00000000..74a4ffa9 Binary files /dev/null and b/bin/Nodes/Shaders/Paint2D_fs.bin differ diff --git a/bin/Nodes/Shaders/Paint3D_fs.bin b/bin/Nodes/Shaders/Paint3D_fs.bin new file mode 100644 index 00000000..e06203d6 Binary files /dev/null and b/bin/Nodes/Shaders/Paint3D_fs.bin differ diff --git a/bin/Nodes/Shaders/Palette_fs.bin b/bin/Nodes/Shaders/Palette_fs.bin new file mode 100644 index 00000000..4471d9c0 Binary files /dev/null and b/bin/Nodes/Shaders/Palette_fs.bin differ diff --git a/bin/Nodes/Shaders/PerlinNoise_fs.bin b/bin/Nodes/Shaders/PerlinNoise_fs.bin new file mode 100644 index 00000000..f9437767 Binary files /dev/null and b/bin/Nodes/Shaders/PerlinNoise_fs.bin differ diff --git a/bin/Nodes/Shaders/PhysicalSky_fs.bin b/bin/Nodes/Shaders/PhysicalSky_fs.bin new file mode 100644 index 00000000..c8991e08 Binary files /dev/null and b/bin/Nodes/Shaders/PhysicalSky_fs.bin differ diff --git a/bin/Nodes/Shaders/Pixelize_fs.bin b/bin/Nodes/Shaders/Pixelize_fs.bin new file mode 100644 index 00000000..6f16c5e9 Binary files /dev/null and b/bin/Nodes/Shaders/Pixelize_fs.bin differ diff --git a/bin/Nodes/Shaders/PolarCoords_fs.bin b/bin/Nodes/Shaders/PolarCoords_fs.bin new file mode 100644 index 00000000..48442848 Binary files /dev/null and b/bin/Nodes/Shaders/PolarCoords_fs.bin differ diff --git a/bin/Nodes/Shaders/ProgressingNode_fs.bin b/bin/Nodes/Shaders/ProgressingNode_fs.bin new file mode 100644 index 00000000..d9b22698 Binary files /dev/null and b/bin/Nodes/Shaders/ProgressingNode_fs.bin differ diff --git a/bin/Nodes/Shaders/Ramp_fs.bin b/bin/Nodes/Shaders/Ramp_fs.bin new file mode 100644 index 00000000..d352bd9c Binary files /dev/null and b/bin/Nodes/Shaders/Ramp_fs.bin differ diff --git a/bin/Nodes/Shaders/ReactionDiffusion_fs.bin b/bin/Nodes/Shaders/ReactionDiffusion_fs.bin new file mode 100644 index 00000000..dd9f118e Binary files /dev/null and b/bin/Nodes/Shaders/ReactionDiffusion_fs.bin differ diff --git a/bin/Nodes/Shaders/Sine_fs.bin b/bin/Nodes/Shaders/Sine_fs.bin new file mode 100644 index 00000000..85a7689b Binary files /dev/null and b/bin/Nodes/Shaders/Sine_fs.bin differ diff --git a/bin/Nodes/Shaders/SmoothStep_fs.bin b/bin/Nodes/Shaders/SmoothStep_fs.bin new file mode 100644 index 00000000..4d8c4345 Binary files /dev/null and b/bin/Nodes/Shaders/SmoothStep_fs.bin differ diff --git a/bin/Nodes/Shaders/Swirl_fs.bin b/bin/Nodes/Shaders/Swirl_fs.bin new file mode 100644 index 00000000..fec1544e Binary files /dev/null and b/bin/Nodes/Shaders/Swirl_fs.bin differ diff --git a/bin/Nodes/Shaders/TerrainPreview_fs.bin b/bin/Nodes/Shaders/TerrainPreview_fs.bin new file mode 100644 index 00000000..b6676379 Binary files /dev/null and b/bin/Nodes/Shaders/TerrainPreview_fs.bin differ diff --git a/bin/Nodes/Shaders/Tile_fs.bin b/bin/Nodes/Shaders/Tile_fs.bin new file mode 100644 index 00000000..444be2ea Binary files /dev/null and b/bin/Nodes/Shaders/Tile_fs.bin differ diff --git a/bin/Nodes/Shaders/Transform_fs.bin b/bin/Nodes/Shaders/Transform_fs.bin new file mode 100644 index 00000000..1d4f4bcb Binary files /dev/null and b/bin/Nodes/Shaders/Transform_fs.bin differ diff --git a/bin/Nodes/Shaders/Voronoi_fs.bin b/bin/Nodes/Shaders/Voronoi_fs.bin new file mode 100644 index 00000000..06fb1773 Binary files /dev/null and b/bin/Nodes/Shaders/Voronoi_fs.bin differ diff --git a/bin/Nodes/Shaders/Warp_fs.bin b/bin/Nodes/Shaders/Warp_fs.bin new file mode 100644 index 00000000..39142e15 Binary files /dev/null and b/bin/Nodes/Shaders/Warp_fs.bin differ diff --git a/bin/Nodes/Shaders/WorleyNoise_fs.bin b/bin/Nodes/Shaders/WorleyNoise_fs.bin new file mode 100644 index 00000000..252d4bc7 Binary files /dev/null and b/bin/Nodes/Shaders/WorleyNoise_fs.bin differ diff --git a/bin/Nodes/Shaders/iqnoise_fs.bin b/bin/Nodes/Shaders/iqnoise_fs.bin new file mode 100644 index 00000000..79f95776 Binary files /dev/null and b/bin/Nodes/Shaders/iqnoise_fs.bin differ diff --git a/bin/Plugins/autotests.py b/bin/Plugins/autotests.py new file mode 100644 index 00000000..44839d6c --- /dev/null +++ b/bin/Plugins/autotests.py @@ -0,0 +1,494 @@ +import Imogen +import os +import math +import datetime +import shutil + +def setDefaultCubemap(node): + Imogen.SetParameter(node, "XPosFilename", "Autotests/Assets/Lycksele/posx.jpg") + Imogen.SetParameter(node, "XNegFilename", "Autotests/Assets/Lycksele/negx.jpg") + Imogen.SetParameter(node, "YPosFilename", "Autotests/Assets/Lycksele/posy.jpg") + Imogen.SetParameter(node, "YNegFilename", "Autotests/Assets/Lycksele/negy.jpg") + Imogen.SetParameter(node, "ZPosFilename", "Autotests/Assets/Lycksele/posz.jpg") + Imogen.SetParameter(node, "ZNegFilename", "Autotests/Assets/Lycksele/negz.jpg") + +def captureGraph(filename): + Imogen.AutoLayout() + Imogen.Render() + Imogen.Render() + Imogen.Render() + Imogen.CaptureScreen(filename, "Graph") + +def imageTests(outDir): + metanodes = Imogen.GetMetaNodes() + Imogen.OpenLibrary(Imogen.NewLibrary(outDir, "tempLibrary", False), False) + + ################################################### + # read one jpg, write it back + Imogen.NewGraph("ImageRead01") + imageRead = Imogen.AddNode("ImageRead") + Imogen.SetParameter(imageRead, "filename", "Autotests/Assets/Vancouver.jpg") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.Connect(imageRead, 0, imageWrite, 0) + + # free + Imogen.SetParameters(imageWrite, {"filename":outDir+"Vancouver-free.jpg", "mode": 0, "width": 2048, "height": 2048}) + Imogen.Build() + # w=512 h=keep ratio + Imogen.SetParameters(imageWrite, {"mode":1, "width": 512, "filename": outDir+"Vancouver-width512.jpg"}) + Imogen.Build() + # h= 1024 w=keep ratio + Imogen.SetParameters(imageWrite, {"mode":2, "height": 1024, "filename": outDir+"Vancouver-height1024.jpg"}) + Imogen.Build() + # same size as source + Imogen.SetParameters(imageWrite, {"mode":3, "filename": outDir+"Vancouver-same.jpg"}) + Imogen.Build() + # same size as source PNG + Imogen.SetParameters(imageWrite, {"format":1, "filename": outDir+"Vancouver-same.png"}) + Imogen.Build() + # same size as source TGA + Imogen.SetParameters(imageWrite, {"format":2, "filename": outDir+"Vancouver-same.tga"}) + Imogen.Build() + # same size as source BMP + Imogen.SetParameters(imageWrite, {"format":3, "filename": outDir+"Vancouver-same.bmp"}) + Imogen.Build() + # same size as source HDR + Imogen.SetParameters(imageWrite, {"format":4, "filename": outDir+"Vancouver-same.hdr"}) + Imogen.Build() + # same size as source DDS + Imogen.SetParameters(imageWrite, {"format":5, "filename": outDir+"Vancouver-same.dds"}) + Imogen.Build() + # same size as source KTX + Imogen.SetParameters(imageWrite, {"format":6, "filename": outDir+"Vancouver-same.ktx"}) + Imogen.Build() + # same size as source EXR + Imogen.SetParameters(imageWrite, {"format":7, "filename": outDir+"Vancouver-same.exr"}) + Imogen.Build() + Imogen.DeleteGraph() + + ################################################### + #read 6 images, write the cubemap dds + Imogen.NewGraph("ImageRead02") + imageRead = Imogen.AddNode("ImageRead") + setDefaultCubemap(imageRead) + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.SetParameters(imageWrite, {"mode":3, "format":5, "filename": outDir+"Cubemap01.dds"}) + Imogen.Connect(imageRead, 0, imageWrite, 0) + Imogen.Build() + # jpg from cubemap + Imogen.SetParameters(imageWrite, {"mode":3, "format":0, "filename": outDir+"JpgFromCubemap.jpg"}) + Imogen.Build() + Imogen.DeleteGraph() + + #read equirect hdr, convert to cubemap, write dds + Imogen.NewGraph("ImageRead03") + imageRead = Imogen.AddNode("ImageRead") + Imogen.SetParameter(imageRead, "filename", "Autotests/Assets/studio022.hdr") + equirect = Imogen.AddNode("EquirectConverter") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.SetParameter(imageWrite, "filename", outDir+"Equirect2cubemap.dds") + Imogen.SetParameter(imageWrite, "format", "5") + Imogen.Connect(imageRead, 0, equirect, 0) + Imogen.Connect(equirect, 0, imageWrite, 0) + Imogen.SetParameter(imageWrite, "width", "256") + Imogen.SetParameter(imageWrite, "height", "256") + Imogen.Build() + Imogen.DeleteGraph() + + # read cube, save same cube + Imogen.NewGraph("ImageRead03b") + imageRead = Imogen.AddNode("ImageRead") + Imogen.SetParameter(imageRead, "filename", outDir+"Cubemap01.dds") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.SetParameters(imageWrite, {"mode":3, "format":5, "filename": outDir+"SameCubemap01.dds"}) + Imogen.Connect(imageRead, 0, imageWrite, 0) + Imogen.Build() + Imogen.DeleteGraph() + + ################################################# + #read a cubemap dds, convert to equirect, save jpg + Imogen.NewGraph("ImageRead04") + imageRead = Imogen.AddNode("ImageRead") + Imogen.SetParameter(imageRead, "filename", outDir+"Cubemap01.dds") + equirect = Imogen.AddNode("EquirectConverter") + Imogen.SetParameter(equirect, "mode", "1") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.SetParameter(imageWrite, "filename", outDir+"EquirectFromCubemap01.jpg") + Imogen.SetParameter(imageWrite, "format", "0") + Imogen.Connect(imageRead, 0, equirect, 0) + Imogen.Connect(equirect, 0, imageWrite, 0) + Imogen.SetParameter(imageWrite, "width", "512") + Imogen.SetParameter(imageWrite, "height", "256") + Imogen.Build() + + # test with a resulting dds + Imogen.SetParameter(imageRead, "filename", outDir+"Equirect2cubemap.dds") + Imogen.SetParameter(imageWrite, "filename", outDir+"EquirectFromCubemap02.jpg") + Imogen.Build() + Imogen.DeleteGraph() + + # physical sky to dds + Imogen.NewGraph("ImageRead05") + physicalSky = Imogen.AddNode("PhysicalSky") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "format":5, "filename": outDir+"Cubemap-PhysicalSky.dds"}) + Imogen.Connect(physicalSky, 0, imageWrite, 0) + Imogen.Build() + Imogen.DeleteGraph() + + # physical sky to equirect-jpg + Imogen.NewGraph("ImageRead05") + physicalSky = Imogen.AddNode("PhysicalSky") + equirect = Imogen.AddNode("EquirectConverter") + Imogen.SetParameter(equirect, "mode", "1") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.SetParameters(imageWrite, {"width":512, "height":256, "format":0, "filename": outDir+"EquirectFromCubemap03.jpg"}) + Imogen.Connect(physicalSky, 0, equirect, 0) + Imogen.Connect(equirect, 0, imageWrite, 0) + Imogen.Build() + Imogen.DeleteGraph() + + # circle -> png + Imogen.NewGraph("Gen01") + circle = Imogen.AddNode("Circle") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.SetParameters(imageWrite, {"width":4096, "height":4096, "format":1, "filename": outDir+"Circle01.png"}) + Imogen.Connect(circle, 0, imageWrite, 0) + Imogen.Build() + Imogen.SetParameters(imageWrite, {"width":512, "height":512, "format":0, "filename": outDir+"Circle02.jpg"}) + Imogen.Build() + Imogen.DeleteGraph() + + ########################################### + # crop -> jpg + Imogen.NewGraph("Crop01") + imageRead = Imogen.AddNode("ImageRead") + Imogen.SetParameter(imageRead, "filename", "Autotests/Assets/Vancouver.jpg") + imageWrite = Imogen.AddNode("ImageWrite") + crop = Imogen.AddNode("Crop") + Imogen.Connect(imageRead, 0, crop, 0) + Imogen.Connect(crop, 0, imageWrite, 0) + # 1K + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "mode":0, "filename": outDir+"crop-1024.jpg"}) + Imogen.Build() + # as source + Imogen.SetParameter(imageWrite, "mode", "3") + Imogen.SetParameter(imageWrite, "filename", outDir+"crop-sourceSize.jpg") + Imogen.Build() + Imogen.DeleteGraph() + + + ########################################### + # channel packer to png + Imogen.NewGraph("Packer") + packer = Imogen.AddNode("ChannelPacker") + circle = Imogen.AddNode("Circle") + ngon = Imogen.AddNode("NGon") + checker = Imogen.AddNode("Checker") + Sine = Imogen.AddNode("Sine") + Imogen.Connect(circle, 0, packer, 0) + Imogen.Connect(ngon, 0, packer, 1) + Imogen.Connect(checker, 0, packer, 2) + Imogen.Connect(Sine, 0, packer, 3) + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.Connect(packer, 0, imageWrite, 0) + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "format":1, "filename": outDir+"ChannelPacker.png"}) + Imogen.Build() + Imogen.DeleteGraph() + + ########################################### + # blur + Imogen.NewGraph("Blur") + imageRead = Imogen.AddNode("ImageRead") + Imogen.SetParameter(imageRead, "filename", "Autotests/Assets/Vancouver.jpg") + imageWrite = Imogen.AddNode("ImageWrite") + blur = Imogen.AddNode("Blur") + Imogen.Connect(imageRead, 0, blur, 0) + Imogen.Connect(blur, 0, imageWrite, 0) + Imogen.SetParameter(blur, "strength", "0.001") + # 1 dir pass + Imogen.SetParameter(blur, "angle", "22.5") + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "mode":0, "filename": outDir+"blur-directional-1pass.jpg"}) + Imogen.Build() + # 30 dir passes + Imogen.SetParameter(blur, "passCount", "30") + Imogen.SetParameter(imageWrite, "filename", outDir+"blur-directional-30passes.jpg") + Imogen.Build() + # 1 box pass + Imogen.SetParameter(blur, "type", "1") + Imogen.SetParameter(blur, "passCount", "1") + Imogen.SetParameter(imageWrite, "filename", outDir+"blur-box-1pass.jpg") + Imogen.Build() + # 30 box pass + Imogen.SetParameter(blur, "passCount", "30") + Imogen.SetParameter(imageWrite, "filename", outDir+"blur-box-30passes.jpg") + Imogen.Build() + Imogen.DeleteGraph() + + ########################################### + # voronoi from image + Imogen.NewGraph("Voronoi") + imageRead = Imogen.AddNode("ImageRead") + Imogen.SetParameter(imageRead, "filename", "Autotests/Assets/Vancouver.jpg") + imageWrite = Imogen.AddNode("ImageWrite") + voronoi = Imogen.AddNode("Voronoi") + Imogen.Connect(imageRead, 0, voronoi, 0) + Imogen.Connect(voronoi, 0, imageWrite, 0) + Imogen.SetParameters(voronoi, {"size":30, "noise":0.5, "colorInterpolation":0}) + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "mode":0, "filename": outDir+"Voronoi-image.jpg"}) + Imogen.Build() + Imogen.DeleteGraph() + # noise generator + Imogen.NewGraph("Voronoi") + imageWrite = Imogen.AddNode("ImageWrite") + voronoi = Imogen.AddNode("Voronoi") + Imogen.Connect(voronoi, 0, imageWrite, 0) + Imogen.SetParameters(voronoi, {"size":20, "noise":1.0, "colorInterpolation":1}) + # from image + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "mode":0, "filename": outDir+"Voronoi-noise.jpg"}) + Imogen.Build() + Imogen.DeleteGraph() + + # circle -> distance -> png + Imogen.NewGraph("Distance01") + circle = Imogen.AddNode("Circle") + distance = Imogen.AddNode("Distance") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.SetParameters(imageWrite, {"width":4096, "height":4096, "format":1, "filename": outDir+"Distance01.png"}) + Imogen.Connect(circle, 0, distance, 0) + Imogen.Connect(distance, 0, imageWrite, 0) + Imogen.Build() + Imogen.DeleteGraph() + + # palette + Imogen.NewGraph("Palette") + imageRead = Imogen.AddNode("ImageRead") + Imogen.SetParameter(imageRead, "filename", "Autotests/Assets/PartyCat.jpg") + imageWrite = Imogen.AddNode("ImageWrite") + palette = Imogen.AddNode("Palette") + Imogen.Connect(imageRead, 0, palette, 0) + Imogen.Connect(palette, 0, imageWrite, 0) + Imogen.SetParameter(palette, "palette", "0") + Imogen.SetParameter(palette, "ditherStrength", "0.0") + Imogen.SetParameter(imageWrite, "format", "1") + Imogen.SetParameter(imageWrite, "mode", "3") + + for pal in range(0, 10): + Imogen.SetParameter(palette, "palette", "{}".format(pal)) + Imogen.SetParameter(imageWrite, "filename", (outDir+"Palette-{}.png").format(pal)); + Imogen.Build() + Imogen.SetParameter(palette, "palette", "0") + for dither in range(0, 10): + Imogen.SetParameter(palette, "ditherStrength", "{}".format(dither/10.0)) + Imogen.SetParameter(imageWrite, "filename", (outDir+"DitherPalette-0-{}.png").format(dither/10.0)); + Imogen.Build() + + # samplers + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "format":1, "mode":0, "filename": outDir+"Palette_1024_linear.png"}) + Imogen.Build() + Imogen.SetSamplers(imageWrite, 0, {"filterMin" : 1}) + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "format":1, "mode":0, "filename": outDir+"Palette_1024_nearest.png"}) + Imogen.Build() + Imogen.DeleteGraph() + + # reaction diffusion + Imogen.NewGraph("ReactionDiffusion") + circle = Imogen.AddNode("Circle") + imageWrite = Imogen.AddNode("ImageWrite") + reactionDiffusion = Imogen.AddNode("ReactionDiffusion") + Imogen.SetParameters(imageWrite, {"width":4096, "height":4096, "format":1, "filename": outDir+"ReactionDiffusion01.png"}) + Imogen.Connect(circle, 0, reactionDiffusion, 0) + Imogen.Connect(reactionDiffusion, 0, imageWrite, 0) + Imogen.Build() + Imogen.SetParameters(reactionDiffusion, {"boost":0.72, "divisor":3.9, "colorStep":0.01}) + Imogen.SetParameter(imageWrite, "filename", outDir+"ReactionDiffusion02.png") + Imogen.Build() + Imogen.DeleteGraph() + + # gltf read + Imogen.NewGraph("GLTF01") + gltf = Imogen.AddNode("GLTFRead") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.SetParameter(gltf, "filename", "Autotests/Assets/CartoonHead.gltf/scene.gltf") + Imogen.SetCameraLookAt(gltf, 2., 1., 3.,0.,-1.,0.); + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "format":0, "filename": outDir+"gltf01.jpg"}) + Imogen.Connect(gltf, 0, imageWrite, 0) + Imogen.Build() + #Imogen.DeleteGraph() + + # blend + Imogen.NewGraph("GraphForBlend") + blendNode = Imogen.AddNode("Blend") + imageRead = Imogen.AddNode("ImageRead") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.SetParameter(imageRead, "filename", "Autotests/Assets/PartyCat.jpg") + sineNode = Imogen.AddNode("Sine") + Imogen.Connect(imageRead, 0, blendNode, 0) + Imogen.Connect(sineNode, 0, blendNode, 1) + Imogen.Connect(blendNode, 0, imageWrite, 0) + + for node in metanodes: + nodeName = node["name"]; + if nodeName == "Blend": + param = next((p for p in node["parameters"] if p["typeString"] == "Enum"), None) + index = 0 + for enum in param["enum"]: + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "mode":0, "filename": outDir+"Blend-"+enum+".jpg"}) + Imogen.SetParameters(blendNode, {"operation":index}) + index = index + 1 + Imogen.Build() + Imogen.DeleteGraph() + + # cubemap radiance filter + + Imogen.NewGraph("CubeRadiance") + imageRead = Imogen.AddNode("ImageRead") + radiance = Imogen.AddNode("CubeRadiance") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.Connect(imageRead, 0, radiance, 0) + Imogen.Connect(radiance, 0, imageWrite, 0) + setDefaultCubemap(imageRead) + Imogen.SetParameters(imageWrite, {"mode":3, "format":5, "filename": outDir+"CubemapRadiance.dds"}) + Imogen.SetParameters(radiance, {"mode":0, "size":1, "sampleCount":1000}) + Imogen.Build() + Imogen.SetParameters(imageWrite, {"mode":3, "format":5, "filename": outDir+"CubemapIrradiance.dds"}) + Imogen.SetParameters(radiance, {"mode":1, "size":1, "sampleCount":1000}) + Imogen.Build() + Imogen.DeleteGraph() + + Imogen.NewGraph("CubeRadiance") + imageRead = Imogen.AddNode("ImageRead") + radiance = Imogen.AddNode("CubeRadiance") + equirect = Imogen.AddNode("EquirectConverter") + Imogen.SetParameter(equirect, "mode", "1") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.Connect(imageRead, 0, radiance, 0) + Imogen.Connect(radiance, 0, equirect, 0) + Imogen.Connect(equirect, 0, imageWrite, 0) + setDefaultCubemap(imageRead) + Imogen.SetParameters(imageWrite, {"width":512, "height":256, "mode":0, "format":1, "filename": outDir+"EquirectRadiance.png"}) + Imogen.SetParameters(radiance, {"mode":0, "size":1, "sampleCount":1000}) + Imogen.Build() + Imogen.DeleteGraph() + + # thumbnail + Imogen.NewGraph("ThumbnailTest") + circle = Imogen.AddNode("Circle") + thumbnail = Imogen.AddNode("Thumbnail") + Imogen.Connect(circle, 0, thumbnail, 0) + Imogen.Build() + thumbnailImage = Imogen.GetThumbnailImage("ThumbnailTest") + Imogen.WriteImage(outDir+"Thumbnail_1.png", thumbnailImage, 1, 0); + Imogen.DeleteGraph() + + # multiplex !! + Imogen.NewGraph("Multiplex") + circle = Imogen.AddNode("Circle") + ngon = Imogen.AddNode("NGon") + checker = Imogen.AddNode("Checker") + sine = Imogen.AddNode("Sine") + multiplexLeft = Imogen.AddNode("Multiplex") + multiplexRight = Imogen.AddNode("Multiplex") + blend = Imogen.AddNode("Blend") + imageWrite = Imogen.AddNode("ImageWrite") + + Imogen.Connect(checker, 0, multiplexLeft, 0) + Imogen.Connect(checker, 0, multiplexRight, 4) + Imogen.Connect(sine, 0, multiplexLeft, 2) + Imogen.Connect(ngon, 0, multiplexLeft, 6) + + Imogen.Connect(circle, 0, multiplexRight, 1) + Imogen.Connect(circle, 0, blend, 0) + + Imogen.Connect(multiplexLeft, 0, multiplexRight, 3) + Imogen.Connect(multiplexRight, 0, blend, 1) + + Imogen.Connect(blend, 0, imageWrite, 0) + + Imogen.Connect(ngon, 0, multiplexRight, 7) # todelete + + captureGraph(outDir+"MultiplexGraph_0.png") + + Imogen.Disconnect(multiplexRight, 7) + captureGraph(outDir+"MultiplexGraph_1.png") + + # get what's connected + + assert Imogen.GetMultiplexList(blend, 0) == [], "List must be empty" + assert Imogen.GetMultiplexList(imageWrite, 0) == [], "List must be empty" + assert Imogen.GetMultiplexList(blend, 1) == [0, 1, 2, 3], "List is incorrect" + assert Imogen.GetMultiplexList(blend, 2) == [], "List must be empty" + assert Imogen.GetMultiplexList(blend, 200) == [], "List must be empty" + assert Imogen.GetSelectedMultiplex(blend, 0) == -1, "Wrong multiplex" + assert Imogen.GetSelectedMultiplex(blend, 1) == -1, "Wrong multiplex" + assert Imogen.GetSelectedMultiplex(blend, 2) == -1, "Wrong multiplex" + assert Imogen.GetSelectedMultiplex(blend, 200) == -1, "Wrong multiplex" + + Imogen.SelectMultiplexIndex(1000, 1000, 1000) + Imogen.SelectMultiplexIndex(blend, 1000, -18) + Imogen.SelectMultiplexIndex(blend, 0, -18) + Imogen.SelectMultiplexIndex(blend, 0, 0) + Imogen.SelectMultiplexIndex(blend, 0, 1) + Imogen.SelectMultiplexIndex(blend, 1, -1) + Imogen.SelectMultiplexIndex(blend, 1, 18) + Imogen.SelectMultiplexIndex(blend, 1, 1) + assert Imogen.GetMultiplexList(blend, 1) == [0, 1, 2, 3] + + assert Imogen.GetSelectedMultiplex(blend, 1) == 1, "Wrong multiplexed value" + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "mode":0, "format":0, "filename": outDir+"Multiplex_build0.jpg"}) + Imogen.Build() + + Imogen.SelectMultiplex(blend, 1, 300) + Imogen.SelectMultiplex(blend, 1, 2) + assert Imogen.GetSelectedMultiplex(blend, 1) == 2, "Wrong multiplexed value" + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "mode":0, "format":0, "filename": outDir+"Multiplex_build1.jpg"}) + Imogen.Build() + + Imogen.DelNode(2) + Imogen.SetParameters(imageWrite-1, {"width":1024, "height":1024, "mode":0, "format":0, "filename": outDir+"Multiplex_build2.jpg"}) + Imogen.Build() + captureGraph(outDir+"MultiplexGraph_2.png") + + assert Imogen.GetSelectedMultiplex(blend, 1) == -1, "Wrong multiplexed value after node deletion" + + # gltf read stylized rock + Imogen.NewGraph("GLTF01") + gltf = Imogen.AddNode("GLTFRead") + imageWrite = Imogen.AddNode("ImageWrite") + Imogen.SetParameter(gltf, "filename", "Media/Mesh/stylized_rock/scene.gltf") + Imogen.SetCameraLookAt(gltf, 2., 1., 3.,0.,-1.,0.); + Imogen.SetParameters(imageWrite, {"width":1024, "height":1024, "format":0, "filename": outDir+"gltf02.jpg"}) + Imogen.Connect(gltf, 0, imageWrite, 0) + Imogen.Build() + Imogen.DeleteGraph() + + Imogen.CloseCurrentLibrary() + + +def clearTests(folder): + for the_file in os.listdir(folder): + file_path = os.path.join(folder, the_file) + try: + if os.path.isfile(file_path): + os.unlink(file_path) + #elif os.path.isdir(file_path): shutil.rmtree(file_path) + except Exception as e: + print(e) + + + +def autotests(): + startTime = datetime.datetime.now() + Imogen.SetSynchronousEvaluation(True) + + outDir = "Autotests/Run/"+Imogen.GetRendererType()+"/" + clearTests(outDir) + + imageTests(outDir) + + Imogen.SetSynchronousEvaluation(False) + endTime = datetime.datetime.now() + Imogen.Log("Autotests in {}\n".format(endTime - startTime)) + + +Imogen.RegisterPlugin("Autotests", "import Plugins.autotests as plg\nplg.autotests()") diff --git a/bin/Plugins/generateDocumentation.py b/bin/Plugins/generateDocumentation.py index 1c6ea66b..708dc2f3 100644 --- a/bin/Plugins/generateDocumentation.py +++ b/bin/Plugins/generateDocumentation.py @@ -30,11 +30,11 @@ def blendExample(filePath, operation, content): Imogen.NewGraph("GraphForBlend") blendNode = Imogen.AddNode("Blend") imageRead = Imogen.AddNode("ImageRead") - Imogen.SetParameter(imageRead, "File name", "Media/Pictures/PartyCat.jpg") + Imogen.SetParameter(imageRead, "filename", "Media/Pictures/PartyCat.jpg") sineNode = Imogen.AddNode("Sine") Imogen.Connect(imageRead, 0, blendNode, 0) Imogen.Connect(sineNode, 0, blendNode, 1) - Imogen.SetParameter(blendNode, "Operation", operation) + Imogen.SetParameter(blendNode, "operation", operation) saveScreen(filePath, content) Imogen.DeleteGraph() @@ -42,9 +42,9 @@ def paletteExample(filePath, operation, content): Imogen.NewGraph("GraphForPalette") paletteNode = Imogen.AddNode("Palette") imageRead = Imogen.AddNode("ImageRead") - Imogen.SetParameter(imageRead, "File name", "Media/Pictures/PartyCat.jpg") + Imogen.SetParameter(imageRead, "filename", "Media/Pictures/PartyCat.jpg") Imogen.Connect(imageRead, 0, paletteNode, 0) - Imogen.SetParameter(paletteNode, "Palette", operation) + Imogen.SetParameter(paletteNode, "palette", operation) saveScreen(filePath, content) Imogen.DeleteGraph() @@ -73,12 +73,12 @@ def appendTable(tab, lineSize, f, makeLink = False): f.write("\n\n") def setDefaultCubemap(node): - Imogen.SetParameter(node, "+X File name", "Media/EnvMaps/Fjaderholmarna/posx.jpg") - Imogen.SetParameter(node, "-X File name", "Media/EnvMaps/Fjaderholmarna/negx.jpg") - Imogen.SetParameter(node, "+Y File name", "Media/EnvMaps/Fjaderholmarna/posy.jpg") - Imogen.SetParameter(node, "-Y File name", "Media/EnvMaps/Fjaderholmarna/negy.jpg") - Imogen.SetParameter(node, "+Z File name", "Media/EnvMaps/Fjaderholmarna/posz.jpg") - Imogen.SetParameter(node, "-Z File name", "Media/EnvMaps/Fjaderholmarna/negz.jpg") + Imogen.SetParameter(node, "XPosFilename", "Media/EnvMaps/Fjaderholmarna/posx.jpg") + Imogen.SetParameter(node, "XNegFilename", "Media/EnvMaps/Fjaderholmarna/negx.jpg") + Imogen.SetParameter(node, "YPosFilename", "Media/EnvMaps/Fjaderholmarna/posy.jpg") + Imogen.SetParameter(node, "YNegFilename", "Media/EnvMaps/Fjaderholmarna/negy.jpg") + Imogen.SetParameter(node, "ZPosFilename", "Media/EnvMaps/Fjaderholmarna/posz.jpg") + Imogen.SetParameter(node, "ZNegFilename", "Media/EnvMaps/Fjaderholmarna/negz.jpg") def generateExample(nodeName, baseDir, f, node): exampleWithCatImage = ["Pixelize", "PolarCoords", "Swirl", "Crop", "Kaleidoscope", "Palette", "Blur", "Invert", "Lens", "MADD", "SmoothStep", "Clamp"] @@ -132,11 +132,11 @@ def generateExample(nodeName, baseDir, f, node): elif nodeName == "ChannelPacker": circle = Imogen.AddNode("Circle") - square = Imogen.AddNode("Square") + ngon = Imogen.AddNode("NGon") checker = Imogen.AddNode("Checker") color = Imogen.AddNode("Color") Imogen.Connect(circle, 0, node, 0) - Imogen.Connect(square, 0, node, 1) + Imogen.Connect(ngon, 0, node, 1) Imogen.Connect(checker, 0, node, 2) Imogen.Connect(color, 0, node, 3) @@ -153,7 +153,7 @@ def generateExample(nodeName, baseDir, f, node): elif nodeName == "Warp": circle = Imogen.AddNode("Circle") imageRead = Imogen.AddNode("ImageRead") - Imogen.SetParameter(imageRead, "File name", "Media/Pictures/PartyCat.jpg") + Imogen.SetParameter(imageRead, "filename", "Media/Pictures/PartyCat.jpg") Imogen.SetParameter(circle, "T", "1.0") Imogen.SetParameter(node, "Mode", "1") Imogen.Connect(imageRead, 0, node, 0) @@ -184,13 +184,22 @@ def generateExample(nodeName, baseDir, f, node): Imogen.Connect(normal1, 0, node, 0) Imogen.Connect(normal2, 0, node, 1) + elif nodeName == "Multiplex": + circle = Imogen.AddNode("Circle") + ngon = Imogen.AddNode("NGon") + imageRead = Imogen.AddNode("ImageRead") + Imogen.SetParameter(imageRead, "filename", "Media/Pictures/PartyCat.jpg") + Imogen.Connect(circle, 0, node, 0) + Imogen.Connect(ngon, 0, node, 1) + Imogen.Connect(imageRead, 0, node, 4) + elif nodeName == "ImageRead" : - Imogen.SetParameter(node, "File name", "Media/Pictures/PartyCat.jpg") + Imogen.SetParameter(node, "filename", "Media/Pictures/PartyCat.jpg") elif nodeName == "EquirectConverter" : imageRead = Imogen.AddNode("ImageRead") view = Imogen.AddNode("CubemapView") - Imogen.SetParameter(imageRead, "File name", "Media/EnvMaps/Equirect/studio022.hdr") + Imogen.SetParameter(imageRead, "filename", "Media/EnvMaps/Equirect/studio022.hdr") Imogen.SetParameter(view, "Mode", "2") Imogen.Connect(imageRead, 0, node, 0) Imogen.Connect(node, 0, view, 0) @@ -212,11 +221,11 @@ def generateExample(nodeName, baseDir, f, node): elif nodeName in exampleWithCatImage : imageRead = Imogen.AddNode("ImageRead") - Imogen.SetParameter(imageRead, "File name", "Media/Pictures/PartyCat.jpg") + Imogen.SetParameter(imageRead, "filename", "Media/Pictures/PartyCat.jpg") Imogen.Connect(imageRead, 0, node, 0) elif nodeName == "SVG" : - Imogen.SetParameter(node, "File name", "Media/Pictures/23.svg") + Imogen.SetParameter(node, "filename", "Media/Pictures/23.svg") finishGraph(f, nodeName, baseDir) diff --git a/bin/Stock/DisplayCubemap.glsl b/bin/Stock/DisplayCubemap.glsl deleted file mode 100644 index 7f2d451d..00000000 --- a/bin/Stock/DisplayCubemap.glsl +++ /dev/null @@ -1,29 +0,0 @@ -#ifdef VERTEX_SHADER - -layout(location = 0)in vec2 inUV; -out vec2 vUV; -void main() -{ - gl_Position = vec4(inUV.xy*2.0 - 1.0,0.5,1.0); - vUV = inUV; -} - -#endif - -#ifdef FRAGMENT_SHADER - -uniform samplerCube samplerCubemap; -layout(location = 0) out vec4 outPixDiffuse; -in vec2 vUV; - -void main() -{ - vec2 uv = (vUV - 0.5) * 2.0; - vec2 ng = uv * vec2(3.14159265, 1.57079633); - vec2 a = cos(ng); - vec2 b = sin(ng); - outPixDiffuse = texture(samplerCubemap, normalize(vec3(a.x*a.y, -b.y, b.x*a.y))); - outPixDiffuse.a = 1.0; -} - -#endif diff --git a/bin/Stock/Fonts/fa-solid-900.ttf b/bin/Stock/Fonts/fa-solid-900.ttf new file mode 100644 index 00000000..f7b857c9 Binary files /dev/null and b/bin/Stock/Fonts/fa-solid-900.ttf differ diff --git a/bin/Stock/NodeError.glsl b/bin/Stock/NodeError.glsl deleted file mode 100644 index 83c6493f..00000000 --- a/bin/Stock/NodeError.glsl +++ /dev/null @@ -1,31 +0,0 @@ -#ifdef VERTEX_SHADER - -layout(location = 0)in vec2 inUV; -out vec2 vUV; - -void main() -{ - gl_Position = vec4(inUV.xy*2.0 - 1.0,0.5,1.0); vUV = inUV; -} - -#endif - -#ifdef FRAGMENT_SHADER - -uniform float time; -#define PI 3.1415926 -layout(location = 0) out vec4 outPixDiffuse; -in vec2 vUV; - -void main() -{ - // base of shader by FabriceNeyret2 https://www.shadertoy.com/view/XlfBW7 - vec2 U = vUV*2.5-1.25; - U.x = asin( U.x / cos( U.y = asin(U.y) )) - time; - U = 6.* sin(8.*U); - outPixDiffuse = vec4(0.5,0.0,0.0,1.0); - outPixDiffuse.r = max(outPixDiffuse.r, outPixDiffuse.r+U.x/U.x); - outPixDiffuse.gb += U.x*U.y; -} - -#endif diff --git a/bin/Stock/PlayLoop.png b/bin/Stock/PlayLoop.png deleted file mode 100644 index 42082860..00000000 Binary files a/bin/Stock/PlayLoop.png and /dev/null differ diff --git a/bin/Stock/PlayNoLoop.png b/bin/Stock/PlayNoLoop.png deleted file mode 100644 index 3d4823ee..00000000 Binary files a/bin/Stock/PlayNoLoop.png and /dev/null differ diff --git a/bin/WebEdition/readme.txt b/bin/WebEdition/readme.txt deleted file mode 100644 index e393a00b..00000000 --- a/bin/WebEdition/readme.txt +++ /dev/null @@ -1 +0,0 @@ -Compile with buildWeb.bat then upload the content of this directory to your web server. \ No newline at end of file diff --git a/bin/buildWeb.bat b/bin/buildWeb.bat deleted file mode 100644 index 94cb93dd..00000000 --- a/bin/buildWeb.bat +++ /dev/null @@ -1 +0,0 @@ -em++ -I../ext -I../ext/GLSL_Pathtracer -I../src -I../ext/glm -I../ext/Nvidia-SBVH -I../ext/SOIL/include ../ext/imgui_stdlib.cpp ../ext/cmft/common/print.cpp ../ext/ImCurveEdit.cpp ../ext/ImGradient.cpp ../ext/ImSequencer.cpp ../ext/cmft/allocator.cpp ../ext/cmft/image.cpp ../src/Bitmap.cpp ../src/EvaluationContext.cpp ../src/EvaluationStages.cpp ../src/Evaluators.cpp ../src/Imogen.cpp ../src/Library.cpp ../src/NodeGraph.cpp ../src/NodeGraphControler.cpp ../src/UI.cpp ../src/Utils.cpp ../src/main.cpp ../ext/imgui_impl_sdl.cpp ../ext/imgui_impl_opengl3.cpp ../ext/imgui.cpp ../ext/imgui_widgets.cpp ../ext/imgui_draw.cpp -s USE_SDL=2 -s USE_WEBGL2=1 -s WASM=1 -s FULL_ES3=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN_TRAP_MODE=clamp --shell-file shell_minimal.html -o WebEdition/index.html -DEMSCRIPTEN -D_X86_ -O2 -g4 --source-map-base http://localhost:8080/ -std=c++14 --preload-file Nodes --preload-file Stock --preload-file library.dat --preload-file imgui.ini diff --git a/bin/imgui.ini b/bin/imgui.ini index 43d9be11..10e54005 100644 --- a/bin/imgui.ini +++ b/bin/imgui.ini @@ -1,154 +1,197 @@ -[Imogen][Imogen] -ShowTimeline=0 -ShowLibrary=1 -ShowNodes=1 -ShowLog=1 -ShowParameters=1 -ShowMouseState=0 -LibraryViewMode=1 -Layout=0xffff0fe0 -PlayPause=0xffffff3e -AnimationFirstFrame=0xffffff19 -AnimationNextFrame=0xffffff11 -AnimationPreviousFrame=0xffffff05 -MaterialExport=0xffff08e0 -MaterialImport=0xffff0ce0 -ToggleLibrary=0xffff1ee0 -ToggleNodeGraph=0xffff1fe0 -ToggleLogger=0xffff20e0 -ToggleSequencer=0xffff21e0 -ToggleParameters=0xffff22e0 -MaterialNew=0xffff11e0 -ReloadShaders=0xffffff40 -DeleteSelectedNodes=0xffffff4c -AnimationSetKey=0xffffff16 -HotKeyEditor=0xffff0ee0 -NewNodePopup=0xffffff2b -Undo=0xffff1de0 -Redo=0xff1de1e0 -Copy=0xffff06e0 -Cut=0xffff1be0 -Paste=0xffff19e0 -BuildMaterial=0xffff05e0 -MouseState=0xffff10e0 -[Window][Imogen] -Pos=0,32 -Size=1920,985 -Collapsed=0 - -[Window][Debug##Default] -Pos=60,60 -Size=400,400 -Collapsed=0 - -[Window][Nodes] -Pos=672,40 -Size=1240,659 -Collapsed=0 -DockId=0x00000005,0 - -[Window][Shaders] -Pos=1439,40 -Size=473,659 -Collapsed=0 -DockId=0x00000005,0 - -[Window][Library] -Pos=8,40 -Size=276,969 -Collapsed=0 -DockId=0x00000002,0 - -[Window][Parameters] -Pos=286,40 -Size=384,659 -Collapsed=0 -DockId=0x0000000B,0 - -[Window][Logs] -Pos=286,701 -Size=1626,308 -Collapsed=0 -DockId=0x00000001,0 - -[Window][Timeline] -Pos=346,701 -Size=1566,308 -Collapsed=0 -DockId=0x00000001,1 - -[Window][Pins] -Pos=292,694 -Size=367,32 -Collapsed=0 -DockId=0x00000008,0 - -[Window][toto] -Pos=60,60 -Size=605,774 -Collapsed=0 - -[Window][Blend_View_000] -Pos=1429,28 -Size=483,981 -Collapsed=0 -DockId=0x0000000A,0 - -[Window][Kaleidoscope_View_001] -Pos=1429,28 -Size=483,981 -Collapsed=0 -DockId=0x0000000A,1 - -[Window][Kaleidoscope_View_000] -Pos=60,60 -Size=256,256 -Collapsed=0 - -[Window][Tile_View_000] -Pos=1682,656 -Size=256,256 -Collapsed=0 - -[Window][TitleBar] -Pos=0,0 -Size=1920,32 -Collapsed=0 - -[Window][GLTFRead_View_000] -Pos=388,114 -Size=924,875 -Collapsed=0 - -[Window][Disolve_View_000] -Pos=667,223 -Size=967,680 -Collapsed=0 - -[Window][PBR2_View_000] -Pos=1439,40 -Size=473,659 -Collapsed=0 -DockId=0x00000005,1 - -[Window][Ramp_View_000] -Pos=286,596 -Size=384,413 -Collapsed=0 -DockId=0x0000000C,0 - -[Docking][Data] -DockSpace ID=0x42052FE6 Pos=8,40 Size=1904,969 Split=X - DockNode ID=0x00000009 Parent=0x42052FE6 SizeRef=1419,981 Split=X - DockNode ID=0x00000002 Parent=0x00000009 SizeRef=276,1001 SelectedTab=0x6E3DA120 - DockNode ID=0x00000003 Parent=0x00000009 SizeRef=1626,1001 Split=Y - DockNode ID=0x00000006 Parent=0x00000003 SizeRef=1904,659 Split=X - DockNode ID=0x00000004 Parent=0x00000006 SizeRef=384,1001 Split=Y SelectedTab=0x49CE4B2E - DockNode ID=0x00000007 Parent=0x00000004 SizeRef=338,661 Split=Y SelectedTab=0x49CE4B2E - DockNode ID=0x0000000B Parent=0x00000007 SizeRef=384,554 SelectedTab=0x49CE4B2E - DockNode ID=0x0000000C Parent=0x00000007 SizeRef=384,413 SelectedTab=0xC58199A5 - DockNode ID=0x00000008 Parent=0x00000004 SizeRef=338,32 SelectedTab=0x9F3D46BE - DockNode ID=0x00000005 Parent=0x00000006 SizeRef=1240,1001 CentralNode=1 SelectedTab=0xDCFC2AF8 - DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1904,308 SelectedTab=0x50BD6962 - DockNode ID=0x0000000A Parent=0x42052FE6 SizeRef=483,981 SelectedTab=0x7C4C220E - +[Imogen][Imogen] +ShowTimeline=1 +ShowLibrary=1 +ShowNodes=1 +ShowLog=1 +ShowParameters=1 +ShowMouseState=0 +LibraryViewMode=1 +Layout=0xffff0fe0 +PlayPause=0xffffff3e +AnimationFirstFrame=0xffffff19 +AnimationNextFrame=0xffffff11 +AnimationPreviousFrame=0xffffff05 +MaterialExport=0xffff08e0 +MaterialImport=0xffff0ce0 +ToggleLibrary=0xffff1ee0 +ToggleNodeGraph=0xffff1fe0 +ToggleLogger=0xffff20e0 +ToggleSequencer=0xffff21e0 +ToggleParameters=0xffff22e0 +MaterialNew=0xffff11e0 +DeleteSelectedNodes=0xffffff4c +AnimationSetKey=0xffffff16 +HotKeyEditor=0xffff0ee0 +NewNodePopup=0xffffff2b +Undo=0xffff1de0 +Redo=0xff1de1e0 +Copy=0xffff06e0 +Cut=0xffff1be0 +Paste=0xffff19e0 +BuildMaterial=0xffff05e0 +CloseLibrary=0xffff1ae0 +MouseState=0xffff10e0 +[Window][Imogen] +Pos=0,32 +Size=2048,1057 +Collapsed=0 + +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][Nodes] +Pos=944,40 +Size=814,785 +Collapsed=0 +DockId=0x00000010,0 + +[Window][Shaders] +Pos=1439,40 +Size=473,659 +Collapsed=0 +DockId=0x00000005,0 + +[Window][Library] +Pos=8,40 +Size=548,1041 +Collapsed=0 +DockId=0x00000015,0 + +[Window][Parameters] +Pos=558,40 +Size=384,785 +Collapsed=0 +DockId=0x0000000F,0 + +[Window][Logs] +Pos=558,827 +Size=1482,254 +Collapsed=0 +DockId=0x00000012,0 + +[Window][Timeline] +Pos=558,827 +Size=1482,254 +Collapsed=0 +DockId=0x00000012,1 + +[Window][Pins] +Pos=292,694 +Size=367,32 +Collapsed=0 +DockId=0x00000008,0 + +[Window][toto] +Pos=60,60 +Size=605,774 +Collapsed=0 + +[Window][Blend_View_000] +Pos=1429,28 +Size=483,981 +Collapsed=0 +DockId=0x0000000A,0 + +[Window][Kaleidoscope_View_001] +Pos=1429,28 +Size=483,981 +Collapsed=0 +DockId=0x0000000A,1 + +[Window][Kaleidoscope_View_000] +Pos=60,60 +Size=256,256 +Collapsed=0 + +[Window][Tile_View_000] +Pos=1656,40 +Size=384,785 +Collapsed=0 +DockId=0x0000000E,0 + +[Window][TitleBar] +Pos=0,0 +Size=2048,32 +Collapsed=0 + +[Window][GLTFRead_View_000] +Pos=388,114 +Size=924,875 +Collapsed=0 + +[Window][Disolve_View_000] +Pos=667,223 +Size=967,680 +Collapsed=0 + +[Window][PBR2_View_000] +Pos=1439,40 +Size=473,659 +Collapsed=0 +DockId=0x00000005,1 + +[Window][Ramp_View_000] +Pos=286,596 +Size=384,413 +Collapsed=0 +DockId=0x0000000C,0 + +[Window][Color_View_000] +Pos=60,60 +Size=256,256 +Collapsed=0 + +[Window][FurDisplay_View_001] +Pos=150,456 +Size=256,256 +Collapsed=0 + +[Window][Debug] +Pos=1760,40 +Size=280,785 +Collapsed=0 +DockId=0x00000006,0 + +[Window][SmoothStep_View_000] +Pos=123,40 +Size=257,247 +Collapsed=0 +DockId=0x0000000B,0 + +[Window][Tile_View_001] +Pos=123,40 +Size=257,247 +Collapsed=0 +DockId=0x0000000B,1 + +[Window][RecentLibrary] +Size=2048,1089 +Collapsed=0 + +[Docking][Data] +DockSpace ID=0x42052FE6 Pos=8,40 Size=2032,1041 Split=X + DockNode ID=0x00000015 Parent=0x42052FE6 SizeRef=548,969 SelectedTab=0x6E3DA120 + DockNode ID=0x00000016 Parent=0x42052FE6 SizeRef=1482,969 Split=X + DockNode ID=0x00000013 Parent=0x00000016 SizeRef=380,969 SelectedTab=0x6E3DA120 + DockNode ID=0x00000014 Parent=0x00000016 SizeRef=1522,969 Split=Y + DockNode ID=0x00000011 Parent=0x00000014 SizeRef=1904,785 Split=X + DockNode ID=0x0000000D Parent=0x00000011 SizeRef=1096,969 Split=X + DockNode ID=0x00000009 Parent=0x0000000D SizeRef=1419,981 Split=X + DockNode ID=0x00000002 Parent=0x00000009 SizeRef=250,1001 SelectedTab=0x6E3DA120 + DockNode ID=0x00000003 Parent=0x00000009 SizeRef=1363,1001 Split=X + DockNode ID=0x00000004 Parent=0x00000003 SizeRef=346,1001 Split=Y SelectedTab=0x49CE4B2E + DockNode ID=0x00000007 Parent=0x00000004 SizeRef=338,661 Split=Y SelectedTab=0x49CE4B2E + DockNode ID=0x0000000B Parent=0x00000007 SizeRef=384,554 SelectedTab=0x49CE4B2E + DockNode ID=0x0000000C Parent=0x00000007 SizeRef=384,413 SelectedTab=0xC58199A5 + DockNode ID=0x00000008 Parent=0x00000004 SizeRef=338,32 SelectedTab=0x9F3D46BE + DockNode ID=0x00000005 Parent=0x00000003 SizeRef=1134,1001 Split=X SelectedTab=0xDCFC2AF8 + DockNode ID=0x00000001 Parent=0x00000005 SizeRef=887,785 Split=X SelectedTab=0xDCFC2AF8 + DockNode ID=0x0000000F Parent=0x00000001 SizeRef=384,785 SelectedTab=0x49CE4B2E + DockNode ID=0x00000010 Parent=0x00000001 SizeRef=814,785 CentralNode=1 SelectedTab=0xDCFC2AF8 + DockNode ID=0x00000006 Parent=0x00000005 SizeRef=207,785 SelectedTab=0xAD6468A3 + DockNode ID=0x0000000A Parent=0x0000000D SizeRef=483,981 SelectedTab=0x7C4C220E + DockNode ID=0x0000000E Parent=0x00000011 SizeRef=384,969 SelectedTab=0x6361A5EA + DockNode ID=0x00000012 Parent=0x00000014 SizeRef=1904,254 SelectedTab=0xBF88A430 + diff --git a/bin/libtcc.dll b/bin/libtcc.dll deleted file mode 100644 index 0a5d8179..00000000 Binary files a/bin/libtcc.dll and /dev/null differ diff --git a/changelog.txt b/changelog.txt index 6f55ae7b..be8170de 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +------------------------------------------------------------------------------- +Imogen - 0.14 codename Eagle Marin + + ------------------------------------------------------------------------------- Imogen - 0.13 codename Chameleon Genet diff --git a/ext/CL/cl.h b/ext/CL/cl.h deleted file mode 100644 index 203c6597..00000000 --- a/ext/CL/cl.h +++ /dev/null @@ -1,1214 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008 - 2012 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - ******************************************************************************/ - -#ifndef __OPENCL_CL_H -#define __OPENCL_CL_H - -#ifdef __APPLE__ -#include -#else -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/******************************************************************************/ - -typedef struct _cl_platform_id * cl_platform_id; -typedef struct _cl_device_id * cl_device_id; -typedef struct _cl_context * cl_context; -typedef struct _cl_command_queue * cl_command_queue; -typedef struct _cl_mem * cl_mem; -typedef struct _cl_program * cl_program; -typedef struct _cl_kernel * cl_kernel; -typedef struct _cl_event * cl_event; -typedef struct _cl_sampler * cl_sampler; - -typedef cl_uint cl_bool; /* WARNING! Unlike cl_ types in cl_platform.h, cl_bool is not guaranteed to be the same size as the bool in kernels. */ -typedef cl_ulong cl_bitfield; -typedef cl_bitfield cl_device_type; -typedef cl_uint cl_platform_info; -typedef cl_uint cl_device_info; -typedef cl_bitfield cl_device_fp_config; -typedef cl_uint cl_device_mem_cache_type; -typedef cl_uint cl_device_local_mem_type; -typedef cl_bitfield cl_device_exec_capabilities; -typedef cl_bitfield cl_command_queue_properties; -typedef intptr_t cl_device_partition_property; -typedef cl_bitfield cl_device_affinity_domain; - -typedef intptr_t cl_context_properties; -typedef cl_uint cl_context_info; -typedef cl_uint cl_command_queue_info; -typedef cl_uint cl_channel_order; -typedef cl_uint cl_channel_type; -typedef cl_bitfield cl_mem_flags; -typedef cl_uint cl_mem_object_type; -typedef cl_uint cl_mem_info; -typedef cl_bitfield cl_mem_migration_flags; -typedef cl_uint cl_image_info; -typedef cl_uint cl_buffer_create_type; -typedef cl_uint cl_addressing_mode; -typedef cl_uint cl_filter_mode; -typedef cl_uint cl_sampler_info; -typedef cl_bitfield cl_map_flags; -typedef cl_uint cl_program_info; -typedef cl_uint cl_program_build_info; -typedef cl_uint cl_program_binary_type; -typedef cl_int cl_build_status; -typedef cl_uint cl_kernel_info; -typedef cl_uint cl_kernel_arg_info; -typedef cl_uint cl_kernel_arg_address_qualifier; -typedef cl_uint cl_kernel_arg_access_qualifier; -typedef cl_bitfield cl_kernel_arg_type_qualifier; -typedef cl_uint cl_kernel_work_group_info; -typedef cl_uint cl_event_info; -typedef cl_uint cl_command_type; -typedef cl_uint cl_profiling_info; - - -typedef struct _cl_image_format { - cl_channel_order image_channel_order; - cl_channel_type image_channel_data_type; -} cl_image_format; - -typedef struct _cl_image_desc { - cl_mem_object_type image_type; - size_t image_width; - size_t image_height; - size_t image_depth; - size_t image_array_size; - size_t image_row_pitch; - size_t image_slice_pitch; - cl_uint num_mip_levels; - cl_uint num_samples; - cl_mem buffer; -} cl_image_desc; - -typedef struct _cl_buffer_region { - size_t origin; - size_t size; -} cl_buffer_region; - - -/******************************************************************************/ - -/* Error Codes */ -#define CL_SUCCESS 0 -#define CL_DEVICE_NOT_FOUND -1 -#define CL_DEVICE_NOT_AVAILABLE -2 -#define CL_COMPILER_NOT_AVAILABLE -3 -#define CL_MEM_OBJECT_ALLOCATION_FAILURE -4 -#define CL_OUT_OF_RESOURCES -5 -#define CL_OUT_OF_HOST_MEMORY -6 -#define CL_PROFILING_INFO_NOT_AVAILABLE -7 -#define CL_MEM_COPY_OVERLAP -8 -#define CL_IMAGE_FORMAT_MISMATCH -9 -#define CL_IMAGE_FORMAT_NOT_SUPPORTED -10 -#define CL_BUILD_PROGRAM_FAILURE -11 -#define CL_MAP_FAILURE -12 -#define CL_MISALIGNED_SUB_BUFFER_OFFSET -13 -#define CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST -14 -#define CL_COMPILE_PROGRAM_FAILURE -15 -#define CL_LINKER_NOT_AVAILABLE -16 -#define CL_LINK_PROGRAM_FAILURE -17 -#define CL_DEVICE_PARTITION_FAILED -18 -#define CL_KERNEL_ARG_INFO_NOT_AVAILABLE -19 - -#define CL_INVALID_VALUE -30 -#define CL_INVALID_DEVICE_TYPE -31 -#define CL_INVALID_PLATFORM -32 -#define CL_INVALID_DEVICE -33 -#define CL_INVALID_CONTEXT -34 -#define CL_INVALID_QUEUE_PROPERTIES -35 -#define CL_INVALID_COMMAND_QUEUE -36 -#define CL_INVALID_HOST_PTR -37 -#define CL_INVALID_MEM_OBJECT -38 -#define CL_INVALID_IMAGE_FORMAT_DESCRIPTOR -39 -#define CL_INVALID_IMAGE_SIZE -40 -#define CL_INVALID_SAMPLER -41 -#define CL_INVALID_BINARY -42 -#define CL_INVALID_BUILD_OPTIONS -43 -#define CL_INVALID_PROGRAM -44 -#define CL_INVALID_PROGRAM_EXECUTABLE -45 -#define CL_INVALID_KERNEL_NAME -46 -#define CL_INVALID_KERNEL_DEFINITION -47 -#define CL_INVALID_KERNEL -48 -#define CL_INVALID_ARG_INDEX -49 -#define CL_INVALID_ARG_VALUE -50 -#define CL_INVALID_ARG_SIZE -51 -#define CL_INVALID_KERNEL_ARGS -52 -#define CL_INVALID_WORK_DIMENSION -53 -#define CL_INVALID_WORK_GROUP_SIZE -54 -#define CL_INVALID_WORK_ITEM_SIZE -55 -#define CL_INVALID_GLOBAL_OFFSET -56 -#define CL_INVALID_EVENT_WAIT_LIST -57 -#define CL_INVALID_EVENT -58 -#define CL_INVALID_OPERATION -59 -#define CL_INVALID_GL_OBJECT -60 -#define CL_INVALID_BUFFER_SIZE -61 -#define CL_INVALID_MIP_LEVEL -62 -#define CL_INVALID_GLOBAL_WORK_SIZE -63 -#define CL_INVALID_PROPERTY -64 -#define CL_INVALID_IMAGE_DESCRIPTOR -65 -#define CL_INVALID_COMPILER_OPTIONS -66 -#define CL_INVALID_LINKER_OPTIONS -67 -#define CL_INVALID_DEVICE_PARTITION_COUNT -68 - -/* OpenCL Version */ -#define CL_VERSION_1_0 1 -#define CL_VERSION_1_1 1 -#define CL_VERSION_1_2 1 - -/* cl_bool */ -#define CL_FALSE 0 -#define CL_TRUE 1 -#define CL_BLOCKING CL_TRUE -#define CL_NON_BLOCKING CL_FALSE - -/* cl_platform_info */ -#define CL_PLATFORM_PROFILE 0x0900 -#define CL_PLATFORM_VERSION 0x0901 -#define CL_PLATFORM_NAME 0x0902 -#define CL_PLATFORM_VENDOR 0x0903 -#define CL_PLATFORM_EXTENSIONS 0x0904 - -/* cl_device_type - bitfield */ -#define CL_DEVICE_TYPE_DEFAULT (1 << 0) -#define CL_DEVICE_TYPE_CPU (1 << 1) -#define CL_DEVICE_TYPE_GPU (1 << 2) -#define CL_DEVICE_TYPE_ACCELERATOR (1 << 3) -#define CL_DEVICE_TYPE_CUSTOM (1 << 4) -#define CL_DEVICE_TYPE_ALL 0xFFFFFFFF - -/* cl_device_info */ -#define CL_DEVICE_TYPE 0x1000 -#define CL_DEVICE_VENDOR_ID 0x1001 -#define CL_DEVICE_MAX_COMPUTE_UNITS 0x1002 -#define CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS 0x1003 -#define CL_DEVICE_MAX_WORK_GROUP_SIZE 0x1004 -#define CL_DEVICE_MAX_WORK_ITEM_SIZES 0x1005 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR 0x1006 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT 0x1007 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT 0x1008 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG 0x1009 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT 0x100A -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE 0x100B -#define CL_DEVICE_MAX_CLOCK_FREQUENCY 0x100C -#define CL_DEVICE_ADDRESS_BITS 0x100D -#define CL_DEVICE_MAX_READ_IMAGE_ARGS 0x100E -#define CL_DEVICE_MAX_WRITE_IMAGE_ARGS 0x100F -#define CL_DEVICE_MAX_MEM_ALLOC_SIZE 0x1010 -#define CL_DEVICE_IMAGE2D_MAX_WIDTH 0x1011 -#define CL_DEVICE_IMAGE2D_MAX_HEIGHT 0x1012 -#define CL_DEVICE_IMAGE3D_MAX_WIDTH 0x1013 -#define CL_DEVICE_IMAGE3D_MAX_HEIGHT 0x1014 -#define CL_DEVICE_IMAGE3D_MAX_DEPTH 0x1015 -#define CL_DEVICE_IMAGE_SUPPORT 0x1016 -#define CL_DEVICE_MAX_PARAMETER_SIZE 0x1017 -#define CL_DEVICE_MAX_SAMPLERS 0x1018 -#define CL_DEVICE_MEM_BASE_ADDR_ALIGN 0x1019 -#define CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE 0x101A -#define CL_DEVICE_SINGLE_FP_CONFIG 0x101B -#define CL_DEVICE_GLOBAL_MEM_CACHE_TYPE 0x101C -#define CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE 0x101D -#define CL_DEVICE_GLOBAL_MEM_CACHE_SIZE 0x101E -#define CL_DEVICE_GLOBAL_MEM_SIZE 0x101F -#define CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE 0x1020 -#define CL_DEVICE_MAX_CONSTANT_ARGS 0x1021 -#define CL_DEVICE_LOCAL_MEM_TYPE 0x1022 -#define CL_DEVICE_LOCAL_MEM_SIZE 0x1023 -#define CL_DEVICE_ERROR_CORRECTION_SUPPORT 0x1024 -#define CL_DEVICE_PROFILING_TIMER_RESOLUTION 0x1025 -#define CL_DEVICE_ENDIAN_LITTLE 0x1026 -#define CL_DEVICE_AVAILABLE 0x1027 -#define CL_DEVICE_COMPILER_AVAILABLE 0x1028 -#define CL_DEVICE_EXECUTION_CAPABILITIES 0x1029 -#define CL_DEVICE_QUEUE_PROPERTIES 0x102A -#define CL_DEVICE_NAME 0x102B -#define CL_DEVICE_VENDOR 0x102C -#define CL_DRIVER_VERSION 0x102D -#define CL_DEVICE_PROFILE 0x102E -#define CL_DEVICE_VERSION 0x102F -#define CL_DEVICE_EXTENSIONS 0x1030 -#define CL_DEVICE_PLATFORM 0x1031 -#define CL_DEVICE_DOUBLE_FP_CONFIG 0x1032 -/* 0x1033 reserved for CL_DEVICE_HALF_FP_CONFIG */ -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF 0x1034 -#define CL_DEVICE_HOST_UNIFIED_MEMORY 0x1035 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR 0x1036 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT 0x1037 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_INT 0x1038 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG 0x1039 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT 0x103A -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE 0x103B -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF 0x103C -#define CL_DEVICE_OPENCL_C_VERSION 0x103D -#define CL_DEVICE_LINKER_AVAILABLE 0x103E -#define CL_DEVICE_BUILT_IN_KERNELS 0x103F -#define CL_DEVICE_IMAGE_MAX_BUFFER_SIZE 0x1040 -#define CL_DEVICE_IMAGE_MAX_ARRAY_SIZE 0x1041 -#define CL_DEVICE_PARENT_DEVICE 0x1042 -#define CL_DEVICE_PARTITION_MAX_SUB_DEVICES 0x1043 -#define CL_DEVICE_PARTITION_PROPERTIES 0x1044 -#define CL_DEVICE_PARTITION_AFFINITY_DOMAIN 0x1045 -#define CL_DEVICE_PARTITION_TYPE 0x1046 -#define CL_DEVICE_REFERENCE_COUNT 0x1047 -#define CL_DEVICE_PREFERRED_INTEROP_USER_SYNC 0x1048 -#define CL_DEVICE_PRINTF_BUFFER_SIZE 0x1049 -#define CL_DEVICE_IMAGE_PITCH_ALIGNMENT 0x104A -#define CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT 0x104B - -/* cl_device_fp_config - bitfield */ -#define CL_FP_DENORM (1 << 0) -#define CL_FP_INF_NAN (1 << 1) -#define CL_FP_ROUND_TO_NEAREST (1 << 2) -#define CL_FP_ROUND_TO_ZERO (1 << 3) -#define CL_FP_ROUND_TO_INF (1 << 4) -#define CL_FP_FMA (1 << 5) -#define CL_FP_SOFT_FLOAT (1 << 6) -#define CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT (1 << 7) - -/* cl_device_mem_cache_type */ -#define CL_NONE 0x0 -#define CL_READ_ONLY_CACHE 0x1 -#define CL_READ_WRITE_CACHE 0x2 - -/* cl_device_local_mem_type */ -#define CL_LOCAL 0x1 -#define CL_GLOBAL 0x2 - -/* cl_device_exec_capabilities - bitfield */ -#define CL_EXEC_KERNEL (1 << 0) -#define CL_EXEC_NATIVE_KERNEL (1 << 1) - -/* cl_command_queue_properties - bitfield */ -#define CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE (1 << 0) -#define CL_QUEUE_PROFILING_ENABLE (1 << 1) - -/* cl_context_info */ -#define CL_CONTEXT_REFERENCE_COUNT 0x1080 -#define CL_CONTEXT_DEVICES 0x1081 -#define CL_CONTEXT_PROPERTIES 0x1082 -#define CL_CONTEXT_NUM_DEVICES 0x1083 - -/* cl_context_properties */ -#define CL_CONTEXT_PLATFORM 0x1084 -#define CL_CONTEXT_INTEROP_USER_SYNC 0x1085 - -/* cl_device_partition_property */ -#define CL_DEVICE_PARTITION_EQUALLY 0x1086 -#define CL_DEVICE_PARTITION_BY_COUNTS 0x1087 -#define CL_DEVICE_PARTITION_BY_COUNTS_LIST_END 0x0 -#define CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN 0x1088 - -/* cl_device_affinity_domain */ -#define CL_DEVICE_AFFINITY_DOMAIN_NUMA (1 << 0) -#define CL_DEVICE_AFFINITY_DOMAIN_L4_CACHE (1 << 1) -#define CL_DEVICE_AFFINITY_DOMAIN_L3_CACHE (1 << 2) -#define CL_DEVICE_AFFINITY_DOMAIN_L2_CACHE (1 << 3) -#define CL_DEVICE_AFFINITY_DOMAIN_L1_CACHE (1 << 4) -#define CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE (1 << 5) - -/* cl_command_queue_info */ -#define CL_QUEUE_CONTEXT 0x1090 -#define CL_QUEUE_DEVICE 0x1091 -#define CL_QUEUE_REFERENCE_COUNT 0x1092 -#define CL_QUEUE_PROPERTIES 0x1093 - -/* cl_mem_flags - bitfield */ -#define CL_MEM_READ_WRITE (1 << 0) -#define CL_MEM_WRITE_ONLY (1 << 1) -#define CL_MEM_READ_ONLY (1 << 2) -#define CL_MEM_USE_HOST_PTR (1 << 3) -#define CL_MEM_ALLOC_HOST_PTR (1 << 4) -#define CL_MEM_COPY_HOST_PTR (1 << 5) -// reserved (1 << 6) -#define CL_MEM_HOST_WRITE_ONLY (1 << 7) -#define CL_MEM_HOST_READ_ONLY (1 << 8) -#define CL_MEM_HOST_NO_ACCESS (1 << 9) - -/* cl_mem_migration_flags - bitfield */ -#define CL_MIGRATE_MEM_OBJECT_HOST (1 << 0) -#define CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED (1 << 1) - -/* cl_channel_order */ -#define CL_R 0x10B0 -#define CL_A 0x10B1 -#define CL_RG 0x10B2 -#define CL_RA 0x10B3 -#define CL_RGB 0x10B4 -#define CL_RGBA 0x10B5 -#define CL_BGRA 0x10B6 -#define CL_ARGB 0x10B7 -#define CL_INTENSITY 0x10B8 -#define CL_LUMINANCE 0x10B9 -#define CL_Rx 0x10BA -#define CL_RGx 0x10BB -#define CL_RGBx 0x10BC -#define CL_DEPTH 0x10BD -#define CL_DEPTH_STENCIL 0x10BE - -/* cl_channel_type */ -#define CL_SNORM_INT8 0x10D0 -#define CL_SNORM_INT16 0x10D1 -#define CL_UNORM_INT8 0x10D2 -#define CL_UNORM_INT16 0x10D3 -#define CL_UNORM_SHORT_565 0x10D4 -#define CL_UNORM_SHORT_555 0x10D5 -#define CL_UNORM_INT_101010 0x10D6 -#define CL_SIGNED_INT8 0x10D7 -#define CL_SIGNED_INT16 0x10D8 -#define CL_SIGNED_INT32 0x10D9 -#define CL_UNSIGNED_INT8 0x10DA -#define CL_UNSIGNED_INT16 0x10DB -#define CL_UNSIGNED_INT32 0x10DC -#define CL_HALF_FLOAT 0x10DD -#define CL_FLOAT 0x10DE -#define CL_UNORM_INT24 0x10DF - -/* cl_mem_object_type */ -#define CL_MEM_OBJECT_BUFFER 0x10F0 -#define CL_MEM_OBJECT_IMAGE2D 0x10F1 -#define CL_MEM_OBJECT_IMAGE3D 0x10F2 -#define CL_MEM_OBJECT_IMAGE2D_ARRAY 0x10F3 -#define CL_MEM_OBJECT_IMAGE1D 0x10F4 -#define CL_MEM_OBJECT_IMAGE1D_ARRAY 0x10F5 -#define CL_MEM_OBJECT_IMAGE1D_BUFFER 0x10F6 - -/* cl_mem_info */ -#define CL_MEM_TYPE 0x1100 -#define CL_MEM_FLAGS 0x1101 -#define CL_MEM_SIZE 0x1102 -#define CL_MEM_HOST_PTR 0x1103 -#define CL_MEM_MAP_COUNT 0x1104 -#define CL_MEM_REFERENCE_COUNT 0x1105 -#define CL_MEM_CONTEXT 0x1106 -#define CL_MEM_ASSOCIATED_MEMOBJECT 0x1107 -#define CL_MEM_OFFSET 0x1108 - -/* cl_image_info */ -#define CL_IMAGE_FORMAT 0x1110 -#define CL_IMAGE_ELEMENT_SIZE 0x1111 -#define CL_IMAGE_ROW_PITCH 0x1112 -#define CL_IMAGE_SLICE_PITCH 0x1113 -#define CL_IMAGE_WIDTH 0x1114 -#define CL_IMAGE_HEIGHT 0x1115 -#define CL_IMAGE_DEPTH 0x1116 -#define CL_IMAGE_ARRAY_SIZE 0x1117 -#define CL_IMAGE_BUFFER 0x1118 -#define CL_IMAGE_NUM_MIP_LEVELS 0x1119 -#define CL_IMAGE_NUM_SAMPLES 0x111A - -/* cl_addressing_mode */ -#define CL_ADDRESS_NONE 0x1130 -#define CL_ADDRESS_CLAMP_TO_EDGE 0x1131 -#define CL_ADDRESS_CLAMP 0x1132 -#define CL_ADDRESS_REPEAT 0x1133 -#define CL_ADDRESS_MIRRORED_REPEAT 0x1134 - -/* cl_filter_mode */ -#define CL_FILTER_NEAREST 0x1140 -#define CL_FILTER_LINEAR 0x1141 - -/* cl_sampler_info */ -#define CL_SAMPLER_REFERENCE_COUNT 0x1150 -#define CL_SAMPLER_CONTEXT 0x1151 -#define CL_SAMPLER_NORMALIZED_COORDS 0x1152 -#define CL_SAMPLER_ADDRESSING_MODE 0x1153 -#define CL_SAMPLER_FILTER_MODE 0x1154 - -/* cl_map_flags - bitfield */ -#define CL_MAP_READ (1 << 0) -#define CL_MAP_WRITE (1 << 1) -#define CL_MAP_WRITE_INVALIDATE_REGION (1 << 2) - -/* cl_program_info */ -#define CL_PROGRAM_REFERENCE_COUNT 0x1160 -#define CL_PROGRAM_CONTEXT 0x1161 -#define CL_PROGRAM_NUM_DEVICES 0x1162 -#define CL_PROGRAM_DEVICES 0x1163 -#define CL_PROGRAM_SOURCE 0x1164 -#define CL_PROGRAM_BINARY_SIZES 0x1165 -#define CL_PROGRAM_BINARIES 0x1166 -#define CL_PROGRAM_NUM_KERNELS 0x1167 -#define CL_PROGRAM_KERNEL_NAMES 0x1168 - -/* cl_program_build_info */ -#define CL_PROGRAM_BUILD_STATUS 0x1181 -#define CL_PROGRAM_BUILD_OPTIONS 0x1182 -#define CL_PROGRAM_BUILD_LOG 0x1183 -#define CL_PROGRAM_BINARY_TYPE 0x1184 - -/* cl_program_binary_type */ -#define CL_PROGRAM_BINARY_TYPE_NONE 0x0 -#define CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT 0x1 -#define CL_PROGRAM_BINARY_TYPE_LIBRARY 0x2 -#define CL_PROGRAM_BINARY_TYPE_EXECUTABLE 0x4 - -/* cl_build_status */ -#define CL_BUILD_SUCCESS 0 -#define CL_BUILD_NONE -1 -#define CL_BUILD_ERROR -2 -#define CL_BUILD_IN_PROGRESS -3 - -/* cl_kernel_info */ -#define CL_KERNEL_FUNCTION_NAME 0x1190 -#define CL_KERNEL_NUM_ARGS 0x1191 -#define CL_KERNEL_REFERENCE_COUNT 0x1192 -#define CL_KERNEL_CONTEXT 0x1193 -#define CL_KERNEL_PROGRAM 0x1194 -#define CL_KERNEL_ATTRIBUTES 0x1195 - -/* cl_kernel_arg_info */ -#define CL_KERNEL_ARG_ADDRESS_QUALIFIER 0x1196 -#define CL_KERNEL_ARG_ACCESS_QUALIFIER 0x1197 -#define CL_KERNEL_ARG_TYPE_NAME 0x1198 -#define CL_KERNEL_ARG_TYPE_QUALIFIER 0x1199 -#define CL_KERNEL_ARG_NAME 0x119A - -/* cl_kernel_arg_address_qualifier */ -#define CL_KERNEL_ARG_ADDRESS_GLOBAL 0x119B -#define CL_KERNEL_ARG_ADDRESS_LOCAL 0x119C -#define CL_KERNEL_ARG_ADDRESS_CONSTANT 0x119D -#define CL_KERNEL_ARG_ADDRESS_PRIVATE 0x119E - -/* cl_kernel_arg_access_qualifier */ -#define CL_KERNEL_ARG_ACCESS_READ_ONLY 0x11A0 -#define CL_KERNEL_ARG_ACCESS_WRITE_ONLY 0x11A1 -#define CL_KERNEL_ARG_ACCESS_READ_WRITE 0x11A2 -#define CL_KERNEL_ARG_ACCESS_NONE 0x11A3 - -/* cl_kernel_arg_type_qualifer */ -#define CL_KERNEL_ARG_TYPE_NONE 0 -#define CL_KERNEL_ARG_TYPE_CONST (1 << 0) -#define CL_KERNEL_ARG_TYPE_RESTRICT (1 << 1) -#define CL_KERNEL_ARG_TYPE_VOLATILE (1 << 2) - -/* cl_kernel_work_group_info */ -#define CL_KERNEL_WORK_GROUP_SIZE 0x11B0 -#define CL_KERNEL_COMPILE_WORK_GROUP_SIZE 0x11B1 -#define CL_KERNEL_LOCAL_MEM_SIZE 0x11B2 -#define CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE 0x11B3 -#define CL_KERNEL_PRIVATE_MEM_SIZE 0x11B4 -#define CL_KERNEL_GLOBAL_WORK_SIZE 0x11B5 - -/* cl_event_info */ -#define CL_EVENT_COMMAND_QUEUE 0x11D0 -#define CL_EVENT_COMMAND_TYPE 0x11D1 -#define CL_EVENT_REFERENCE_COUNT 0x11D2 -#define CL_EVENT_COMMAND_EXECUTION_STATUS 0x11D3 -#define CL_EVENT_CONTEXT 0x11D4 - -/* cl_command_type */ -#define CL_COMMAND_NDRANGE_KERNEL 0x11F0 -#define CL_COMMAND_TASK 0x11F1 -#define CL_COMMAND_NATIVE_KERNEL 0x11F2 -#define CL_COMMAND_READ_BUFFER 0x11F3 -#define CL_COMMAND_WRITE_BUFFER 0x11F4 -#define CL_COMMAND_COPY_BUFFER 0x11F5 -#define CL_COMMAND_READ_IMAGE 0x11F6 -#define CL_COMMAND_WRITE_IMAGE 0x11F7 -#define CL_COMMAND_COPY_IMAGE 0x11F8 -#define CL_COMMAND_COPY_IMAGE_TO_BUFFER 0x11F9 -#define CL_COMMAND_COPY_BUFFER_TO_IMAGE 0x11FA -#define CL_COMMAND_MAP_BUFFER 0x11FB -#define CL_COMMAND_MAP_IMAGE 0x11FC -#define CL_COMMAND_UNMAP_MEM_OBJECT 0x11FD -#define CL_COMMAND_MARKER 0x11FE -#define CL_COMMAND_ACQUIRE_GL_OBJECTS 0x11FF -#define CL_COMMAND_RELEASE_GL_OBJECTS 0x1200 -#define CL_COMMAND_READ_BUFFER_RECT 0x1201 -#define CL_COMMAND_WRITE_BUFFER_RECT 0x1202 -#define CL_COMMAND_COPY_BUFFER_RECT 0x1203 -#define CL_COMMAND_USER 0x1204 -#define CL_COMMAND_BARRIER 0x1205 -#define CL_COMMAND_MIGRATE_MEM_OBJECTS 0x1206 -#define CL_COMMAND_FILL_BUFFER 0x1207 -#define CL_COMMAND_FILL_IMAGE 0x1208 - -/* command execution status */ -#define CL_COMPLETE 0x0 -#define CL_RUNNING 0x1 -#define CL_SUBMITTED 0x2 -#define CL_QUEUED 0x3 - -/* cl_buffer_create_type */ -#define CL_BUFFER_CREATE_TYPE_REGION 0x1220 - -/* cl_profiling_info */ -#define CL_PROFILING_COMMAND_QUEUED 0x1280 -#define CL_PROFILING_COMMAND_SUBMIT 0x1281 -#define CL_PROFILING_COMMAND_START 0x1282 -#define CL_PROFILING_COMMAND_END 0x1283 - -/********************************************************************************************************/ - -/* Platform API */ -extern CL_API_ENTRY cl_int CL_API_CALL -clGetPlatformIDs(cl_uint /* num_entries */, - cl_platform_id * /* platforms */, - cl_uint * /* num_platforms */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetPlatformInfo(cl_platform_id /* platform */, - cl_platform_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -/* Device APIs */ -extern CL_API_ENTRY cl_int CL_API_CALL -clGetDeviceIDs(cl_platform_id /* platform */, - cl_device_type /* device_type */, - cl_uint /* num_entries */, - cl_device_id * /* devices */, - cl_uint * /* num_devices */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetDeviceInfo(cl_device_id /* device */, - cl_device_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clCreateSubDevices(cl_device_id /* in_device */, - const cl_device_partition_property * /* properties */, - cl_uint /* num_devices */, - cl_device_id * /* out_devices */, - cl_uint * /* num_devices_ret */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_int CL_API_CALL -clRetainDevice(cl_device_id /* device */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_int CL_API_CALL -clReleaseDevice(cl_device_id /* device */) CL_API_SUFFIX__VERSION_1_2; - -/* Context APIs */ -extern CL_API_ENTRY cl_context CL_API_CALL -clCreateContext(const cl_context_properties * /* properties */, - cl_uint /* num_devices */, - const cl_device_id * /* devices */, - void (CL_CALLBACK * /* pfn_notify */)(const char *, const void *, size_t, void *), - void * /* user_data */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_context CL_API_CALL -clCreateContextFromType(const cl_context_properties * /* properties */, - cl_device_type /* device_type */, - void (CL_CALLBACK * /* pfn_notify*/ )(const char *, const void *, size_t, void *), - void * /* user_data */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clRetainContext(cl_context /* context */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clReleaseContext(cl_context /* context */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetContextInfo(cl_context /* context */, - cl_context_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -/* Command Queue APIs */ -extern CL_API_ENTRY cl_command_queue CL_API_CALL -clCreateCommandQueue(cl_context /* context */, - cl_device_id /* device */, - cl_command_queue_properties /* properties */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clRetainCommandQueue(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clReleaseCommandQueue(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetCommandQueueInfo(cl_command_queue /* command_queue */, - cl_command_queue_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -/* Memory Object APIs */ -extern CL_API_ENTRY cl_mem CL_API_CALL -clCreateBuffer(cl_context /* context */, - cl_mem_flags /* flags */, - size_t /* size */, - void * /* host_ptr */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_mem CL_API_CALL -clCreateSubBuffer(cl_mem /* buffer */, - cl_mem_flags /* flags */, - cl_buffer_create_type /* buffer_create_type */, - const void * /* buffer_create_info */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_1; - -extern CL_API_ENTRY cl_mem CL_API_CALL -clCreateImage(cl_context /* context */, - cl_mem_flags /* flags */, - const cl_image_format * /* image_format */, - const cl_image_desc * /* image_desc */, - void * /* host_ptr */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_int CL_API_CALL -clRetainMemObject(cl_mem /* memobj */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clReleaseMemObject(cl_mem /* memobj */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetSupportedImageFormats(cl_context /* context */, - cl_mem_flags /* flags */, - cl_mem_object_type /* image_type */, - cl_uint /* num_entries */, - cl_image_format * /* image_formats */, - cl_uint * /* num_image_formats */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetMemObjectInfo(cl_mem /* memobj */, - cl_mem_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetImageInfo(cl_mem /* image */, - cl_image_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clSetMemObjectDestructorCallback( cl_mem /* memobj */, - void (CL_CALLBACK * /*pfn_notify*/)( cl_mem /* memobj */, void* /*user_data*/), - void * /*user_data */ ) CL_API_SUFFIX__VERSION_1_1; - -/* Sampler APIs */ -extern CL_API_ENTRY cl_sampler CL_API_CALL -clCreateSampler(cl_context /* context */, - cl_bool /* normalized_coords */, - cl_addressing_mode /* addressing_mode */, - cl_filter_mode /* filter_mode */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clRetainSampler(cl_sampler /* sampler */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clReleaseSampler(cl_sampler /* sampler */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetSamplerInfo(cl_sampler /* sampler */, - cl_sampler_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -/* Program Object APIs */ -extern CL_API_ENTRY cl_program CL_API_CALL -clCreateProgramWithSource(cl_context /* context */, - cl_uint /* count */, - const char ** /* strings */, - const size_t * /* lengths */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_program CL_API_CALL -clCreateProgramWithBinary(cl_context /* context */, - cl_uint /* num_devices */, - const cl_device_id * /* device_list */, - const size_t * /* lengths */, - const unsigned char ** /* binaries */, - cl_int * /* binary_status */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_program CL_API_CALL -clCreateProgramWithBuiltInKernels(cl_context /* context */, - cl_uint /* num_devices */, - const cl_device_id * /* device_list */, - const char * /* kernel_names */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_int CL_API_CALL -clRetainProgram(cl_program /* program */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clReleaseProgram(cl_program /* program */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clBuildProgram(cl_program /* program */, - cl_uint /* num_devices */, - const cl_device_id * /* device_list */, - const char * /* options */, - void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */), - void * /* user_data */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clCompileProgram(cl_program /* program */, - cl_uint /* num_devices */, - const cl_device_id * /* device_list */, - const char * /* options */, - cl_uint /* num_input_headers */, - const cl_program * /* input_headers */, - const char ** /* header_include_names */, - void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */), - void * /* user_data */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_program CL_API_CALL -clLinkProgram(cl_context /* context */, - cl_uint /* num_devices */, - const cl_device_id * /* device_list */, - const char * /* options */, - cl_uint /* num_input_programs */, - const cl_program * /* input_programs */, - void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */), - void * /* user_data */, - cl_int * /* errcode_ret */ ) CL_API_SUFFIX__VERSION_1_2; - - -extern CL_API_ENTRY cl_int CL_API_CALL -clUnloadPlatformCompiler(cl_platform_id /* platform */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetProgramInfo(cl_program /* program */, - cl_program_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetProgramBuildInfo(cl_program /* program */, - cl_device_id /* device */, - cl_program_build_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -/* Kernel Object APIs */ -extern CL_API_ENTRY cl_kernel CL_API_CALL -clCreateKernel(cl_program /* program */, - const char * /* kernel_name */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clCreateKernelsInProgram(cl_program /* program */, - cl_uint /* num_kernels */, - cl_kernel * /* kernels */, - cl_uint * /* num_kernels_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clRetainKernel(cl_kernel /* kernel */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clReleaseKernel(cl_kernel /* kernel */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clSetKernelArg(cl_kernel /* kernel */, - cl_uint /* arg_index */, - size_t /* arg_size */, - const void * /* arg_value */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetKernelInfo(cl_kernel /* kernel */, - cl_kernel_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetKernelArgInfo(cl_kernel /* kernel */, - cl_uint /* arg_indx */, - cl_kernel_arg_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetKernelWorkGroupInfo(cl_kernel /* kernel */, - cl_device_id /* device */, - cl_kernel_work_group_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -/* Event Object APIs */ -extern CL_API_ENTRY cl_int CL_API_CALL -clWaitForEvents(cl_uint /* num_events */, - const cl_event * /* event_list */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetEventInfo(cl_event /* event */, - cl_event_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_event CL_API_CALL -clCreateUserEvent(cl_context /* context */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_1; - -extern CL_API_ENTRY cl_int CL_API_CALL -clRetainEvent(cl_event /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clReleaseEvent(cl_event /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clSetUserEventStatus(cl_event /* event */, - cl_int /* execution_status */) CL_API_SUFFIX__VERSION_1_1; - -extern CL_API_ENTRY cl_int CL_API_CALL -clSetEventCallback( cl_event /* event */, - cl_int /* command_exec_callback_type */, - void (CL_CALLBACK * /* pfn_notify */)(cl_event, cl_int, void *), - void * /* user_data */) CL_API_SUFFIX__VERSION_1_1; - -/* Profiling APIs */ -extern CL_API_ENTRY cl_int CL_API_CALL -clGetEventProfilingInfo(cl_event /* event */, - cl_profiling_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -/* Flush and Finish APIs */ -extern CL_API_ENTRY cl_int CL_API_CALL -clFlush(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clFinish(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; - -/* Enqueued Commands APIs */ -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueReadBuffer(cl_command_queue /* command_queue */, - cl_mem /* buffer */, - cl_bool /* blocking_read */, - size_t /* offset */, - size_t /* size */, - void * /* ptr */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueReadBufferRect(cl_command_queue /* command_queue */, - cl_mem /* buffer */, - cl_bool /* blocking_read */, - const size_t * /* buffer_offset */, - const size_t * /* host_offset */, - const size_t * /* region */, - size_t /* buffer_row_pitch */, - size_t /* buffer_slice_pitch */, - size_t /* host_row_pitch */, - size_t /* host_slice_pitch */, - void * /* ptr */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_1; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueWriteBuffer(cl_command_queue /* command_queue */, - cl_mem /* buffer */, - cl_bool /* blocking_write */, - size_t /* offset */, - size_t /* size */, - const void * /* ptr */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueWriteBufferRect(cl_command_queue /* command_queue */, - cl_mem /* buffer */, - cl_bool /* blocking_write */, - const size_t * /* buffer_offset */, - const size_t * /* host_offset */, - const size_t * /* region */, - size_t /* buffer_row_pitch */, - size_t /* buffer_slice_pitch */, - size_t /* host_row_pitch */, - size_t /* host_slice_pitch */, - const void * /* ptr */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_1; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueFillBuffer(cl_command_queue /* command_queue */, - cl_mem /* buffer */, - const void * /* pattern */, - size_t /* pattern_size */, - size_t /* offset */, - size_t /* size */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueCopyBuffer(cl_command_queue /* command_queue */, - cl_mem /* src_buffer */, - cl_mem /* dst_buffer */, - size_t /* src_offset */, - size_t /* dst_offset */, - size_t /* size */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueCopyBufferRect(cl_command_queue /* command_queue */, - cl_mem /* src_buffer */, - cl_mem /* dst_buffer */, - const size_t * /* src_origin */, - const size_t * /* dst_origin */, - const size_t * /* region */, - size_t /* src_row_pitch */, - size_t /* src_slice_pitch */, - size_t /* dst_row_pitch */, - size_t /* dst_slice_pitch */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_1; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueReadImage(cl_command_queue /* command_queue */, - cl_mem /* image */, - cl_bool /* blocking_read */, - const size_t * /* origin[3] */, - const size_t * /* region[3] */, - size_t /* row_pitch */, - size_t /* slice_pitch */, - void * /* ptr */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueWriteImage(cl_command_queue /* command_queue */, - cl_mem /* image */, - cl_bool /* blocking_write */, - const size_t * /* origin[3] */, - const size_t * /* region[3] */, - size_t /* input_row_pitch */, - size_t /* input_slice_pitch */, - const void * /* ptr */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueFillImage(cl_command_queue /* command_queue */, - cl_mem /* image */, - const void * /* fill_color */, - const size_t * /* origin[3] */, - const size_t * /* region[3] */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueCopyImage(cl_command_queue /* command_queue */, - cl_mem /* src_image */, - cl_mem /* dst_image */, - const size_t * /* src_origin[3] */, - const size_t * /* dst_origin[3] */, - const size_t * /* region[3] */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueCopyImageToBuffer(cl_command_queue /* command_queue */, - cl_mem /* src_image */, - cl_mem /* dst_buffer */, - const size_t * /* src_origin[3] */, - const size_t * /* region[3] */, - size_t /* dst_offset */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueCopyBufferToImage(cl_command_queue /* command_queue */, - cl_mem /* src_buffer */, - cl_mem /* dst_image */, - size_t /* src_offset */, - const size_t * /* dst_origin[3] */, - const size_t * /* region[3] */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY void * CL_API_CALL -clEnqueueMapBuffer(cl_command_queue /* command_queue */, - cl_mem /* buffer */, - cl_bool /* blocking_map */, - cl_map_flags /* map_flags */, - size_t /* offset */, - size_t /* size */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY void * CL_API_CALL -clEnqueueMapImage(cl_command_queue /* command_queue */, - cl_mem /* image */, - cl_bool /* blocking_map */, - cl_map_flags /* map_flags */, - const size_t * /* origin[3] */, - const size_t * /* region[3] */, - size_t * /* image_row_pitch */, - size_t * /* image_slice_pitch */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueUnmapMemObject(cl_command_queue /* command_queue */, - cl_mem /* memobj */, - void * /* mapped_ptr */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueMigrateMemObjects(cl_command_queue /* command_queue */, - cl_uint /* num_mem_objects */, - const cl_mem * /* mem_objects */, - cl_mem_migration_flags /* flags */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueNDRangeKernel(cl_command_queue /* command_queue */, - cl_kernel /* kernel */, - cl_uint /* work_dim */, - const size_t * /* global_work_offset */, - const size_t * /* global_work_size */, - const size_t * /* local_work_size */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueTask(cl_command_queue /* command_queue */, - cl_kernel /* kernel */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueNativeKernel(cl_command_queue /* command_queue */, - void (CL_CALLBACK * /*user_func*/)(void *), - void * /* args */, - size_t /* cb_args */, - cl_uint /* num_mem_objects */, - const cl_mem * /* mem_list */, - const void ** /* args_mem_loc */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueMarkerWithWaitList(cl_command_queue /* command_queue */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueBarrierWithWaitList(cl_command_queue /* command_queue */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_2; - - -/* Extension function access - * - * Returns the extension function address for the given function name, - * or NULL if a valid function can not be found. The client must - * check to make sure the address is not NULL, before using or - * calling the returned function address. - */ -extern CL_API_ENTRY void * CL_API_CALL -clGetExtensionFunctionAddressForPlatform(cl_platform_id /* platform */, - const char * /* func_name */) CL_API_SUFFIX__VERSION_1_2; - - -// Deprecated OpenCL 1.1 APIs -extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL -clCreateImage2D(cl_context /* context */, - cl_mem_flags /* flags */, - const cl_image_format * /* image_format */, - size_t /* image_width */, - size_t /* image_height */, - size_t /* image_row_pitch */, - void * /* host_ptr */, - cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; - -extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL -clCreateImage3D(cl_context /* context */, - cl_mem_flags /* flags */, - const cl_image_format * /* image_format */, - size_t /* image_width */, - size_t /* image_height */, - size_t /* image_depth */, - size_t /* image_row_pitch */, - size_t /* image_slice_pitch */, - void * /* host_ptr */, - cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; - -extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL -clEnqueueMarker(cl_command_queue /* command_queue */, - cl_event * /* event */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; - -extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL -clEnqueueWaitForEvents(cl_command_queue /* command_queue */, - cl_uint /* num_events */, - const cl_event * /* event_list */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; - -extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL -clEnqueueBarrier(cl_command_queue /* command_queue */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; - -extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL -clUnloadCompiler(void) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; - -extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED void * CL_API_CALL -clGetExtensionFunctionAddress(const char * /* func_name */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; - -#ifdef __cplusplus -} -#endif - -#endif /* __OPENCL_CL_H */ - diff --git a/ext/CL/cl_d3d10.h b/ext/CL/cl_d3d10.h deleted file mode 100644 index 81b0d372..00000000 --- a/ext/CL/cl_d3d10.h +++ /dev/null @@ -1,126 +0,0 @@ -/********************************************************************************** - * Copyright (c) 2008-2012 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - **********************************************************************************/ - -/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */ - -#ifndef __OPENCL_CL_D3D10_H -#define __OPENCL_CL_D3D10_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/****************************************************************************** - * cl_khr_d3d10_sharing */ -#define cl_khr_d3d10_sharing 1 - -typedef cl_uint cl_d3d10_device_source_khr; -typedef cl_uint cl_d3d10_device_set_khr; - -/******************************************************************************/ - -// Error Codes -#define CL_INVALID_D3D10_DEVICE_KHR -1002 -#define CL_INVALID_D3D10_RESOURCE_KHR -1003 -#define CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR -1004 -#define CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR -1005 - -// cl_d3d10_device_source_nv -#define CL_D3D10_DEVICE_KHR 0x4010 -#define CL_D3D10_DXGI_ADAPTER_KHR 0x4011 - -// cl_d3d10_device_set_nv -#define CL_PREFERRED_DEVICES_FOR_D3D10_KHR 0x4012 -#define CL_ALL_DEVICES_FOR_D3D10_KHR 0x4013 - -// cl_context_info -#define CL_CONTEXT_D3D10_DEVICE_KHR 0x4014 -#define CL_CONTEXT_D3D10_PREFER_SHARED_RESOURCES_KHR 0x402C - -// cl_mem_info -#define CL_MEM_D3D10_RESOURCE_KHR 0x4015 - -// cl_image_info -#define CL_IMAGE_D3D10_SUBRESOURCE_KHR 0x4016 - -// cl_command_type -#define CL_COMMAND_ACQUIRE_D3D10_OBJECTS_KHR 0x4017 -#define CL_COMMAND_RELEASE_D3D10_OBJECTS_KHR 0x4018 - -/******************************************************************************/ - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clGetDeviceIDsFromD3D10KHR_fn)( - cl_platform_id platform, - cl_d3d10_device_source_khr d3d_device_source, - void * d3d_object, - cl_d3d10_device_set_khr d3d_device_set, - cl_uint num_entries, - cl_device_id * devices, - cl_uint * num_devices) CL_API_SUFFIX__VERSION_1_0; - -typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D10BufferKHR_fn)( - cl_context context, - cl_mem_flags flags, - ID3D10Buffer * resource, - cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; - -typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D10Texture2DKHR_fn)( - cl_context context, - cl_mem_flags flags, - ID3D10Texture2D * resource, - UINT subresource, - cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; - -typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D10Texture3DKHR_fn)( - cl_context context, - cl_mem_flags flags, - ID3D10Texture3D * resource, - UINT subresource, - cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueAcquireD3D10ObjectsKHR_fn)( - cl_command_queue command_queue, - cl_uint num_objects, - const cl_mem * mem_objects, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event) CL_API_SUFFIX__VERSION_1_0; - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueReleaseD3D10ObjectsKHR_fn)( - cl_command_queue command_queue, - cl_uint num_objects, - const cl_mem * mem_objects, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event) CL_API_SUFFIX__VERSION_1_0; - -#ifdef __cplusplus -} -#endif - -#endif // __OPENCL_CL_D3D10_H - diff --git a/ext/CL/cl_d3d11.h b/ext/CL/cl_d3d11.h deleted file mode 100644 index d3c8bdc2..00000000 --- a/ext/CL/cl_d3d11.h +++ /dev/null @@ -1,126 +0,0 @@ -/********************************************************************************** - * Copyright (c) 2008-2012 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - **********************************************************************************/ - -/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */ - -#ifndef __OPENCL_CL_D3D11_H -#define __OPENCL_CL_D3D11_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/****************************************************************************** - * cl_khr_d3d11_sharing */ -#define cl_khr_d3d11_sharing 1 - -typedef cl_uint cl_d3d11_device_source_khr; -typedef cl_uint cl_d3d11_device_set_khr; - -/******************************************************************************/ - -// Error Codes -#define CL_INVALID_D3D11_DEVICE_KHR -1006 -#define CL_INVALID_D3D11_RESOURCE_KHR -1007 -#define CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR -1008 -#define CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR -1009 - -// cl_d3d11_device_source -#define CL_D3D11_DEVICE_KHR 0x4019 -#define CL_D3D11_DXGI_ADAPTER_KHR 0x401A - -// cl_d3d11_device_set -#define CL_PREFERRED_DEVICES_FOR_D3D11_KHR 0x401B -#define CL_ALL_DEVICES_FOR_D3D11_KHR 0x401C - -// cl_context_info -#define CL_CONTEXT_D3D11_DEVICE_KHR 0x401D -#define CL_CONTEXT_D3D11_PREFER_SHARED_RESOURCES_KHR 0x402D - -// cl_mem_info -#define CL_MEM_D3D11_RESOURCE_KHR 0x401E - -// cl_image_info -#define CL_IMAGE_D3D11_SUBRESOURCE_KHR 0x401F - -// cl_command_type -#define CL_COMMAND_ACQUIRE_D3D11_OBJECTS_KHR 0x4020 -#define CL_COMMAND_RELEASE_D3D11_OBJECTS_KHR 0x4021 - -/******************************************************************************/ - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clGetDeviceIDsFromD3D11KHR_fn)( - cl_platform_id platform, - cl_d3d11_device_source_khr d3d_device_source, - void * d3d_object, - cl_d3d11_device_set_khr d3d_device_set, - cl_uint num_entries, - cl_device_id * devices, - cl_uint * num_devices) CL_API_SUFFIX__VERSION_1_2; - -typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D11BufferKHR_fn)( - cl_context context, - cl_mem_flags flags, - ID3D11Buffer * resource, - cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; - -typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D11Texture2DKHR_fn)( - cl_context context, - cl_mem_flags flags, - ID3D11Texture2D * resource, - UINT subresource, - cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; - -typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D11Texture3DKHR_fn)( - cl_context context, - cl_mem_flags flags, - ID3D11Texture3D * resource, - UINT subresource, - cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueAcquireD3D11ObjectsKHR_fn)( - cl_command_queue command_queue, - cl_uint num_objects, - const cl_mem * mem_objects, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event) CL_API_SUFFIX__VERSION_1_2; - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueReleaseD3D11ObjectsKHR_fn)( - cl_command_queue command_queue, - cl_uint num_objects, - const cl_mem * mem_objects, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event) CL_API_SUFFIX__VERSION_1_2; - -#ifdef __cplusplus -} -#endif - -#endif // __OPENCL_CL_D3D11_H - diff --git a/ext/CL/cl_dx9_media_sharing.h b/ext/CL/cl_dx9_media_sharing.h deleted file mode 100644 index 1ef543a5..00000000 --- a/ext/CL/cl_dx9_media_sharing.h +++ /dev/null @@ -1,127 +0,0 @@ -/********************************************************************************** - * Copyright (c) 2008-2012 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - **********************************************************************************/ - -/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */ - -#ifndef __OPENCL_CL_DX9_MEDIA_SHARING_H -#define __OPENCL_CL_DX9_MEDIA_SHARING_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/****************************************************************************** -/* cl_khr_dx9_media_sharing */ -#define cl_khr_dx9_media_sharing 1 - -typedef cl_uint cl_dx9_media_adapter_type_khr; -typedef cl_uint cl_dx9_media_adapter_set_khr; - -#if defined(_WIN32) -#include -typedef struct _cl_dx9_surface_info_khr -{ - IDirect3DSurface9 *resource; - HANDLE shared_handle; -} cl_dx9_surface_info_khr; -#endif - - -/******************************************************************************/ - -// Error Codes -#define CL_INVALID_DX9_MEDIA_ADAPTER_KHR -1010 -#define CL_INVALID_DX9_MEDIA_SURFACE_KHR -1011 -#define CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR -1012 -#define CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR -1013 - -// cl_media_adapter_type_khr -#define CL_ADAPTER_D3D9_KHR 0x2020 -#define CL_ADAPTER_D3D9EX_KHR 0x2021 -#define CL_ADAPTER_DXVA_KHR 0x2022 - -// cl_media_adapter_set_khr -#define CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR 0x2023 -#define CL_ALL_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR 0x2024 - -// cl_context_info -#define CL_CONTEXT_ADAPTER_D3D9_KHR 0x2025 -#define CL_CONTEXT_ADAPTER_D3D9EX_KHR 0x2026 -#define CL_CONTEXT_ADAPTER_DXVA_KHR 0x2027 - -// cl_mem_info -#define CL_MEM_DX9_MEDIA_ADAPTER_TYPE_KHR 0x2028 -#define CL_MEM_DX9_MEDIA_SURFACE_INFO_KHR 0x2029 - -// cl_image_info -#define CL_IMAGE_DX9_MEDIA_PLANE_KHR 0x202A - -// cl_command_type -#define CL_COMMAND_ACQUIRE_DX9_MEDIA_SURFACES_KHR 0x202B -#define CL_COMMAND_RELEASE_DX9_MEDIA_SURFACES_KHR 0x202C - -/******************************************************************************/ - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clGetDeviceIDsFromDX9MediaAdapterKHR_fn)( - cl_platform_id platform, - cl_uint num_media_adapters, - cl_dx9_media_adapter_type_khr * media_adapter_type, - void * media_adapters, - cl_dx9_media_adapter_set_khr media_adapter_set, - cl_uint num_entries, - cl_device_id * devices, - cl_uint * num_devices) CL_API_SUFFIX__VERSION_1_2; - -typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromDX9MediaSurfaceKHR_fn)( - cl_context context, - cl_mem_flags flags, - cl_dx9_media_adapter_type_khr adapter_type, - void * surface_info, - cl_uint plane, - cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueAcquireDX9MediaSurfacesKHR_fn)( - cl_command_queue command_queue, - cl_uint num_objects, - const cl_mem * mem_objects, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event) CL_API_SUFFIX__VERSION_1_2; - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueReleaseDX9MediaSurfacesKHR_fn)( - cl_command_queue command_queue, - cl_uint num_objects, - const cl_mem * mem_objects, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event) CL_API_SUFFIX__VERSION_1_2; - -#ifdef __cplusplus -} -#endif - -#endif // __OPENCL_CL_DX9_MEDIA_SHARING_H - diff --git a/ext/CL/cl_egl.h b/ext/CL/cl_egl.h deleted file mode 100644 index c1bd4f39..00000000 --- a/ext/CL/cl_egl.h +++ /dev/null @@ -1,131 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008-2010 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - ******************************************************************************/ - -#ifndef __OPENCL_CL_EGL_H -#define __OPENCL_CL_EGL_H - -#ifdef __APPLE__ - -#else -#include -#include -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Command type for events created with clEnqueueAcquireEGLObjectsKHR */ -#define CL_COMMAND_EGL_FENCE_SYNC_OBJECT_KHR 0x202F -#define CL_COMMAND_ACQUIRE_EGL_OBJECTS_KHR 0x202D -#define CL_COMMAND_RELEASE_EGL_OBJECTS_KHR 0x202E - -/* Error type for clCreateFromEGLImageKHR */ -#define CL_INVALID_EGL_OBJECT_KHR -1093 -#define CL_EGL_RESOURCE_NOT_ACQUIRED_KHR -1092 - -/* CLeglImageKHR is an opaque handle to an EGLImage */ -typedef void* CLeglImageKHR; - -/* CLeglDisplayKHR is an opaque handle to an EGLDisplay */ -typedef void* CLeglDisplayKHR; - -/* properties passed to clCreateFromEGLImageKHR */ -typedef intptr_t cl_egl_image_properties_khr; - - -#define cl_khr_egl_image 1 - -extern CL_API_ENTRY cl_mem CL_API_CALL -clCreateFromEGLImageKHR(cl_context /* context */, - CLeglDisplayKHR /* egldisplay */, - CLeglImageKHR /* eglimage */, - cl_mem_flags /* flags */, - const cl_egl_image_properties_khr * /* properties */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromEGLImageKHR_fn)( - cl_context context, - CLeglDisplayKHR egldisplay, - CLeglImageKHR eglimage, - cl_mem_flags flags, - const cl_egl_image_properties_khr * properties, - cl_int * errcode_ret); - - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueAcquireEGLObjectsKHR(cl_command_queue /* command_queue */, - cl_uint /* num_objects */, - const cl_mem * /* mem_objects */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueAcquireEGLObjectsKHR_fn)( - cl_command_queue command_queue, - cl_uint num_objects, - const cl_mem * mem_objects, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event); - - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueReleaseEGLObjectsKHR(cl_command_queue /* command_queue */, - cl_uint /* num_objects */, - const cl_mem * /* mem_objects */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueReleaseEGLObjectsKHR_fn)( - cl_command_queue command_queue, - cl_uint num_objects, - const cl_mem * mem_objects, - cl_uint num_events_in_wait_list, - const cl_event * event_wait_list, - cl_event * event); - - -#define cl_khr_egl_event 1 - -extern CL_API_ENTRY cl_event CL_API_CALL -clCreateEventFromEGLSyncKHR(cl_context /* context */, - EGLSyncKHR /* sync */, - EGLDisplay /* display */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -typedef CL_API_ENTRY cl_event (CL_API_CALL *clCreateEventFromEGLSyncKHR_fn)( - cl_context context, - EGLSyncKHR sync, - EGLDisplay display, - cl_int * errcode_ret); - - -#ifdef __cplusplus -} -#endif - -#endif /* __OPENCL_CL_EGL_H */ diff --git a/ext/CL/cl_ext.h b/ext/CL/cl_ext.h deleted file mode 100644 index 6908b7ed..00000000 --- a/ext/CL/cl_ext.h +++ /dev/null @@ -1,306 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008-2013 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - ******************************************************************************/ - -/* $Revision: 11928 $ on $Date: 2010-07-13 09:04:56 -0700 (Tue, 13 Jul 2010) $ */ - -/* cl_ext.h contains OpenCL extensions which don't have external */ -/* (OpenGL, D3D) dependencies. */ - -#ifndef __CL_EXT_H -#define __CL_EXT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __APPLE__ - #include - #include -#else - #include -#endif - -/* cl_khr_fp16 extension - no extension #define since it has no functions */ -#define CL_DEVICE_HALF_FP_CONFIG 0x1033 - -/* Memory object destruction - * - * Apple extension for use to manage externally allocated buffers used with cl_mem objects with CL_MEM_USE_HOST_PTR - * - * Registers a user callback function that will be called when the memory object is deleted and its resources - * freed. Each call to clSetMemObjectCallbackFn registers the specified user callback function on a callback - * stack associated with memobj. The registered user callback functions are called in the reverse order in - * which they were registered. The user callback functions are called and then the memory object is deleted - * and its resources freed. This provides a mechanism for the application (and libraries) using memobj to be - * notified when the memory referenced by host_ptr, specified when the memory object is created and used as - * the storage bits for the memory object, can be reused or freed. - * - * The application may not call CL api's with the cl_mem object passed to the pfn_notify. - * - * Please check for the "cl_APPLE_SetMemObjectDestructor" extension using clGetDeviceInfo(CL_DEVICE_EXTENSIONS) - * before using. - */ -#define cl_APPLE_SetMemObjectDestructor 1 -cl_int CL_API_ENTRY clSetMemObjectDestructorAPPLE( cl_mem /* memobj */, - void (* /*pfn_notify*/)( cl_mem /* memobj */, void* /*user_data*/), - void * /*user_data */ ) CL_EXT_SUFFIX__VERSION_1_0; - - -/* Context Logging Functions - * - * The next three convenience functions are intended to be used as the pfn_notify parameter to clCreateContext(). - * Please check for the "cl_APPLE_ContextLoggingFunctions" extension using clGetDeviceInfo(CL_DEVICE_EXTENSIONS) - * before using. - * - * clLogMessagesToSystemLog fowards on all log messages to the Apple System Logger - */ -#define cl_APPLE_ContextLoggingFunctions 1 -extern void CL_API_ENTRY clLogMessagesToSystemLogAPPLE( const char * /* errstr */, - const void * /* private_info */, - size_t /* cb */, - void * /* user_data */ ) CL_EXT_SUFFIX__VERSION_1_0; - -/* clLogMessagesToStdout sends all log messages to the file descriptor stdout */ -extern void CL_API_ENTRY clLogMessagesToStdoutAPPLE( const char * /* errstr */, - const void * /* private_info */, - size_t /* cb */, - void * /* user_data */ ) CL_EXT_SUFFIX__VERSION_1_0; - -/* clLogMessagesToStderr sends all log messages to the file descriptor stderr */ -extern void CL_API_ENTRY clLogMessagesToStderrAPPLE( const char * /* errstr */, - const void * /* private_info */, - size_t /* cb */, - void * /* user_data */ ) CL_EXT_SUFFIX__VERSION_1_0; - - -/************************ -* cl_khr_icd extension * -************************/ -#define cl_khr_icd 1 - -/* cl_platform_info */ -#define CL_PLATFORM_ICD_SUFFIX_KHR 0x0920 - -/* Additional Error Codes */ -#define CL_PLATFORM_NOT_FOUND_KHR -1001 - -extern CL_API_ENTRY cl_int CL_API_CALL -clIcdGetPlatformIDsKHR(cl_uint /* num_entries */, - cl_platform_id * /* platforms */, - cl_uint * /* num_platforms */); - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clIcdGetPlatformIDsKHR_fn)( - cl_uint /* num_entries */, - cl_platform_id * /* platforms */, - cl_uint * /* num_platforms */); - - -/* Extension: cl_khr_image2D_buffer - * - * This extension allows a 2D image to be created from a cl_mem buffer without a copy. - * The type associated with a 2D image created from a buffer in an OpenCL program is image2d_t. - * Both the sampler and sampler-less read_image built-in functions are supported for 2D images - * and 2D images created from a buffer. Similarly, the write_image built-ins are also supported - * for 2D images created from a buffer. - * - * When the 2D image from buffer is created, the client must specify the width, - * height, image format (i.e. channel order and channel data type) and optionally the row pitch - * - * The pitch specified must be a multiple of CL_DEVICE_IMAGE_PITCH_ALIGNMENT pixels. - * The base address of the buffer must be aligned to CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT pixels. - */ - -/************************************* - * cl_khr_initalize_memory extension * - *************************************/ - -#define CL_CONTEXT_MEMORY_INITIALIZE_KHR 0x200E - - -/************************************** - * cl_khr_terminate_context extension * - **************************************/ - -#define CL_DEVICE_TERMINATE_CAPABILITY_KHR 0x200F -#define CL_CONTEXT_TERMINATE_KHR 0x2010 - -#define cl_khr_terminate_context 1 -extern CL_API_ENTRY cl_int CL_API_CALL clTerminateContextKHR(cl_context /* context */) CL_EXT_SUFFIX__VERSION_1_2; - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clTerminateContextKHR_fn)(cl_context /* context */) CL_EXT_SUFFIX__VERSION_1_2; - - -/* - * Extension: cl_khr_spir - * - * This extension adds support to create an OpenCL program object from a - * Standard Portable Intermediate Representation (SPIR) instance - */ - -/****************************************** -* cl_nv_device_attribute_query extension * -******************************************/ -/* cl_nv_device_attribute_query extension - no extension #define since it has no functions */ -#define CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV 0x4000 -#define CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV 0x4001 -#define CL_DEVICE_REGISTERS_PER_BLOCK_NV 0x4002 -#define CL_DEVICE_WARP_SIZE_NV 0x4003 -#define CL_DEVICE_GPU_OVERLAP_NV 0x4004 -#define CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV 0x4005 -#define CL_DEVICE_INTEGRATED_MEMORY_NV 0x4006 - -/********************************* -* cl_amd_device_attribute_query * -*********************************/ -#define CL_DEVICE_PROFILING_TIMER_OFFSET_AMD 0x4036 - -#ifdef CL_VERSION_1_1 - /*********************************** - * cl_ext_device_fission extension * - ***********************************/ - #define cl_ext_device_fission 1 - - extern CL_API_ENTRY cl_int CL_API_CALL - clReleaseDeviceEXT( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1; - - typedef CL_API_ENTRY cl_int - (CL_API_CALL *clReleaseDeviceEXT_fn)( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1; - - extern CL_API_ENTRY cl_int CL_API_CALL - clRetainDeviceEXT( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1; - - typedef CL_API_ENTRY cl_int - (CL_API_CALL *clRetainDeviceEXT_fn)( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1; - - typedef cl_ulong cl_device_partition_property_ext; - extern CL_API_ENTRY cl_int CL_API_CALL - clCreateSubDevicesEXT( cl_device_id /*in_device*/, - const cl_device_partition_property_ext * /* properties */, - cl_uint /*num_entries*/, - cl_device_id * /*out_devices*/, - cl_uint * /*num_devices*/ ) CL_EXT_SUFFIX__VERSION_1_1; - - typedef CL_API_ENTRY cl_int - ( CL_API_CALL * clCreateSubDevicesEXT_fn)( cl_device_id /*in_device*/, - const cl_device_partition_property_ext * /* properties */, - cl_uint /*num_entries*/, - cl_device_id * /*out_devices*/, - cl_uint * /*num_devices*/ ) CL_EXT_SUFFIX__VERSION_1_1; - - /* cl_device_partition_property_ext */ - #define CL_DEVICE_PARTITION_EQUALLY_EXT 0x4050 - #define CL_DEVICE_PARTITION_BY_COUNTS_EXT 0x4051 - #define CL_DEVICE_PARTITION_BY_NAMES_EXT 0x4052 - #define CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN_EXT 0x4053 - - /* clDeviceGetInfo selectors */ - #define CL_DEVICE_PARENT_DEVICE_EXT 0x4054 - #define CL_DEVICE_PARTITION_TYPES_EXT 0x4055 - #define CL_DEVICE_AFFINITY_DOMAINS_EXT 0x4056 - #define CL_DEVICE_REFERENCE_COUNT_EXT 0x4057 - #define CL_DEVICE_PARTITION_STYLE_EXT 0x4058 - - /* error codes */ - #define CL_DEVICE_PARTITION_FAILED_EXT -1057 - #define CL_INVALID_PARTITION_COUNT_EXT -1058 - #define CL_INVALID_PARTITION_NAME_EXT -1059 - - /* CL_AFFINITY_DOMAINs */ - #define CL_AFFINITY_DOMAIN_L1_CACHE_EXT 0x1 - #define CL_AFFINITY_DOMAIN_L2_CACHE_EXT 0x2 - #define CL_AFFINITY_DOMAIN_L3_CACHE_EXT 0x3 - #define CL_AFFINITY_DOMAIN_L4_CACHE_EXT 0x4 - #define CL_AFFINITY_DOMAIN_NUMA_EXT 0x10 - #define CL_AFFINITY_DOMAIN_NEXT_FISSIONABLE_EXT 0x100 - - /* cl_device_partition_property_ext list terminators */ - #define CL_PROPERTIES_LIST_END_EXT ((cl_device_partition_property_ext) 0) - #define CL_PARTITION_BY_COUNTS_LIST_END_EXT ((cl_device_partition_property_ext) 0) - #define CL_PARTITION_BY_NAMES_LIST_END_EXT ((cl_device_partition_property_ext) 0 - 1) - -/********************************* -* cl_qcom_ext_host_ptr extension -*********************************/ - -#define CL_MEM_EXT_HOST_PTR_QCOM (1 << 29) - -#define CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM 0x40A0 -#define CL_DEVICE_PAGE_SIZE_QCOM 0x40A1 -#define CL_IMAGE_ROW_ALIGNMENT_QCOM 0x40A2 -#define CL_IMAGE_SLICE_ALIGNMENT_QCOM 0x40A3 -#define CL_MEM_HOST_UNCACHED_QCOM 0x40A4 -#define CL_MEM_HOST_WRITEBACK_QCOM 0x40A5 -#define CL_MEM_HOST_WRITETHROUGH_QCOM 0x40A6 -#define CL_MEM_HOST_WRITE_COMBINING_QCOM 0x40A7 - -typedef cl_uint cl_image_pitch_info_qcom; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetDeviceImageInfoQCOM(cl_device_id device, - size_t image_width, - size_t image_height, - const cl_image_format *image_format, - cl_image_pitch_info_qcom param_name, - size_t param_value_size, - void *param_value, - size_t *param_value_size_ret); - -typedef struct _cl_mem_ext_host_ptr -{ - // Type of external memory allocation. - // Legal values will be defined in layered extensions. - cl_uint allocation_type; - - // Host cache policy for this external memory allocation. - cl_uint host_cache_policy; - -} cl_mem_ext_host_ptr; - -/********************************* -* cl_qcom_ion_host_ptr extension -*********************************/ - -#define CL_MEM_ION_HOST_PTR_QCOM 0x40A8 - -typedef struct _cl_mem_ion_host_ptr -{ - // Type of external memory allocation. - // Must be CL_MEM_ION_HOST_PTR_QCOM for ION allocations. - cl_mem_ext_host_ptr ext_host_ptr; - - // ION file descriptor - int ion_filedesc; - - // Host pointer to the ION allocated memory - void* ion_hostptr; - -} cl_mem_ion_host_ptr; - -#endif /* CL_VERSION_1_1 */ - -#ifdef __cplusplus -} -#endif - - -#endif /* __CL_EXT_H */ diff --git a/ext/CL/cl_gl.h b/ext/CL/cl_gl.h deleted file mode 100644 index af2036cc..00000000 --- a/ext/CL/cl_gl.h +++ /dev/null @@ -1,162 +0,0 @@ -/********************************************************************************** - * Copyright (c) 2008 - 2012 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - **********************************************************************************/ - -#ifndef __OPENCL_CL_GL_H -#define __OPENCL_CL_GL_H - -#ifdef __APPLE__ -#include -#else -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef cl_uint cl_gl_object_type; -typedef cl_uint cl_gl_texture_info; -typedef cl_uint cl_gl_platform_info; -typedef struct __GLsync *cl_GLsync; - -/* cl_gl_object_type = 0x2000 - 0x200F enum values are currently taken */ -#define CL_GL_OBJECT_BUFFER 0x2000 -#define CL_GL_OBJECT_TEXTURE2D 0x2001 -#define CL_GL_OBJECT_TEXTURE3D 0x2002 -#define CL_GL_OBJECT_RENDERBUFFER 0x2003 -#define CL_GL_OBJECT_TEXTURE2D_ARRAY 0x200E -#define CL_GL_OBJECT_TEXTURE1D 0x200F -#define CL_GL_OBJECT_TEXTURE1D_ARRAY 0x2010 -#define CL_GL_OBJECT_TEXTURE_BUFFER 0x2011 - -/* cl_gl_texture_info */ -#define CL_GL_TEXTURE_TARGET 0x2004 -#define CL_GL_MIPMAP_LEVEL 0x2005 -#define CL_GL_NUM_SAMPLES 0x2012 - - -extern CL_API_ENTRY cl_mem CL_API_CALL -clCreateFromGLBuffer(cl_context /* context */, - cl_mem_flags /* flags */, - cl_GLuint /* bufobj */, - int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_mem CL_API_CALL -clCreateFromGLTexture(cl_context /* context */, - cl_mem_flags /* flags */, - cl_GLenum /* target */, - cl_GLint /* miplevel */, - cl_GLuint /* texture */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_2; - -extern CL_API_ENTRY cl_mem CL_API_CALL -clCreateFromGLRenderbuffer(cl_context /* context */, - cl_mem_flags /* flags */, - cl_GLuint /* renderbuffer */, - cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetGLObjectInfo(cl_mem /* memobj */, - cl_gl_object_type * /* gl_object_type */, - cl_GLuint * /* gl_object_name */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetGLTextureInfo(cl_mem /* memobj */, - cl_gl_texture_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueAcquireGLObjects(cl_command_queue /* command_queue */, - cl_uint /* num_objects */, - const cl_mem * /* mem_objects */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - -extern CL_API_ENTRY cl_int CL_API_CALL -clEnqueueReleaseGLObjects(cl_command_queue /* command_queue */, - cl_uint /* num_objects */, - const cl_mem * /* mem_objects */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; - - -// Deprecated OpenCL 1.1 APIs -extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL -clCreateFromGLTexture2D(cl_context /* context */, - cl_mem_flags /* flags */, - cl_GLenum /* target */, - cl_GLint /* miplevel */, - cl_GLuint /* texture */, - cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; - -extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL -clCreateFromGLTexture3D(cl_context /* context */, - cl_mem_flags /* flags */, - cl_GLenum /* target */, - cl_GLint /* miplevel */, - cl_GLuint /* texture */, - cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; - -/* cl_khr_gl_sharing extension */ - -#define cl_khr_gl_sharing 1 - -typedef cl_uint cl_gl_context_info; - -/* Additional Error Codes */ -#define CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR -1000 - -/* cl_gl_context_info */ -#define CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR 0x2006 -#define CL_DEVICES_FOR_GL_CONTEXT_KHR 0x2007 - -/* Additional cl_context_properties */ -#define CL_GL_CONTEXT_KHR 0x2008 -#define CL_EGL_DISPLAY_KHR 0x2009 -#define CL_GLX_DISPLAY_KHR 0x200A -#define CL_WGL_HDC_KHR 0x200B -#define CL_CGL_SHAREGROUP_KHR 0x200C - -extern CL_API_ENTRY cl_int CL_API_CALL -clGetGLContextInfoKHR(const cl_context_properties * /* properties */, - cl_gl_context_info /* param_name */, - size_t /* param_value_size */, - void * /* param_value */, - size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; - -typedef CL_API_ENTRY cl_int (CL_API_CALL *clGetGLContextInfoKHR_fn)( - const cl_context_properties * properties, - cl_gl_context_info param_name, - size_t param_value_size, - void * param_value, - size_t * param_value_size_ret); - -#ifdef __cplusplus -} -#endif - -#endif /* __OPENCL_CL_GL_H */ diff --git a/ext/CL/cl_gl_ext.h b/ext/CL/cl_gl_ext.h deleted file mode 100644 index 77d53536..00000000 --- a/ext/CL/cl_gl_ext.h +++ /dev/null @@ -1,69 +0,0 @@ -/********************************************************************************** - * Copyright (c) 2008-2012 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - **********************************************************************************/ - -/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */ - -/* cl_gl_ext.h contains vendor (non-KHR) OpenCL extensions which have */ -/* OpenGL dependencies. */ - -#ifndef __OPENCL_CL_GL_EXT_H -#define __OPENCL_CL_GL_EXT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __APPLE__ - #include -#else - #include -#endif - -/* - * For each extension, follow this template - * cl_VEN_extname extension */ -/* #define cl_VEN_extname 1 - * ... define new types, if any - * ... define new tokens, if any - * ... define new APIs, if any - * - * If you need GLtypes here, mirror them with a cl_GLtype, rather than including a GL header - * This allows us to avoid having to decide whether to include GL headers or GLES here. - */ - -/* - * cl_khr_gl_event extension - * See section 9.9 in the OpenCL 1.1 spec for more information - */ -#define CL_COMMAND_GL_FENCE_SYNC_OBJECT_KHR 0x200D - -extern CL_API_ENTRY cl_event CL_API_CALL -clCreateEventFromGLsyncKHR(cl_context /* context */, - cl_GLsync /* cl_GLsync */, - cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1; - -#ifdef __cplusplus -} -#endif - -#endif /* __OPENCL_CL_GL_EXT_H */ diff --git a/ext/CL/cl_platform.h b/ext/CL/cl_platform.h deleted file mode 100644 index cf7b2542..00000000 --- a/ext/CL/cl_platform.h +++ /dev/null @@ -1,1254 +0,0 @@ -/********************************************************************************** - * Copyright (c) 2008-2012 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - **********************************************************************************/ - -/* $Revision: 11803 $ on $Date: 2010-06-25 10:02:12 -0700 (Fri, 25 Jun 2010) $ */ - -#ifndef __CL_PLATFORM_H -#define __CL_PLATFORM_H - -#ifdef __APPLE__ - /* Contains #defines for AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER below */ - #include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(_WIN32) - #define CL_API_ENTRY - #define CL_API_CALL __stdcall - #define CL_CALLBACK __stdcall -#else - #define CL_API_ENTRY - #define CL_API_CALL - #define CL_CALLBACK -#endif - -#ifdef __APPLE__ - #define CL_EXTENSION_WEAK_LINK __attribute__((weak_import)) - #define CL_API_SUFFIX__VERSION_1_0 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER - #define CL_EXT_SUFFIX__VERSION_1_0 CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER - #define CL_API_SUFFIX__VERSION_1_1 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER - #define GCL_API_SUFFIX__VERSION_1_1 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER - #define CL_EXT_SUFFIX__VERSION_1_1 CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER - #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 - - #ifdef AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER - #define CL_API_SUFFIX__VERSION_1_2 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER - #define GCL_API_SUFFIX__VERSION_1_2 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER - #define CL_EXT_SUFFIX__VERSION_1_2 CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER - #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 - #else - #warning This path should never happen outside of internal operating system development. AvailabilityMacros do not function correctly here! - #define CL_API_SUFFIX__VERSION_1_2 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER - #define GCL_API_SUFFIX__VERSION_1_2 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER - #define CL_EXT_SUFFIX__VERSION_1_2 CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER - #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER - #endif -#else - #define CL_EXTENSION_WEAK_LINK - #define CL_API_SUFFIX__VERSION_1_0 - #define CL_EXT_SUFFIX__VERSION_1_0 - #define CL_API_SUFFIX__VERSION_1_1 - #define CL_EXT_SUFFIX__VERSION_1_1 - #define CL_API_SUFFIX__VERSION_1_2 - #define CL_EXT_SUFFIX__VERSION_1_2 - - #ifdef __GNUC__ - #ifdef CL_USE_DEPRECATED_OPENCL_1_0_APIS - #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED - #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED - #else - #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED __attribute__((deprecated)) - #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED - #endif - - #ifdef CL_USE_DEPRECATED_OPENCL_1_1_APIS - #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - #else - #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED __attribute__((deprecated)) - #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - #endif - #elif defined(_WIN32) - #ifdef CL_USE_DEPRECATED_OPENCL_1_0_APIS - #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED - #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED - #else - #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED - #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED __declspec(deprecated) - #endif - - #ifdef CL_USE_DEPRECATED_OPENCL_1_1_APIS - #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - #else - #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED __declspec(deprecated) - #endif - #else - #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED - #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED - - #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - #endif -#endif - -#if (defined (_WIN32) && defined(_MSC_VER)) - -/* scalar types */ -typedef signed __int8 cl_char; -typedef unsigned __int8 cl_uchar; -typedef signed __int16 cl_short; -typedef unsigned __int16 cl_ushort; -typedef signed __int32 cl_int; -typedef unsigned __int32 cl_uint; -typedef signed __int64 cl_long; -typedef unsigned __int64 cl_ulong; - -typedef unsigned __int16 cl_half; -typedef float cl_float; -typedef double cl_double; - -/* Macro names and corresponding values defined by OpenCL */ -#define CL_CHAR_BIT 8 -#define CL_SCHAR_MAX 127 -#define CL_SCHAR_MIN (-127-1) -#define CL_CHAR_MAX CL_SCHAR_MAX -#define CL_CHAR_MIN CL_SCHAR_MIN -#define CL_UCHAR_MAX 255 -#define CL_SHRT_MAX 32767 -#define CL_SHRT_MIN (-32767-1) -#define CL_USHRT_MAX 65535 -#define CL_INT_MAX 2147483647 -#define CL_INT_MIN (-2147483647-1) -#define CL_UINT_MAX 0xffffffffU -#define CL_LONG_MAX ((cl_long) 0x7FFFFFFFFFFFFFFFLL) -#define CL_LONG_MIN ((cl_long) -0x7FFFFFFFFFFFFFFFLL - 1LL) -#define CL_ULONG_MAX ((cl_ulong) 0xFFFFFFFFFFFFFFFFULL) - -#define CL_FLT_DIG 6 -#define CL_FLT_MANT_DIG 24 -#define CL_FLT_MAX_10_EXP +38 -#define CL_FLT_MAX_EXP +128 -#define CL_FLT_MIN_10_EXP -37 -#define CL_FLT_MIN_EXP -125 -#define CL_FLT_RADIX 2 -#define CL_FLT_MAX 340282346638528859811704183484516925440.0f -#define CL_FLT_MIN 1.175494350822287507969e-38f -#define CL_FLT_EPSILON 0x1.0p-23f - -#define CL_DBL_DIG 15 -#define CL_DBL_MANT_DIG 53 -#define CL_DBL_MAX_10_EXP +308 -#define CL_DBL_MAX_EXP +1024 -#define CL_DBL_MIN_10_EXP -307 -#define CL_DBL_MIN_EXP -1021 -#define CL_DBL_RADIX 2 -#define CL_DBL_MAX 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 -#define CL_DBL_MIN 2.225073858507201383090e-308 -#define CL_DBL_EPSILON 2.220446049250313080847e-16 - -#define CL_M_E 2.718281828459045090796 -#define CL_M_LOG2E 1.442695040888963387005 -#define CL_M_LOG10E 0.434294481903251816668 -#define CL_M_LN2 0.693147180559945286227 -#define CL_M_LN10 2.302585092994045901094 -#define CL_M_PI 3.141592653589793115998 -#define CL_M_PI_2 1.570796326794896557999 -#define CL_M_PI_4 0.785398163397448278999 -#define CL_M_1_PI 0.318309886183790691216 -#define CL_M_2_PI 0.636619772367581382433 -#define CL_M_2_SQRTPI 1.128379167095512558561 -#define CL_M_SQRT2 1.414213562373095145475 -#define CL_M_SQRT1_2 0.707106781186547572737 - -#define CL_M_E_F 2.71828174591064f -#define CL_M_LOG2E_F 1.44269502162933f -#define CL_M_LOG10E_F 0.43429449200630f -#define CL_M_LN2_F 0.69314718246460f -#define CL_M_LN10_F 2.30258512496948f -#define CL_M_PI_F 3.14159274101257f -#define CL_M_PI_2_F 1.57079637050629f -#define CL_M_PI_4_F 0.78539818525314f -#define CL_M_1_PI_F 0.31830987334251f -#define CL_M_2_PI_F 0.63661974668503f -#define CL_M_2_SQRTPI_F 1.12837922573090f -#define CL_M_SQRT2_F 1.41421353816986f -#define CL_M_SQRT1_2_F 0.70710676908493f - -#define CL_NAN (CL_INFINITY - CL_INFINITY) -#define CL_HUGE_VALF ((cl_float) 1e50) -#define CL_HUGE_VAL ((cl_double) 1e500) -#define CL_MAXFLOAT CL_FLT_MAX -#define CL_INFINITY CL_HUGE_VALF - -#else - -#include - -/* scalar types */ -typedef int8_t cl_char; -typedef uint8_t cl_uchar; -typedef int16_t cl_short __attribute__((aligned(2))); -typedef uint16_t cl_ushort __attribute__((aligned(2))); -typedef int32_t cl_int __attribute__((aligned(4))); -typedef uint32_t cl_uint __attribute__((aligned(4))); -typedef int64_t cl_long __attribute__((aligned(8))); -typedef uint64_t cl_ulong __attribute__((aligned(8))); - -typedef uint16_t cl_half __attribute__((aligned(2))); -typedef float cl_float __attribute__((aligned(4))); -typedef double cl_double __attribute__((aligned(8))); - -/* Macro names and corresponding values defined by OpenCL */ -#define CL_CHAR_BIT 8 -#define CL_SCHAR_MAX 127 -#define CL_SCHAR_MIN (-127-1) -#define CL_CHAR_MAX CL_SCHAR_MAX -#define CL_CHAR_MIN CL_SCHAR_MIN -#define CL_UCHAR_MAX 255 -#define CL_SHRT_MAX 32767 -#define CL_SHRT_MIN (-32767-1) -#define CL_USHRT_MAX 65535 -#define CL_INT_MAX 2147483647 -#define CL_INT_MIN (-2147483647-1) -#define CL_UINT_MAX 0xffffffffU -#define CL_LONG_MAX ((cl_long) 0x7FFFFFFFFFFFFFFFLL) -#define CL_LONG_MIN ((cl_long) -0x7FFFFFFFFFFFFFFFLL - 1LL) -#define CL_ULONG_MAX ((cl_ulong) 0xFFFFFFFFFFFFFFFFULL) - -#define CL_FLT_DIG 6 -#define CL_FLT_MANT_DIG 24 -#define CL_FLT_MAX_10_EXP +38 -#define CL_FLT_MAX_EXP +128 -#define CL_FLT_MIN_10_EXP -37 -#define CL_FLT_MIN_EXP -125 -#define CL_FLT_RADIX 2 -#define CL_FLT_MAX 0x1.fffffep127f -#define CL_FLT_MIN 0x1.0p-126f -#define CL_FLT_EPSILON 0x1.0p-23f - -#define CL_DBL_DIG 15 -#define CL_DBL_MANT_DIG 53 -#define CL_DBL_MAX_10_EXP +308 -#define CL_DBL_MAX_EXP +1024 -#define CL_DBL_MIN_10_EXP -307 -#define CL_DBL_MIN_EXP -1021 -#define CL_DBL_RADIX 2 -#define CL_DBL_MAX 0x1.fffffffffffffp1023 -#define CL_DBL_MIN 0x1.0p-1022 -#define CL_DBL_EPSILON 0x1.0p-52 - -#define CL_M_E 2.718281828459045090796 -#define CL_M_LOG2E 1.442695040888963387005 -#define CL_M_LOG10E 0.434294481903251816668 -#define CL_M_LN2 0.693147180559945286227 -#define CL_M_LN10 2.302585092994045901094 -#define CL_M_PI 3.141592653589793115998 -#define CL_M_PI_2 1.570796326794896557999 -#define CL_M_PI_4 0.785398163397448278999 -#define CL_M_1_PI 0.318309886183790691216 -#define CL_M_2_PI 0.636619772367581382433 -#define CL_M_2_SQRTPI 1.128379167095512558561 -#define CL_M_SQRT2 1.414213562373095145475 -#define CL_M_SQRT1_2 0.707106781186547572737 - -#define CL_M_E_F 2.71828174591064f -#define CL_M_LOG2E_F 1.44269502162933f -#define CL_M_LOG10E_F 0.43429449200630f -#define CL_M_LN2_F 0.69314718246460f -#define CL_M_LN10_F 2.30258512496948f -#define CL_M_PI_F 3.14159274101257f -#define CL_M_PI_2_F 1.57079637050629f -#define CL_M_PI_4_F 0.78539818525314f -#define CL_M_1_PI_F 0.31830987334251f -#define CL_M_2_PI_F 0.63661974668503f -#define CL_M_2_SQRTPI_F 1.12837922573090f -#define CL_M_SQRT2_F 1.41421353816986f -#define CL_M_SQRT1_2_F 0.70710676908493f - -#if defined( __GNUC__ ) - #define CL_HUGE_VALF __builtin_huge_valf() - #define CL_HUGE_VAL __builtin_huge_val() - #define CL_NAN __builtin_nanf( "" ) -#else - #define CL_HUGE_VALF ((cl_float) 1e50) - #define CL_HUGE_VAL ((cl_double) 1e500) - float nanf( const char * ); - #define CL_NAN nanf( "" ) -#endif -#define CL_MAXFLOAT CL_FLT_MAX -#define CL_INFINITY CL_HUGE_VALF - -#endif - -#include - -/* Mirror types to GL types. Mirror types allow us to avoid deciding which 87s to load based on whether we are using GL or GLES here. */ -typedef unsigned int cl_GLuint; -typedef int cl_GLint; -typedef unsigned int cl_GLenum; - -/* - * Vector types - * - * Note: OpenCL requires that all types be naturally aligned. - * This means that vector types must be naturally aligned. - * For example, a vector of four floats must be aligned to - * a 16 byte boundary (calculated as 4 * the natural 4-byte - * alignment of the float). The alignment qualifiers here - * will only function properly if your compiler supports them - * and if you don't actively work to defeat them. For example, - * in order for a cl_float4 to be 16 byte aligned in a struct, - * the start of the struct must itself be 16-byte aligned. - * - * Maintaining proper alignment is the user's responsibility. - */ - -/* Define basic vector types */ -#if defined( __VEC__ ) - #include /* may be omitted depending on compiler. AltiVec spec provides no way to detect whether the header is required. */ - typedef vector unsigned char __cl_uchar16; - typedef vector signed char __cl_char16; - typedef vector unsigned short __cl_ushort8; - typedef vector signed short __cl_short8; - typedef vector unsigned int __cl_uint4; - typedef vector signed int __cl_int4; - typedef vector float __cl_float4; - #define __CL_UCHAR16__ 1 - #define __CL_CHAR16__ 1 - #define __CL_USHORT8__ 1 - #define __CL_SHORT8__ 1 - #define __CL_UINT4__ 1 - #define __CL_INT4__ 1 - #define __CL_FLOAT4__ 1 -#endif - -#if defined( __SSE__ ) - #if defined( __MINGW64__ ) - #include - #else - #include - #endif - #if defined( __GNUC__ ) - typedef float __cl_float4 __attribute__((vector_size(16))); - #else - typedef __m128 __cl_float4; - #endif - #define __CL_FLOAT4__ 1 -#endif - -#if defined( __SSE2__ ) - #if defined( __MINGW64__ ) - #include - #else - #include - #endif - #if defined( __GNUC__ ) - typedef cl_uchar __cl_uchar16 __attribute__((vector_size(16))); - typedef cl_char __cl_char16 __attribute__((vector_size(16))); - typedef cl_ushort __cl_ushort8 __attribute__((vector_size(16))); - typedef cl_short __cl_short8 __attribute__((vector_size(16))); - typedef cl_uint __cl_uint4 __attribute__((vector_size(16))); - typedef cl_int __cl_int4 __attribute__((vector_size(16))); - typedef cl_ulong __cl_ulong2 __attribute__((vector_size(16))); - typedef cl_long __cl_long2 __attribute__((vector_size(16))); - typedef cl_double __cl_double2 __attribute__((vector_size(16))); - #else - typedef __m128i __cl_uchar16; - typedef __m128i __cl_char16; - typedef __m128i __cl_ushort8; - typedef __m128i __cl_short8; - typedef __m128i __cl_uint4; - typedef __m128i __cl_int4; - typedef __m128i __cl_ulong2; - typedef __m128i __cl_long2; - typedef __m128d __cl_double2; - #endif - #define __CL_UCHAR16__ 1 - #define __CL_CHAR16__ 1 - #define __CL_USHORT8__ 1 - #define __CL_SHORT8__ 1 - #define __CL_INT4__ 1 - #define __CL_UINT4__ 1 - #define __CL_ULONG2__ 1 - #define __CL_LONG2__ 1 - #define __CL_DOUBLE2__ 1 -#endif - -#if defined( __MMX__ ) - #include - #if defined( __GNUC__ ) - typedef cl_uchar __cl_uchar8 __attribute__((vector_size(8))); - typedef cl_char __cl_char8 __attribute__((vector_size(8))); - typedef cl_ushort __cl_ushort4 __attribute__((vector_size(8))); - typedef cl_short __cl_short4 __attribute__((vector_size(8))); - typedef cl_uint __cl_uint2 __attribute__((vector_size(8))); - typedef cl_int __cl_int2 __attribute__((vector_size(8))); - typedef cl_ulong __cl_ulong1 __attribute__((vector_size(8))); - typedef cl_long __cl_long1 __attribute__((vector_size(8))); - typedef cl_float __cl_float2 __attribute__((vector_size(8))); - #else - typedef __m64 __cl_uchar8; - typedef __m64 __cl_char8; - typedef __m64 __cl_ushort4; - typedef __m64 __cl_short4; - typedef __m64 __cl_uint2; - typedef __m64 __cl_int2; - typedef __m64 __cl_ulong1; - typedef __m64 __cl_long1; - typedef __m64 __cl_float2; - #endif - #define __CL_UCHAR8__ 1 - #define __CL_CHAR8__ 1 - #define __CL_USHORT4__ 1 - #define __CL_SHORT4__ 1 - #define __CL_INT2__ 1 - #define __CL_UINT2__ 1 - #define __CL_ULONG1__ 1 - #define __CL_LONG1__ 1 - #define __CL_FLOAT2__ 1 -#endif - -#if defined( __AVX__ ) - #if defined( __MINGW64__ ) - #include - #else - #include - #endif - #if defined( __GNUC__ ) - typedef cl_float __cl_float8 __attribute__((vector_size(32))); - typedef cl_double __cl_double4 __attribute__((vector_size(32))); - #else - typedef __m256 __cl_float8; - typedef __m256d __cl_double4; - #endif - #define __CL_FLOAT8__ 1 - #define __CL_DOUBLE4__ 1 -#endif - -/* Define alignment keys */ -#if defined( __GNUC__ ) - #define CL_ALIGNED(_x) __attribute__ ((aligned(_x))) -#elif defined( _WIN32 ) && defined( _MSC_VER ) - /* Alignment keys neutered on windows because MSVC can't swallow function arguments with alignment requirements */ - /* http://msdn.microsoft.com/en-us/library/373ak2y1%28VS.71%29.aspx */ - /* #include */ - /* #define CL_ALIGNED(_x) _CRT_ALIGN(_x) */ - #define CL_ALIGNED(_x) -#else - #warning Need to implement some method to align data here - #define CL_ALIGNED(_x) -#endif - -/* Indicate whether .xyzw, .s0123 and .hi.lo are supported */ -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - /* .xyzw and .s0123...{f|F} are supported */ - #define CL_HAS_NAMED_VECTOR_FIELDS 1 - /* .hi and .lo are supported */ - #define CL_HAS_HI_LO_VECTOR_FIELDS 1 -#endif - -/* Define cl_vector types */ - -/* ---- cl_charn ---- */ -typedef union -{ - cl_char CL_ALIGNED(2) s[2]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_char x, y; }; - __extension__ struct{ cl_char s0, s1; }; - __extension__ struct{ cl_char lo, hi; }; -#endif -#if defined( __CL_CHAR2__) - __cl_char2 v2; -#endif -}cl_char2; - -typedef union -{ - cl_char CL_ALIGNED(4) s[4]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_char x, y, z, w; }; - __extension__ struct{ cl_char s0, s1, s2, s3; }; - __extension__ struct{ cl_char2 lo, hi; }; -#endif -#if defined( __CL_CHAR2__) - __cl_char2 v2[2]; -#endif -#if defined( __CL_CHAR4__) - __cl_char4 v4; -#endif -}cl_char4; - -/* cl_char3 is identical in size, alignment and behavior to cl_char4. See section 6.1.5. */ -typedef cl_char4 cl_char3; - -typedef union -{ - cl_char CL_ALIGNED(8) s[8]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_char x, y, z, w; }; - __extension__ struct{ cl_char s0, s1, s2, s3, s4, s5, s6, s7; }; - __extension__ struct{ cl_char4 lo, hi; }; -#endif -#if defined( __CL_CHAR2__) - __cl_char2 v2[4]; -#endif -#if defined( __CL_CHAR4__) - __cl_char4 v4[2]; -#endif -#if defined( __CL_CHAR8__ ) - __cl_char8 v8; -#endif -}cl_char8; - -typedef union -{ - cl_char CL_ALIGNED(16) s[16]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_char x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; - __extension__ struct{ cl_char s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; - __extension__ struct{ cl_char8 lo, hi; }; -#endif -#if defined( __CL_CHAR2__) - __cl_char2 v2[8]; -#endif -#if defined( __CL_CHAR4__) - __cl_char4 v4[4]; -#endif -#if defined( __CL_CHAR8__ ) - __cl_char8 v8[2]; -#endif -#if defined( __CL_CHAR16__ ) - __cl_char16 v16; -#endif -}cl_char16; - - -/* ---- cl_ucharn ---- */ -typedef union -{ - cl_uchar CL_ALIGNED(2) s[2]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_uchar x, y; }; - __extension__ struct{ cl_uchar s0, s1; }; - __extension__ struct{ cl_uchar lo, hi; }; -#endif -#if defined( __cl_uchar2__) - __cl_uchar2 v2; -#endif -}cl_uchar2; - -typedef union -{ - cl_uchar CL_ALIGNED(4) s[4]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_uchar x, y, z, w; }; - __extension__ struct{ cl_uchar s0, s1, s2, s3; }; - __extension__ struct{ cl_uchar2 lo, hi; }; -#endif -#if defined( __CL_UCHAR2__) - __cl_uchar2 v2[2]; -#endif -#if defined( __CL_UCHAR4__) - __cl_uchar4 v4; -#endif -}cl_uchar4; - -/* cl_uchar3 is identical in size, alignment and behavior to cl_uchar4. See section 6.1.5. */ -typedef cl_uchar4 cl_uchar3; - -typedef union -{ - cl_uchar CL_ALIGNED(8) s[8]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_uchar x, y, z, w; }; - __extension__ struct{ cl_uchar s0, s1, s2, s3, s4, s5, s6, s7; }; - __extension__ struct{ cl_uchar4 lo, hi; }; -#endif -#if defined( __CL_UCHAR2__) - __cl_uchar2 v2[4]; -#endif -#if defined( __CL_UCHAR4__) - __cl_uchar4 v4[2]; -#endif -#if defined( __CL_UCHAR8__ ) - __cl_uchar8 v8; -#endif -}cl_uchar8; - -typedef union -{ - cl_uchar CL_ALIGNED(16) s[16]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_uchar x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; - __extension__ struct{ cl_uchar s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; - __extension__ struct{ cl_uchar8 lo, hi; }; -#endif -#if defined( __CL_UCHAR2__) - __cl_uchar2 v2[8]; -#endif -#if defined( __CL_UCHAR4__) - __cl_uchar4 v4[4]; -#endif -#if defined( __CL_UCHAR8__ ) - __cl_uchar8 v8[2]; -#endif -#if defined( __CL_UCHAR16__ ) - __cl_uchar16 v16; -#endif -}cl_uchar16; - - -/* ---- cl_shortn ---- */ -typedef union -{ - cl_short CL_ALIGNED(4) s[2]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_short x, y; }; - __extension__ struct{ cl_short s0, s1; }; - __extension__ struct{ cl_short lo, hi; }; -#endif -#if defined( __CL_SHORT2__) - __cl_short2 v2; -#endif -}cl_short2; - -typedef union -{ - cl_short CL_ALIGNED(8) s[4]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_short x, y, z, w; }; - __extension__ struct{ cl_short s0, s1, s2, s3; }; - __extension__ struct{ cl_short2 lo, hi; }; -#endif -#if defined( __CL_SHORT2__) - __cl_short2 v2[2]; -#endif -#if defined( __CL_SHORT4__) - __cl_short4 v4; -#endif -}cl_short4; - -/* cl_short3 is identical in size, alignment and behavior to cl_short4. See section 6.1.5. */ -typedef cl_short4 cl_short3; - -typedef union -{ - cl_short CL_ALIGNED(16) s[8]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_short x, y, z, w; }; - __extension__ struct{ cl_short s0, s1, s2, s3, s4, s5, s6, s7; }; - __extension__ struct{ cl_short4 lo, hi; }; -#endif -#if defined( __CL_SHORT2__) - __cl_short2 v2[4]; -#endif -#if defined( __CL_SHORT4__) - __cl_short4 v4[2]; -#endif -#if defined( __CL_SHORT8__ ) - __cl_short8 v8; -#endif -}cl_short8; - -typedef union -{ - cl_short CL_ALIGNED(32) s[16]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_short x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; - __extension__ struct{ cl_short s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; - __extension__ struct{ cl_short8 lo, hi; }; -#endif -#if defined( __CL_SHORT2__) - __cl_short2 v2[8]; -#endif -#if defined( __CL_SHORT4__) - __cl_short4 v4[4]; -#endif -#if defined( __CL_SHORT8__ ) - __cl_short8 v8[2]; -#endif -#if defined( __CL_SHORT16__ ) - __cl_short16 v16; -#endif -}cl_short16; - - -/* ---- cl_ushortn ---- */ -typedef union -{ - cl_ushort CL_ALIGNED(4) s[2]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_ushort x, y; }; - __extension__ struct{ cl_ushort s0, s1; }; - __extension__ struct{ cl_ushort lo, hi; }; -#endif -#if defined( __CL_USHORT2__) - __cl_ushort2 v2; -#endif -}cl_ushort2; - -typedef union -{ - cl_ushort CL_ALIGNED(8) s[4]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_ushort x, y, z, w; }; - __extension__ struct{ cl_ushort s0, s1, s2, s3; }; - __extension__ struct{ cl_ushort2 lo, hi; }; -#endif -#if defined( __CL_USHORT2__) - __cl_ushort2 v2[2]; -#endif -#if defined( __CL_USHORT4__) - __cl_ushort4 v4; -#endif -}cl_ushort4; - -/* cl_ushort3 is identical in size, alignment and behavior to cl_ushort4. See section 6.1.5. */ -typedef cl_ushort4 cl_ushort3; - -typedef union -{ - cl_ushort CL_ALIGNED(16) s[8]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_ushort x, y, z, w; }; - __extension__ struct{ cl_ushort s0, s1, s2, s3, s4, s5, s6, s7; }; - __extension__ struct{ cl_ushort4 lo, hi; }; -#endif -#if defined( __CL_USHORT2__) - __cl_ushort2 v2[4]; -#endif -#if defined( __CL_USHORT4__) - __cl_ushort4 v4[2]; -#endif -#if defined( __CL_USHORT8__ ) - __cl_ushort8 v8; -#endif -}cl_ushort8; - -typedef union -{ - cl_ushort CL_ALIGNED(32) s[16]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_ushort x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; - __extension__ struct{ cl_ushort s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; - __extension__ struct{ cl_ushort8 lo, hi; }; -#endif -#if defined( __CL_USHORT2__) - __cl_ushort2 v2[8]; -#endif -#if defined( __CL_USHORT4__) - __cl_ushort4 v4[4]; -#endif -#if defined( __CL_USHORT8__ ) - __cl_ushort8 v8[2]; -#endif -#if defined( __CL_USHORT16__ ) - __cl_ushort16 v16; -#endif -}cl_ushort16; - -/* ---- cl_intn ---- */ -typedef union -{ - cl_int CL_ALIGNED(8) s[2]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_int x, y; }; - __extension__ struct{ cl_int s0, s1; }; - __extension__ struct{ cl_int lo, hi; }; -#endif -#if defined( __CL_INT2__) - __cl_int2 v2; -#endif -}cl_int2; - -typedef union -{ - cl_int CL_ALIGNED(16) s[4]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_int x, y, z, w; }; - __extension__ struct{ cl_int s0, s1, s2, s3; }; - __extension__ struct{ cl_int2 lo, hi; }; -#endif -#if defined( __CL_INT2__) - __cl_int2 v2[2]; -#endif -#if defined( __CL_INT4__) - __cl_int4 v4; -#endif -}cl_int4; - -/* cl_int3 is identical in size, alignment and behavior to cl_int4. See section 6.1.5. */ -typedef cl_int4 cl_int3; - -typedef union -{ - cl_int CL_ALIGNED(32) s[8]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_int x, y, z, w; }; - __extension__ struct{ cl_int s0, s1, s2, s3, s4, s5, s6, s7; }; - __extension__ struct{ cl_int4 lo, hi; }; -#endif -#if defined( __CL_INT2__) - __cl_int2 v2[4]; -#endif -#if defined( __CL_INT4__) - __cl_int4 v4[2]; -#endif -#if defined( __CL_INT8__ ) - __cl_int8 v8; -#endif -}cl_int8; - -typedef union -{ - cl_int CL_ALIGNED(64) s[16]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_int x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; - __extension__ struct{ cl_int s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; - __extension__ struct{ cl_int8 lo, hi; }; -#endif -#if defined( __CL_INT2__) - __cl_int2 v2[8]; -#endif -#if defined( __CL_INT4__) - __cl_int4 v4[4]; -#endif -#if defined( __CL_INT8__ ) - __cl_int8 v8[2]; -#endif -#if defined( __CL_INT16__ ) - __cl_int16 v16; -#endif -}cl_int16; - - -/* ---- cl_uintn ---- */ -typedef union -{ - cl_uint CL_ALIGNED(8) s[2]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_uint x, y; }; - __extension__ struct{ cl_uint s0, s1; }; - __extension__ struct{ cl_uint lo, hi; }; -#endif -#if defined( __CL_UINT2__) - __cl_uint2 v2; -#endif -}cl_uint2; - -typedef union -{ - cl_uint CL_ALIGNED(16) s[4]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_uint x, y, z, w; }; - __extension__ struct{ cl_uint s0, s1, s2, s3; }; - __extension__ struct{ cl_uint2 lo, hi; }; -#endif -#if defined( __CL_UINT2__) - __cl_uint2 v2[2]; -#endif -#if defined( __CL_UINT4__) - __cl_uint4 v4; -#endif -}cl_uint4; - -/* cl_uint3 is identical in size, alignment and behavior to cl_uint4. See section 6.1.5. */ -typedef cl_uint4 cl_uint3; - -typedef union -{ - cl_uint CL_ALIGNED(32) s[8]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_uint x, y, z, w; }; - __extension__ struct{ cl_uint s0, s1, s2, s3, s4, s5, s6, s7; }; - __extension__ struct{ cl_uint4 lo, hi; }; -#endif -#if defined( __CL_UINT2__) - __cl_uint2 v2[4]; -#endif -#if defined( __CL_UINT4__) - __cl_uint4 v4[2]; -#endif -#if defined( __CL_UINT8__ ) - __cl_uint8 v8; -#endif -}cl_uint8; - -typedef union -{ - cl_uint CL_ALIGNED(64) s[16]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_uint x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; - __extension__ struct{ cl_uint s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; - __extension__ struct{ cl_uint8 lo, hi; }; -#endif -#if defined( __CL_UINT2__) - __cl_uint2 v2[8]; -#endif -#if defined( __CL_UINT4__) - __cl_uint4 v4[4]; -#endif -#if defined( __CL_UINT8__ ) - __cl_uint8 v8[2]; -#endif -#if defined( __CL_UINT16__ ) - __cl_uint16 v16; -#endif -}cl_uint16; - -/* ---- cl_longn ---- */ -typedef union -{ - cl_long CL_ALIGNED(16) s[2]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_long x, y; }; - __extension__ struct{ cl_long s0, s1; }; - __extension__ struct{ cl_long lo, hi; }; -#endif -#if defined( __CL_LONG2__) - __cl_long2 v2; -#endif -}cl_long2; - -typedef union -{ - cl_long CL_ALIGNED(32) s[4]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_long x, y, z, w; }; - __extension__ struct{ cl_long s0, s1, s2, s3; }; - __extension__ struct{ cl_long2 lo, hi; }; -#endif -#if defined( __CL_LONG2__) - __cl_long2 v2[2]; -#endif -#if defined( __CL_LONG4__) - __cl_long4 v4; -#endif -}cl_long4; - -/* cl_long3 is identical in size, alignment and behavior to cl_long4. See section 6.1.5. */ -typedef cl_long4 cl_long3; - -typedef union -{ - cl_long CL_ALIGNED(64) s[8]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_long x, y, z, w; }; - __extension__ struct{ cl_long s0, s1, s2, s3, s4, s5, s6, s7; }; - __extension__ struct{ cl_long4 lo, hi; }; -#endif -#if defined( __CL_LONG2__) - __cl_long2 v2[4]; -#endif -#if defined( __CL_LONG4__) - __cl_long4 v4[2]; -#endif -#if defined( __CL_LONG8__ ) - __cl_long8 v8; -#endif -}cl_long8; - -typedef union -{ - cl_long CL_ALIGNED(128) s[16]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_long x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; - __extension__ struct{ cl_long s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; - __extension__ struct{ cl_long8 lo, hi; }; -#endif -#if defined( __CL_LONG2__) - __cl_long2 v2[8]; -#endif -#if defined( __CL_LONG4__) - __cl_long4 v4[4]; -#endif -#if defined( __CL_LONG8__ ) - __cl_long8 v8[2]; -#endif -#if defined( __CL_LONG16__ ) - __cl_long16 v16; -#endif -}cl_long16; - - -/* ---- cl_ulongn ---- */ -typedef union -{ - cl_ulong CL_ALIGNED(16) s[2]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_ulong x, y; }; - __extension__ struct{ cl_ulong s0, s1; }; - __extension__ struct{ cl_ulong lo, hi; }; -#endif -#if defined( __CL_ULONG2__) - __cl_ulong2 v2; -#endif -}cl_ulong2; - -typedef union -{ - cl_ulong CL_ALIGNED(32) s[4]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_ulong x, y, z, w; }; - __extension__ struct{ cl_ulong s0, s1, s2, s3; }; - __extension__ struct{ cl_ulong2 lo, hi; }; -#endif -#if defined( __CL_ULONG2__) - __cl_ulong2 v2[2]; -#endif -#if defined( __CL_ULONG4__) - __cl_ulong4 v4; -#endif -}cl_ulong4; - -/* cl_ulong3 is identical in size, alignment and behavior to cl_ulong4. See section 6.1.5. */ -typedef cl_ulong4 cl_ulong3; - -typedef union -{ - cl_ulong CL_ALIGNED(64) s[8]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_ulong x, y, z, w; }; - __extension__ struct{ cl_ulong s0, s1, s2, s3, s4, s5, s6, s7; }; - __extension__ struct{ cl_ulong4 lo, hi; }; -#endif -#if defined( __CL_ULONG2__) - __cl_ulong2 v2[4]; -#endif -#if defined( __CL_ULONG4__) - __cl_ulong4 v4[2]; -#endif -#if defined( __CL_ULONG8__ ) - __cl_ulong8 v8; -#endif -}cl_ulong8; - -typedef union -{ - cl_ulong CL_ALIGNED(128) s[16]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_ulong x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; - __extension__ struct{ cl_ulong s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; - __extension__ struct{ cl_ulong8 lo, hi; }; -#endif -#if defined( __CL_ULONG2__) - __cl_ulong2 v2[8]; -#endif -#if defined( __CL_ULONG4__) - __cl_ulong4 v4[4]; -#endif -#if defined( __CL_ULONG8__ ) - __cl_ulong8 v8[2]; -#endif -#if defined( __CL_ULONG16__ ) - __cl_ulong16 v16; -#endif -}cl_ulong16; - - -/* --- cl_floatn ---- */ - -typedef union -{ - cl_float CL_ALIGNED(8) s[2]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_float x, y; }; - __extension__ struct{ cl_float s0, s1; }; - __extension__ struct{ cl_float lo, hi; }; -#endif -#if defined( __CL_FLOAT2__) - __cl_float2 v2; -#endif -}cl_float2; - -typedef union -{ - cl_float CL_ALIGNED(16) s[4]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_float x, y, z, w; }; - __extension__ struct{ cl_float s0, s1, s2, s3; }; - __extension__ struct{ cl_float2 lo, hi; }; -#endif -#if defined( __CL_FLOAT2__) - __cl_float2 v2[2]; -#endif -#if defined( __CL_FLOAT4__) - __cl_float4 v4; -#endif -}cl_float4; - -/* cl_float3 is identical in size, alignment and behavior to cl_float4. See section 6.1.5. */ -typedef cl_float4 cl_float3; - -typedef union -{ - cl_float CL_ALIGNED(32) s[8]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_float x, y, z, w; }; - __extension__ struct{ cl_float s0, s1, s2, s3, s4, s5, s6, s7; }; - __extension__ struct{ cl_float4 lo, hi; }; -#endif -#if defined( __CL_FLOAT2__) - __cl_float2 v2[4]; -#endif -#if defined( __CL_FLOAT4__) - __cl_float4 v4[2]; -#endif -#if defined( __CL_FLOAT8__ ) - __cl_float8 v8; -#endif -}cl_float8; - -typedef union -{ - cl_float CL_ALIGNED(64) s[16]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_float x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; - __extension__ struct{ cl_float s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; - __extension__ struct{ cl_float8 lo, hi; }; -#endif -#if defined( __CL_FLOAT2__) - __cl_float2 v2[8]; -#endif -#if defined( __CL_FLOAT4__) - __cl_float4 v4[4]; -#endif -#if defined( __CL_FLOAT8__ ) - __cl_float8 v8[2]; -#endif -#if defined( __CL_FLOAT16__ ) - __cl_float16 v16; -#endif -}cl_float16; - -/* --- cl_doublen ---- */ - -typedef union -{ - cl_double CL_ALIGNED(16) s[2]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_double x, y; }; - __extension__ struct{ cl_double s0, s1; }; - __extension__ struct{ cl_double lo, hi; }; -#endif -#if defined( __CL_DOUBLE2__) - __cl_double2 v2; -#endif -}cl_double2; - -typedef union -{ - cl_double CL_ALIGNED(32) s[4]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_double x, y, z, w; }; - __extension__ struct{ cl_double s0, s1, s2, s3; }; - __extension__ struct{ cl_double2 lo, hi; }; -#endif -#if defined( __CL_DOUBLE2__) - __cl_double2 v2[2]; -#endif -#if defined( __CL_DOUBLE4__) - __cl_double4 v4; -#endif -}cl_double4; - -/* cl_double3 is identical in size, alignment and behavior to cl_double4. See section 6.1.5. */ -typedef cl_double4 cl_double3; - -typedef union -{ - cl_double CL_ALIGNED(64) s[8]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_double x, y, z, w; }; - __extension__ struct{ cl_double s0, s1, s2, s3, s4, s5, s6, s7; }; - __extension__ struct{ cl_double4 lo, hi; }; -#endif -#if defined( __CL_DOUBLE2__) - __cl_double2 v2[4]; -#endif -#if defined( __CL_DOUBLE4__) - __cl_double4 v4[2]; -#endif -#if defined( __CL_DOUBLE8__ ) - __cl_double8 v8; -#endif -}cl_double8; - -typedef union -{ - cl_double CL_ALIGNED(128) s[16]; -#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) - __extension__ struct{ cl_double x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; - __extension__ struct{ cl_double s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; - __extension__ struct{ cl_double8 lo, hi; }; -#endif -#if defined( __CL_DOUBLE2__) - __cl_double2 v2[8]; -#endif -#if defined( __CL_DOUBLE4__) - __cl_double4 v4[4]; -#endif -#if defined( __CL_DOUBLE8__ ) - __cl_double8 v8[2]; -#endif -#if defined( __CL_DOUBLE16__ ) - __cl_double16 v16; -#endif -}cl_double16; - -/* Macro to facilitate debugging - * Usage: - * Place CL_PROGRAM_STRING_DEBUG_INFO on the line before the first line of your source. - * The first line ends with: CL_PROGRAM_STRING_DEBUG_INFO \" - * Each line thereafter of OpenCL C source must end with: \n\ - * The last line ends in "; - * - * Example: - * - * const char *my_program = CL_PROGRAM_STRING_DEBUG_INFO "\ - * kernel void foo( int a, float * b ) \n\ - * { \n\ - * // my comment \n\ - * *b[ get_global_id(0)] = a; \n\ - * } \n\ - * "; - * - * This should correctly set up the line, (column) and file information for your source - * string so you can do source level debugging. - */ -#define __CL_STRINGIFY( _x ) # _x -#define _CL_STRINGIFY( _x ) __CL_STRINGIFY( _x ) -#define CL_PROGRAM_STRING_DEBUG_INFO "#line " _CL_STRINGIFY(__LINE__) " \"" __FILE__ "\" \n\n" - -#ifdef __cplusplus -} -#endif - -#endif /* __CL_PLATFORM_H */ diff --git a/ext/CL/opencl.h b/ext/CL/opencl.h deleted file mode 100644 index 3f005247..00000000 --- a/ext/CL/opencl.h +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008-2012 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - ******************************************************************************/ - -/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */ - -#ifndef __OPENCL_H -#define __OPENCL_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __APPLE__ - -#include -#include -#include -#include - -#else - -#include -#include -#include -#include - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __OPENCL_H */ - diff --git a/ext/GLSL_Pathtracer/Camera.cpp b/ext/GLSL_Pathtracer/Camera.cpp index 72f40156..d6c21640 100644 --- a/ext/GLSL_Pathtracer/Camera.cpp +++ b/ext/GLSL_Pathtracer/Camera.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace GLSLPathTracer { @@ -55,4 +56,4 @@ namespace GLSLPathTracer right = glm::normalize(glm::cross(forward, worldUp)); up = glm::normalize(glm::cross(right, forward)); } -} \ No newline at end of file +} diff --git a/ext/GLSL_Pathtracer/Config.h b/ext/GLSL_Pathtracer/Config.h index ae0dc084..c2177396 100644 --- a/ext/GLSL_Pathtracer/Config.h +++ b/ext/GLSL_Pathtracer/Config.h @@ -2,4 +2,9 @@ #ifndef __EMSCRIPTEN__ #include +#endif + +#ifdef __EMSCRIPTEN__ +#include +#include #endif \ No newline at end of file diff --git a/ext/GLSL_Pathtracer/Loader.cpp b/ext/GLSL_Pathtracer/Loader.cpp index 4e527918..be74b4b4 100644 --- a/ext/GLSL_Pathtracer/Loader.cpp +++ b/ext/GLSL_Pathtracer/Loader.cpp @@ -31,14 +31,47 @@ freely, subject to the following restrictions: #include #include #include -#include #include "linear_math.h" #include "Scene.h" #include "Camera.h" - +//#include "bgfx/stb_image_aug.h" +unsigned char* stbi_load(char const* filename, int* x, int* y, int* channels_in_file, int desired_channels) +{ + return 0; +} namespace GLSLPathTracer { - + enum + { + SOIL_LOAD_AUTO = 0, + SOIL_LOAD_L = 1, + SOIL_LOAD_LA = 2, + SOIL_LOAD_RGB = 3, + SOIL_LOAD_RGBA = 4 + }; + + unsigned char* + SOIL_load_image + ( + const char* filename, + int* width, int* height, int* channels, + int force_channels + ) + { + unsigned char* result = stbi_load(filename, + width, height, channels, force_channels); + if (result == NULL) + { + //result_string_pointer = stbi_failure_reason(); + } + else + { + //result_string_pointer = "Image loaded"; + } + return result; + } + + #undef M_PI static const float M_PI = 3.14159265358979323846f; static const int kMaxLineLength = 2048; @@ -133,7 +166,7 @@ namespace GLSLPathTracer Scene* LoadScene(const std::string &filename) { FILE* file; - fopen_s(&file, filename.c_str(), "r"); + file = fopen(filename.c_str(), "r"); if (!file) { @@ -401,7 +434,7 @@ namespace GLSLPathTracer Log("Loading Model: %s\n", meshPath.c_str()); if (!LoadModel(scene, meshPath, materialId)) { - return false; + return nullptr; } } } @@ -456,4 +489,4 @@ namespace GLSLPathTracer return scene; } -} \ No newline at end of file +} diff --git a/ext/GLSL_Pathtracer/Program.cpp b/ext/GLSL_Pathtracer/Program.cpp index 8a33d21f..acfabba0 100644 --- a/ext/GLSL_Pathtracer/Program.cpp +++ b/ext/GLSL_Pathtracer/Program.cpp @@ -1,4 +1,5 @@ #include "Program.h" +#include namespace GLSLPathTracer { @@ -49,4 +50,4 @@ namespace GLSLPathTracer { return _object; } -} \ No newline at end of file +} diff --git a/ext/GLSL_Pathtracer/Quad.h b/ext/GLSL_Pathtracer/Quad.h index f7dbe362..c74ca4ed 100644 --- a/ext/GLSL_Pathtracer/Quad.h +++ b/ext/GLSL_Pathtracer/Quad.h @@ -10,6 +10,6 @@ namespace GLSLPathTracer Quad(); void Draw(Program *); private: - GLuint vao, vbo; + unsigned int vao, vbo; }; } \ No newline at end of file diff --git a/ext/GLSL_Pathtracer/Renderer.h b/ext/GLSL_Pathtracer/Renderer.h index 150f716b..8a5456e5 100644 --- a/ext/GLSL_Pathtracer/Renderer.h +++ b/ext/GLSL_Pathtracer/Renderer.h @@ -5,7 +5,6 @@ #include "Program.h" #include "GPUBVH.h" #include "Loader.h" -#include "SOIL.h" namespace GLSLPathTracer { diff --git a/ext/GLSL_Pathtracer/Shader.cpp b/ext/GLSL_Pathtracer/Shader.cpp index 1b2ee364..ec706861 100644 --- a/ext/GLSL_Pathtracer/Shader.cpp +++ b/ext/GLSL_Pathtracer/Shader.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace GLSLPathTracer { @@ -39,7 +40,7 @@ namespace GLSLPathTracer delete[] info; glDeleteShader(_object); _object = 0; - Log("Shader compilation error %s\n", msg); + Log("Shader compilation error %s\n", msg.c_str()); throw std::runtime_error(msg); } } diff --git a/ext/IconsFontAwesome5.h b/ext/IconsFontAwesome5.h new file mode 100644 index 00000000..9ed3f39f --- /dev/null +++ b/ext/IconsFontAwesome5.h @@ -0,0 +1,967 @@ +// Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for language C++11 +// from https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/metadata/icons.yml +// for use with https://github.com/FortAwesome/Font-Awesome/blob/master/webfonts/fa-solid-900.ttf, https://github.com/FortAwesome/Font-Awesome/blob/master/webfonts/fa-regular-400.ttf, +#pragma once + +#define FONT_ICON_FILE_NAME_FAR "fa-regular-400.ttf" +#define FONT_ICON_FILE_NAME_FAS "fa-solid-900.ttf" + +#define ICON_MIN_FA 0xf000 +#define ICON_MAX_FA 0xf897 +#define ICON_FA_CLOUD_SHOWERS_HEAVY u8"\uf740" +#define ICON_FA_CHEVRON_CIRCLE_RIGHT u8"\uf138" +#define ICON_FA_DHARMACHAKRA u8"\uf655" +#define ICON_FA_BROADCAST_TOWER u8"\uf519" +#define ICON_FA_EXTERNAL_LINK_SQUARE_ALT u8"\uf360" +#define ICON_FA_SMOKING u8"\uf48d" +#define ICON_FA_PENCIL_ALT u8"\uf303" +#define ICON_FA_CHESS_BISHOP u8"\uf43a" +#define ICON_FA_ICONS u8"\uf86d" +#define ICON_FA_TV u8"\uf26c" +#define ICON_FA_CROP_ALT u8"\uf565" +#define ICON_FA_LIST u8"\uf03a" +#define ICON_FA_BATTERY_QUARTER u8"\uf243" +#define ICON_FA_TH u8"\uf00a" +#define ICON_FA_RECYCLE u8"\uf1b8" +#define ICON_FA_SMILE u8"\uf118" +#define ICON_FA_FAX u8"\uf1ac" +#define ICON_FA_DRAFTING_COMPASS u8"\uf568" +#define ICON_FA_USER_INJURED u8"\uf728" +#define ICON_FA_SCREWDRIVER u8"\uf54a" +#define ICON_FA_CROSSHAIRS u8"\uf05b" +#define ICON_FA_HAND_PEACE u8"\uf25b" +#define ICON_FA_FAN u8"\uf863" +#define ICON_FA_GOPURAM u8"\uf664" +#define ICON_FA_CARET_UP u8"\uf0d8" +#define ICON_FA_SCHOOL u8"\uf549" +#define ICON_FA_FILE_PDF u8"\uf1c1" +#define ICON_FA_USERS_COG u8"\uf509" +#define ICON_FA_BALANCE_SCALE u8"\uf24e" +#define ICON_FA_UPLOAD u8"\uf093" +#define ICON_FA_LAPTOP_MEDICAL u8"\uf812" +#define ICON_FA_VENUS u8"\uf221" +#define ICON_FA_HEADING u8"\uf1dc" +#define ICON_FA_ARROW_DOWN u8"\uf063" +#define ICON_FA_BICYCLE u8"\uf206" +#define ICON_FA_TIRED u8"\uf5c8" +#define ICON_FA_COMMENT_MEDICAL u8"\uf7f5" +#define ICON_FA_BACON u8"\uf7e5" +#define ICON_FA_SYNC u8"\uf021" +#define ICON_FA_PAPER_PLANE u8"\uf1d8" +#define ICON_FA_VOLLEYBALL_BALL u8"\uf45f" +#define ICON_FA_RIBBON u8"\uf4d6" +#define ICON_FA_SQUARE_ROOT_ALT u8"\uf698" +#define ICON_FA_SUN u8"\uf185" +#define ICON_FA_FILE_POWERPOINT u8"\uf1c4" +#define ICON_FA_MICROCHIP u8"\uf2db" +#define ICON_FA_TRASH_RESTORE_ALT u8"\uf82a" +#define ICON_FA_GRADUATION_CAP u8"\uf19d" +#define ICON_FA_INFO_CIRCLE u8"\uf05a" +#define ICON_FA_TAGS u8"\uf02c" +#define ICON_FA_HAND_PAPER u8"\uf256" +#define ICON_FA_EQUALS u8"\uf52c" +#define ICON_FA_DIRECTIONS u8"\uf5eb" +#define ICON_FA_FILE_INVOICE u8"\uf570" +#define ICON_FA_SEARCH u8"\uf002" +#define ICON_FA_BIBLE u8"\uf647" +#define ICON_FA_DUMBBELL u8"\uf44b" +#define ICON_FA_WEIGHT_HANGING u8"\uf5cd" +#define ICON_FA_CALENDAR_TIMES u8"\uf273" +#define ICON_FA_GREATER_THAN_EQUAL u8"\uf532" +#define ICON_FA_SLIDERS_H u8"\uf1de" +#define ICON_FA_EYE_SLASH u8"\uf070" +#define ICON_FA_BIRTHDAY_CAKE u8"\uf1fd" +#define ICON_FA_FEATHER_ALT u8"\uf56b" +#define ICON_FA_DNA u8"\uf471" +#define ICON_FA_BASEBALL_BALL u8"\uf433" +#define ICON_FA_HOSPITAL u8"\uf0f8" +#define ICON_FA_COINS u8"\uf51e" +#define ICON_FA_TEMPERATURE_HIGH u8"\uf769" +#define ICON_FA_FONT_AWESOME_LOGO_FULL u8"\uf4e6" +#define ICON_FA_PASSPORT u8"\uf5ab" +#define ICON_FA_SHOPPING_CART u8"\uf07a" +#define ICON_FA_AWARD u8"\uf559" +#define ICON_FA_WINDOW_RESTORE u8"\uf2d2" +#define ICON_FA_PHONE u8"\uf095" +#define ICON_FA_FLAG u8"\uf024" +#define ICON_FA_FILE_INVOICE_DOLLAR u8"\uf571" +#define ICON_FA_DICE_D6 u8"\uf6d1" +#define ICON_FA_OUTDENT u8"\uf03b" +#define ICON_FA_LONG_ARROW_ALT_RIGHT u8"\uf30b" +#define ICON_FA_PIZZA_SLICE u8"\uf818" +#define ICON_FA_ADDRESS_CARD u8"\uf2bb" +#define ICON_FA_PARAGRAPH u8"\uf1dd" +#define ICON_FA_MALE u8"\uf183" +#define ICON_FA_HISTORY u8"\uf1da" +#define ICON_FA_USER_TIE u8"\uf508" +#define ICON_FA_SEARCH_PLUS u8"\uf00e" +#define ICON_FA_LIFE_RING u8"\uf1cd" +#define ICON_FA_STEP_FORWARD u8"\uf051" +#define ICON_FA_MOUSE_POINTER u8"\uf245" +#define ICON_FA_ALIGN_JUSTIFY u8"\uf039" +#define ICON_FA_TOILET_PAPER u8"\uf71e" +#define ICON_FA_BATTERY_THREE_QUARTERS u8"\uf241" +#define ICON_FA_OBJECT_UNGROUP u8"\uf248" +#define ICON_FA_BRIEFCASE u8"\uf0b1" +#define ICON_FA_OIL_CAN u8"\uf613" +#define ICON_FA_THERMOMETER_FULL u8"\uf2c7" +#define ICON_FA_SNOWBOARDING u8"\uf7ce" +#define ICON_FA_UNLINK u8"\uf127" +#define ICON_FA_WINDOW_MAXIMIZE u8"\uf2d0" +#define ICON_FA_YEN_SIGN u8"\uf157" +#define ICON_FA_SHARE_ALT_SQUARE u8"\uf1e1" +#define ICON_FA_STEP_BACKWARD u8"\uf048" +#define ICON_FA_DRAGON u8"\uf6d5" +#define ICON_FA_MICROPHONE_SLASH u8"\uf131" +#define ICON_FA_USER_PLUS u8"\uf234" +#define ICON_FA_WRENCH u8"\uf0ad" +#define ICON_FA_AMBULANCE u8"\uf0f9" +#define ICON_FA_ETHERNET u8"\uf796" +#define ICON_FA_EGG u8"\uf7fb" +#define ICON_FA_WIND u8"\uf72e" +#define ICON_FA_UNIVERSAL_ACCESS u8"\uf29a" +#define ICON_FA_BURN u8"\uf46a" +#define ICON_FA_RADIATION u8"\uf7b9" +#define ICON_FA_DICE_ONE u8"\uf525" +#define ICON_FA_KEYBOARD u8"\uf11c" +#define ICON_FA_CHECK_DOUBLE u8"\uf560" +#define ICON_FA_HEADPHONES_ALT u8"\uf58f" +#define ICON_FA_BATTERY_HALF u8"\uf242" +#define ICON_FA_PROJECT_DIAGRAM u8"\uf542" +#define ICON_FA_PRAY u8"\uf683" +#define ICON_FA_PHONE_ALT u8"\uf879" +#define ICON_FA_BABY_CARRIAGE u8"\uf77d" +#define ICON_FA_TH_LIST u8"\uf00b" +#define ICON_FA_GRIN_TEARS u8"\uf588" +#define ICON_FA_SORT_AMOUNT_UP u8"\uf161" +#define ICON_FA_COFFEE u8"\uf0f4" +#define ICON_FA_TABLET_ALT u8"\uf3fa" +#define ICON_FA_GRIN_BEAM_SWEAT u8"\uf583" +#define ICON_FA_HAND_POINT_RIGHT u8"\uf0a4" +#define ICON_FA_GRIN_STARS u8"\uf587" +#define ICON_FA_CHARGING_STATION u8"\uf5e7" +#define ICON_FA_VOTE_YEA u8"\uf772" +#define ICON_FA_VOLUME_OFF u8"\uf026" +#define ICON_FA_SAD_TEAR u8"\uf5b4" +#define ICON_FA_CARET_RIGHT u8"\uf0da" +#define ICON_FA_BONG u8"\uf55c" +#define ICON_FA_BONE u8"\uf5d7" +#define ICON_FA_WEIGHT u8"\uf496" +#define ICON_FA_CARET_SQUARE_RIGHT u8"\uf152" +#define ICON_FA_FISH u8"\uf578" +#define ICON_FA_SPIDER u8"\uf717" +#define ICON_FA_QRCODE u8"\uf029" +#define ICON_FA_SPINNER u8"\uf110" +#define ICON_FA_ELLIPSIS_H u8"\uf141" +#define ICON_FA_RUPEE_SIGN u8"\uf156" +#define ICON_FA_ASSISTIVE_LISTENING_SYSTEMS u8"\uf2a2" +#define ICON_FA_SMS u8"\uf7cd" +#define ICON_FA_POUND_SIGN u8"\uf154" +#define ICON_FA_HAND_POINT_DOWN u8"\uf0a7" +#define ICON_FA_ADJUST u8"\uf042" +#define ICON_FA_PRINT u8"\uf02f" +#define ICON_FA_SURPRISE u8"\uf5c2" +#define ICON_FA_SORT_NUMERIC_UP u8"\uf163" +#define ICON_FA_VIDEO_SLASH u8"\uf4e2" +#define ICON_FA_SUBWAY u8"\uf239" +#define ICON_FA_SORT_AMOUNT_DOWN u8"\uf160" +#define ICON_FA_WINE_BOTTLE u8"\uf72f" +#define ICON_FA_BOOK_READER u8"\uf5da" +#define ICON_FA_COOKIE u8"\uf563" +#define ICON_FA_MONEY_BILL u8"\uf0d6" +#define ICON_FA_CHEVRON_DOWN u8"\uf078" +#define ICON_FA_CAR_SIDE u8"\uf5e4" +#define ICON_FA_FILTER u8"\uf0b0" +#define ICON_FA_FOLDER_OPEN u8"\uf07c" +#define ICON_FA_SIGNATURE u8"\uf5b7" +#define ICON_FA_HEARTBEAT u8"\uf21e" +#define ICON_FA_THUMBTACK u8"\uf08d" +#define ICON_FA_USER u8"\uf007" +#define ICON_FA_LAUGH_WINK u8"\uf59c" +#define ICON_FA_BREAD_SLICE u8"\uf7ec" +#define ICON_FA_TEXT_HEIGHT u8"\uf034" +#define ICON_FA_VOLUME_MUTE u8"\uf6a9" +#define ICON_FA_GRIN_TONGUE u8"\uf589" +#define ICON_FA_CAMPGROUND u8"\uf6bb" +#define ICON_FA_MERCURY u8"\uf223" +#define ICON_FA_USER_ASTRONAUT u8"\uf4fb" +#define ICON_FA_HORSE u8"\uf6f0" +#define ICON_FA_SORT_DOWN u8"\uf0dd" +#define ICON_FA_PERCENTAGE u8"\uf541" +#define ICON_FA_AIR_FRESHENER u8"\uf5d0" +#define ICON_FA_STORE u8"\uf54e" +#define ICON_FA_COMMENT_DOTS u8"\uf4ad" +#define ICON_FA_SMILE_WINK u8"\uf4da" +#define ICON_FA_HOTEL u8"\uf594" +#define ICON_FA_PEPPER_HOT u8"\uf816" +#define ICON_FA_CUBES u8"\uf1b3" +#define ICON_FA_DUMPSTER_FIRE u8"\uf794" +#define ICON_FA_CLOUD_SUN_RAIN u8"\uf743" +#define ICON_FA_GLOBE_ASIA u8"\uf57e" +#define ICON_FA_VIAL u8"\uf492" +#define ICON_FA_STROOPWAFEL u8"\uf551" +#define ICON_FA_CALENDAR_MINUS u8"\uf272" +#define ICON_FA_TREE u8"\uf1bb" +#define ICON_FA_SHOWER u8"\uf2cc" +#define ICON_FA_DRUM_STEELPAN u8"\uf56a" +#define ICON_FA_FILE_UPLOAD u8"\uf574" +#define ICON_FA_MEDKIT u8"\uf0fa" +#define ICON_FA_MINUS u8"\uf068" +#define ICON_FA_SHEKEL_SIGN u8"\uf20b" +#define ICON_FA_USER_NINJA u8"\uf504" +#define ICON_FA_KAABA u8"\uf66b" +#define ICON_FA_BELL_SLASH u8"\uf1f6" +#define ICON_FA_SPELL_CHECK u8"\uf891" +#define ICON_FA_MAIL_BULK u8"\uf674" +#define ICON_FA_MOUNTAIN u8"\uf6fc" +#define ICON_FA_COUCH u8"\uf4b8" +#define ICON_FA_CHESS u8"\uf439" +#define ICON_FA_FILE_EXPORT u8"\uf56e" +#define ICON_FA_SIGN_LANGUAGE u8"\uf2a7" +#define ICON_FA_SNOWFLAKE u8"\uf2dc" +#define ICON_FA_PLAY u8"\uf04b" +#define ICON_FA_HEADSET u8"\uf590" +#define ICON_FA_CHART_BAR u8"\uf080" +#define ICON_FA_WAVE_SQUARE u8"\uf83e" +#define ICON_FA_CHART_AREA u8"\uf1fe" +#define ICON_FA_EURO_SIGN u8"\uf153" +#define ICON_FA_CHESS_KING u8"\uf43f" +#define ICON_FA_MOBILE u8"\uf10b" +#define ICON_FA_CLOCK u8"\uf017" +#define ICON_FA_BOX_OPEN u8"\uf49e" +#define ICON_FA_DOG u8"\uf6d3" +#define ICON_FA_FUTBOL u8"\uf1e3" +#define ICON_FA_LIRA_SIGN u8"\uf195" +#define ICON_FA_LIGHTBULB u8"\uf0eb" +#define ICON_FA_BOMB u8"\uf1e2" +#define ICON_FA_MITTEN u8"\uf7b5" +#define ICON_FA_TRUCK_MONSTER u8"\uf63b" +#define ICON_FA_RANDOM u8"\uf074" +#define ICON_FA_CHESS_ROOK u8"\uf447" +#define ICON_FA_FIRE_EXTINGUISHER u8"\uf134" +#define ICON_FA_ARROWS_ALT_V u8"\uf338" +#define ICON_FA_ICICLES u8"\uf7ad" +#define ICON_FA_FONT u8"\uf031" +#define ICON_FA_CAMERA_RETRO u8"\uf083" +#define ICON_FA_BLENDER u8"\uf517" +#define ICON_FA_THUMBS_DOWN u8"\uf165" +#define ICON_FA_ROCKET u8"\uf135" +#define ICON_FA_COPYRIGHT u8"\uf1f9" +#define ICON_FA_TRAM u8"\uf7da" +#define ICON_FA_JEDI u8"\uf669" +#define ICON_FA_HOCKEY_PUCK u8"\uf453" +#define ICON_FA_STOP_CIRCLE u8"\uf28d" +#define ICON_FA_BEZIER_CURVE u8"\uf55b" +#define ICON_FA_FOLDER u8"\uf07b" +#define ICON_FA_CALENDAR_CHECK u8"\uf274" +#define ICON_FA_YIN_YANG u8"\uf6ad" +#define ICON_FA_COLUMNS u8"\uf0db" +#define ICON_FA_GLASS_CHEERS u8"\uf79f" +#define ICON_FA_GRIN_WINK u8"\uf58c" +#define ICON_FA_STOP u8"\uf04d" +#define ICON_FA_MONEY_CHECK_ALT u8"\uf53d" +#define ICON_FA_COMPASS u8"\uf14e" +#define ICON_FA_TOOLBOX u8"\uf552" +#define ICON_FA_LIST_OL u8"\uf0cb" +#define ICON_FA_WINE_GLASS u8"\uf4e3" +#define ICON_FA_HORSE_HEAD u8"\uf7ab" +#define ICON_FA_USER_ALT_SLASH u8"\uf4fa" +#define ICON_FA_USER_TAG u8"\uf507" +#define ICON_FA_MICROSCOPE u8"\uf610" +#define ICON_FA_BRUSH u8"\uf55d" +#define ICON_FA_BAN u8"\uf05e" +#define ICON_FA_BARS u8"\uf0c9" +#define ICON_FA_CAR_CRASH u8"\uf5e1" +#define ICON_FA_ARROW_ALT_CIRCLE_DOWN u8"\uf358" +#define ICON_FA_MONEY_BILL_ALT u8"\uf3d1" +#define ICON_FA_JOURNAL_WHILLS u8"\uf66a" +#define ICON_FA_CHALKBOARD_TEACHER u8"\uf51c" +#define ICON_FA_PORTRAIT u8"\uf3e0" +#define ICON_FA_BALANCE_SCALE_LEFT u8"\uf515" +#define ICON_FA_HAMMER u8"\uf6e3" +#define ICON_FA_RETWEET u8"\uf079" +#define ICON_FA_HOURGLASS u8"\uf254" +#define ICON_FA_BORDER_NONE u8"\uf850" +#define ICON_FA_FILE_ALT u8"\uf15c" +#define ICON_FA_SUBSCRIPT u8"\uf12c" +#define ICON_FA_DONATE u8"\uf4b9" +#define ICON_FA_GLASS_MARTINI_ALT u8"\uf57b" +#define ICON_FA_CODE_BRANCH u8"\uf126" +#define ICON_FA_MEH u8"\uf11a" +#define ICON_FA_LIST_ALT u8"\uf022" +#define ICON_FA_USER_COG u8"\uf4fe" +#define ICON_FA_PRESCRIPTION u8"\uf5b1" +#define ICON_FA_TABLET u8"\uf10a" +#define ICON_FA_LAUGH_SQUINT u8"\uf59b" +#define ICON_FA_CREDIT_CARD u8"\uf09d" +#define ICON_FA_ARCHWAY u8"\uf557" +#define ICON_FA_HARD_HAT u8"\uf807" +#define ICON_FA_TRAFFIC_LIGHT u8"\uf637" +#define ICON_FA_COG u8"\uf013" +#define ICON_FA_HANUKIAH u8"\uf6e6" +#define ICON_FA_SHUTTLE_VAN u8"\uf5b6" +#define ICON_FA_MONEY_CHECK u8"\uf53c" +#define ICON_FA_BELL u8"\uf0f3" +#define ICON_FA_CALENDAR_DAY u8"\uf783" +#define ICON_FA_TINT_SLASH u8"\uf5c7" +#define ICON_FA_PLANE_DEPARTURE u8"\uf5b0" +#define ICON_FA_USER_CHECK u8"\uf4fc" +#define ICON_FA_CHURCH u8"\uf51d" +#define ICON_FA_SEARCH_MINUS u8"\uf010" +#define ICON_FA_SHIPPING_FAST u8"\uf48b" +#define ICON_FA_TINT u8"\uf043" +#define ICON_FA_ALIGN_RIGHT u8"\uf038" +#define ICON_FA_QUOTE_RIGHT u8"\uf10e" +#define ICON_FA_BEER u8"\uf0fc" +#define ICON_FA_GRIN_ALT u8"\uf581" +#define ICON_FA_SORT_NUMERIC_DOWN u8"\uf162" +#define ICON_FA_FIRE u8"\uf06d" +#define ICON_FA_FAST_FORWARD u8"\uf050" +#define ICON_FA_MAP_MARKED_ALT u8"\uf5a0" +#define ICON_FA_CHILD u8"\uf1ae" +#define ICON_FA_KISS_BEAM u8"\uf597" +#define ICON_FA_TRUCK_LOADING u8"\uf4de" +#define ICON_FA_EXPAND_ARROWS_ALT u8"\uf31e" +#define ICON_FA_CARET_SQUARE_DOWN u8"\uf150" +#define ICON_FA_CRUTCH u8"\uf7f7" +#define ICON_FA_OBJECT_GROUP u8"\uf247" +#define ICON_FA_BIKING u8"\uf84a" +#define ICON_FA_ANCHOR u8"\uf13d" +#define ICON_FA_HAND_POINT_LEFT u8"\uf0a5" +#define ICON_FA_USER_TIMES u8"\uf235" +#define ICON_FA_CALCULATOR u8"\uf1ec" +#define ICON_FA_DIZZY u8"\uf567" +#define ICON_FA_KISS_WINK_HEART u8"\uf598" +#define ICON_FA_FILE_MEDICAL u8"\uf477" +#define ICON_FA_SWIMMING_POOL u8"\uf5c5" +#define ICON_FA_VR_CARDBOARD u8"\uf729" +#define ICON_FA_USER_FRIENDS u8"\uf500" +#define ICON_FA_FAST_BACKWARD u8"\uf049" +#define ICON_FA_SATELLITE u8"\uf7bf" +#define ICON_FA_MINUS_CIRCLE u8"\uf056" +#define ICON_FA_CHESS_PAWN u8"\uf443" +#define ICON_FA_DATABASE u8"\uf1c0" +#define ICON_FA_LANDMARK u8"\uf66f" +#define ICON_FA_SWATCHBOOK u8"\uf5c3" +#define ICON_FA_HOTDOG u8"\uf80f" +#define ICON_FA_SNOWMAN u8"\uf7d0" +#define ICON_FA_LAPTOP u8"\uf109" +#define ICON_FA_TORAH u8"\uf6a0" +#define ICON_FA_FROWN_OPEN u8"\uf57a" +#define ICON_FA_REDO_ALT u8"\uf2f9" +#define ICON_FA_AD u8"\uf641" +#define ICON_FA_USER_CIRCLE u8"\uf2bd" +#define ICON_FA_DIVIDE u8"\uf529" +#define ICON_FA_HANDSHAKE u8"\uf2b5" +#define ICON_FA_CUT u8"\uf0c4" +#define ICON_FA_GAMEPAD u8"\uf11b" +#define ICON_FA_STREET_VIEW u8"\uf21d" +#define ICON_FA_GREATER_THAN u8"\uf531" +#define ICON_FA_PASTAFARIANISM u8"\uf67b" +#define ICON_FA_MINUS_SQUARE u8"\uf146" +#define ICON_FA_SAVE u8"\uf0c7" +#define ICON_FA_COMMENT_DOLLAR u8"\uf651" +#define ICON_FA_TRASH_ALT u8"\uf2ed" +#define ICON_FA_PUZZLE_PIECE u8"\uf12e" +#define ICON_FA_SORT_ALPHA_UP_ALT u8"\uf882" +#define ICON_FA_MENORAH u8"\uf676" +#define ICON_FA_CLOUD_SUN u8"\uf6c4" +#define ICON_FA_USER_EDIT u8"\uf4ff" +#define ICON_FA_THEATER_MASKS u8"\uf630" +#define ICON_FA_FILE_MEDICAL_ALT u8"\uf478" +#define ICON_FA_BOXES u8"\uf468" +#define ICON_FA_THERMOMETER_EMPTY u8"\uf2cb" +#define ICON_FA_EXCLAMATION_TRIANGLE u8"\uf071" +#define ICON_FA_GIFT u8"\uf06b" +#define ICON_FA_COGS u8"\uf085" +#define ICON_FA_SIGNAL u8"\uf012" +#define ICON_FA_SHAPES u8"\uf61f" +#define ICON_FA_CLOUD_RAIN u8"\uf73d" +#define ICON_FA_LESS_THAN_EQUAL u8"\uf537" +#define ICON_FA_CHEVRON_CIRCLE_LEFT u8"\uf137" +#define ICON_FA_MORTAR_PESTLE u8"\uf5a7" +#define ICON_FA_SITEMAP u8"\uf0e8" +#define ICON_FA_BUS_ALT u8"\uf55e" +#define ICON_FA_FILE_CODE u8"\uf1c9" +#define ICON_FA_BATTERY_FULL u8"\uf240" +#define ICON_FA_CROWN u8"\uf521" +#define ICON_FA_EXCHANGE_ALT u8"\uf362" +#define ICON_FA_TRANSGENDER_ALT u8"\uf225" +#define ICON_FA_STAR_OF_DAVID u8"\uf69a" +#define ICON_FA_CASH_REGISTER u8"\uf788" +#define ICON_FA_TOOLS u8"\uf7d9" +#define ICON_FA_EXCLAMATION_CIRCLE u8"\uf06a" +#define ICON_FA_COMMENTS u8"\uf086" +#define ICON_FA_BRIEFCASE_MEDICAL u8"\uf469" +#define ICON_FA_COMMENTS_DOLLAR u8"\uf653" +#define ICON_FA_BACKSPACE u8"\uf55a" +#define ICON_FA_SLASH u8"\uf715" +#define ICON_FA_HOT_TUB u8"\uf593" +#define ICON_FA_SUITCASE_ROLLING u8"\uf5c1" +#define ICON_FA_BOLD u8"\uf032" +#define ICON_FA_HANDS_HELPING u8"\uf4c4" +#define ICON_FA_SLEIGH u8"\uf7cc" +#define ICON_FA_BOLT u8"\uf0e7" +#define ICON_FA_THERMOMETER_QUARTER u8"\uf2ca" +#define ICON_FA_TROPHY u8"\uf091" +#define ICON_FA_USER_ALT u8"\uf406" +#define ICON_FA_BRAILLE u8"\uf2a1" +#define ICON_FA_PLUS u8"\uf067" +#define ICON_FA_LIST_UL u8"\uf0ca" +#define ICON_FA_SMOKING_BAN u8"\uf54d" +#define ICON_FA_BOOK u8"\uf02d" +#define ICON_FA_VOLUME_DOWN u8"\uf027" +#define ICON_FA_QUESTION_CIRCLE u8"\uf059" +#define ICON_FA_CARROT u8"\uf787" +#define ICON_FA_BATH u8"\uf2cd" +#define ICON_FA_GAVEL u8"\uf0e3" +#define ICON_FA_CANDY_CANE u8"\uf786" +#define ICON_FA_NETWORK_WIRED u8"\uf6ff" +#define ICON_FA_CARET_SQUARE_LEFT u8"\uf191" +#define ICON_FA_PLANE_ARRIVAL u8"\uf5af" +#define ICON_FA_SHARE_SQUARE u8"\uf14d" +#define ICON_FA_MEDAL u8"\uf5a2" +#define ICON_FA_THERMOMETER_HALF u8"\uf2c9" +#define ICON_FA_QUESTION u8"\uf128" +#define ICON_FA_CAR_BATTERY u8"\uf5df" +#define ICON_FA_DOOR_CLOSED u8"\uf52a" +#define ICON_FA_USER_MINUS u8"\uf503" +#define ICON_FA_MUSIC u8"\uf001" +#define ICON_FA_HOUSE_DAMAGE u8"\uf6f1" +#define ICON_FA_CHEVRON_RIGHT u8"\uf054" +#define ICON_FA_GRIP_HORIZONTAL u8"\uf58d" +#define ICON_FA_DICE_FOUR u8"\uf524" +#define ICON_FA_DEAF u8"\uf2a4" +#define ICON_FA_MEH_BLANK u8"\uf5a4" +#define ICON_FA_WINDOW_CLOSE u8"\uf410" +#define ICON_FA_LINK u8"\uf0c1" +#define ICON_FA_ATOM u8"\uf5d2" +#define ICON_FA_LESS_THAN u8"\uf536" +#define ICON_FA_OTTER u8"\uf700" +#define ICON_FA_DICE_TWO u8"\uf528" +#define ICON_FA_SORT_ALPHA_DOWN_ALT u8"\uf881" +#define ICON_FA_EJECT u8"\uf052" +#define ICON_FA_SKULL u8"\uf54c" +#define ICON_FA_GRIP_LINES u8"\uf7a4" +#define ICON_FA_SORT_AMOUNT_DOWN_ALT u8"\uf884" +#define ICON_FA_HOSPITAL_SYMBOL u8"\uf47e" +#define ICON_FA_X_RAY u8"\uf497" +#define ICON_FA_ARROW_UP u8"\uf062" +#define ICON_FA_MONEY_BILL_WAVE u8"\uf53a" +#define ICON_FA_DOT_CIRCLE u8"\uf192" +#define ICON_FA_IMAGES u8"\uf302" +#define ICON_FA_STAR_HALF u8"\uf089" +#define ICON_FA_SPLOTCH u8"\uf5bc" +#define ICON_FA_STAR_HALF_ALT u8"\uf5c0" +#define ICON_FA_SHIP u8"\uf21a" +#define ICON_FA_BOOK_DEAD u8"\uf6b7" +#define ICON_FA_CHECK u8"\uf00c" +#define ICON_FA_RAINBOW u8"\uf75b" +#define ICON_FA_POWER_OFF u8"\uf011" +#define ICON_FA_LEMON u8"\uf094" +#define ICON_FA_GLOBE_AMERICAS u8"\uf57d" +#define ICON_FA_PEACE u8"\uf67c" +#define ICON_FA_THERMOMETER_THREE_QUARTERS u8"\uf2c8" +#define ICON_FA_WAREHOUSE u8"\uf494" +#define ICON_FA_TRANSGENDER u8"\uf224" +#define ICON_FA_PLUS_SQUARE u8"\uf0fe" +#define ICON_FA_BULLSEYE u8"\uf140" +#define ICON_FA_COOKIE_BITE u8"\uf564" +#define ICON_FA_USERS u8"\uf0c0" +#define ICON_FA_DRUMSTICK_BITE u8"\uf6d7" +#define ICON_FA_ASTERISK u8"\uf069" +#define ICON_FA_PLUS_CIRCLE u8"\uf055" +#define ICON_FA_CART_ARROW_DOWN u8"\uf218" +#define ICON_FA_LEAF u8"\uf06c" +#define ICON_FA_FLUSHED u8"\uf579" +#define ICON_FA_STORE_ALT u8"\uf54f" +#define ICON_FA_PEOPLE_CARRY u8"\uf4ce" +#define ICON_FA_CHESS_BOARD u8"\uf43c" +#define ICON_FA_LONG_ARROW_ALT_DOWN u8"\uf309" +#define ICON_FA_SAD_CRY u8"\uf5b3" +#define ICON_FA_DIGITAL_TACHOGRAPH u8"\uf566" +#define ICON_FA_ANGLE_DOUBLE_DOWN u8"\uf103" +#define ICON_FA_FILE_EXCEL u8"\uf1c3" +#define ICON_FA_TEETH u8"\uf62e" +#define ICON_FA_HAND_SCISSORS u8"\uf257" +#define ICON_FA_STETHOSCOPE u8"\uf0f1" +#define ICON_FA_BACKWARD u8"\uf04a" +#define ICON_FA_SCROLL u8"\uf70e" +#define ICON_FA_IGLOO u8"\uf7ae" +#define ICON_FA_NOTES_MEDICAL u8"\uf481" +#define ICON_FA_CODE u8"\uf121" +#define ICON_FA_SORT_NUMERIC_UP_ALT u8"\uf887" +#define ICON_FA_NOT_EQUAL u8"\uf53e" +#define ICON_FA_SKIING u8"\uf7c9" +#define ICON_FA_CHAIR u8"\uf6c0" +#define ICON_FA_HAND_LIZARD u8"\uf258" +#define ICON_FA_QUIDDITCH u8"\uf458" +#define ICON_FA_ANGLE_DOUBLE_LEFT u8"\uf100" +#define ICON_FA_MOSQUE u8"\uf678" +#define ICON_FA_PEN u8"\uf304" +#define ICON_FA_HRYVNIA u8"\uf6f2" +#define ICON_FA_ANGLE_LEFT u8"\uf104" +#define ICON_FA_ATLAS u8"\uf558" +#define ICON_FA_PIGGY_BANK u8"\uf4d3" +#define ICON_FA_DOLLY_FLATBED u8"\uf474" +#define ICON_FA_ARROWS_ALT_H u8"\uf337" +#define ICON_FA_PEN_ALT u8"\uf305" +#define ICON_FA_PRAYING_HANDS u8"\uf684" +#define ICON_FA_VOLUME_UP u8"\uf028" +#define ICON_FA_CLIPBOARD_LIST u8"\uf46d" +#define ICON_FA_BORDER_ALL u8"\uf84c" +#define ICON_FA_MAGIC u8"\uf0d0" +#define ICON_FA_FOLDER_MINUS u8"\uf65d" +#define ICON_FA_DEMOCRAT u8"\uf747" +#define ICON_FA_MAGNET u8"\uf076" +#define ICON_FA_VIHARA u8"\uf6a7" +#define ICON_FA_GRIMACE u8"\uf57f" +#define ICON_FA_CHECK_CIRCLE u8"\uf058" +#define ICON_FA_SEARCH_DOLLAR u8"\uf688" +#define ICON_FA_LONG_ARROW_ALT_LEFT u8"\uf30a" +#define ICON_FA_FILE_PRESCRIPTION u8"\uf572" +#define ICON_FA_CROW u8"\uf520" +#define ICON_FA_EYE_DROPPER u8"\uf1fb" +#define ICON_FA_CROP u8"\uf125" +#define ICON_FA_SIGN u8"\uf4d9" +#define ICON_FA_ARROW_CIRCLE_DOWN u8"\uf0ab" +#define ICON_FA_VIDEO u8"\uf03d" +#define ICON_FA_DOWNLOAD u8"\uf019" +#define ICON_FA_CARET_DOWN u8"\uf0d7" +#define ICON_FA_CHEVRON_LEFT u8"\uf053" +#define ICON_FA_GLOBE_AFRICA u8"\uf57c" +#define ICON_FA_HAMSA u8"\uf665" +#define ICON_FA_CART_PLUS u8"\uf217" +#define ICON_FA_CLIPBOARD u8"\uf328" +#define ICON_FA_SHOE_PRINTS u8"\uf54b" +#define ICON_FA_PHONE_SLASH u8"\uf3dd" +#define ICON_FA_REPLY u8"\uf3e5" +#define ICON_FA_HOURGLASS_HALF u8"\uf252" +#define ICON_FA_LONG_ARROW_ALT_UP u8"\uf30c" +#define ICON_FA_CHESS_KNIGHT u8"\uf441" +#define ICON_FA_BARCODE u8"\uf02a" +#define ICON_FA_DRAW_POLYGON u8"\uf5ee" +#define ICON_FA_WATER u8"\uf773" +#define ICON_FA_WINE_GLASS_ALT u8"\uf5ce" +#define ICON_FA_PHONE_VOLUME u8"\uf2a0" +#define ICON_FA_GLASS_WHISKEY u8"\uf7a0" +#define ICON_FA_BOX u8"\uf466" +#define ICON_FA_DIAGNOSES u8"\uf470" +#define ICON_FA_FILE_IMAGE u8"\uf1c5" +#define ICON_FA_VENUS_MARS u8"\uf228" +#define ICON_FA_TASKS u8"\uf0ae" +#define ICON_FA_HIKING u8"\uf6ec" +#define ICON_FA_VECTOR_SQUARE u8"\uf5cb" +#define ICON_FA_QUOTE_LEFT u8"\uf10d" +#define ICON_FA_MOBILE_ALT u8"\uf3cd" +#define ICON_FA_USER_SHIELD u8"\uf505" +#define ICON_FA_BLOG u8"\uf781" +#define ICON_FA_MARKER u8"\uf5a1" +#define ICON_FA_HAMBURGER u8"\uf805" +#define ICON_FA_REDO u8"\uf01e" +#define ICON_FA_CLOUD u8"\uf0c2" +#define ICON_FA_HAND_HOLDING_USD u8"\uf4c0" +#define ICON_FA_CERTIFICATE u8"\uf0a3" +#define ICON_FA_ANGRY u8"\uf556" +#define ICON_FA_FROG u8"\uf52e" +#define ICON_FA_CAMERA u8"\uf030" +#define ICON_FA_DICE_THREE u8"\uf527" +#define ICON_FA_MEMORY u8"\uf538" +#define ICON_FA_PEN_SQUARE u8"\uf14b" +#define ICON_FA_SORT u8"\uf0dc" +#define ICON_FA_PLUG u8"\uf1e6" +#define ICON_FA_SHARE u8"\uf064" +#define ICON_FA_ENVELOPE u8"\uf0e0" +#define ICON_FA_LAYER_GROUP u8"\uf5fd" +#define ICON_FA_TRAIN u8"\uf238" +#define ICON_FA_BULLHORN u8"\uf0a1" +#define ICON_FA_BABY u8"\uf77c" +#define ICON_FA_CONCIERGE_BELL u8"\uf562" +#define ICON_FA_CIRCLE u8"\uf111" +#define ICON_FA_I_CURSOR u8"\uf246" +#define ICON_FA_CAR u8"\uf1b9" +#define ICON_FA_CAT u8"\uf6be" +#define ICON_FA_WALLET u8"\uf555" +#define ICON_FA_BOOK_MEDICAL u8"\uf7e6" +#define ICON_FA_H_SQUARE u8"\uf0fd" +#define ICON_FA_HEART u8"\uf004" +#define ICON_FA_LOCK_OPEN u8"\uf3c1" +#define ICON_FA_STREAM u8"\uf550" +#define ICON_FA_LOCK u8"\uf023" +#define ICON_FA_PARACHUTE_BOX u8"\uf4cd" +#define ICON_FA_TAG u8"\uf02b" +#define ICON_FA_SMILE_BEAM u8"\uf5b8" +#define ICON_FA_USER_NURSE u8"\uf82f" +#define ICON_FA_MICROPHONE_ALT u8"\uf3c9" +#define ICON_FA_SPA u8"\uf5bb" +#define ICON_FA_CHEVRON_CIRCLE_DOWN u8"\uf13a" +#define ICON_FA_FOLDER_PLUS u8"\uf65e" +#define ICON_FA_TICKET_ALT u8"\uf3ff" +#define ICON_FA_BOOK_OPEN u8"\uf518" +#define ICON_FA_MAP u8"\uf279" +#define ICON_FA_COCKTAIL u8"\uf561" +#define ICON_FA_CLONE u8"\uf24d" +#define ICON_FA_ID_CARD_ALT u8"\uf47f" +#define ICON_FA_CHECK_SQUARE u8"\uf14a" +#define ICON_FA_CHART_LINE u8"\uf201" +#define ICON_FA_POO_STORM u8"\uf75a" +#define ICON_FA_DOVE u8"\uf4ba" +#define ICON_FA_MARS_STROKE u8"\uf229" +#define ICON_FA_ENVELOPE_OPEN u8"\uf2b6" +#define ICON_FA_WHEELCHAIR u8"\uf193" +#define ICON_FA_ROBOT u8"\uf544" +#define ICON_FA_UNDO_ALT u8"\uf2ea" +#define ICON_FA_CLOUD_MEATBALL u8"\uf73b" +#define ICON_FA_TRUCK u8"\uf0d1" +#define ICON_FA_FLASK u8"\uf0c3" +#define ICON_FA_WON_SIGN u8"\uf159" +#define ICON_FA_SUPERSCRIPT u8"\uf12b" +#define ICON_FA_TTY u8"\uf1e4" +#define ICON_FA_USER_MD u8"\uf0f0" +#define ICON_FA_BRAIN u8"\uf5dc" +#define ICON_FA_TABLETS u8"\uf490" +#define ICON_FA_MOTORCYCLE u8"\uf21c" +#define ICON_FA_PHONE_SQUARE_ALT u8"\uf87b" +#define ICON_FA_ANGLE_UP u8"\uf106" +#define ICON_FA_BROOM u8"\uf51a" +#define ICON_FA_DICE_D20 u8"\uf6cf" +#define ICON_FA_LEVEL_DOWN_ALT u8"\uf3be" +#define ICON_FA_PAPERCLIP u8"\uf0c6" +#define ICON_FA_USER_CLOCK u8"\uf4fd" +#define ICON_FA_MUG_HOT u8"\uf7b6" +#define ICON_FA_SORT_ALPHA_UP u8"\uf15e" +#define ICON_FA_AUDIO_DESCRIPTION u8"\uf29e" +#define ICON_FA_FILE_CSV u8"\uf6dd" +#define ICON_FA_FILE_DOWNLOAD u8"\uf56d" +#define ICON_FA_SYNC_ALT u8"\uf2f1" +#define ICON_FA_ANGLE_DOUBLE_UP u8"\uf102" +#define ICON_FA_HANDS u8"\uf4c2" +#define ICON_FA_REPUBLICAN u8"\uf75e" +#define ICON_FA_UNIVERSITY u8"\uf19c" +#define ICON_FA_KHANDA u8"\uf66d" +#define ICON_FA_GLASSES u8"\uf530" +#define ICON_FA_SQUARE u8"\uf0c8" +#define ICON_FA_GRIN_SQUINT u8"\uf585" +#define ICON_FA_CLOSED_CAPTIONING u8"\uf20a" +#define ICON_FA_RECEIPT u8"\uf543" +#define ICON_FA_STRIKETHROUGH u8"\uf0cc" +#define ICON_FA_UNLOCK u8"\uf09c" +#define ICON_FA_ARROW_LEFT u8"\uf060" +#define ICON_FA_DICE_SIX u8"\uf526" +#define ICON_FA_GRIP_VERTICAL u8"\uf58e" +#define ICON_FA_PILLS u8"\uf484" +#define ICON_FA_EXCLAMATION u8"\uf12a" +#define ICON_FA_PERSON_BOOTH u8"\uf756" +#define ICON_FA_CALENDAR_PLUS u8"\uf271" +#define ICON_FA_SMOG u8"\uf75f" +#define ICON_FA_LOCATION_ARROW u8"\uf124" +#define ICON_FA_UMBRELLA u8"\uf0e9" +#define ICON_FA_QURAN u8"\uf687" +#define ICON_FA_UNDO u8"\uf0e2" +#define ICON_FA_DUMPSTER u8"\uf793" +#define ICON_FA_FUNNEL_DOLLAR u8"\uf662" +#define ICON_FA_INDENT u8"\uf03c" +#define ICON_FA_LANGUAGE u8"\uf1ab" +#define ICON_FA_ARROW_ALT_CIRCLE_UP u8"\uf35b" +#define ICON_FA_ROUTE u8"\uf4d7" +#define ICON_FA_HEADPHONES u8"\uf025" +#define ICON_FA_TIMES u8"\uf00d" +#define ICON_FA_CLINIC_MEDICAL u8"\uf7f2" +#define ICON_FA_PLANE u8"\uf072" +#define ICON_FA_TORII_GATE u8"\uf6a1" +#define ICON_FA_LEVEL_UP_ALT u8"\uf3bf" +#define ICON_FA_BLIND u8"\uf29d" +#define ICON_FA_CHEESE u8"\uf7ef" +#define ICON_FA_PHONE_SQUARE u8"\uf098" +#define ICON_FA_SHOPPING_BASKET u8"\uf291" +#define ICON_FA_ICE_CREAM u8"\uf810" +#define ICON_FA_RING u8"\uf70b" +#define ICON_FA_CITY u8"\uf64f" +#define ICON_FA_TEXT_WIDTH u8"\uf035" +#define ICON_FA_RSS_SQUARE u8"\uf143" +#define ICON_FA_PAINT_BRUSH u8"\uf1fc" +#define ICON_FA_BOOKMARK u8"\uf02e" +#define ICON_FA_PHOTO_VIDEO u8"\uf87c" +#define ICON_FA_SIM_CARD u8"\uf7c4" +#define ICON_FA_CLOUD_UPLOAD_ALT u8"\uf382" +#define ICON_FA_COMPACT_DISC u8"\uf51f" +#define ICON_FA_SORT_UP u8"\uf0de" +#define ICON_FA_SIGN_OUT_ALT u8"\uf2f5" +#define ICON_FA_SIGN_IN_ALT u8"\uf2f6" +#define ICON_FA_FORWARD u8"\uf04e" +#define ICON_FA_SHARE_ALT u8"\uf1e0" +#define ICON_FA_COPY u8"\uf0c5" +#define ICON_FA_RSS u8"\uf09e" +#define ICON_FA_PEN_FANCY u8"\uf5ac" +#define ICON_FA_BIOHAZARD u8"\uf780" +#define ICON_FA_BED u8"\uf236" +#define ICON_FA_INFO u8"\uf129" +#define ICON_FA_TOGGLE_OFF u8"\uf204" +#define ICON_FA_MAP_MARKER_ALT u8"\uf3c5" +#define ICON_FA_TRACTOR u8"\uf722" +#define ICON_FA_CLOUD_DOWNLOAD_ALT u8"\uf381" +#define ICON_FA_ID_BADGE u8"\uf2c1" +#define ICON_FA_SORT_NUMERIC_DOWN_ALT u8"\uf886" +#define ICON_FA_RULER_HORIZONTAL u8"\uf547" +#define ICON_FA_PAINT_ROLLER u8"\uf5aa" +#define ICON_FA_HAT_WIZARD u8"\uf6e8" +#define ICON_FA_MAP_SIGNS u8"\uf277" +#define ICON_FA_MICROPHONE u8"\uf130" +#define ICON_FA_FOOTBALL_BALL u8"\uf44e" +#define ICON_FA_ALLERGIES u8"\uf461" +#define ICON_FA_ID_CARD u8"\uf2c2" +#define ICON_FA_USER_LOCK u8"\uf502" +#define ICON_FA_PLAY_CIRCLE u8"\uf144" +#define ICON_FA_REMOVE_FORMAT u8"\uf87d" +#define ICON_FA_THERMOMETER u8"\uf491" +#define ICON_FA_REGISTERED u8"\uf25d" +#define ICON_FA_DOLLAR_SIGN u8"\uf155" +#define ICON_FA_DUNGEON u8"\uf6d9" +#define ICON_FA_COMPRESS u8"\uf066" +#define ICON_FA_SEARCH_LOCATION u8"\uf689" +#define ICON_FA_UTENSILS u8"\uf2e7" +#define ICON_FA_BLENDER_PHONE u8"\uf6b6" +#define ICON_FA_ANGLE_RIGHT u8"\uf105" +#define ICON_FA_CHESS_QUEEN u8"\uf445" +#define ICON_FA_PAGER u8"\uf815" +#define ICON_FA_SORT_AMOUNT_UP_ALT u8"\uf885" +#define ICON_FA_CLIPBOARD_CHECK u8"\uf46c" +#define ICON_FA_HOURGLASS_END u8"\uf253" +#define ICON_FA_TOOTH u8"\uf5c9" +#define ICON_FA_BUSINESS_TIME u8"\uf64a" +#define ICON_FA_PLACE_OF_WORSHIP u8"\uf67f" +#define ICON_FA_GRIN_TONGUE_SQUINT u8"\uf58a" +#define ICON_FA_MEH_ROLLING_EYES u8"\uf5a5" +#define ICON_FA_WALKING u8"\uf554" +#define ICON_FA_EDIT u8"\uf044" +#define ICON_FA_CARET_LEFT u8"\uf0d9" +#define ICON_FA_PAUSE u8"\uf04c" +#define ICON_FA_DICE u8"\uf522" +#define ICON_FA_RUBLE_SIGN u8"\uf158" +#define ICON_FA_TERMINAL u8"\uf120" +#define ICON_FA_RULER_VERTICAL u8"\uf548" +#define ICON_FA_HAND_POINTER u8"\uf25a" +#define ICON_FA_TAPE u8"\uf4db" +#define ICON_FA_SHOPPING_BAG u8"\uf290" +#define ICON_FA_SKIING_NORDIC u8"\uf7ca" +#define ICON_FA_FIST_RAISED u8"\uf6de" +#define ICON_FA_CUBE u8"\uf1b2" +#define ICON_FA_CAPSULES u8"\uf46b" +#define ICON_FA_KIWI_BIRD u8"\uf535" +#define ICON_FA_CHEVRON_CIRCLE_UP u8"\uf139" +#define ICON_FA_MARS_STROKE_V u8"\uf22a" +#define ICON_FA_FILE_ARCHIVE u8"\uf1c6" +#define ICON_FA_JOINT u8"\uf595" +#define ICON_FA_MARS_STROKE_H u8"\uf22b" +#define ICON_FA_ADDRESS_BOOK u8"\uf2b9" +#define ICON_FA_PROCEDURES u8"\uf487" +#define ICON_FA_GEM u8"\uf3a5" +#define ICON_FA_RULER_COMBINED u8"\uf546" +#define ICON_FA_ALIGN_LEFT u8"\uf036" +#define ICON_FA_STAR_AND_CRESCENT u8"\uf699" +#define ICON_FA_FIGHTER_JET u8"\uf0fb" +#define ICON_FA_SPACE_SHUTTLE u8"\uf197" +#define ICON_FA_MAP_PIN u8"\uf276" +#define ICON_FA_GLOBE u8"\uf0ac" +#define ICON_FA_ALIGN_CENTER u8"\uf037" +#define ICON_FA_SORT_ALPHA_DOWN u8"\uf15d" +#define ICON_FA_PARKING u8"\uf540" +#define ICON_FA_CALENDAR u8"\uf133" +#define ICON_FA_PALETTE u8"\uf53f" +#define ICON_FA_GLASS_MARTINI u8"\uf000" +#define ICON_FA_TIMES_CIRCLE u8"\uf057" +#define ICON_FA_EYE u8"\uf06e" +#define ICON_FA_MONUMENT u8"\uf5a6" +#define ICON_FA_TRASH_RESTORE u8"\uf829" +#define ICON_FA_GUITAR u8"\uf7a6" +#define ICON_FA_GRIN_BEAM u8"\uf582" +#define ICON_FA_KEY u8"\uf084" +#define ICON_FA_FIRST_AID u8"\uf479" +#define ICON_FA_UMBRELLA_BEACH u8"\uf5ca" +#define ICON_FA_DRUM u8"\uf569" +#define ICON_FA_FILE_CONTRACT u8"\uf56c" +#define ICON_FA_VOICEMAIL u8"\uf897" +#define ICON_FA_RESTROOM u8"\uf7bd" +#define ICON_FA_UNLOCK_ALT u8"\uf13e" +#define ICON_FA_MICROPHONE_ALT_SLASH u8"\uf539" +#define ICON_FA_USER_SECRET u8"\uf21b" +#define ICON_FA_ARROW_RIGHT u8"\uf061" +#define ICON_FA_FILE_VIDEO u8"\uf1c8" +#define ICON_FA_ARROW_ALT_CIRCLE_RIGHT u8"\uf35a" +#define ICON_FA_CALENDAR_WEEK u8"\uf784" +#define ICON_FA_USER_GRADUATE u8"\uf501" +#define ICON_FA_HAND_MIDDLE_FINGER u8"\uf806" +#define ICON_FA_POO u8"\uf2fe" +#define ICON_FA_LAUGH u8"\uf599" +#define ICON_FA_TABLE u8"\uf0ce" +#define ICON_FA_POLL u8"\uf681" +#define ICON_FA_CAR_ALT u8"\uf5de" +#define ICON_FA_THUMBS_UP u8"\uf164" +#define ICON_FA_SWIMMER u8"\uf5c4" +#define ICON_FA_TRADEMARK u8"\uf25c" +#define ICON_FA_CLOUD_MOON_RAIN u8"\uf73c" +#define ICON_FA_VIALS u8"\uf493" +#define ICON_FA_ERASER u8"\uf12d" +#define ICON_FA_MARS u8"\uf222" +#define ICON_FA_HELICOPTER u8"\uf533" +#define ICON_FA_FEATHER u8"\uf52d" +#define ICON_FA_SQUARE_FULL u8"\uf45c" +#define ICON_FA_DOLLY u8"\uf472" +#define ICON_FA_HAND_HOLDING u8"\uf4bd" +#define ICON_FA_HOURGLASS_START u8"\uf251" +#define ICON_FA_GRIN_HEARTS u8"\uf584" +#define ICON_FA_VENUS_DOUBLE u8"\uf226" +#define ICON_FA_HASHTAG u8"\uf292" +#define ICON_FA_FINGERPRINT u8"\uf577" +#define ICON_FA_SEEDLING u8"\uf4d8" +#define ICON_FA_HAYKAL u8"\uf666" +#define ICON_FA_TSHIRT u8"\uf553" +#define ICON_FA_PENCIL_RULER u8"\uf5ae" +#define ICON_FA_HDD u8"\uf0a0" +#define ICON_FA_NEWSPAPER u8"\uf1ea" +#define ICON_FA_HOSPITAL_ALT u8"\uf47d" +#define ICON_FA_USER_SLASH u8"\uf506" +#define ICON_FA_FILE_WORD u8"\uf1c2" +#define ICON_FA_ENVELOPE_SQUARE u8"\uf199" +#define ICON_FA_GENDERLESS u8"\uf22d" +#define ICON_FA_DICE_FIVE u8"\uf523" +#define ICON_FA_SYNAGOGUE u8"\uf69b" +#define ICON_FA_PAW u8"\uf1b0" +#define ICON_FA_HAND_HOLDING_HEART u8"\uf4be" +#define ICON_FA_CROSS u8"\uf654" +#define ICON_FA_ARCHIVE u8"\uf187" +#define ICON_FA_SOLAR_PANEL u8"\uf5ba" +#define ICON_FA_INFINITY u8"\uf534" +#define ICON_FA_ANKH u8"\uf644" +#define ICON_FA_MAP_MARKER u8"\uf041" +#define ICON_FA_CALENDAR_ALT u8"\uf073" +#define ICON_FA_AMERICAN_SIGN_LANGUAGE_INTERPRETING u8"\uf2a3" +#define ICON_FA_BINOCULARS u8"\uf1e5" +#define ICON_FA_STICKY_NOTE u8"\uf249" +#define ICON_FA_RUNNING u8"\uf70c" +#define ICON_FA_PEN_NIB u8"\uf5ad" +#define ICON_FA_MAP_MARKED u8"\uf59f" +#define ICON_FA_EXPAND u8"\uf065" +#define ICON_FA_TRUCK_PICKUP u8"\uf63c" +#define ICON_FA_HOLLY_BERRY u8"\uf7aa" +#define ICON_FA_PRESCRIPTION_BOTTLE u8"\uf485" +#define ICON_FA_LAPTOP_CODE u8"\uf5fc" +#define ICON_FA_GOLF_BALL u8"\uf450" +#define ICON_FA_SKULL_CROSSBONES u8"\uf714" +#define ICON_FA_TAXI u8"\uf1ba" +#define ICON_FA_COMMENT u8"\uf075" +#define ICON_FA_KISS u8"\uf596" +#define ICON_FA_HIPPO u8"\uf6ed" +#define ICON_FA_ARROWS_ALT u8"\uf0b2" +#define ICON_FA_UNDERLINE u8"\uf0cd" +#define ICON_FA_ARROW_CIRCLE_UP u8"\uf0aa" +#define ICON_FA_BASKETBALL_BALL u8"\uf434" +#define ICON_FA_DESKTOP u8"\uf108" +#define ICON_FA_PALLET u8"\uf482" +#define ICON_FA_TOGGLE_ON u8"\uf205" +#define ICON_FA_STOPWATCH u8"\uf2f2" +#define ICON_FA_ARROW_ALT_CIRCLE_LEFT u8"\uf359" +#define ICON_FA_GAS_PUMP u8"\uf52f" +#define ICON_FA_EXTERNAL_LINK_ALT u8"\uf35d" +#define ICON_FA_FROWN u8"\uf119" +#define ICON_FA_RULER u8"\uf545" +#define ICON_FA_FLAG_USA u8"\uf74d" +#define ICON_FA_GRIN u8"\uf580" +#define ICON_FA_ARROW_CIRCLE_LEFT u8"\uf0a8" +#define ICON_FA_HIGHLIGHTER u8"\uf591" +#define ICON_FA_POLL_H u8"\uf682" +#define ICON_FA_SERVER u8"\uf233" +#define ICON_FA_BATTERY_EMPTY u8"\uf244" +#define ICON_FA_SPRAY_CAN u8"\uf5bd" +#define ICON_FA_BOWLING_BALL u8"\uf436" +#define ICON_FA_GRIP_LINES_VERTICAL u8"\uf7a5" +#define ICON_FA_GLOBE_EUROPE u8"\uf7a2" +#define ICON_FA_WINDOW_MINIMIZE u8"\uf2d1" +#define ICON_FA_MARS_DOUBLE u8"\uf227" +#define ICON_FA_PAUSE_CIRCLE u8"\uf28b" +#define ICON_FA_HOME u8"\uf015" +#define ICON_FA_COMMENT_ALT u8"\uf27a" +#define ICON_FA_UTENSIL_SPOON u8"\uf2e5" +#define ICON_FA_APPLE_ALT u8"\uf5d1" +#define ICON_FA_MOON u8"\uf186" +#define ICON_FA_CANNABIS u8"\uf55f" +#define ICON_FA_LAUGH_BEAM u8"\uf59a" +#define ICON_FA_TEETH_OPEN u8"\uf62f" +#define ICON_FA_CHART_PIE u8"\uf200" +#define ICON_FA_SOCKS u8"\uf696" +#define ICON_FA_SD_CARD u8"\uf7c2" +#define ICON_FA_ARROW_CIRCLE_RIGHT u8"\uf0a9" +#define ICON_FA_PASTE u8"\uf0ea" +#define ICON_FA_OM u8"\uf679" +#define ICON_FA_LUGGAGE_CART u8"\uf59d" +#define ICON_FA_INDUSTRY u8"\uf275" +#define ICON_FA_STAMP u8"\uf5bf" +#define ICON_FA_RADIATION_ALT u8"\uf7ba" +#define ICON_FA_COMPRESS_ARROWS_ALT u8"\uf78c" +#define ICON_FA_ROAD u8"\uf018" +#define ICON_FA_IMAGE u8"\uf03e" +#define ICON_FA_BALANCE_SCALE_RIGHT u8"\uf516" +#define ICON_FA_ANGLE_DOUBLE_RIGHT u8"\uf101" +#define ICON_FA_CLOUD_MOON u8"\uf6c3" +#define ICON_FA_DOOR_OPEN u8"\uf52b" +#define ICON_FA_GRIN_TONGUE_WINK u8"\uf58b" +#define ICON_FA_REPLY_ALL u8"\uf122" +#define ICON_FA_TEMPERATURE_LOW u8"\uf76b" +#define ICON_FA_INBOX u8"\uf01c" +#define ICON_FA_FEMALE u8"\uf182" +#define ICON_FA_SYRINGE u8"\uf48e" +#define ICON_FA_CIRCLE_NOTCH u8"\uf1ce" +#define ICON_FA_ELLIPSIS_V u8"\uf142" +#define ICON_FA_SNOWPLOW u8"\uf7d2" +#define ICON_FA_TABLE_TENNIS u8"\uf45d" +#define ICON_FA_LOW_VISION u8"\uf2a8" +#define ICON_FA_FILE_IMPORT u8"\uf56f" +#define ICON_FA_ITALIC u8"\uf033" +#define ICON_FA_FILE_SIGNATURE u8"\uf573" +#define ICON_FA_CHALKBOARD u8"\uf51b" +#define ICON_FA_GHOST u8"\uf6e2" +#define ICON_FA_TACHOMETER_ALT u8"\uf3fd" +#define ICON_FA_BUS u8"\uf207" +#define ICON_FA_ANGLE_DOWN u8"\uf107" +#define ICON_FA_HAND_ROCK u8"\uf255" +#define ICON_FA_BORDER_STYLE u8"\uf853" +#define ICON_FA_STAR_OF_LIFE u8"\uf621" +#define ICON_FA_PODCAST u8"\uf2ce" +#define ICON_FA_TRUCK_MOVING u8"\uf4df" +#define ICON_FA_BUG u8"\uf188" +#define ICON_FA_SHIELD_ALT u8"\uf3ed" +#define ICON_FA_FILL_DRIP u8"\uf576" +#define ICON_FA_COMMENT_SLASH u8"\uf4b3" +#define ICON_FA_SUITCASE u8"\uf0f2" +#define ICON_FA_SKATING u8"\uf7c5" +#define ICON_FA_TOILET u8"\uf7d8" +#define ICON_FA_ENVELOPE_OPEN_TEXT u8"\uf658" +#define ICON_FA_HEART_BROKEN u8"\uf7a9" +#define ICON_FA_CARET_SQUARE_UP u8"\uf151" +#define ICON_FA_TH_LARGE u8"\uf009" +#define ICON_FA_AT u8"\uf1fa" +#define ICON_FA_FILE u8"\uf15b" +#define ICON_FA_TENGE u8"\uf7d7" +#define ICON_FA_FLAG_CHECKERED u8"\uf11e" +#define ICON_FA_FILM u8"\uf008" +#define ICON_FA_FILL u8"\uf575" +#define ICON_FA_GRIN_SQUINT_TEARS u8"\uf586" +#define ICON_FA_PERCENT u8"\uf295" +#define ICON_FA_METEOR u8"\uf753" +#define ICON_FA_TRASH u8"\uf1f8" +#define ICON_FA_FILE_AUDIO u8"\uf1c7" +#define ICON_FA_SATELLITE_DISH u8"\uf7c0" +#define ICON_FA_POOP u8"\uf619" +#define ICON_FA_STAR u8"\uf005" +#define ICON_FA_GIFTS u8"\uf79c" +#define ICON_FA_FIRE_ALT u8"\uf7e4" +#define ICON_FA_BUILDING u8"\uf1ad" +#define ICON_FA_PRESCRIPTION_BOTTLE_ALT u8"\uf486" +#define ICON_FA_MONEY_BILL_WAVE_ALT u8"\uf53b" +#define ICON_FA_NEUTER u8"\uf22c" +#define ICON_FA_BAND_AID u8"\uf462" +#define ICON_FA_WIFI u8"\uf1eb" +#define ICON_FA_MASK u8"\uf6fa" +#define ICON_FA_CHEVRON_UP u8"\uf077" +#define ICON_FA_HAND_SPOCK u8"\uf259" +#define ICON_FA_HAND_POINT_UP u8"\uf0a6" diff --git a/ext/ImCurveEdit.cpp b/ext/ImCurveEdit.cpp index 4f78f3b3..4cb42674 100644 --- a/ext/ImCurveEdit.cpp +++ b/ext/ImCurveEdit.cpp @@ -84,7 +84,7 @@ namespace ImCurveEdit { offsets[i] = pos * size + localOffsets[i]*4.5f + offset; } - + const ImVec2 center = pos * size + offset; const ImRect anchor(center - ImVec2(5, 5), center + ImVec2(5, 5)); draw_list->AddConvexPolyFilled(offsets, 4, 0xFF000000); @@ -100,7 +100,7 @@ namespace ImCurveEdit draw_list->AddPolyline(offsets, 4, 0xFF80B0FF, true, 2.0f); else draw_list->AddPolyline(offsets, 4, 0xFF0080FF, true, 2.0f); - + return ret; } @@ -153,7 +153,7 @@ namespace ImCurveEdit } } ImVec2 range = max - min + ImVec2(1.f, 0.f); // +1 because of inclusive last frame - + const ImVec2 viewSize(size.x, -size.y); const ImVec2 sizeOfPixel = ImVec2(1.f, 1.f) / viewSize; const size_t curveCount = delegate.GetCurveCount(); @@ -281,7 +281,7 @@ namespace ImCurveEdit static std::vector originalPoints; if (overSelectedPoint && io.MouseDown[0]) { - if (fabsf(io.MouseDelta.x) > 0.f || fabsf(io.MouseDelta.y) > 0.f && !selection.empty()) + if ((fabsf(io.MouseDelta.x) > 0.f || fabsf(io.MouseDelta.y) > 0.f) && !selection.empty()) { if (!pointsMoved) { diff --git a/ext/ImGradient.cpp b/ext/ImGradient.cpp deleted file mode 100644 index 84d0ea90..00000000 --- a/ext/ImGradient.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "ImGradient.h" -#include "imgui.h" -#include "imgui_internal.h" -#include -#include - -namespace ImGradient -{ -#ifndef IMGUI_DEFINE_MATH_OPERATORS - static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); } - static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } - static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } - static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } - static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x*rhs.x, lhs.y*rhs.y); } - static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } -#endif - - static int DrawPoint(ImDrawList* draw_list, ImVec4 color, const ImVec2 size, bool editing, ImVec2 pos) - { - int ret = 0; - ImGuiIO& io = ImGui::GetIO(); - - ImVec2 p1 = ImLerp(pos, ImVec2(pos + ImVec2(size.x - size.y, 0.f)), color.w) + ImVec2(3, 3); - ImVec2 p2 = ImLerp(pos + ImVec2(size.y, size.y), ImVec2(pos + size), color.w) - ImVec2(3, 3); - ImRect rc(p1, p2); - - color.w = 1.f; - draw_list->AddRectFilled(p1, p2, ImColor(color)); - if (editing) - draw_list->AddRect(p1, p2, 0xFFFFFFFF, 2.f, 15, 2.5f); - else - draw_list->AddRect(p1, p2, 0x80FFFFFF, 2.f, 15, 1.25f); - - if (rc.Contains(io.MousePos)) - { - if (io.MouseClicked[0]) - return 2; - return 1; - } - return 0; - } - - bool Edit(Delegate &delegate, const ImVec2& size, int& selection) - { - bool ret = false; - ImGuiIO& io = ImGui::GetIO(); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGui::BeginChildFrame(137, size); - - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - const ImVec2 offset = ImGui::GetCursorScreenPos(); - - const ImVec4* pts = delegate.GetPoints(); - static int currentSelection = -1; - static int movingPt = -1; - if (currentSelection >= int(delegate.GetPointCount())) - currentSelection = -1; - if (movingPt != -1) - { - ImVec4 current = pts[movingPt]; - current.w += io.MouseDelta.x / size.x; - current.w = ImClamp(current.w, 0.f, 1.f); - delegate.EditPoint(movingPt, current); - ret = true; - if (!io.MouseDown[0]) - movingPt = -1; - } - for (size_t i = 0; i < delegate.GetPointCount(); i++) - { - int ptSel = DrawPoint(draw_list, pts[i], size, i == currentSelection, offset); - if (ptSel == 2) - { - currentSelection = int(i); - ret = true; - } - if (ptSel == 1 && io.MouseDown[0] && movingPt == -1) - { - movingPt = int(i); - } - } - ImRect rc(offset, offset + size); - if (rc.Contains(io.MousePos) && io.MouseDoubleClicked[0]) - { - float t = (io.MousePos.x - offset.x) / size.x; - delegate.AddPoint(delegate.GetPoint(t)); - ret = true; - } - ImGui::EndChildFrame(); - ImGui::PopStyleVar(); - - selection = currentSelection; - return ret; - } -} diff --git a/ext/ImGradient.h b/ext/ImGradient.h deleted file mode 100644 index d85b927c..00000000 --- a/ext/ImGradient.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include - -struct ImVec4; -struct ImVec2; - -namespace ImGradient -{ - struct Delegate - { - virtual size_t GetPointCount() = 0; - virtual ImVec4* GetPoints() = 0; - virtual int EditPoint(int pointIndex, ImVec4 value) = 0; - virtual ImVec4 GetPoint(float t) = 0; - virtual void AddPoint(ImVec4 value) = 0; - }; - - bool Edit(Delegate &delegate, const ImVec2& size, int& selection); -} diff --git a/ext/ImGuizmo.cpp b/ext/ImGuizmo.cpp new file mode 100644 index 00000000..fdd0a6a9 --- /dev/null +++ b/ext/ImGuizmo.cpp @@ -0,0 +1,2311 @@ +// The MIT License(MIT) +// +// Copyright(c) 2016 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "imgui.h" +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" +#include "ImGuizmo.h" + +// includes patches for multiview from +// https://github.com/CedricGuillemet/ImGuizmo/issues/15 + +namespace ImGuizmo +{ + static const float ZPI = 3.14159265358979323846f; + static const float RAD2DEG = (180.f / ZPI); + static const float DEG2RAD = (ZPI / 180.f); + static const float gGizmoSizeClipSpace = 0.1f; + const float screenRotateSize = 0.06f; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // utility and math + + void FPU_MatrixF_x_MatrixF(const float *a, const float *b, float *r) + { + r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12]; + r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13]; + r[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14]; + r[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15]; + + r[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12]; + r[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13]; + r[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14]; + r[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15]; + + r[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12]; + r[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13]; + r[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14]; + r[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15]; + + r[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12]; + r[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13]; + r[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14]; + r[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15]; + } + + void Frustum(float left, float right, float bottom, float top, float znear, float zfar, float* m16) + { + float temp, temp2, temp3, temp4; + temp = 2.0f * znear; + temp2 = right - left; + temp3 = top - bottom; + temp4 = zfar - znear; + m16[0] = temp / temp2; + m16[1] = 0.0; + m16[2] = 0.0; + m16[3] = 0.0; + m16[4] = 0.0; + m16[5] = temp / temp3; + m16[6] = 0.0; + m16[7] = 0.0; + m16[8] = (right + left) / temp2; + m16[9] = (top + bottom) / temp3; + m16[10] = (-zfar - znear) / temp4; + m16[11] = -1.0f; + m16[12] = 0.0; + m16[13] = 0.0; + m16[14] = (-temp * zfar) / temp4; + m16[15] = 0.0; + } + + void Perspective(float fovyInDegrees, float aspectRatio, float znear, float zfar, float* m16) + { + float ymax, xmax; + ymax = znear * tanf(fovyInDegrees * DEG2RAD); + xmax = ymax * aspectRatio; + Frustum(-xmax, xmax, -ymax, ymax, znear, zfar, m16); + } + + void Cross(const float* a, const float* b, float* r) + { + r[0] = a[1] * b[2] - a[2] * b[1]; + r[1] = a[2] * b[0] - a[0] * b[2]; + r[2] = a[0] * b[1] - a[1] * b[0]; + } + + float Dot(const float* a, const float* b) + { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + } + + void Normalize(const float* a, float* r) + { + float il = 1.f / (sqrtf(Dot(a, a)) + FLT_EPSILON); + r[0] = a[0] * il; + r[1] = a[1] * il; + r[2] = a[2] * il; + } + + void LookAt(const float* eye, const float* at, const float* up, float* m16) + { + float X[3], Y[3], Z[3], tmp[3]; + + tmp[0] = eye[0] - at[0]; + tmp[1] = eye[1] - at[1]; + tmp[2] = eye[2] - at[2]; + Normalize(tmp, Z); + Normalize(up, Y); + Cross(Y, Z, tmp); + Normalize(tmp, X); + Cross(Z, X, tmp); + Normalize(tmp, Y); + + m16[0] = X[0]; + m16[1] = Y[0]; + m16[2] = Z[0]; + m16[3] = 0.0f; + m16[4] = X[1]; + m16[5] = Y[1]; + m16[6] = Z[1]; + m16[7] = 0.0f; + m16[8] = X[2]; + m16[9] = Y[2]; + m16[10] = Z[2]; + m16[11] = 0.0f; + m16[12] = -Dot(X, eye); + m16[13] = -Dot(Y, eye); + m16[14] = -Dot(Z, eye); + m16[15] = 1.0f; + } + + template T Clamp(T x, T y, T z) { return ((xz) ? z : x)); } + template T max(T x, T y) { return (x > y) ? x : y; } + template T min(T x, T y) { return (x < y) ? x : y; } + template bool IsWithin(T x, T y, T z) { return (x>=y) && (x<=z); } + + struct matrix_t; + struct vec_t + { + public: + float x, y, z, w; + + void Lerp(const vec_t& v, float t) + { + x += (v.x - x) * t; + y += (v.y - y) * t; + z += (v.z - z) * t; + w += (v.w - w) * t; + } + + void Set(float v) { x = y = z = w = v; } + void Set(float _x, float _y, float _z = 0.f, float _w = 0.f) { x = _x; y = _y; z = _z; w = _w; } + + vec_t& operator -= (const vec_t& v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; } + vec_t& operator += (const vec_t& v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; } + vec_t& operator *= (const vec_t& v) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; } + vec_t& operator *= (float v) { x *= v; y *= v; z *= v; w *= v; return *this; } + + vec_t operator * (float f) const; + vec_t operator - () const; + vec_t operator - (const vec_t& v) const; + vec_t operator + (const vec_t& v) const; + vec_t operator * (const vec_t& v) const; + + const vec_t& operator + () const { return (*this); } + float Length() const { return sqrtf(x*x + y*y + z*z); }; + float LengthSq() const { return (x*x + y*y + z*z); }; + vec_t Normalize() { (*this) *= (1.f / Length()); return (*this); } + vec_t Normalize(const vec_t& v) { this->Set(v.x, v.y, v.z, v.w); this->Normalize(); return (*this); } + vec_t Abs() const; + void Cross(const vec_t& v) + { + vec_t res; + res.x = y * v.z - z * v.y; + res.y = z * v.x - x * v.z; + res.z = x * v.y - y * v.x; + + x = res.x; + y = res.y; + z = res.z; + w = 0.f; + } + void Cross(const vec_t& v1, const vec_t& v2) + { + x = v1.y * v2.z - v1.z * v2.y; + y = v1.z * v2.x - v1.x * v2.z; + z = v1.x * v2.y - v1.y * v2.x; + w = 0.f; + } + float Dot(const vec_t &v) const + { + return (x * v.x) + (y * v.y) + (z * v.z) + (w * v.w); + } + float Dot3(const vec_t &v) const + { + return (x * v.x) + (y * v.y) + (z * v.z); + } + + void Transform(const matrix_t& matrix); + void Transform(const vec_t & s, const matrix_t& matrix); + + void TransformVector(const matrix_t& matrix); + void TransformPoint(const matrix_t& matrix); + void TransformVector(const vec_t& v, const matrix_t& matrix) { (*this) = v; this->TransformVector(matrix); } + void TransformPoint(const vec_t& v, const matrix_t& matrix) { (*this) = v; this->TransformPoint(matrix); } + + float& operator [] (size_t index) { return ((float*)&x)[index]; } + const float& operator [] (size_t index) const { return ((float*)&x)[index]; } + }; + + vec_t makeVect(float _x, float _y, float _z = 0.f, float _w = 0.f) { vec_t res; res.x = _x; res.y = _y; res.z = _z; res.w = _w; return res; } + vec_t makeVect(ImVec2 v) { vec_t res; res.x = v.x; res.y = v.y; res.z = 0.f; res.w = 0.f; return res; } + vec_t vec_t::operator * (float f) const { return makeVect(x * f, y * f, z * f, w *f); } + vec_t vec_t::operator - () const { return makeVect(-x, -y, -z, -w); } + vec_t vec_t::operator - (const vec_t& v) const { return makeVect(x - v.x, y - v.y, z - v.z, w - v.w); } + vec_t vec_t::operator + (const vec_t& v) const { return makeVect(x + v.x, y + v.y, z + v.z, w + v.w); } + vec_t vec_t::operator * (const vec_t& v) const { return makeVect(x * v.x, y * v.y, z * v.z, w * v.w); } + vec_t vec_t::Abs() const { return makeVect(fabsf(x), fabsf(y), fabsf(z)); } + + vec_t Normalized(const vec_t& v) { vec_t res; res = v; res.Normalize(); return res; } + vec_t Cross(const vec_t& v1, const vec_t& v2) + { + vec_t res; + res.x = v1.y * v2.z - v1.z * v2.y; + res.y = v1.z * v2.x - v1.x * v2.z; + res.z = v1.x * v2.y - v1.y * v2.x; + res.w = 0.f; + return res; + } + + float Dot(const vec_t &v1, const vec_t &v2) + { + return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z); + } + + vec_t BuildPlan(const vec_t & p_point1, const vec_t & p_normal) + { + vec_t normal, res; + normal.Normalize(p_normal); + res.w = normal.Dot(p_point1); + res.x = normal.x; + res.y = normal.y; + res.z = normal.z; + return res; + } + + struct matrix_t + { + public: + + union + { + float m[4][4]; + float m16[16]; + struct + { + vec_t right, up, dir, position; + } v; + vec_t component[4]; + }; + + matrix_t(const matrix_t& other) { memcpy(&m16[0], &other.m16[0], sizeof(float) * 16); } + matrix_t() {} + + operator float * () { return m16; } + operator const float* () const { return m16; } + void Translation(float _x, float _y, float _z) { this->Translation(makeVect(_x, _y, _z)); } + + void Translation(const vec_t& vt) + { + v.right.Set(1.f, 0.f, 0.f, 0.f); + v.up.Set(0.f, 1.f, 0.f, 0.f); + v.dir.Set(0.f, 0.f, 1.f, 0.f); + v.position.Set(vt.x, vt.y, vt.z, 1.f); + } + + void Scale(float _x, float _y, float _z) + { + v.right.Set(_x, 0.f, 0.f, 0.f); + v.up.Set(0.f, _y, 0.f, 0.f); + v.dir.Set(0.f, 0.f, _z, 0.f); + v.position.Set(0.f, 0.f, 0.f, 1.f); + } + void Scale(const vec_t& s) { Scale(s.x, s.y, s.z); } + + matrix_t& operator *= (const matrix_t& mat) + { + matrix_t tmpMat; + tmpMat = *this; + tmpMat.Multiply(mat); + *this = tmpMat; + return *this; + } + matrix_t operator * (const matrix_t& mat) const + { + matrix_t matT; + matT.Multiply(*this, mat); + return matT; + } + + void Multiply(const matrix_t &matrix) + { + matrix_t tmp; + tmp = *this; + + FPU_MatrixF_x_MatrixF((float*)&tmp, (float*)&matrix, (float*)this); + } + + void Multiply(const matrix_t &m1, const matrix_t &m2) + { + FPU_MatrixF_x_MatrixF((float*)&m1, (float*)&m2, (float*)this); + } + + float GetDeterminant() const + { + return m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - + m[0][2] * m[1][1] * m[2][0] - m[0][1] * m[1][0] * m[2][2] - m[0][0] * m[1][2] * m[2][1]; + } + + float Inverse(const matrix_t &srcMatrix, bool affine = false); + void SetToIdentity() + { + v.right.Set(1.f, 0.f, 0.f, 0.f); + v.up.Set(0.f, 1.f, 0.f, 0.f); + v.dir.Set(0.f, 0.f, 1.f, 0.f); + v.position.Set(0.f, 0.f, 0.f, 1.f); + } + void Transpose() + { + matrix_t tmpm; + for (int l = 0; l < 4; l++) + { + for (int c = 0; c < 4; c++) + { + tmpm.m[l][c] = m[c][l]; + } + } + (*this) = tmpm; + } + + void RotationAxis(const vec_t & axis, float angle); + + void OrthoNormalize() + { + v.right.Normalize(); + v.up.Normalize(); + v.dir.Normalize(); + } + }; + + void vec_t::Transform(const matrix_t& matrix) + { + vec_t out; + + out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + w * matrix.m[3][0]; + out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + w * matrix.m[3][1]; + out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + w * matrix.m[3][2]; + out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + w * matrix.m[3][3]; + + x = out.x; + y = out.y; + z = out.z; + w = out.w; + } + + void vec_t::Transform(const vec_t & s, const matrix_t& matrix) + { + *this = s; + Transform(matrix); + } + + void vec_t::TransformPoint(const matrix_t& matrix) + { + vec_t out; + + out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + matrix.m[3][0]; + out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + matrix.m[3][1]; + out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + matrix.m[3][2]; + out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + matrix.m[3][3]; + + x = out.x; + y = out.y; + z = out.z; + w = out.w; + } + + + void vec_t::TransformVector(const matrix_t& matrix) + { + vec_t out; + + out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0]; + out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1]; + out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2]; + out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3]; + + x = out.x; + y = out.y; + z = out.z; + w = out.w; + } + + float matrix_t::Inverse(const matrix_t &srcMatrix, bool affine) + { + float det = 0; + + if (affine) + { + det = GetDeterminant(); + float s = 1 / det; + m[0][0] = (srcMatrix.m[1][1] * srcMatrix.m[2][2] - srcMatrix.m[1][2] * srcMatrix.m[2][1]) * s; + m[0][1] = (srcMatrix.m[2][1] * srcMatrix.m[0][2] - srcMatrix.m[2][2] * srcMatrix.m[0][1]) * s; + m[0][2] = (srcMatrix.m[0][1] * srcMatrix.m[1][2] - srcMatrix.m[0][2] * srcMatrix.m[1][1]) * s; + m[1][0] = (srcMatrix.m[1][2] * srcMatrix.m[2][0] - srcMatrix.m[1][0] * srcMatrix.m[2][2]) * s; + m[1][1] = (srcMatrix.m[2][2] * srcMatrix.m[0][0] - srcMatrix.m[2][0] * srcMatrix.m[0][2]) * s; + m[1][2] = (srcMatrix.m[0][2] * srcMatrix.m[1][0] - srcMatrix.m[0][0] * srcMatrix.m[1][2]) * s; + m[2][0] = (srcMatrix.m[1][0] * srcMatrix.m[2][1] - srcMatrix.m[1][1] * srcMatrix.m[2][0]) * s; + m[2][1] = (srcMatrix.m[2][0] * srcMatrix.m[0][1] - srcMatrix.m[2][1] * srcMatrix.m[0][0]) * s; + m[2][2] = (srcMatrix.m[0][0] * srcMatrix.m[1][1] - srcMatrix.m[0][1] * srcMatrix.m[1][0]) * s; + m[3][0] = -(m[0][0] * srcMatrix.m[3][0] + m[1][0] * srcMatrix.m[3][1] + m[2][0] * srcMatrix.m[3][2]); + m[3][1] = -(m[0][1] * srcMatrix.m[3][0] + m[1][1] * srcMatrix.m[3][1] + m[2][1] * srcMatrix.m[3][2]); + m[3][2] = -(m[0][2] * srcMatrix.m[3][0] + m[1][2] * srcMatrix.m[3][1] + m[2][2] * srcMatrix.m[3][2]); + } + else + { + // transpose matrix + float src[16]; + for (int i = 0; i < 4; ++i) + { + src[i] = srcMatrix.m16[i * 4]; + src[i + 4] = srcMatrix.m16[i * 4 + 1]; + src[i + 8] = srcMatrix.m16[i * 4 + 2]; + src[i + 12] = srcMatrix.m16[i * 4 + 3]; + } + + // calculate pairs for first 8 elements (cofactors) + float tmp[12]; // temp array for pairs + tmp[0] = src[10] * src[15]; + tmp[1] = src[11] * src[14]; + tmp[2] = src[9] * src[15]; + tmp[3] = src[11] * src[13]; + tmp[4] = src[9] * src[14]; + tmp[5] = src[10] * src[13]; + tmp[6] = src[8] * src[15]; + tmp[7] = src[11] * src[12]; + tmp[8] = src[8] * src[14]; + tmp[9] = src[10] * src[12]; + tmp[10] = src[8] * src[13]; + tmp[11] = src[9] * src[12]; + + // calculate first 8 elements (cofactors) + m16[0] = (tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7]) - (tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7]); + m16[1] = (tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7]) - (tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7]); + m16[2] = (tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7]) - (tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7]); + m16[3] = (tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6]) - (tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6]); + m16[4] = (tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3]) - (tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3]); + m16[5] = (tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3]) - (tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3]); + m16[6] = (tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3]) - (tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3]); + m16[7] = (tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2]) - (tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2]); + + // calculate pairs for second 8 elements (cofactors) + tmp[0] = src[2] * src[7]; + tmp[1] = src[3] * src[6]; + tmp[2] = src[1] * src[7]; + tmp[3] = src[3] * src[5]; + tmp[4] = src[1] * src[6]; + tmp[5] = src[2] * src[5]; + tmp[6] = src[0] * src[7]; + tmp[7] = src[3] * src[4]; + tmp[8] = src[0] * src[6]; + tmp[9] = src[2] * src[4]; + tmp[10] = src[0] * src[5]; + tmp[11] = src[1] * src[4]; + + // calculate second 8 elements (cofactors) + m16[8] = (tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15]) - (tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15]); + m16[9] = (tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15]) - (tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15]); + m16[10] = (tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15]) - (tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15]); + m16[11] = (tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14]) - (tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14]); + m16[12] = (tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9]) - (tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10]); + m16[13] = (tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10]) - (tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8]); + m16[14] = (tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8]) - (tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9]); + m16[15] = (tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9]) - (tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8]); + + // calculate determinant + det = src[0] * m16[0] + src[1] * m16[1] + src[2] * m16[2] + src[3] * m16[3]; + + // calculate matrix inverse + float invdet = 1 / det; + for (int j = 0; j < 16; ++j) + { + m16[j] *= invdet; + } + } + + return det; + } + + void matrix_t::RotationAxis(const vec_t & axis, float angle) + { + float length2 = axis.LengthSq(); + if (length2 < FLT_EPSILON) + { + SetToIdentity(); + return; + } + + vec_t n = axis * (1.f / sqrtf(length2)); + float s = sinf(angle); + float c = cosf(angle); + float k = 1.f - c; + + float xx = n.x * n.x * k + c; + float yy = n.y * n.y * k + c; + float zz = n.z * n.z * k + c; + float xy = n.x * n.y * k; + float yz = n.y * n.z * k; + float zx = n.z * n.x * k; + float xs = n.x * s; + float ys = n.y * s; + float zs = n.z * s; + + m[0][0] = xx; + m[0][1] = xy + zs; + m[0][2] = zx - ys; + m[0][3] = 0.f; + m[1][0] = xy - zs; + m[1][1] = yy; + m[1][2] = yz + xs; + m[1][3] = 0.f; + m[2][0] = zx + ys; + m[2][1] = yz - xs; + m[2][2] = zz; + m[2][3] = 0.f; + m[3][0] = 0.f; + m[3][1] = 0.f; + m[3][2] = 0.f; + m[3][3] = 1.f; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + + enum MOVETYPE + { + NONE, + MOVE_X, + MOVE_Y, + MOVE_Z, + MOVE_YZ, + MOVE_ZX, + MOVE_XY, + MOVE_SCREEN, + ROTATE_X, + ROTATE_Y, + ROTATE_Z, + ROTATE_SCREEN, + SCALE_X, + SCALE_Y, + SCALE_Z, + SCALE_XYZ + }; + + struct Context + { + Context() : mbUsing(false), mbEnable(true), mbUsingBounds(false) + { + } + + ImDrawList* mDrawList; + + MODE mMode; + matrix_t mViewMat; + matrix_t mProjectionMat; + matrix_t mModel; + matrix_t mModelInverse; + matrix_t mModelSource; + matrix_t mModelSourceInverse; + matrix_t mMVP; + matrix_t mViewProjection; + + vec_t mModelScaleOrigin; + vec_t mCameraEye; + vec_t mCameraRight; + vec_t mCameraDir; + vec_t mCameraUp; + vec_t mRayOrigin; + vec_t mRayVector; + + float mRadiusSquareCenter; + ImVec2 mScreenSquareCenter; + ImVec2 mScreenSquareMin; + ImVec2 mScreenSquareMax; + + float mScreenFactor; + vec_t mRelativeOrigin; + + bool mbUsing; + bool mbEnable; + + // translation + vec_t mTranslationPlan; + vec_t mTranslationPlanOrigin; + vec_t mMatrixOrigin; + + // rotation + vec_t mRotationVectorSource; + float mRotationAngle; + float mRotationAngleOrigin; + //vec_t mWorldToLocalAxis; + + // scale + vec_t mScale; + vec_t mScaleValueOrigin; + float mSaveMousePosx; + + // save axis factor when using gizmo + bool mBelowAxisLimit[3]; + bool mBelowPlaneLimit[3]; + float mAxisFactor[3]; + + // bounds stretching + vec_t mBoundsPivot; + vec_t mBoundsAnchor; + vec_t mBoundsPlan; + vec_t mBoundsLocalPivot; + int mBoundsBestAxis; + int mBoundsAxis[2]; + bool mbUsingBounds; + matrix_t mBoundsMatrix; + + // + int mCurrentOperation; + + float mX = 0.f; + float mY = 0.f; + float mWidth = 0.f; + float mHeight = 0.f; + float mXMax = 0.f; + float mYMax = 0.f; + float mDisplayRatio = 1.f; + + bool mIsOrthographic = false; + }; + + static Context gContext; + + static const float angleLimit = 0.96f; + static const float planeLimit = 0.2f; + + static const vec_t directionUnary[3] = { makeVect(1.f, 0.f, 0.f), makeVect(0.f, 1.f, 0.f), makeVect(0.f, 0.f, 1.f) }; + static const ImU32 directionColor[3] = { 0xFF0000AA, 0xFF00AA00, 0xFFAA0000 }; + + // Alpha: 100%: FF, 87%: DE, 70%: B3, 54%: 8A, 50%: 80, 38%: 61, 12%: 1F + static const ImU32 planeColor[3] = { 0x610000AA, 0x6100AA00, 0x61AA0000 }; + static const ImU32 selectionColor = 0x8A1080FF; + static const ImU32 inactiveColor = 0x99999999; + static const ImU32 translationLineColor = 0xAAAAAAAA; + static const char *translationInfoMask[] = { "X : %5.3f", "Y : %5.3f", "Z : %5.3f", + "Y : %5.3f Z : %5.3f", "X : %5.3f Z : %5.3f", "X : %5.3f Y : %5.3f", + "X : %5.3f Y : %5.3f Z : %5.3f" }; + static const char *scaleInfoMask[] = { "X : %5.2f", "Y : %5.2f", "Z : %5.2f", "XYZ : %5.2f" }; + static const char *rotationInfoMask[] = { "X : %5.2f deg %5.2f rad", "Y : %5.2f deg %5.2f rad", "Z : %5.2f deg %5.2f rad", "Screen : %5.2f deg %5.2f rad" }; + static const int translationInfoIndex[] = { 0,0,0, 1,0,0, 2,0,0, 1,2,0, 0,2,0, 0,1,0, 0,1,2 }; + static const float quadMin = 0.5f; + static const float quadMax = 0.8f; + static const float quadUV[8] = { quadMin, quadMin, quadMin, quadMax, quadMax, quadMax, quadMax, quadMin }; + static const int halfCircleSegmentCount = 64; + static const float snapTension = 0.5f; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + static int GetMoveType(vec_t *gizmoHitProportion); + static int GetRotateType(); + static int GetScaleType(); + + static ImVec2 worldToPos(const vec_t& worldPos, const matrix_t& mat, ImVec2 position = ImVec2(gContext.mX, gContext.mY), ImVec2 size = ImVec2(gContext.mWidth, gContext.mHeight)) + { + vec_t trans; + trans.TransformPoint(worldPos, mat); + trans *= 0.5f / trans.w; + trans += makeVect(0.5f, 0.5f); + trans.y = 1.f - trans.y; + trans.x *= size.x; + trans.y *= size.y; + trans.x += position.x; + trans.y += position.y; + return ImVec2(trans.x, trans.y); + } + + static void ComputeCameraRay(vec_t &rayOrigin, vec_t &rayDir, ImVec2 position = ImVec2(gContext.mX, gContext.mY), ImVec2 size = ImVec2(gContext.mWidth, gContext.mHeight)) + { + ImGuiIO& io = ImGui::GetIO(); + + matrix_t mViewProjInverse; + mViewProjInverse.Inverse(gContext.mViewMat * gContext.mProjectionMat); + + float mox = ((io.MousePos.x - position.x) / size.x) * 2.f - 1.f; + float moy = (1.f - ((io.MousePos.y - position.y) / size.y)) * 2.f - 1.f; + + rayOrigin.Transform(makeVect(mox, moy, 0.f, 1.f), mViewProjInverse); + rayOrigin *= 1.f / rayOrigin.w; + vec_t rayEnd; + rayEnd.Transform(makeVect(mox, moy, 1.f, 1.f), mViewProjInverse); + rayEnd *= 1.f / rayEnd.w; + rayDir = Normalized(rayEnd - rayOrigin); + } + + static float GetSegmentLengthClipSpace(const vec_t& start, const vec_t& end) + { + vec_t startOfSegment = start; + startOfSegment.TransformPoint(gContext.mMVP); + if (fabsf(startOfSegment.w)> FLT_EPSILON) // check for axis aligned with camera direction + startOfSegment *= 1.f / startOfSegment.w; + + vec_t endOfSegment = end; + endOfSegment.TransformPoint(gContext.mMVP); + if (fabsf(endOfSegment.w)> FLT_EPSILON) // check for axis aligned with camera direction + endOfSegment *= 1.f / endOfSegment.w; + + vec_t clipSpaceAxis = endOfSegment - startOfSegment; + clipSpaceAxis.y /= gContext.mDisplayRatio; + float segmentLengthInClipSpace = sqrtf(clipSpaceAxis.x*clipSpaceAxis.x + clipSpaceAxis.y*clipSpaceAxis.y); + return segmentLengthInClipSpace; + } + + static float GetParallelogram(const vec_t& ptO, const vec_t& ptA, const vec_t& ptB) + { + vec_t pts[] = { ptO, ptA, ptB }; + for (unsigned int i = 0; i < 3; i++) + { + pts[i].TransformPoint(gContext.mMVP); + if (fabsf(pts[i].w)> FLT_EPSILON) // check for axis aligned with camera direction + pts[i] *= 1.f / pts[i].w; + } + vec_t segA = pts[1] - pts[0]; + vec_t segB = pts[2] - pts[0]; + segA.y /= gContext.mDisplayRatio; + segB.y /= gContext.mDisplayRatio; + vec_t segAOrtho = makeVect(-segA.y, segA.x); + segAOrtho.Normalize(); + float dt = segAOrtho.Dot3(segB); + float surface = sqrtf(segA.x*segA.x + segA.y*segA.y) * fabsf(dt); + return surface; + } + + inline vec_t PointOnSegment(const vec_t & point, const vec_t & vertPos1, const vec_t & vertPos2) + { + vec_t c = point - vertPos1; + vec_t V; + + V.Normalize(vertPos2 - vertPos1); + float d = (vertPos2 - vertPos1).Length(); + float t = V.Dot3(c); + + if (t < 0.f) + return vertPos1; + + if (t > d) + return vertPos2; + + return vertPos1 + V * t; + } + + static float IntersectRayPlane(const vec_t & rOrigin, const vec_t& rVector, const vec_t& plan) + { + float numer = plan.Dot3(rOrigin) - plan.w; + float denom = plan.Dot3(rVector); + + if (fabsf(denom) < FLT_EPSILON) // normal is orthogonal to vector, cant intersect + return -1.0f; + + return -(numer / denom); + } + + static bool IsInContextRect( ImVec2 p ) + { + return IsWithin( p.x, gContext.mX, gContext.mXMax ) && IsWithin(p.y, gContext.mY, gContext.mYMax ); + } + + void SetRect(float x, float y, float width, float height) + { + gContext.mX = x; + gContext.mY = y; + gContext.mWidth = width; + gContext.mHeight = height; + gContext.mXMax = gContext.mX + gContext.mWidth; + gContext.mYMax = gContext.mY + gContext.mXMax; + gContext.mDisplayRatio = width / height; + } + + IMGUI_API void SetOrthographic(bool isOrthographic) + { + gContext.mIsOrthographic = isOrthographic; + } + + void SetDrawlist() + { + gContext.mDrawList = ImGui::GetWindowDrawList(); + } + + void BeginFrame() + { + ImGuiIO& io = ImGui::GetIO(); + + const ImU32 flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus; + ImGui::SetNextWindowSize(io.DisplaySize); + ImGui::SetNextWindowPos(ImVec2(0, 0)); + + ImGui::PushStyleColor(ImGuiCol_WindowBg, 0); + ImGui::PushStyleColor(ImGuiCol_Border, 0); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + + ImGui::Begin("gizmo", NULL, flags); + gContext.mDrawList = ImGui::GetWindowDrawList(); + ImGui::End(); + ImGui::PopStyleVar(); + ImGui::PopStyleColor(2); + } + + bool IsUsing() + { + return gContext.mbUsing||gContext.mbUsingBounds; + } + + bool IsOver() + { + return (GetMoveType(NULL) != NONE) || GetRotateType() != NONE || GetScaleType() != NONE || IsUsing(); + } + + void Enable(bool enable) + { + gContext.mbEnable = enable; + if (!enable) + { + gContext.mbUsing = false; + gContext.mbUsingBounds = false; + } + } + + static float GetUniform(const vec_t& position, const matrix_t& mat) + { + vec_t trf = makeVect(position.x, position.y, position.z, 1.f); + trf.Transform(mat); + return trf.w; + } + + static void ComputeContext(const float *view, const float *projection, float *matrix, MODE mode) + { + gContext.mMode = mode; + gContext.mViewMat = *(matrix_t*)view; + gContext.mProjectionMat = *(matrix_t*)projection; + + if (mode == LOCAL) + { + gContext.mModel = *(matrix_t*)matrix; + gContext.mModel.OrthoNormalize(); + } + else + { + gContext.mModel.Translation(((matrix_t*)matrix)->v.position); + } + gContext.mModelSource = *(matrix_t*)matrix; + gContext.mModelScaleOrigin.Set(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length()); + + gContext.mModelInverse.Inverse(gContext.mModel); + gContext.mModelSourceInverse.Inverse(gContext.mModelSource); + gContext.mViewProjection = gContext.mViewMat * gContext.mProjectionMat; + gContext.mMVP = gContext.mModel * gContext.mViewProjection; + + matrix_t viewInverse; + viewInverse.Inverse(gContext.mViewMat); + gContext.mCameraDir = viewInverse.v.dir; + gContext.mCameraEye = viewInverse.v.position; + gContext.mCameraRight = viewInverse.v.right; + gContext.mCameraUp = viewInverse.v.up; + + // compute scale from the size of camera right vector projected on screen at the matrix position + vec_t pointRight = viewInverse.v.right; + pointRight.TransformPoint(gContext.mViewProjection); + gContext.mScreenFactor = gGizmoSizeClipSpace / (pointRight.x / pointRight.w - gContext.mMVP.v.position.x / gContext.mMVP.v.position.w); + + vec_t rightViewInverse = viewInverse.v.right; + rightViewInverse.TransformVector(gContext.mModelInverse); + float rightLength = GetSegmentLengthClipSpace(makeVect(0.f, 0.f), rightViewInverse); + gContext.mScreenFactor = gGizmoSizeClipSpace / rightLength; + + ImVec2 centerSSpace = worldToPos(makeVect(0.f, 0.f), gContext.mMVP); + gContext.mScreenSquareCenter = centerSSpace; + gContext.mScreenSquareMin = ImVec2(centerSSpace.x - 10.f, centerSSpace.y - 10.f); + gContext.mScreenSquareMax = ImVec2(centerSSpace.x + 10.f, centerSSpace.y + 10.f); + + ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector); + } + + static void ComputeColors(ImU32 *colors, int type, OPERATION operation) + { + if (gContext.mbEnable) + { + switch (operation) + { + case TRANSLATE: + colors[0] = (type == MOVE_SCREEN) ? selectionColor : 0xFFFFFFFF; + for (int i = 0; i < 3; i++) + { + colors[i + 1] = (type == (int)(MOVE_X + i)) ? selectionColor : directionColor[i]; + colors[i + 4] = (type == (int)(MOVE_YZ + i)) ? selectionColor : planeColor[i]; + colors[i + 4] = (type == MOVE_SCREEN) ? selectionColor : colors[i + 4]; + } + break; + case ROTATE: + colors[0] = (type == ROTATE_SCREEN) ? selectionColor : 0xFFFFFFFF; + for (int i = 0; i < 3; i++) + colors[i + 1] = (type == (int)(ROTATE_X + i)) ? selectionColor : directionColor[i]; + break; + case SCALE: + colors[0] = (type == SCALE_XYZ) ? selectionColor : 0xFFFFFFFF; + for (int i = 0; i < 3; i++) + colors[i + 1] = (type == (int)(SCALE_X + i)) ? selectionColor : directionColor[i]; + break; + case BOUNDS: + break; + } + } + else + { + for (int i = 0; i < 7; i++) + colors[i] = inactiveColor; + } + } + + static void ComputeTripodAxisAndVisibility(int axisIndex, vec_t& dirAxis, vec_t& dirPlaneX, vec_t& dirPlaneY, bool& belowAxisLimit, bool& belowPlaneLimit) + { + dirAxis = directionUnary[axisIndex]; + dirPlaneX = directionUnary[(axisIndex + 1) % 3]; + dirPlaneY = directionUnary[(axisIndex + 2) % 3]; + + if (gContext.mbUsing) + { + // when using, use stored factors so the gizmo doesn't flip when we translate + belowAxisLimit = gContext.mBelowAxisLimit[axisIndex]; + belowPlaneLimit = gContext.mBelowPlaneLimit[axisIndex]; + + dirAxis *= gContext.mAxisFactor[axisIndex]; + dirPlaneX *= gContext.mAxisFactor[(axisIndex + 1) % 3]; + dirPlaneY *= gContext.mAxisFactor[(axisIndex + 2) % 3]; + } + else + { + // new method + float lenDir = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirAxis); + float lenDirMinus = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirAxis); + + float lenDirPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirPlaneX); + float lenDirMinusPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirPlaneX); + + float lenDirPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirPlaneY); + float lenDirMinusPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirPlaneY); + + float mulAxis = (lenDir < lenDirMinus && fabsf(lenDir - lenDirMinus) > FLT_EPSILON) ? -1.f : 1.f; + float mulAxisX = (lenDirPlaneX < lenDirMinusPlaneX && fabsf(lenDirPlaneX - lenDirMinusPlaneX) > FLT_EPSILON) ? -1.f : 1.f; + float mulAxisY = (lenDirPlaneY < lenDirMinusPlaneY && fabsf(lenDirPlaneY - lenDirMinusPlaneY) > FLT_EPSILON) ? -1.f : 1.f; + dirAxis *= mulAxis; + dirPlaneX *= mulAxisX; + dirPlaneY *= mulAxisY; + + // for axis + float axisLengthInClipSpace = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirAxis * gContext.mScreenFactor); + + float paraSurf = GetParallelogram(makeVect(0.f, 0.f, 0.f), dirPlaneX * gContext.mScreenFactor, dirPlaneY * gContext.mScreenFactor); + belowPlaneLimit = (paraSurf > 0.0025f); + belowAxisLimit = (axisLengthInClipSpace > 0.02f); + + // and store values + gContext.mAxisFactor[axisIndex] = mulAxis; + gContext.mAxisFactor[(axisIndex + 1) % 3] = mulAxisX; + gContext.mAxisFactor[(axisIndex + 2) % 3] = mulAxisY; + gContext.mBelowAxisLimit[axisIndex] = belowAxisLimit; + gContext.mBelowPlaneLimit[axisIndex] = belowPlaneLimit; + } + } + + static void ComputeSnap(float*value, float snap) + { + if (snap <= FLT_EPSILON) + return; + float modulo = fmodf(*value, snap); + float moduloRatio = fabsf(modulo) / snap; + if (moduloRatio < snapTension) + *value -= modulo; + else if (moduloRatio >(1.f - snapTension)) + *value = *value - modulo + snap * ((*value<0.f) ? -1.f : 1.f); + } + static void ComputeSnap(vec_t& value, float *snap) + { + for (int i = 0; i < 3; i++) + { + ComputeSnap(&value[i], snap[i]); + } + } + + static float ComputeAngleOnPlan() + { + const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan); + vec_t localPos = Normalized(gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position); + + vec_t perpendicularVector; + perpendicularVector.Cross(gContext.mRotationVectorSource, gContext.mTranslationPlan); + perpendicularVector.Normalize(); + float acosAngle = Clamp(Dot(localPos, gContext.mRotationVectorSource), -0.9999f, 0.9999f); + float angle = acosf(acosAngle); + angle *= (Dot(localPos, perpendicularVector) < 0.f) ? 1.f : -1.f; + return angle; + } + + static void DrawRotationGizmo(int type) + { + ImDrawList* drawList = gContext.mDrawList; + + // colors + ImU32 colors[7]; + ComputeColors(colors, type, ROTATE); + + vec_t cameraToModelNormalized; + if (gContext.mIsOrthographic) + { + matrix_t viewInverse; + viewInverse.Inverse(*(matrix_t*)&gContext.mViewMat); + cameraToModelNormalized = viewInverse.v.dir; + } + else + { + cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye); + } + + cameraToModelNormalized.TransformVector(gContext.mModelInverse); + + gContext.mRadiusSquareCenter = screenRotateSize * gContext.mHeight; + + for (int axis = 0; axis < 3; axis++) + { + ImVec2 circlePos[halfCircleSegmentCount]; + + float angleStart = atan2f(cameraToModelNormalized[(4-axis)%3], cameraToModelNormalized[(3 - axis) % 3]) + ZPI * 0.5f; + + for (unsigned int i = 0; i < halfCircleSegmentCount; i++) + { + float ng = angleStart + ZPI * ((float)i / (float)halfCircleSegmentCount); + vec_t axisPos = makeVect(cosf(ng), sinf(ng), 0.f); + vec_t pos = makeVect(axisPos[axis], axisPos[(axis+1)%3], axisPos[(axis+2)%3]) * gContext.mScreenFactor; + circlePos[i] = worldToPos(pos, gContext.mMVP); + } + + float radiusAxis = sqrtf( (ImLengthSqr(worldToPos(gContext.mModel.v.position, gContext.mViewProjection) - circlePos[0]) )); + if(radiusAxis > gContext.mRadiusSquareCenter) + gContext.mRadiusSquareCenter = radiusAxis; + + drawList->AddPolyline(circlePos, halfCircleSegmentCount, colors[3 - axis], false, 2); + } + drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), gContext.mRadiusSquareCenter, colors[0], 64, 3.f); + + if (gContext.mbUsing) + { + ImVec2 circlePos[halfCircleSegmentCount +1]; + + circlePos[0] = worldToPos(gContext.mModel.v.position, gContext.mViewProjection); + for (unsigned int i = 1; i < halfCircleSegmentCount; i++) + { + float ng = gContext.mRotationAngle * ((float)(i-1) / (float)(halfCircleSegmentCount -1)); + matrix_t rotateVectorMatrix; + rotateVectorMatrix.RotationAxis(gContext.mTranslationPlan, ng); + vec_t pos; + pos.TransformPoint(gContext.mRotationVectorSource, rotateVectorMatrix); + pos *= gContext.mScreenFactor; + circlePos[i] = worldToPos(pos + gContext.mModel.v.position, gContext.mViewProjection); + } + drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount, 0x801080FF); + drawList->AddPolyline(circlePos, halfCircleSegmentCount, 0xFF1080FF, true, 2); + + ImVec2 destinationPosOnScreen = circlePos[1]; + char tmps[512]; + ImFormatString(tmps, sizeof(tmps), rotationInfoMask[type - ROTATE_X], (gContext.mRotationAngle/ZPI)*180.f, gContext.mRotationAngle); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), 0xFF000000, tmps); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), 0xFFFFFFFF, tmps); + } + } + + static void DrawHatchedAxis(const vec_t& axis) + { + for (int j = 1; j < 10; j++) + { + ImVec2 baseSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2) * gContext.mScreenFactor, gContext.mMVP); + ImVec2 worldDirSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2 + 1) * gContext.mScreenFactor, gContext.mMVP); + gContext.mDrawList->AddLine(baseSSpace2, worldDirSSpace2, 0x80000000, 6.f); + } + } + + static void DrawScaleGizmo(int type) + { + ImDrawList* drawList = gContext.mDrawList; + + // colors + ImU32 colors[7]; + ComputeColors(colors, type, SCALE); + + // draw + vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f }; + + if (gContext.mbUsing) + scaleDisplay = gContext.mScale; + + for (unsigned int i = 0; i < 3; i++) + { + vec_t dirPlaneX, dirPlaneY, dirAxis; + bool belowAxisLimit, belowPlaneLimit; + ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit); + + // draw axis + if (belowAxisLimit) + { + ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVP); + ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * gContext.mScreenFactor, gContext.mMVP); + ImVec2 worldDirSSpace = worldToPos((dirAxis * scaleDisplay[i]) * gContext.mScreenFactor, gContext.mMVP); + + if (gContext.mbUsing) + { + drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, 0xFF404040, 3.f); + drawList->AddCircleFilled(worldDirSSpaceNoScale, 6.f, 0xFF404040); + } + + drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f); + drawList->AddCircleFilled(worldDirSSpace, 6.f, colors[i + 1]); + + if (gContext.mAxisFactor[i] < 0.f) + DrawHatchedAxis(dirAxis * scaleDisplay[i]); + } + } + + // draw screen cirle + drawList->AddCircleFilled(gContext.mScreenSquareCenter, 6.f, colors[0], 32); + + if (gContext.mbUsing) + { + //ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection); + ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection); + /*vec_t dif(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y); + dif.Normalize(); + dif *= 5.f; + drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor); + drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor); + drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f); + */ + char tmps[512]; + //vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin; + int componentInfoIndex = (type - SCALE_X) * 3; + ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - SCALE_X], scaleDisplay[translationInfoIndex[componentInfoIndex]]); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), 0xFF000000, tmps); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), 0xFFFFFFFF, tmps); + } + } + + + static void DrawTranslationGizmo(int type) + { + ImDrawList* drawList = gContext.mDrawList; + if (!drawList) + return; + + // colors + ImU32 colors[7]; + ComputeColors(colors, type, TRANSLATE); + + const ImVec2 origin = worldToPos(gContext.mModel.v.position, gContext.mViewProjection); + + // draw + bool belowAxisLimit = false; + bool belowPlaneLimit = false; + for (unsigned int i = 0; i < 3; ++i) + { + vec_t dirPlaneX, dirPlaneY, dirAxis; + ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit); + + // draw axis + if (belowAxisLimit) + { + ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVP); + ImVec2 worldDirSSpace = worldToPos(dirAxis * gContext.mScreenFactor, gContext.mMVP); + + drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f); + + // Arrow head begin + ImVec2 dir(origin - worldDirSSpace); + + float d = sqrtf(ImLengthSqr(dir)); + dir /= d; // Normalize + dir *= 6.0f; + + ImVec2 ortogonalDir(dir.y, -dir.x); // Perpendicular vector + ImVec2 a(worldDirSSpace + dir); + drawList->AddTriangleFilled(worldDirSSpace - dir, a + ortogonalDir, a - ortogonalDir, colors[i + 1]); + // Arrow head end + + if (gContext.mAxisFactor[i] < 0.f) + DrawHatchedAxis(dirAxis); + } + + // draw plane + if (belowPlaneLimit) + { + ImVec2 screenQuadPts[4]; + for (int j = 0; j < 4; ++j) + { + vec_t cornerWorldPos = (dirPlaneX * quadUV[j * 2] + dirPlaneY * quadUV[j * 2 + 1]) * gContext.mScreenFactor; + screenQuadPts[j] = worldToPos(cornerWorldPos, gContext.mMVP); + } + drawList->AddPolyline(screenQuadPts, 4, directionColor[i], true, 1.0f); + drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4]); + } + } + + drawList->AddCircleFilled(gContext.mScreenSquareCenter, 6.f, colors[0], 32); + + if (gContext.mbUsing) + { + ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection); + ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection); + vec_t dif = { destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y, 0.f, 0.f }; + dif.Normalize(); + dif *= 5.f; + drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor); + drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor); + drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f); + + char tmps[512]; + vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin; + int componentInfoIndex = (type - MOVE_X) * 3; + ImFormatString(tmps, sizeof(tmps), translationInfoMask[type - MOVE_X], deltaInfo[translationInfoIndex[componentInfoIndex]], deltaInfo[translationInfoIndex[componentInfoIndex + 1]], deltaInfo[translationInfoIndex[componentInfoIndex + 2]]); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), 0xFF000000, tmps); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), 0xFFFFFFFF, tmps); + } + } + + static bool CanActivate() + { + if (ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered() && !ImGui::IsAnyItemActive()) + return true; + return false; + } + + static void HandleAndDrawLocalBounds(float *bounds, matrix_t *matrix, float *snapValues, OPERATION operation) + { + ImGuiIO& io = ImGui::GetIO(); + ImDrawList* drawList = gContext.mDrawList; + + // compute best projection axis + vec_t axesWorldDirections[3]; + vec_t bestAxisWorldDirection = { 0.0f, 0.0f, 0.0f, 0.0f }; + int axes[3]; + unsigned int numAxes = 1; + axes[0] = gContext.mBoundsBestAxis; + int bestAxis = axes[0]; + if (!gContext.mbUsingBounds) + { + numAxes = 0; + float bestDot = 0.f; + for (unsigned int i = 0; i < 3; i++) + { + vec_t dirPlaneNormalWorld; + dirPlaneNormalWorld.TransformVector(directionUnary[i], gContext.mModelSource); + dirPlaneNormalWorld.Normalize(); + + float dt = fabsf( Dot(Normalized(gContext.mCameraEye - gContext.mModelSource.v.position), dirPlaneNormalWorld) ); + if ( dt >= bestDot ) + { + bestDot = dt; + bestAxis = i; + bestAxisWorldDirection = dirPlaneNormalWorld; + } + + if( dt >= 0.1f ) + { + axes[numAxes] = i; + axesWorldDirections[numAxes] = dirPlaneNormalWorld; + ++numAxes; + } + } + } + + if( numAxes == 0 ) + { + axes[0] = bestAxis; + axesWorldDirections[0] = bestAxisWorldDirection; + numAxes = 1; + } + else if( bestAxis != axes[0] ) + { + unsigned int bestIndex = 0; + for (unsigned int i = 0; i < numAxes; i++) + { + if( axes[i] == bestAxis ) + { + bestIndex = i; + break; + } + } + int tempAxis = axes[0]; + axes[0] = axes[bestIndex]; + axes[bestIndex] = tempAxis; + vec_t tempDirection = axesWorldDirections[0]; + axesWorldDirections[0] = axesWorldDirections[bestIndex]; + axesWorldDirections[bestIndex] = tempDirection; + } + + for (unsigned int axisIndex = 0; axisIndex < numAxes; ++axisIndex) + { + bestAxis = axes[axisIndex]; + bestAxisWorldDirection = axesWorldDirections[axisIndex]; + + // corners + vec_t aabb[4]; + + int secondAxis = (bestAxis + 1) % 3; + int thirdAxis = (bestAxis + 2) % 3; + + for (int i = 0; i < 4; i++) + { + aabb[i][3] = aabb[i][bestAxis] = 0.f; + aabb[i][secondAxis] = bounds[secondAxis + 3 * (i >> 1)]; + aabb[i][thirdAxis] = bounds[thirdAxis + 3 * ((i >> 1) ^ (i & 1))]; + } + + // draw bounds + unsigned int anchorAlpha = gContext.mbEnable ? 0xFF000000 : 0x80000000; + + matrix_t boundsMVP = gContext.mModelSource * gContext.mViewProjection; + for (int i = 0; i < 4;i++) + { + ImVec2 worldBound1 = worldToPos(aabb[i], boundsMVP); + ImVec2 worldBound2 = worldToPos(aabb[(i+1)%4], boundsMVP); + if( !IsInContextRect( worldBound1 ) || !IsInContextRect( worldBound2 ) ) + { + continue; + } + float boundDistance = sqrtf(ImLengthSqr(worldBound1 - worldBound2)); + int stepCount = (int)(boundDistance / 10.f); + stepCount = min( stepCount, 1000 ); + float stepLength = 1.f / (float)stepCount; + for (int j = 0; j < stepCount; j++) + { + float t1 = (float)j * stepLength; + float t2 = (float)j * stepLength + stepLength * 0.5f; + ImVec2 worldBoundSS1 = ImLerp(worldBound1, worldBound2, ImVec2(t1, t1)); + ImVec2 worldBoundSS2 = ImLerp(worldBound1, worldBound2, ImVec2(t2, t2)); + //drawList->AddLine(worldBoundSS1, worldBoundSS2, 0x000000 + anchorAlpha, 3.f); + drawList->AddLine(worldBoundSS1, worldBoundSS2, 0xAAAAAA + anchorAlpha, 2.f); + } + vec_t midPoint = (aabb[i] + aabb[(i + 1) % 4] ) * 0.5f; + ImVec2 midBound = worldToPos(midPoint, boundsMVP); + static const float AnchorBigRadius = 8.f; + static const float AnchorSmallRadius = 6.f; + bool overBigAnchor = ImLengthSqr(worldBound1 - io.MousePos) <= (AnchorBigRadius*AnchorBigRadius); + bool overSmallAnchor = ImLengthSqr(midBound - io.MousePos) <= (AnchorBigRadius*AnchorBigRadius); + + int type = NONE; + vec_t gizmoHitProportion; + + switch (operation) + { + case TRANSLATE: type = GetMoveType(&gizmoHitProportion); break; + case ROTATE: type = GetRotateType(); break; + case SCALE: type = GetScaleType(); break; + case BOUNDS: break; + } + if (type != NONE) + { + overBigAnchor = false; + overSmallAnchor = false; + } + + + unsigned int bigAnchorColor = overBigAnchor ? selectionColor : (0xAAAAAA + anchorAlpha); + unsigned int smallAnchorColor = overSmallAnchor ? selectionColor : (0xAAAAAA + anchorAlpha); + + drawList->AddCircleFilled(worldBound1, AnchorBigRadius, 0xFF000000); + drawList->AddCircleFilled(worldBound1, AnchorBigRadius-1.2f, bigAnchorColor); + + drawList->AddCircleFilled(midBound, AnchorSmallRadius, 0xFF000000); + drawList->AddCircleFilled(midBound, AnchorSmallRadius-1.2f, smallAnchorColor); + int oppositeIndex = (i + 2) % 4; + // big anchor on corners + if (!gContext.mbUsingBounds && gContext.mbEnable && overBigAnchor && CanActivate()) + { + gContext.mBoundsPivot.TransformPoint(aabb[(i + 2) % 4], gContext.mModelSource); + gContext.mBoundsAnchor.TransformPoint(aabb[i], gContext.mModelSource); + gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection); + gContext.mBoundsBestAxis = bestAxis; + gContext.mBoundsAxis[0] = secondAxis; + gContext.mBoundsAxis[1] = thirdAxis; + + gContext.mBoundsLocalPivot.Set(0.f); + gContext.mBoundsLocalPivot[secondAxis] = aabb[oppositeIndex][secondAxis]; + gContext.mBoundsLocalPivot[thirdAxis] = aabb[oppositeIndex][thirdAxis]; + + gContext.mbUsingBounds = true; + gContext.mBoundsMatrix = gContext.mModelSource; + } + // small anchor on middle of segment + if (!gContext.mbUsingBounds && gContext.mbEnable && overSmallAnchor && CanActivate()) + { + vec_t midPointOpposite = (aabb[(i + 2) % 4] + aabb[(i + 3) % 4]) * 0.5f; + gContext.mBoundsPivot.TransformPoint(midPointOpposite, gContext.mModelSource); + gContext.mBoundsAnchor.TransformPoint(midPoint, gContext.mModelSource); + gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection); + gContext.mBoundsBestAxis = bestAxis; + int indices[] = { secondAxis , thirdAxis }; + gContext.mBoundsAxis[0] = indices[i%2]; + gContext.mBoundsAxis[1] = -1; + + gContext.mBoundsLocalPivot.Set(0.f); + gContext.mBoundsLocalPivot[gContext.mBoundsAxis[0]] = aabb[oppositeIndex][indices[i % 2]];// bounds[gContext.mBoundsAxis[0]] * (((i + 1) & 2) ? 1.f : -1.f); + + gContext.mbUsingBounds = true; + gContext.mBoundsMatrix = gContext.mModelSource; + } + } + + if (gContext.mbUsingBounds) + { + matrix_t scale; + scale.SetToIdentity(); + + // compute projected mouse position on plan + const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mBoundsPlan); + vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len; + + // compute a reference and delta vectors base on mouse move + vec_t deltaVector = (newPos - gContext.mBoundsPivot).Abs(); + vec_t referenceVector = (gContext.mBoundsAnchor - gContext.mBoundsPivot).Abs(); + + // for 1 or 2 axes, compute a ratio that's used for scale and snap it based on resulting length + for (int i = 0; i < 2; i++) + { + int axisIndex1 = gContext.mBoundsAxis[i]; + if (axisIndex1 == -1) + continue; + + float ratioAxis = 1.f; + vec_t axisDir = gContext.mBoundsMatrix.component[axisIndex1].Abs(); + + float dtAxis = axisDir.Dot(referenceVector); + float boundSize = bounds[axisIndex1 + 3] - bounds[axisIndex1]; + if (dtAxis > FLT_EPSILON) + ratioAxis = axisDir.Dot(deltaVector) / dtAxis; + + if (snapValues) + { + float length = boundSize * ratioAxis; + ComputeSnap(&length, snapValues[axisIndex1]); + if (boundSize > FLT_EPSILON) + ratioAxis = length / boundSize; + } + scale.component[axisIndex1] *= ratioAxis; + } + + // transform matrix + matrix_t preScale, postScale; + preScale.Translation(-gContext.mBoundsLocalPivot); + postScale.Translation(gContext.mBoundsLocalPivot); + matrix_t res = preScale * scale * postScale * gContext.mBoundsMatrix; + *matrix = res; + + // info text + char tmps[512]; + ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection); + ImFormatString(tmps, sizeof(tmps), "X: %.2f Y: %.2f Z:%.2f" + , (bounds[3] - bounds[0]) * gContext.mBoundsMatrix.component[0].Length() * scale.component[0].Length() + , (bounds[4] - bounds[1]) * gContext.mBoundsMatrix.component[1].Length() * scale.component[1].Length() + , (bounds[5] - bounds[2]) * gContext.mBoundsMatrix.component[2].Length() * scale.component[2].Length() + ); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), 0xFF000000, tmps); + drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), 0xFFFFFFFF, tmps); + } + + if (!io.MouseDown[0]) + gContext.mbUsingBounds = false; + + if( gContext.mbUsingBounds ) + break; + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + + static int GetScaleType() + { + ImGuiIO& io = ImGui::GetIO(); + int type = NONE; + + // screen + if (io.MousePos.x >= gContext.mScreenSquareMin.x && io.MousePos.x <= gContext.mScreenSquareMax.x && + io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y) + type = SCALE_XYZ; + + // compute + for (unsigned int i = 0; i < 3 && type == NONE; i++) + { + vec_t dirPlaneX, dirPlaneY, dirAxis; + bool belowAxisLimit, belowPlaneLimit; + ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit); + dirAxis.TransformVector(gContext.mModel); + dirPlaneX.TransformVector(gContext.mModel); + dirPlaneY.TransformVector(gContext.mModel); + + const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModel.v.position, dirAxis)); + vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len; + + const ImVec2 posOnPlanScreen = worldToPos(posOnPlan, gContext.mViewProjection); + const ImVec2 axisStartOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor * 0.1f, gContext.mViewProjection); + const ImVec2 axisEndOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor, gContext.mViewProjection); + + vec_t closestPointOnAxis = PointOnSegment(makeVect(posOnPlanScreen), makeVect(axisStartOnScreen), makeVect(axisEndOnScreen)); + + if ((closestPointOnAxis - makeVect(posOnPlanScreen)).Length() < 12.f) // pixel size + type = SCALE_X + i; + } + return type; + } + + static int GetRotateType() + { + ImGuiIO& io = ImGui::GetIO(); + int type = NONE; + + vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f }; + float dist = deltaScreen.Length(); + if (dist >= (gContext.mRadiusSquareCenter - 1.0f) && dist < (gContext.mRadiusSquareCenter + 1.0f)) + type = ROTATE_SCREEN; + + const vec_t planNormals[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir}; + + for (unsigned int i = 0; i < 3 && type == NONE; i++) + { + // pickup plan + vec_t pickupPlan = BuildPlan(gContext.mModel.v.position, planNormals[i]); + + const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, pickupPlan); + vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position; + + if (Dot(Normalized(localPos), gContext.mRayVector) > FLT_EPSILON) + continue; + vec_t idealPosOnCircle = Normalized(localPos); + idealPosOnCircle.TransformVector(gContext.mModelInverse); + ImVec2 idealPosOnCircleScreen = worldToPos(idealPosOnCircle * gContext.mScreenFactor, gContext.mMVP); + + //gContext.mDrawList->AddCircle(idealPosOnCircleScreen, 5.f, 0xFFFFFFFF); + ImVec2 distanceOnScreen = idealPosOnCircleScreen - io.MousePos; + + float distance = makeVect(distanceOnScreen).Length(); + if (distance < 8.f) // pixel size + type = ROTATE_X + i; + } + + return type; + } + + static int GetMoveType(vec_t *gizmoHitProportion) + { + ImGuiIO& io = ImGui::GetIO(); + int type = NONE; + + // screen + if (io.MousePos.x >= gContext.mScreenSquareMin.x && io.MousePos.x <= gContext.mScreenSquareMax.x && + io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y) + type = MOVE_SCREEN; + + // compute + for (unsigned int i = 0; i < 3 && type == NONE; i++) + { + vec_t dirPlaneX, dirPlaneY, dirAxis; + bool belowAxisLimit, belowPlaneLimit; + ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit); + dirAxis.TransformVector(gContext.mModel); + dirPlaneX.TransformVector(gContext.mModel); + dirPlaneY.TransformVector(gContext.mModel); + + const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModel.v.position, dirAxis)); + vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len; + + const ImVec2 posOnPlanScreen = worldToPos(posOnPlan, gContext.mViewProjection); + const ImVec2 axisStartOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor * 0.1f, gContext.mViewProjection); + const ImVec2 axisEndOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor, gContext.mViewProjection); + + vec_t closestPointOnAxis = PointOnSegment(makeVect(posOnPlanScreen), makeVect(axisStartOnScreen), makeVect(axisEndOnScreen)); + + if ((closestPointOnAxis - makeVect(posOnPlanScreen)).Length() < 12.f) // pixel size + type = MOVE_X + i; + + const float dx = dirPlaneX.Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor)); + const float dy = dirPlaneY.Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor)); + if (belowPlaneLimit && dx >= quadUV[0] && dx <= quadUV[4] && dy >= quadUV[1] && dy <= quadUV[3]) + type = MOVE_YZ + i; + + if (gizmoHitProportion) + *gizmoHitProportion = makeVect(dx, dy, 0.f); + } + return type; + } + + static void HandleTranslation(float *matrix, float *deltaMatrix, int& type, float *snap) + { + ImGuiIO& io = ImGui::GetIO(); + bool applyRotationLocaly = gContext.mMode == LOCAL || type == MOVE_SCREEN; + + // move + if (gContext.mbUsing) + { + ImGui::CaptureMouseFromApp(); + const float len = fabsf(IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan)); // near plan + vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len; + + + + // compute delta + vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor; + vec_t delta = newOrigin - gContext.mModel.v.position; + + // 1 axis constraint + if (gContext.mCurrentOperation >= MOVE_X && gContext.mCurrentOperation <= MOVE_Z) + { + int axisIndex = gContext.mCurrentOperation - MOVE_X; + const vec_t& axisValue = *(vec_t*)&gContext.mModel.m[axisIndex]; + float lengthOnAxis = Dot(axisValue, delta); + delta = axisValue * lengthOnAxis; + } + + // snap + if (snap) + { + vec_t cumulativeDelta = gContext.mModel.v.position + delta - gContext.mMatrixOrigin; + if (applyRotationLocaly) + { + matrix_t modelSourceNormalized = gContext.mModelSource; + modelSourceNormalized.OrthoNormalize(); + matrix_t modelSourceNormalizedInverse; + modelSourceNormalizedInverse.Inverse(modelSourceNormalized); + cumulativeDelta.TransformVector(modelSourceNormalizedInverse); + ComputeSnap(cumulativeDelta, snap); + cumulativeDelta.TransformVector(modelSourceNormalized); + } + else + { + ComputeSnap(cumulativeDelta, snap); + } + delta = gContext.mMatrixOrigin + cumulativeDelta - gContext.mModel.v.position; + + } + + // compute matrix & delta + matrix_t deltaMatrixTranslation; + deltaMatrixTranslation.Translation(delta); + if (deltaMatrix) + memcpy(deltaMatrix, deltaMatrixTranslation.m16, sizeof(float) * 16); + + + matrix_t res = gContext.mModelSource * deltaMatrixTranslation; + *(matrix_t*)matrix = res; + + if (!io.MouseDown[0]) + gContext.mbUsing = false; + + type = gContext.mCurrentOperation; + } + else + { + // find new possible way to move + vec_t gizmoHitProportion; + type = GetMoveType(&gizmoHitProportion); + if(type != NONE) + { + ImGui::CaptureMouseFromApp(); + } + if (CanActivate() && type != NONE) + { + gContext.mbUsing = true; + gContext.mCurrentOperation = type; + vec_t movePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, + gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, + -gContext.mCameraDir }; + + vec_t cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye); + for (unsigned int i = 0; i < 3; i++) + { + vec_t orthoVector = Cross(movePlanNormal[i], cameraToModelNormalized); + movePlanNormal[i].Cross(orthoVector); + movePlanNormal[i].Normalize(); + } + // pickup plan + gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - MOVE_X]); + const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan); + gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len; + gContext.mMatrixOrigin = gContext.mModel.v.position; + + gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor); + } + } + } + + static void HandleScale(float *matrix, float *deltaMatrix, int& type, float *snap) + { + ImGuiIO& io = ImGui::GetIO(); + + if (!gContext.mbUsing) + { + // find new possible way to scale + type = GetScaleType(); + if(type != NONE) + { + ImGui::CaptureMouseFromApp(); + } + if (CanActivate() && type != NONE) + { + gContext.mbUsing = true; + gContext.mCurrentOperation = type; + const vec_t movePlanNormal[] = { gContext.mModel.v.up, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.dir, gContext.mModel.v.up, gContext.mModel.v.right, -gContext.mCameraDir }; + // pickup plan + + gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - SCALE_X]); + const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan); + gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len; + gContext.mMatrixOrigin = gContext.mModel.v.position; + gContext.mScale.Set(1.f, 1.f, 1.f); + gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor); + gContext.mScaleValueOrigin = makeVect(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length()); + gContext.mSaveMousePosx = io.MousePos.x; + } + } + // scale + if (gContext.mbUsing) + { + ImGui::CaptureMouseFromApp(); + const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan); + vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len; + vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor; + vec_t delta = newOrigin - gContext.mModel.v.position; + + // 1 axis constraint + if (gContext.mCurrentOperation >= SCALE_X && gContext.mCurrentOperation <= SCALE_Z) + { + int axisIndex = gContext.mCurrentOperation - SCALE_X; + const vec_t& axisValue = *(vec_t*)&gContext.mModel.m[axisIndex]; + float lengthOnAxis = Dot(axisValue, delta); + delta = axisValue * lengthOnAxis; + + vec_t baseVector = gContext.mTranslationPlanOrigin - gContext.mModel.v.position; + float ratio = Dot(axisValue, baseVector + delta) / Dot(axisValue, baseVector); + + gContext.mScale[axisIndex] = max(ratio, 0.001f); + } + else + { + float scaleDelta = (io.MousePos.x - gContext.mSaveMousePosx) * 0.01f; + gContext.mScale.Set(max(1.f + scaleDelta, 0.001f)); + } + + // snap + if (snap) + { + float scaleSnap[] = { snap[0], snap[0], snap[0] }; + ComputeSnap(gContext.mScale, scaleSnap); + } + + // no 0 allowed + for (int i = 0; i < 3;i++) + gContext.mScale[i] = max(gContext.mScale[i], 0.001f); + + // compute matrix & delta + matrix_t deltaMatrixScale; + deltaMatrixScale.Scale(gContext.mScale * gContext.mScaleValueOrigin); + + matrix_t res = deltaMatrixScale * gContext.mModel; + *(matrix_t*)matrix = res; + + if (deltaMatrix) + { + deltaMatrixScale.Scale(gContext.mScale); + memcpy(deltaMatrix, deltaMatrixScale.m16, sizeof(float) * 16); + } + + if (!io.MouseDown[0]) + gContext.mbUsing = false; + + type = gContext.mCurrentOperation; + } + } + + static void HandleRotation(float *matrix, float *deltaMatrix, int& type, float *snap) + { + ImGuiIO& io = ImGui::GetIO(); + bool applyRotationLocaly = gContext.mMode == LOCAL; + + if (!gContext.mbUsing) + { + type = GetRotateType(); + + if(type != NONE) + { + ImGui::CaptureMouseFromApp(); + } + + if (type == ROTATE_SCREEN) + { + applyRotationLocaly = true; + } + + if (CanActivate() && type != NONE) + { + gContext.mbUsing = true; + gContext.mCurrentOperation = type; + const vec_t rotatePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, -gContext.mCameraDir }; + // pickup plan + if (applyRotationLocaly) + { + gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, rotatePlanNormal[type - ROTATE_X]); + } + else + { + gContext.mTranslationPlan = BuildPlan(gContext.mModelSource.v.position, directionUnary[type - ROTATE_X]); + } + + const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan); + vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position; + gContext.mRotationVectorSource = Normalized(localPos); + gContext.mRotationAngleOrigin = ComputeAngleOnPlan(); + } + } + + // rotation + if (gContext.mbUsing) + { + ImGui::CaptureMouseFromApp(); + gContext.mRotationAngle = ComputeAngleOnPlan(); + if (snap) + { + float snapInRadian = snap[0] * DEG2RAD; + ComputeSnap(&gContext.mRotationAngle, snapInRadian); + } + vec_t rotationAxisLocalSpace; + + rotationAxisLocalSpace.TransformVector(makeVect(gContext.mTranslationPlan.x, gContext.mTranslationPlan.y, gContext.mTranslationPlan.z, 0.f), gContext.mModelInverse); + rotationAxisLocalSpace.Normalize(); + + matrix_t deltaRotation; + deltaRotation.RotationAxis(rotationAxisLocalSpace, gContext.mRotationAngle - gContext.mRotationAngleOrigin); + gContext.mRotationAngleOrigin = gContext.mRotationAngle; + + matrix_t scaleOrigin; + scaleOrigin.Scale(gContext.mModelScaleOrigin); + + if (applyRotationLocaly) + { + *(matrix_t*)matrix = scaleOrigin * deltaRotation * gContext.mModel; + } + else + { + matrix_t res = gContext.mModelSource; + res.v.position.Set(0.f); + + *(matrix_t*)matrix = res * deltaRotation; + ((matrix_t*)matrix)->v.position = gContext.mModelSource.v.position; + } + + if (deltaMatrix) + { + *(matrix_t*)deltaMatrix = gContext.mModelInverse * deltaRotation * gContext.mModel; + } + + if (!io.MouseDown[0]) + gContext.mbUsing = false; + + type = gContext.mCurrentOperation; + } + } + + void DecomposeMatrixToComponents(const float *matrix, float *translation, float *rotation, float *scale) + { + matrix_t mat = *(matrix_t*)matrix; + + scale[0] = mat.v.right.Length(); + scale[1] = mat.v.up.Length(); + scale[2] = mat.v.dir.Length(); + + mat.OrthoNormalize(); + + rotation[0] = RAD2DEG * atan2f(mat.m[1][2], mat.m[2][2]); + rotation[1] = RAD2DEG * atan2f(-mat.m[0][2], sqrtf(mat.m[1][2] * mat.m[1][2] + mat.m[2][2]* mat.m[2][2])); + rotation[2] = RAD2DEG * atan2f(mat.m[0][1], mat.m[0][0]); + + translation[0] = mat.v.position.x; + translation[1] = mat.v.position.y; + translation[2] = mat.v.position.z; + } + + void RecomposeMatrixFromComponents(const float *translation, const float *rotation, const float *scale, float *matrix) + { + matrix_t& mat = *(matrix_t*)matrix; + + matrix_t rot[3]; + for (int i = 0; i < 3;i++) + rot[i].RotationAxis(directionUnary[i], rotation[i] * DEG2RAD); + + mat = rot[0] * rot[1] * rot[2]; + + float validScale[3]; + for (int i = 0; i < 3; i++) + { + if (fabsf(scale[i]) < FLT_EPSILON) + validScale[i] = 0.001f; + else + validScale[i] = scale[i]; + } + mat.v.right *= validScale[0]; + mat.v.up *= validScale[1]; + mat.v.dir *= validScale[2]; + mat.v.position.Set(translation[0], translation[1], translation[2], 1.f); + } + + void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix, float *snap, float *localBounds, float *boundsSnap) + { + ComputeContext(view, projection, matrix, mode); + + // set delta to identity + if (deltaMatrix) + ((matrix_t*)deltaMatrix)->SetToIdentity(); + + // behind camera + vec_t camSpacePosition; + camSpacePosition.TransformPoint(makeVect(0.f, 0.f, 0.f), gContext.mMVP); + if (!gContext.mIsOrthographic && camSpacePosition.z < 0.001f) + return; + + // -- + int type = NONE; + if (gContext.mbEnable) + { + if (!gContext.mbUsingBounds) + { + switch (operation) + { + case ROTATE: + HandleRotation(matrix, deltaMatrix, type, snap); + break; + case TRANSLATE: + HandleTranslation(matrix, deltaMatrix, type, snap); + break; + case SCALE: + HandleScale(matrix, deltaMatrix, type, snap); + break; + case BOUNDS: + break; + } + } + } + + if (localBounds && !gContext.mbUsing) + HandleAndDrawLocalBounds(localBounds, (matrix_t*)matrix, boundsSnap, operation); + + if (!gContext.mbUsingBounds) + { + switch (operation) + { + case ROTATE: + DrawRotationGizmo(type); + break; + case TRANSLATE: + DrawTranslationGizmo(type); + break; + case SCALE: + DrawScaleGizmo(type); + break; + case BOUNDS: + break; + } + } + } + + void DrawCube(const float *view, const float *projection, const float *matrix) + { + matrix_t viewInverse; + viewInverse.Inverse(*(matrix_t*)view); + const matrix_t& model = *(matrix_t*)matrix; + matrix_t res = *(matrix_t*)matrix * *(matrix_t*)view * *(matrix_t*)projection; + matrix_t modelView = *(matrix_t*)matrix * *(matrix_t*)view; + + for (int iFace = 0; iFace < 6; iFace++) + { + const int normalIndex = (iFace % 3); + const int perpXIndex = (normalIndex + 1) % 3; + const int perpYIndex = (normalIndex + 2) % 3; + const float invert = (iFace > 2) ? -1.f : 1.f; + + const vec_t faceCoords[4] = { directionUnary[normalIndex] + directionUnary[perpXIndex] + directionUnary[perpYIndex], + directionUnary[normalIndex] + directionUnary[perpXIndex] - directionUnary[perpYIndex], + directionUnary[normalIndex] - directionUnary[perpXIndex] - directionUnary[perpYIndex], + directionUnary[normalIndex] - directionUnary[perpXIndex] + directionUnary[perpYIndex], + }; + + // clipping + bool skipFace = false; + for (unsigned int iCoord = 0; iCoord < 4; iCoord++) + { + vec_t camSpacePosition; + camSpacePosition.TransformPoint(faceCoords[iCoord] * 0.5f * invert, gContext.mMVP); + if (camSpacePosition.z < 0.001f) + { + skipFace = true; + break; + } + } + if (skipFace) + continue; + + // 3D->2D + ImVec2 faceCoordsScreen[4]; + for (unsigned int iCoord = 0; iCoord < 4; iCoord++) + { + faceCoordsScreen[iCoord] = worldToPos(faceCoords[iCoord] * 0.5f * invert, res); + } + + // back face culling + + const vec_t n = directionUnary[normalIndex] * invert; + vec_t viewSpaceNormal = n; + vec_t viewSpacePoint = n * 0.5f; + viewSpaceNormal.TransformVector(modelView); + viewSpaceNormal.Normalize(); + viewSpacePoint.TransformPoint(modelView); + const vec_t viewSpaceFacePlan = BuildPlan(viewSpacePoint, viewSpaceNormal); + + // back face culling + if (viewSpaceFacePlan.w > 0.f) + { + continue; + } + /* + vec_t cullPos, cullNormal; + cullPos.TransformPoint(faceCoords[0] * 0.5f * invert, model); + cullNormal.TransformVector(directionUnary[normalIndex] * invert, model); + float dt = Dot(Normalized(cullPos - viewInverse.v.position), Normalized(cullNormal)); + if (dt>0.f) + { + continue; + } + */ + // draw face with lighter color + gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, directionColor[normalIndex] | 0x808080); + } + } + + void DrawGrid(const float *view, const float *projection, const float *matrix, const float gridSize) + { + matrix_t res = *(matrix_t*)matrix * *(matrix_t*)view * *(matrix_t*)projection; + + for (float f = -gridSize; f <= gridSize; f += 1.f) + { + gContext.mDrawList->AddLine(worldToPos(makeVect(f, 0.f, -gridSize), res), worldToPos(makeVect(f, 0.f, gridSize), res), 0xFF808080); + gContext.mDrawList->AddLine(worldToPos(makeVect(-gridSize, 0.f, f), res), worldToPos(makeVect(gridSize, 0.f, f), res), 0xFF808080); + } + } + + bool ViewManipulate(float* view, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor) + { + bool ret = false; + static bool isDraging = false; + static bool isClicking = false; + static bool isInside = false; + static vec_t interpolationUp; + static vec_t interpolationDir; + static int interpolationFrames = 0; + const vec_t referenceUp = makeVect(0.f, 1.f, 0.f); + + ImGuiIO& io = ImGui::GetIO(); + gContext.mDrawList->AddRectFilled(position, position + size, backgroundColor, 4); + matrix_t viewInverse; + viewInverse.Inverse(*(matrix_t*)view); + + const vec_t camTarget = viewInverse.v.position - viewInverse.v.dir * length; + + // view/projection matrices + const float distance = 3.f; + matrix_t cubeProjection, cubeView; + float fov = acosf(distance / ( sqrtf(distance * distance + 3.f))) * RAD2DEG; + Perspective(fov / sqrtf(2.f), size.x / size.y, 0.01f, 1000.f, cubeProjection.m16); + + vec_t dir = makeVect(viewInverse.m[2][0], viewInverse.m[2][1], viewInverse.m[2][2]); + vec_t up = makeVect(viewInverse.m[1][0], viewInverse.m[1][1], viewInverse.m[1][2]); + vec_t eye = dir * distance; + vec_t zero = makeVect(0.f, 0.f); + LookAt(&eye.x, &zero.x, &up.x, cubeView.m16); + + // set context + gContext.mViewMat = cubeView; + gContext.mProjectionMat = cubeProjection; + ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector, position, size); + + const matrix_t res = cubeView * cubeProjection; + + // panels + static const ImVec2 panelPosition[9] = { ImVec2(0.75f,0.75f), ImVec2(0.25f, 0.75f), ImVec2(0.f, 0.75f), + ImVec2(0.75f, 0.25f), ImVec2(0.25f, 0.25f), ImVec2(0.f, 0.25f), + ImVec2(0.75f, 0.f), ImVec2(0.25f, 0.f), ImVec2(0.f, 0.f) }; + + static const ImVec2 panelSize[9] = { ImVec2(0.25f,0.25f), ImVec2(0.5f, 0.25f), ImVec2(0.25f, 0.25f), + ImVec2(0.25f, 0.5f), ImVec2(0.5f, 0.5f), ImVec2(0.25f, 0.5f), + ImVec2(0.25f, 0.25f), ImVec2(0.5f, 0.25f), ImVec2(0.25f, 0.25f) }; + + // tag faces + bool boxes[27] {}; + for (int iPass = 0;iPass < 2; iPass++) + { + for (int iFace = 0; iFace < 6; iFace++) + { + const int normalIndex = (iFace % 3); + const int perpXIndex = (normalIndex + 1) % 3; + const int perpYIndex = (normalIndex + 2) % 3; + const float invert = (iFace > 2) ? -1.f : 1.f; + const vec_t indexVectorX = directionUnary[perpXIndex] * invert; + const vec_t indexVectorY = directionUnary[perpYIndex] * invert; + const vec_t boxOrigin = directionUnary[normalIndex] * -invert - indexVectorX - indexVectorY; + const vec_t faceCoords[4] = { directionUnary[normalIndex] + directionUnary[perpXIndex] + directionUnary[perpYIndex], + directionUnary[normalIndex] + directionUnary[perpXIndex] - directionUnary[perpYIndex], + directionUnary[normalIndex] - directionUnary[perpXIndex] - directionUnary[perpYIndex], + directionUnary[normalIndex] - directionUnary[perpXIndex] + directionUnary[perpYIndex] }; + + // plan local space + const vec_t n = directionUnary[normalIndex] * invert; + vec_t viewSpaceNormal = n; + vec_t viewSpacePoint = n * 0.5f; + viewSpaceNormal.TransformVector(cubeView); + viewSpaceNormal.Normalize(); + viewSpacePoint.TransformPoint(cubeView); + const vec_t viewSpaceFacePlan = BuildPlan(viewSpacePoint, viewSpaceNormal); + + // back face culling + if (viewSpaceFacePlan.w > 0.f) + { + continue; + } + + const vec_t facePlan = BuildPlan(n * 0.5f, n); + + const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, facePlan); + vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len - (n * 0.5f); + + float localx = Dot(directionUnary[perpXIndex], posOnPlan) * invert + 0.5f; + float localy = Dot(directionUnary[perpYIndex], posOnPlan) * invert + 0.5f; + + // panels + const vec_t dx = directionUnary[perpXIndex]; + const vec_t dy = directionUnary[perpYIndex]; + const vec_t origin = directionUnary[normalIndex] - dx - dy; + for (int iPanel = 0; iPanel < 9; iPanel++) + { + vec_t boxCoord = boxOrigin + indexVectorX * float(iPanel % 3) + indexVectorY * float(iPanel / 3) + makeVect(1.f, 1.f, 1.f); + const ImVec2 p = panelPosition[iPanel] * 2.f; + const ImVec2 s = panelSize[iPanel] * 2.f; + ImVec2 faceCoordsScreen[4]; + vec_t panelPos[4] = { dx * p.x + dy * p.y, + dx * p.x + dy * (p.y + s.y), + dx * (p.x + s.x) + dy * (p.y + s.y), + dx * (p.x + s.x) + dy * p.y }; + + for (unsigned int iCoord = 0; iCoord < 4; iCoord++) + { + faceCoordsScreen[iCoord] = worldToPos((panelPos[iCoord] + origin) * 0.5f * invert, res, position, size); + } + + const ImVec2 panelCorners[2] = { panelPosition[iPanel], panelPosition[iPanel] + panelSize[iPanel] }; + bool insidePanel = localx > panelCorners[0].x && localx < panelCorners[1].x && localy > panelCorners[0].y && localy < panelCorners[1].y; + int boxCoordInt = int(boxCoord.x * 9.f + boxCoord.y * 3.f + boxCoord.z); + assert(boxCoordInt < 27); + boxes[boxCoordInt] |= insidePanel && (!isDraging); + + // draw face with lighter color + if (iPass) + { + gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, (directionColor[normalIndex] | 0x80808080) | (isInside ? 0x080808 : 0)); + if (boxes[boxCoordInt]) + { + gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, 0x8060A0F0); + + if (!io.MouseDown[0] && !isDraging && isClicking) + { + // apply new view direction + int cx = boxCoordInt / 9; + int cy = (boxCoordInt - cx * 9) / 3; + int cz = boxCoordInt % 3; + interpolationDir = makeVect(1.f - cx, 1.f - cy, 1.f - cz); + interpolationDir.Normalize(); + + if (fabsf(Dot(interpolationDir, referenceUp)) > 1.0f - 0.01f) + { + vec_t right = viewInverse.v.right; + if (fabsf(right.x) > fabsf(right.z)) + { + right.z = 0.f; + } + else + { + right.x = 0.f; + } + right.Normalize(); + interpolationUp = Cross(interpolationDir, right); + interpolationUp.Normalize(); + } + else + { + interpolationUp = referenceUp; + } + interpolationFrames = 40; + isClicking = false; + } + if (io.MouseDown[0] && !isDraging) + { + isClicking = true; + } + } + } + } + } + } + if (interpolationFrames) + { + interpolationFrames --; + vec_t newDir = viewInverse.v.dir; + newDir.Lerp(interpolationDir, 0.2f); + newDir.Normalize(); + + vec_t newUp = viewInverse.v.up; + newUp.Lerp(interpolationUp, 0.3f); + newUp.Normalize(); + newUp = interpolationUp; + vec_t newEye = camTarget + newDir * length; + LookAt(&newEye.x, &camTarget.x, &newUp.x, view); + ret = true; + } + isInside = ImRect(position, position + size).Contains(io.MousePos); + + // drag view + if (!isDraging && io.MouseDown[0] && isInside && (fabsf(io.MouseDelta.x) > 0.f || fabsf(io.MouseDelta.y) > 0.f)) + { + isDraging = true; + isClicking = false; + } + else if (isDraging && !io.MouseDown[0]) + { + isDraging = false; + } + + if (isDraging) + { + matrix_t rx, ry, roll; + + rx.RotationAxis(referenceUp, -io.MouseDelta.x * 0.01f); + ry.RotationAxis(viewInverse.v.right, -io.MouseDelta.y * 0.01f); + + roll = rx * ry; + + vec_t newDir = viewInverse.v.dir; + newDir.TransformVector(roll); + newDir.Normalize(); + + // clamp + vec_t planDir = Cross(viewInverse.v.right, referenceUp); + planDir.y = 0.f; + planDir.Normalize(); + float dt = Dot(planDir, newDir); + if (dt < 0.0f) + { + newDir += planDir * dt; + newDir.Normalize(); + } + + vec_t newEye = camTarget + newDir * length; + LookAt(&newEye.x, &camTarget.x, &referenceUp.x, view); + ret = true; + } + return ret; + } +}; + diff --git a/ext/ImGuizmo.h b/ext/ImGuizmo.h new file mode 100644 index 00000000..93b6e7c8 --- /dev/null +++ b/ext/ImGuizmo.h @@ -0,0 +1,180 @@ +// https://github.com/CedricGuillemet/ImGuizmo +// v 1.61 WIP +// +// The MIT License(MIT) +// +// Copyright(c) 2016 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// ------------------------------------------------------------------------------------------- +// History : +// 2019/11/03 View gizmo +// 2016/09/11 Behind camera culling. Scaling Delta matrix not multiplied by source matrix scales. local/world rotation and translation fixed. Display message is incorrect (X: ... Y:...) in local mode. +// 2016/09/09 Hatched negative axis. Snapping. Documentation update. +// 2016/09/04 Axis switch and translation plan autohiding. Scale transform stability improved +// 2016/09/01 Mogwai changed to Manipulate. Draw debug cube. Fixed inverted scale. Mixing scale and translation/rotation gives bad results. +// 2016/08/31 First version +// +// ------------------------------------------------------------------------------------------- +// Future (no order): +// +// - Multi view +// - display rotation/translation/scale infos in local/world space and not only local +// - finish local/world matrix application +// - OPERATION as bitmask +// +// ------------------------------------------------------------------------------------------- +// Example +#if 0 +void EditTransform(const Camera& camera, matrix_t& matrix) +{ + static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE); + static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::WORLD); + if (ImGui::IsKeyPressed(90)) + mCurrentGizmoOperation = ImGuizmo::TRANSLATE; + if (ImGui::IsKeyPressed(69)) + mCurrentGizmoOperation = ImGuizmo::ROTATE; + if (ImGui::IsKeyPressed(82)) // r Key + mCurrentGizmoOperation = ImGuizmo::SCALE; + if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE)) + mCurrentGizmoOperation = ImGuizmo::TRANSLATE; + ImGui::SameLine(); + if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE)) + mCurrentGizmoOperation = ImGuizmo::ROTATE; + ImGui::SameLine(); + if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE)) + mCurrentGizmoOperation = ImGuizmo::SCALE; + float matrixTranslation[3], matrixRotation[3], matrixScale[3]; + ImGuizmo::DecomposeMatrixToComponents(matrix.m16, matrixTranslation, matrixRotation, matrixScale); + ImGui::InputFloat3("Tr", matrixTranslation, 3); + ImGui::InputFloat3("Rt", matrixRotation, 3); + ImGui::InputFloat3("Sc", matrixScale, 3); + ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix.m16); + + if (mCurrentGizmoOperation != ImGuizmo::SCALE) + { + if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL)) + mCurrentGizmoMode = ImGuizmo::LOCAL; + ImGui::SameLine(); + if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD)) + mCurrentGizmoMode = ImGuizmo::WORLD; + } + static bool useSnap(false); + if (ImGui::IsKeyPressed(83)) + useSnap = !useSnap; + ImGui::Checkbox("", &useSnap); + ImGui::SameLine(); + vec_t snap; + switch (mCurrentGizmoOperation) + { + case ImGuizmo::TRANSLATE: + snap = config.mSnapTranslation; + ImGui::InputFloat3("Snap", &snap.x); + break; + case ImGuizmo::ROTATE: + snap = config.mSnapRotation; + ImGui::InputFloat("Angle Snap", &snap.x); + break; + case ImGuizmo::SCALE: + snap = config.mSnapScale; + ImGui::InputFloat("Scale Snap", &snap.x); + break; + } + ImGuiIO& io = ImGui::GetIO(); + ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y); + ImGuizmo::Manipulate(camera.mView.m16, camera.mProjection.m16, mCurrentGizmoOperation, mCurrentGizmoMode, matrix.m16, NULL, useSnap ? &snap.x : NULL); +} +#endif +#pragma once + +#ifdef USE_IMGUI_API +#include "imconfig.h" +#endif +#ifndef IMGUI_API +#define IMGUI_API +#endif + +namespace ImGuizmo +{ + // call inside your own window and before Manipulate() in order to draw gizmo to that window. + IMGUI_API void SetDrawlist(); + + // call BeginFrame right after ImGui_XXXX_NewFrame(); + IMGUI_API void BeginFrame(); + + // return true if mouse cursor is over any gizmo control (axis, plan or screen component) + IMGUI_API bool IsOver(); + + // return true if mouse IsOver or if the gizmo is in moving state + IMGUI_API bool IsUsing(); + + // enable/disable the gizmo. Stay in the state until next call to Enable. + // gizmo is rendered with gray half transparent color when disabled + IMGUI_API void Enable(bool enable); + + // helper functions for manualy editing translation/rotation/scale with an input float + // translation, rotation and scale float points to 3 floats each + // Angles are in degrees (more suitable for human editing) + // example: + // float matrixTranslation[3], matrixRotation[3], matrixScale[3]; + // ImGuizmo::DecomposeMatrixToComponents(gizmoMatrix.m16, matrixTranslation, matrixRotation, matrixScale); + // ImGui::InputFloat3("Tr", matrixTranslation, 3); + // ImGui::InputFloat3("Rt", matrixRotation, 3); + // ImGui::InputFloat3("Sc", matrixScale, 3); + // ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, gizmoMatrix.m16); + // + // These functions have some numerical stability issues for now. Use with caution. + IMGUI_API void DecomposeMatrixToComponents(const float *matrix, float *translation, float *rotation, float *scale); + IMGUI_API void RecomposeMatrixFromComponents(const float *translation, const float *rotation, const float *scale, float *matrix); + + IMGUI_API void SetRect(float x, float y, float width, float height); + // default is false + IMGUI_API void SetOrthographic(bool isOrthographic); + + // Render a cube with face color corresponding to face normal. Usefull for debug/tests + IMGUI_API void DrawCube(const float *view, const float *projection, const float *matrix); + IMGUI_API void DrawGrid(const float *view, const float *projection, const float *matrix, const float gridSize); + + // call it when you want a gizmo + // Needs view and projection matrices. + // matrix parameter is the source matrix (where will be gizmo be drawn) and might be transformed by the function. Return deltaMatrix is optional + // translation is applied in world space + enum OPERATION + { + TRANSLATE, + ROTATE, + SCALE, + BOUNDS, + }; + + enum MODE + { + LOCAL, + WORLD + }; + + IMGUI_API void Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix = 0, float *snap = 0, float *localBounds = NULL, float *boundsSnap = NULL); + // + // Please note that this cubeview is patented by Autodesk : https://patents.google.com/patent/US7782319B2/en + // It seems to be a defensive patent in the US. I don't think it will bring troubles using it as + // other software are using the same mechanics. But just in case, you are now warned! + // + IMGUI_API bool ViewManipulate(float* view, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor); +}; diff --git a/ext/Nvidia-SBVH/BVHNode.h b/ext/Nvidia-SBVH/BVHNode.h index 528f85dd..025501ae 100644 --- a/ext/Nvidia-SBVH/BVHNode.h +++ b/ext/Nvidia-SBVH/BVHNode.h @@ -59,15 +59,16 @@ class AABB inline AABB operator+ (const AABB& aabb) const { AABB u(*this); u.grow(aabb); return u; } private: - Vec3f m_mn; // AABB min bound + Vec3f m_mn; // AABB min bound Vec3f m_mx; // AABB max bound }; class BVHNode { public: - BVHNode() : m_probability(1.f), m_parentProbability(1.f), m_treelet(-1), m_index(-1) {} - virtual bool isLeaf() const = 0; + BVHNode() : m_probability(1.f), m_parentProbability(1.f), m_treelet(-1), m_index(-1) {} + virtual ~BVHNode() = default; + virtual bool isLeaf() const = 0; virtual S32 getNumChildNodes() const = 0; virtual BVHNode* getChildNode(S32 i) const = 0; virtual S32 getNumTriangles() const { return 0; } diff --git a/ext/Nvidia-SBVH/Timer.cpp b/ext/Nvidia-SBVH/Timer.cpp index 256e8bcc..b98350c4 100644 --- a/ext/Nvidia-SBVH/Timer.cpp +++ b/ext/Nvidia-SBVH/Timer.cpp @@ -27,7 +27,10 @@ #include "Timer.h" #include + +#ifdef WIN32 #include +#endif using namespace FW; @@ -38,8 +41,10 @@ S64 Timer::s_prevTicks = 0; //------------------------------------------------------------------------ #define max(x,y) ((x>y)?x:y) +#ifdef WIN32 void Timer::staticInit(void) { + #ifdef WIN LARGE_INTEGER freq; if (!QueryPerformanceFrequency(&freq)) { @@ -47,15 +52,30 @@ void Timer::staticInit(void) exit(0); } s_ticksToSecsCoef = max(1.0 / (F64)freq.QuadPart, 0.0); + #endif } S64 Timer::queryTicks(void) { + #ifdef WIN + LARGE_INTEGER ticks; QueryPerformanceCounter(&ticks); ticks.QuadPart = max(s_prevTicks, ticks.QuadPart); s_prevTicks = ticks.QuadPart; // increasing little endian => thread-safe return ticks.QuadPart; + #else + throw ""; + #endif } +#else +void Timer::staticInit(void) +{ + } +S64 Timer::queryTicks(void) +{ + return 0; +} +#endif //------------------------------------------------------------------------ diff --git a/ext/Nvidia-SBVH/Util.h b/ext/Nvidia-SBVH/Util.h index 75a76d0b..dbf08b4e 100644 --- a/ext/Nvidia-SBVH/Util.h +++ b/ext/Nvidia-SBVH/Util.h @@ -34,7 +34,9 @@ #define FW_F32_MIN (1.175494351e-38f) #define FW_F32_MAX (3.402823466e+38f) +#ifndef NULL #define NULL 0 +#endif #define FW_ASSERT(X) ((void)0) typedef unsigned char U8; diff --git a/ext/SDL2-2.0.8/lib/x64/SDL2.dll b/ext/SDL2-2.0.8/lib/x64/SDL2.dll deleted file mode 100644 index 6cf858ca..00000000 Binary files a/ext/SDL2-2.0.8/lib/x64/SDL2.dll and /dev/null differ diff --git a/ext/SDL2-2.0.8/lib/x64/SDL2.lib b/ext/SDL2-2.0.8/lib/x64/SDL2.lib deleted file mode 100644 index 933a1770..00000000 Binary files a/ext/SDL2-2.0.8/lib/x64/SDL2.lib and /dev/null differ diff --git a/ext/SDL2-2.0.8/lib/x64/SDL2main.lib b/ext/SDL2-2.0.8/lib/x64/SDL2main.lib deleted file mode 100644 index 1de4551d..00000000 Binary files a/ext/SDL2-2.0.8/lib/x64/SDL2main.lib and /dev/null differ diff --git a/ext/SDL2-2.0.8/lib/x86/SDL2.dll b/ext/SDL2-2.0.8/lib/x86/SDL2.dll deleted file mode 100644 index a25b05a0..00000000 Binary files a/ext/SDL2-2.0.8/lib/x86/SDL2.dll and /dev/null differ diff --git a/ext/SDL2-2.0.8/lib/x86/SDL2.lib b/ext/SDL2-2.0.8/lib/x86/SDL2.lib deleted file mode 100644 index 034efbd9..00000000 Binary files a/ext/SDL2-2.0.8/lib/x86/SDL2.lib and /dev/null differ diff --git a/ext/SDL2-2.0.8/lib/x86/SDL2main.lib b/ext/SDL2-2.0.8/lib/x86/SDL2main.lib deleted file mode 100644 index 965a7dea..00000000 Binary files a/ext/SDL2-2.0.8/lib/x86/SDL2main.lib and /dev/null differ diff --git a/ext/SDL2-2.0.8/lib/x86/SDL2test.lib b/ext/SDL2-2.0.8/lib/x86/SDL2test.lib deleted file mode 100644 index e6c157ec..00000000 Binary files a/ext/SDL2-2.0.8/lib/x86/SDL2test.lib and /dev/null differ diff --git a/ext/SDL2-2.0.8/BUGS.txt b/ext/SDL2/BUGS.txt similarity index 100% rename from ext/SDL2-2.0.8/BUGS.txt rename to ext/SDL2/BUGS.txt diff --git a/ext/SDL2-2.0.8/COPYING.txt b/ext/SDL2/COPYING.txt similarity index 100% rename from ext/SDL2-2.0.8/COPYING.txt rename to ext/SDL2/COPYING.txt diff --git a/ext/SDL2-2.0.8/README-SDL.txt b/ext/SDL2/README-SDL.txt similarity index 100% rename from ext/SDL2-2.0.8/README-SDL.txt rename to ext/SDL2/README-SDL.txt diff --git a/ext/SDL2-2.0.8/README.txt b/ext/SDL2/README.txt similarity index 100% rename from ext/SDL2-2.0.8/README.txt rename to ext/SDL2/README.txt diff --git a/ext/SDL2-2.0.8/WhatsNew.txt b/ext/SDL2/WhatsNew.txt similarity index 100% rename from ext/SDL2-2.0.8/WhatsNew.txt rename to ext/SDL2/WhatsNew.txt diff --git a/ext/SDL2-2.0.8/docs/README-android.md b/ext/SDL2/docs/README-android.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-android.md rename to ext/SDL2/docs/README-android.md diff --git a/ext/SDL2-2.0.8/docs/README-cmake.md b/ext/SDL2/docs/README-cmake.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-cmake.md rename to ext/SDL2/docs/README-cmake.md diff --git a/ext/SDL2-2.0.8/docs/README-directfb.md b/ext/SDL2/docs/README-directfb.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-directfb.md rename to ext/SDL2/docs/README-directfb.md diff --git a/ext/SDL2-2.0.8/docs/README-dynapi.md b/ext/SDL2/docs/README-dynapi.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-dynapi.md rename to ext/SDL2/docs/README-dynapi.md diff --git a/ext/SDL2-2.0.8/docs/README-emscripten.md b/ext/SDL2/docs/README-emscripten.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-emscripten.md rename to ext/SDL2/docs/README-emscripten.md diff --git a/ext/SDL2-2.0.8/docs/README-gesture.md b/ext/SDL2/docs/README-gesture.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-gesture.md rename to ext/SDL2/docs/README-gesture.md diff --git a/ext/SDL2-2.0.8/docs/README-hg.md b/ext/SDL2/docs/README-hg.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-hg.md rename to ext/SDL2/docs/README-hg.md diff --git a/ext/SDL2-2.0.8/docs/README-ios.md b/ext/SDL2/docs/README-ios.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-ios.md rename to ext/SDL2/docs/README-ios.md diff --git a/ext/SDL2-2.0.8/docs/README-linux.md b/ext/SDL2/docs/README-linux.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-linux.md rename to ext/SDL2/docs/README-linux.md diff --git a/ext/SDL2-2.0.8/docs/README-macosx.md b/ext/SDL2/docs/README-macosx.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-macosx.md rename to ext/SDL2/docs/README-macosx.md diff --git a/ext/SDL2-2.0.8/docs/README-nacl.md b/ext/SDL2/docs/README-nacl.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-nacl.md rename to ext/SDL2/docs/README-nacl.md diff --git a/ext/SDL2-2.0.8/docs/README-pandora.md b/ext/SDL2/docs/README-pandora.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-pandora.md rename to ext/SDL2/docs/README-pandora.md diff --git a/ext/SDL2-2.0.8/docs/README-platforms.md b/ext/SDL2/docs/README-platforms.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-platforms.md rename to ext/SDL2/docs/README-platforms.md diff --git a/ext/SDL2-2.0.8/docs/README-porting.md b/ext/SDL2/docs/README-porting.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-porting.md rename to ext/SDL2/docs/README-porting.md diff --git a/ext/SDL2-2.0.8/docs/README-psp.md b/ext/SDL2/docs/README-psp.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-psp.md rename to ext/SDL2/docs/README-psp.md diff --git a/ext/SDL2-2.0.8/docs/README-raspberrypi.md b/ext/SDL2/docs/README-raspberrypi.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-raspberrypi.md rename to ext/SDL2/docs/README-raspberrypi.md diff --git a/ext/SDL2-2.0.8/docs/README-touch.md b/ext/SDL2/docs/README-touch.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-touch.md rename to ext/SDL2/docs/README-touch.md diff --git a/ext/SDL2-2.0.8/docs/README-wince.md b/ext/SDL2/docs/README-wince.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-wince.md rename to ext/SDL2/docs/README-wince.md diff --git a/ext/SDL2-2.0.8/docs/README-windows.md b/ext/SDL2/docs/README-windows.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-windows.md rename to ext/SDL2/docs/README-windows.md diff --git a/ext/SDL2-2.0.8/docs/README-winrt.md b/ext/SDL2/docs/README-winrt.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README-winrt.md rename to ext/SDL2/docs/README-winrt.md diff --git a/ext/SDL2-2.0.8/docs/README.md b/ext/SDL2/docs/README.md similarity index 100% rename from ext/SDL2-2.0.8/docs/README.md rename to ext/SDL2/docs/README.md diff --git a/ext/SDL2-2.0.8/docs/doxyfile b/ext/SDL2/docs/doxyfile similarity index 100% rename from ext/SDL2-2.0.8/docs/doxyfile rename to ext/SDL2/docs/doxyfile diff --git a/ext/SDL2-2.0.8/include/SDL.h b/ext/SDL2/include/SDL2/SDL.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL.h rename to ext/SDL2/include/SDL2/SDL.h diff --git a/ext/SDL2-2.0.8/include/SDL_assert.h b/ext/SDL2/include/SDL2/SDL_assert.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_assert.h rename to ext/SDL2/include/SDL2/SDL_assert.h diff --git a/ext/SDL2-2.0.8/include/SDL_atomic.h b/ext/SDL2/include/SDL2/SDL_atomic.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_atomic.h rename to ext/SDL2/include/SDL2/SDL_atomic.h diff --git a/ext/SDL2-2.0.8/include/SDL_audio.h b/ext/SDL2/include/SDL2/SDL_audio.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_audio.h rename to ext/SDL2/include/SDL2/SDL_audio.h diff --git a/ext/SDL2-2.0.8/include/SDL_bits.h b/ext/SDL2/include/SDL2/SDL_bits.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_bits.h rename to ext/SDL2/include/SDL2/SDL_bits.h diff --git a/ext/SDL2-2.0.8/include/SDL_blendmode.h b/ext/SDL2/include/SDL2/SDL_blendmode.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_blendmode.h rename to ext/SDL2/include/SDL2/SDL_blendmode.h diff --git a/ext/SDL2-2.0.8/include/SDL_clipboard.h b/ext/SDL2/include/SDL2/SDL_clipboard.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_clipboard.h rename to ext/SDL2/include/SDL2/SDL_clipboard.h diff --git a/ext/SDL2-2.0.8/include/SDL_config.h b/ext/SDL2/include/SDL2/SDL_config.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config.h rename to ext/SDL2/include/SDL2/SDL_config.h diff --git a/ext/SDL2-2.0.8/include/SDL_config.h.cmake b/ext/SDL2/include/SDL2/SDL_config.h.cmake similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config.h.cmake rename to ext/SDL2/include/SDL2/SDL_config.h.cmake diff --git a/ext/SDL2-2.0.8/include/SDL_config.h.in b/ext/SDL2/include/SDL2/SDL_config.h.in similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config.h.in rename to ext/SDL2/include/SDL2/SDL_config.h.in diff --git a/ext/SDL2-2.0.8/include/SDL_config_android.h b/ext/SDL2/include/SDL2/SDL_config_android.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config_android.h rename to ext/SDL2/include/SDL2/SDL_config_android.h diff --git a/ext/SDL2-2.0.8/include/SDL_config_iphoneos.h b/ext/SDL2/include/SDL2/SDL_config_iphoneos.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config_iphoneos.h rename to ext/SDL2/include/SDL2/SDL_config_iphoneos.h diff --git a/ext/SDL2-2.0.8/include/SDL_config_macosx.h b/ext/SDL2/include/SDL2/SDL_config_macosx.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config_macosx.h rename to ext/SDL2/include/SDL2/SDL_config_macosx.h diff --git a/ext/SDL2-2.0.8/include/SDL_config_macosx.h.orig b/ext/SDL2/include/SDL2/SDL_config_macosx.h.orig similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config_macosx.h.orig rename to ext/SDL2/include/SDL2/SDL_config_macosx.h.orig diff --git a/ext/SDL2-2.0.8/include/SDL_config_minimal.h b/ext/SDL2/include/SDL2/SDL_config_minimal.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config_minimal.h rename to ext/SDL2/include/SDL2/SDL_config_minimal.h diff --git a/ext/SDL2-2.0.8/include/SDL_config_pandora.h b/ext/SDL2/include/SDL2/SDL_config_pandora.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config_pandora.h rename to ext/SDL2/include/SDL2/SDL_config_pandora.h diff --git a/ext/SDL2-2.0.8/include/SDL_config_psp.h b/ext/SDL2/include/SDL2/SDL_config_psp.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config_psp.h rename to ext/SDL2/include/SDL2/SDL_config_psp.h diff --git a/ext/SDL2-2.0.8/include/SDL_config_windows.h b/ext/SDL2/include/SDL2/SDL_config_windows.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config_windows.h rename to ext/SDL2/include/SDL2/SDL_config_windows.h diff --git a/ext/SDL2-2.0.8/include/SDL_config_winrt.h b/ext/SDL2/include/SDL2/SDL_config_winrt.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config_winrt.h rename to ext/SDL2/include/SDL2/SDL_config_winrt.h diff --git a/ext/SDL2-2.0.8/include/SDL_config_wiz.h b/ext/SDL2/include/SDL2/SDL_config_wiz.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_config_wiz.h rename to ext/SDL2/include/SDL2/SDL_config_wiz.h diff --git a/ext/SDL2-2.0.8/include/SDL_copying.h b/ext/SDL2/include/SDL2/SDL_copying.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_copying.h rename to ext/SDL2/include/SDL2/SDL_copying.h diff --git a/ext/SDL2-2.0.8/include/SDL_cpuinfo.h b/ext/SDL2/include/SDL2/SDL_cpuinfo.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_cpuinfo.h rename to ext/SDL2/include/SDL2/SDL_cpuinfo.h diff --git a/ext/SDL2-2.0.8/include/SDL_egl.h b/ext/SDL2/include/SDL2/SDL_egl.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_egl.h rename to ext/SDL2/include/SDL2/SDL_egl.h diff --git a/ext/SDL2-2.0.8/include/SDL_endian.h b/ext/SDL2/include/SDL2/SDL_endian.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_endian.h rename to ext/SDL2/include/SDL2/SDL_endian.h diff --git a/ext/SDL2-2.0.8/include/SDL_error.h b/ext/SDL2/include/SDL2/SDL_error.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_error.h rename to ext/SDL2/include/SDL2/SDL_error.h diff --git a/ext/SDL2-2.0.8/include/SDL_events.h b/ext/SDL2/include/SDL2/SDL_events.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_events.h rename to ext/SDL2/include/SDL2/SDL_events.h diff --git a/ext/SDL2-2.0.8/include/SDL_filesystem.h b/ext/SDL2/include/SDL2/SDL_filesystem.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_filesystem.h rename to ext/SDL2/include/SDL2/SDL_filesystem.h diff --git a/ext/SDL2-2.0.8/include/SDL_gamecontroller.h b/ext/SDL2/include/SDL2/SDL_gamecontroller.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_gamecontroller.h rename to ext/SDL2/include/SDL2/SDL_gamecontroller.h diff --git a/ext/SDL2-2.0.8/include/SDL_gesture.h b/ext/SDL2/include/SDL2/SDL_gesture.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_gesture.h rename to ext/SDL2/include/SDL2/SDL_gesture.h diff --git a/ext/SDL2-2.0.8/include/SDL_haptic.h b/ext/SDL2/include/SDL2/SDL_haptic.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_haptic.h rename to ext/SDL2/include/SDL2/SDL_haptic.h diff --git a/ext/SDL2-2.0.8/include/SDL_hints.h b/ext/SDL2/include/SDL2/SDL_hints.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_hints.h rename to ext/SDL2/include/SDL2/SDL_hints.h diff --git a/ext/SDL2-2.0.8/include/SDL_joystick.h b/ext/SDL2/include/SDL2/SDL_joystick.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_joystick.h rename to ext/SDL2/include/SDL2/SDL_joystick.h diff --git a/ext/SDL2-2.0.8/include/SDL_keyboard.h b/ext/SDL2/include/SDL2/SDL_keyboard.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_keyboard.h rename to ext/SDL2/include/SDL2/SDL_keyboard.h diff --git a/ext/SDL2-2.0.8/include/SDL_keycode.h b/ext/SDL2/include/SDL2/SDL_keycode.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_keycode.h rename to ext/SDL2/include/SDL2/SDL_keycode.h diff --git a/ext/SDL2-2.0.8/include/SDL_loadso.h b/ext/SDL2/include/SDL2/SDL_loadso.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_loadso.h rename to ext/SDL2/include/SDL2/SDL_loadso.h diff --git a/ext/SDL2-2.0.8/include/SDL_log.h b/ext/SDL2/include/SDL2/SDL_log.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_log.h rename to ext/SDL2/include/SDL2/SDL_log.h diff --git a/ext/SDL2-2.0.8/include/SDL_main.h b/ext/SDL2/include/SDL2/SDL_main.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_main.h rename to ext/SDL2/include/SDL2/SDL_main.h diff --git a/ext/SDL2-2.0.8/include/SDL_messagebox.h b/ext/SDL2/include/SDL2/SDL_messagebox.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_messagebox.h rename to ext/SDL2/include/SDL2/SDL_messagebox.h diff --git a/ext/SDL2-2.0.8/include/SDL_mouse.h b/ext/SDL2/include/SDL2/SDL_mouse.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_mouse.h rename to ext/SDL2/include/SDL2/SDL_mouse.h diff --git a/ext/SDL2-2.0.8/include/SDL_mutex.h b/ext/SDL2/include/SDL2/SDL_mutex.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_mutex.h rename to ext/SDL2/include/SDL2/SDL_mutex.h diff --git a/ext/SDL2-2.0.8/include/SDL_name.h b/ext/SDL2/include/SDL2/SDL_name.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_name.h rename to ext/SDL2/include/SDL2/SDL_name.h diff --git a/ext/SDL2-2.0.8/include/SDL_opengl.h b/ext/SDL2/include/SDL2/SDL_opengl.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_opengl.h rename to ext/SDL2/include/SDL2/SDL_opengl.h diff --git a/ext/SDL2-2.0.8/include/SDL_opengl_glext.h b/ext/SDL2/include/SDL2/SDL_opengl_glext.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_opengl_glext.h rename to ext/SDL2/include/SDL2/SDL_opengl_glext.h diff --git a/ext/SDL2-2.0.8/include/SDL_opengles.h b/ext/SDL2/include/SDL2/SDL_opengles.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_opengles.h rename to ext/SDL2/include/SDL2/SDL_opengles.h diff --git a/ext/SDL2-2.0.8/include/SDL_opengles2.h b/ext/SDL2/include/SDL2/SDL_opengles2.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_opengles2.h rename to ext/SDL2/include/SDL2/SDL_opengles2.h diff --git a/ext/SDL2-2.0.8/include/SDL_opengles2_gl2.h b/ext/SDL2/include/SDL2/SDL_opengles2_gl2.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_opengles2_gl2.h rename to ext/SDL2/include/SDL2/SDL_opengles2_gl2.h diff --git a/ext/SDL2-2.0.8/include/SDL_opengles2_gl2ext.h b/ext/SDL2/include/SDL2/SDL_opengles2_gl2ext.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_opengles2_gl2ext.h rename to ext/SDL2/include/SDL2/SDL_opengles2_gl2ext.h diff --git a/ext/SDL2-2.0.8/include/SDL_opengles2_gl2platform.h b/ext/SDL2/include/SDL2/SDL_opengles2_gl2platform.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_opengles2_gl2platform.h rename to ext/SDL2/include/SDL2/SDL_opengles2_gl2platform.h diff --git a/ext/SDL2-2.0.8/include/SDL_opengles2_khrplatform.h b/ext/SDL2/include/SDL2/SDL_opengles2_khrplatform.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_opengles2_khrplatform.h rename to ext/SDL2/include/SDL2/SDL_opengles2_khrplatform.h diff --git a/ext/SDL2-2.0.8/include/SDL_pixels.h b/ext/SDL2/include/SDL2/SDL_pixels.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_pixels.h rename to ext/SDL2/include/SDL2/SDL_pixels.h diff --git a/ext/SDL2-2.0.8/include/SDL_platform.h b/ext/SDL2/include/SDL2/SDL_platform.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_platform.h rename to ext/SDL2/include/SDL2/SDL_platform.h diff --git a/ext/SDL2-2.0.8/include/SDL_power.h b/ext/SDL2/include/SDL2/SDL_power.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_power.h rename to ext/SDL2/include/SDL2/SDL_power.h diff --git a/ext/SDL2-2.0.8/include/SDL_quit.h b/ext/SDL2/include/SDL2/SDL_quit.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_quit.h rename to ext/SDL2/include/SDL2/SDL_quit.h diff --git a/ext/SDL2-2.0.8/include/SDL_rect.h b/ext/SDL2/include/SDL2/SDL_rect.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_rect.h rename to ext/SDL2/include/SDL2/SDL_rect.h diff --git a/ext/SDL2-2.0.8/include/SDL_render.h b/ext/SDL2/include/SDL2/SDL_render.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_render.h rename to ext/SDL2/include/SDL2/SDL_render.h diff --git a/ext/SDL2-2.0.8/include/SDL_revision.h b/ext/SDL2/include/SDL2/SDL_revision.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_revision.h rename to ext/SDL2/include/SDL2/SDL_revision.h diff --git a/ext/SDL2-2.0.8/include/SDL_rwops.h b/ext/SDL2/include/SDL2/SDL_rwops.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_rwops.h rename to ext/SDL2/include/SDL2/SDL_rwops.h diff --git a/ext/SDL2-2.0.8/include/SDL_scancode.h b/ext/SDL2/include/SDL2/SDL_scancode.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_scancode.h rename to ext/SDL2/include/SDL2/SDL_scancode.h diff --git a/ext/SDL2-2.0.8/include/SDL_shape.h b/ext/SDL2/include/SDL2/SDL_shape.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_shape.h rename to ext/SDL2/include/SDL2/SDL_shape.h diff --git a/ext/SDL2-2.0.8/include/SDL_stdinc.h b/ext/SDL2/include/SDL2/SDL_stdinc.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_stdinc.h rename to ext/SDL2/include/SDL2/SDL_stdinc.h diff --git a/ext/SDL2-2.0.8/include/SDL_surface.h b/ext/SDL2/include/SDL2/SDL_surface.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_surface.h rename to ext/SDL2/include/SDL2/SDL_surface.h diff --git a/ext/SDL2-2.0.8/include/SDL_system.h b/ext/SDL2/include/SDL2/SDL_system.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_system.h rename to ext/SDL2/include/SDL2/SDL_system.h diff --git a/ext/SDL2-2.0.8/include/SDL_syswm.h b/ext/SDL2/include/SDL2/SDL_syswm.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_syswm.h rename to ext/SDL2/include/SDL2/SDL_syswm.h diff --git a/ext/SDL2-2.0.8/include/SDL_test.h b/ext/SDL2/include/SDL2/SDL_test.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test.h rename to ext/SDL2/include/SDL2/SDL_test.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_assert.h b/ext/SDL2/include/SDL2/SDL_test_assert.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_assert.h rename to ext/SDL2/include/SDL2/SDL_test_assert.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_common.h b/ext/SDL2/include/SDL2/SDL_test_common.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_common.h rename to ext/SDL2/include/SDL2/SDL_test_common.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_compare.h b/ext/SDL2/include/SDL2/SDL_test_compare.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_compare.h rename to ext/SDL2/include/SDL2/SDL_test_compare.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_crc32.h b/ext/SDL2/include/SDL2/SDL_test_crc32.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_crc32.h rename to ext/SDL2/include/SDL2/SDL_test_crc32.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_font.h b/ext/SDL2/include/SDL2/SDL_test_font.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_font.h rename to ext/SDL2/include/SDL2/SDL_test_font.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_fuzzer.h b/ext/SDL2/include/SDL2/SDL_test_fuzzer.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_fuzzer.h rename to ext/SDL2/include/SDL2/SDL_test_fuzzer.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_harness.h b/ext/SDL2/include/SDL2/SDL_test_harness.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_harness.h rename to ext/SDL2/include/SDL2/SDL_test_harness.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_images.h b/ext/SDL2/include/SDL2/SDL_test_images.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_images.h rename to ext/SDL2/include/SDL2/SDL_test_images.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_log.h b/ext/SDL2/include/SDL2/SDL_test_log.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_log.h rename to ext/SDL2/include/SDL2/SDL_test_log.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_md5.h b/ext/SDL2/include/SDL2/SDL_test_md5.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_md5.h rename to ext/SDL2/include/SDL2/SDL_test_md5.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_memory.h b/ext/SDL2/include/SDL2/SDL_test_memory.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_memory.h rename to ext/SDL2/include/SDL2/SDL_test_memory.h diff --git a/ext/SDL2-2.0.8/include/SDL_test_random.h b/ext/SDL2/include/SDL2/SDL_test_random.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_test_random.h rename to ext/SDL2/include/SDL2/SDL_test_random.h diff --git a/ext/SDL2-2.0.8/include/SDL_thread.h b/ext/SDL2/include/SDL2/SDL_thread.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_thread.h rename to ext/SDL2/include/SDL2/SDL_thread.h diff --git a/ext/SDL2-2.0.8/include/SDL_timer.h b/ext/SDL2/include/SDL2/SDL_timer.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_timer.h rename to ext/SDL2/include/SDL2/SDL_timer.h diff --git a/ext/SDL2-2.0.8/include/SDL_touch.h b/ext/SDL2/include/SDL2/SDL_touch.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_touch.h rename to ext/SDL2/include/SDL2/SDL_touch.h diff --git a/ext/SDL2-2.0.8/include/SDL_types.h b/ext/SDL2/include/SDL2/SDL_types.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_types.h rename to ext/SDL2/include/SDL2/SDL_types.h diff --git a/ext/SDL2-2.0.8/include/SDL_version.h b/ext/SDL2/include/SDL2/SDL_version.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_version.h rename to ext/SDL2/include/SDL2/SDL_version.h diff --git a/ext/SDL2-2.0.8/include/SDL_video.h b/ext/SDL2/include/SDL2/SDL_video.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_video.h rename to ext/SDL2/include/SDL2/SDL_video.h diff --git a/ext/SDL2-2.0.8/include/SDL_vulkan.h b/ext/SDL2/include/SDL2/SDL_vulkan.h similarity index 100% rename from ext/SDL2-2.0.8/include/SDL_vulkan.h rename to ext/SDL2/include/SDL2/SDL_vulkan.h diff --git a/ext/SDL2-2.0.8/include/begin_code.h b/ext/SDL2/include/SDL2/begin_code.h similarity index 100% rename from ext/SDL2-2.0.8/include/begin_code.h rename to ext/SDL2/include/SDL2/begin_code.h diff --git a/ext/SDL2-2.0.8/include/close_code.h b/ext/SDL2/include/SDL2/close_code.h similarity index 100% rename from ext/SDL2-2.0.8/include/close_code.h rename to ext/SDL2/include/SDL2/close_code.h diff --git a/ext/SDL2/lib/x64/SDL2.dll b/ext/SDL2/lib/x64/SDL2.dll new file mode 100644 index 00000000..934f8091 Binary files /dev/null and b/ext/SDL2/lib/x64/SDL2.dll differ diff --git a/ext/SDL2/lib/x64/SDL2.lib b/ext/SDL2/lib/x64/SDL2.lib new file mode 100644 index 00000000..f4941ae0 Binary files /dev/null and b/ext/SDL2/lib/x64/SDL2.lib differ diff --git a/ext/SDL2/lib/x64/SDL2main.lib b/ext/SDL2/lib/x64/SDL2main.lib new file mode 100644 index 00000000..61299465 Binary files /dev/null and b/ext/SDL2/lib/x64/SDL2main.lib differ diff --git a/ext/SDL2-2.0.8/lib/x64/SDL2test.lib b/ext/SDL2/lib/x64/SDL2test.lib similarity index 61% rename from ext/SDL2-2.0.8/lib/x64/SDL2test.lib rename to ext/SDL2/lib/x64/SDL2test.lib index 32e9ba96..5b032828 100644 Binary files a/ext/SDL2-2.0.8/lib/x64/SDL2test.lib and b/ext/SDL2/lib/x64/SDL2test.lib differ diff --git a/ext/SOIL/include/SOIL.h b/ext/SOIL/include/SOIL.h deleted file mode 100644 index 43f634f8..00000000 --- a/ext/SOIL/include/SOIL.h +++ /dev/null @@ -1,433 +0,0 @@ -/** - @mainpage SOIL - - Jonathan Dummer - 2007-07-26-10.36 - - Simple OpenGL Image Library - - A tiny c library for uploading images as - textures into OpenGL. Also saving and - loading of images is supported. - - I'm using Sean's Tool Box image loader as a base: - http://www.nothings.org/ - - I'm upgrading it to load TGA and DDS files, and a direct - path for loading DDS files straight into OpenGL textures, - when applicable. - - Image Formats: - - BMP load & save - - TGA load & save - - DDS load & save - - PNG load - - JPG load - - OpenGL Texture Features: - - resample to power-of-two sizes - - MIPmap generation - - compressed texture S3TC formats (if supported) - - can pre-multiply alpha for you, for better compositing - - can flip image about the y-axis (except pre-compressed DDS files) - - Thanks to: - * Sean Barret - for the awesome stb_image - * Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts - * everybody at gamedev.net -**/ - -#ifndef HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY -#define HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY - -#ifdef __cplusplus -extern "C" { -#endif - -/** - The format of images that may be loaded (force_channels). - SOIL_LOAD_AUTO leaves the image in whatever format it was found. - SOIL_LOAD_L forces the image to load as Luminous (greyscale) - SOIL_LOAD_LA forces the image to load as Luminous with Alpha - SOIL_LOAD_RGB forces the image to load as Red Green Blue - SOIL_LOAD_RGBA forces the image to load as Red Green Blue Alpha -**/ -enum -{ - SOIL_LOAD_AUTO = 0, - SOIL_LOAD_L = 1, - SOIL_LOAD_LA = 2, - SOIL_LOAD_RGB = 3, - SOIL_LOAD_RGBA = 4 -}; - -/** - Passed in as reuse_texture_ID, will cause SOIL to - register a new texture ID using glGenTextures(). - If the value passed into reuse_texture_ID > 0 then - SOIL will just re-use that texture ID (great for - reloading image assets in-game!) -**/ -enum -{ - SOIL_CREATE_NEW_ID = 0 -}; - -/** - flags you can pass into SOIL_load_OGL_texture() - and SOIL_create_OGL_texture(). - (note that if SOIL_FLAG_DDS_LOAD_DIRECT is used - the rest of the flags with the exception of - SOIL_FLAG_TEXTURE_REPEATS will be ignored while - loading already-compressed DDS files.) - - SOIL_FLAG_POWER_OF_TWO: force the image to be POT - SOIL_FLAG_MIPMAPS: generate mipmaps for the texture - SOIL_FLAG_TEXTURE_REPEATS: otherwise will clamp - SOIL_FLAG_MULTIPLY_ALPHA: for using (GL_ONE,GL_ONE_MINUS_SRC_ALPHA) blending - SOIL_FLAG_INVERT_Y: flip the image vertically - SOIL_FLAG_COMPRESS_TO_DXT: if the card can display them, will convert RGB to DXT1, RGBA to DXT5 - SOIL_FLAG_DDS_LOAD_DIRECT: will load DDS files directly without _ANY_ additional processing - SOIL_FLAG_NTSC_SAFE_RGB: clamps RGB components to the range [16,235] - SOIL_FLAG_CoCg_Y: Google YCoCg; RGB=>CoYCg, RGBA=>CoCgAY - SOIL_FLAG_TEXTURE_RECTANGE: uses ARB_texture_rectangle ; pixel indexed & no repeat or MIPmaps or cubemaps -**/ -enum -{ - SOIL_FLAG_POWER_OF_TWO = 1, - SOIL_FLAG_MIPMAPS = 2, - SOIL_FLAG_TEXTURE_REPEATS = 4, - SOIL_FLAG_MULTIPLY_ALPHA = 8, - SOIL_FLAG_INVERT_Y = 16, - SOIL_FLAG_COMPRESS_TO_DXT = 32, - SOIL_FLAG_DDS_LOAD_DIRECT = 64, - SOIL_FLAG_NTSC_SAFE_RGB = 128, - SOIL_FLAG_CoCg_Y = 256, - SOIL_FLAG_TEXTURE_RECTANGLE = 512 -}; - -/** - The types of images that may be saved. - (TGA supports uncompressed RGB / RGBA) - (BMP supports uncompressed RGB) - (DDS supports DXT1 and DXT5) -**/ -enum -{ - SOIL_SAVE_TYPE_TGA = 0, - SOIL_SAVE_TYPE_BMP = 1, - SOIL_SAVE_TYPE_DDS = 2 -}; - -/** - Defines the order of faces in a DDS cubemap. - I recommend that you use the same order in single - image cubemap files, so they will be interchangeable - with DDS cubemaps when using SOIL. -**/ -#define SOIL_DDS_CUBEMAP_FACE_ORDER "EWUDNS" - -/** - The types of internal fake HDR representations - - SOIL_HDR_RGBE: RGB * pow( 2.0, A - 128.0 ) - SOIL_HDR_RGBdivA: RGB / A - SOIL_HDR_RGBdivA2: RGB / (A*A) -**/ -enum -{ - SOIL_HDR_RGBE = 0, - SOIL_HDR_RGBdivA = 1, - SOIL_HDR_RGBdivA2 = 2 -}; - -/** - Loads an image from disk into an OpenGL texture. - \param filename the name of the file to upload as a texture - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_texture - ( - const char *filename, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads 6 images from disk into an OpenGL cubemap texture. - \param x_pos_file the name of the file to upload as the +x cube face - \param x_neg_file the name of the file to upload as the -x cube face - \param y_pos_file the name of the file to upload as the +y cube face - \param y_neg_file the name of the file to upload as the -y cube face - \param z_pos_file the name of the file to upload as the +z cube face - \param z_neg_file the name of the file to upload as the -z cube face - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_cubemap - ( - const char *x_pos_file, - const char *x_neg_file, - const char *y_pos_file, - const char *y_neg_file, - const char *z_pos_file, - const char *z_neg_file, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads 1 image from disk and splits it into an OpenGL cubemap texture. - \param filename the name of the file to upload as a texture - \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc. - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_single_cubemap - ( - const char *filename, - const char face_order[6], - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads an HDR image from disk into an OpenGL texture. - \param filename the name of the file to upload as a texture - \param fake_HDR_format SOIL_HDR_RGBE, SOIL_HDR_RGBdivA, SOIL_HDR_RGBdivA2 - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_HDR_texture - ( - const char *filename, - int fake_HDR_format, - int rescale_to_max, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads an image from RAM into an OpenGL texture. - \param buffer the image data in RAM just as if it were still in a file - \param buffer_length the size of the buffer in bytes - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_texture_from_memory - ( - const unsigned char *const buffer, - int buffer_length, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads 6 images from memory into an OpenGL cubemap texture. - \param x_pos_buffer the image data in RAM to upload as the +x cube face - \param x_pos_buffer_length the size of the above buffer - \param x_neg_buffer the image data in RAM to upload as the +x cube face - \param x_neg_buffer_length the size of the above buffer - \param y_pos_buffer the image data in RAM to upload as the +x cube face - \param y_pos_buffer_length the size of the above buffer - \param y_neg_buffer the image data in RAM to upload as the +x cube face - \param y_neg_buffer_length the size of the above buffer - \param z_pos_buffer the image data in RAM to upload as the +x cube face - \param z_pos_buffer_length the size of the above buffer - \param z_neg_buffer the image data in RAM to upload as the +x cube face - \param z_neg_buffer_length the size of the above buffer - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_cubemap_from_memory - ( - const unsigned char *const x_pos_buffer, - int x_pos_buffer_length, - const unsigned char *const x_neg_buffer, - int x_neg_buffer_length, - const unsigned char *const y_pos_buffer, - int y_pos_buffer_length, - const unsigned char *const y_neg_buffer, - int y_neg_buffer_length, - const unsigned char *const z_pos_buffer, - int z_pos_buffer_length, - const unsigned char *const z_neg_buffer, - int z_neg_buffer_length, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads 1 image from RAM and splits it into an OpenGL cubemap texture. - \param buffer the image data in RAM just as if it were still in a file - \param buffer_length the size of the buffer in bytes - \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc. - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_single_cubemap_from_memory - ( - const unsigned char *const buffer, - int buffer_length, - const char face_order[6], - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Creates a 2D OpenGL texture from raw image data. Note that the raw data is - _NOT_ freed after the upload (so the user can load various versions). - \param data the raw data to be uploaded as an OpenGL texture - \param width the width of the image in pixels - \param height the height of the image in pixels - \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_create_OGL_texture - ( - const unsigned char *const data, - int width, int height, int channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Creates an OpenGL cubemap texture by splitting up 1 image into 6 parts. - \param data the raw data to be uploaded as an OpenGL texture - \param width the width of the image in pixels - \param height the height of the image in pixels - \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param face_order the order of the faces in the file, and combination of NSWEUD, for North, South, Up, etc. - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_create_OGL_single_cubemap - ( - const unsigned char *const data, - int width, int height, int channels, - const char face_order[6], - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Captures the OpenGL window (RGB) and saves it to disk - \return 0 if it failed, otherwise returns 1 -**/ -int - SOIL_save_screenshot - ( - const char *filename, - int image_type, - int x, int y, - int width, int height - ); - -/** - Loads an image from disk into an array of unsigned chars. - Note that *channels return the original channel count of the - image. If force_channels was other than SOIL_LOAD_AUTO, - the resulting image has force_channels, but *channels may be - different (if the original image had a different channel - count). - \return 0 if failed, otherwise returns 1 -**/ -unsigned char* - SOIL_load_image - ( - const char *filename, - int *width, int *height, int *channels, - int force_channels - ); - -/** - Loads an image from memory into an array of unsigned chars. - Note that *channels return the original channel count of the - image. If force_channels was other than SOIL_LOAD_AUTO, - the resulting image has force_channels, but *channels may be - different (if the original image had a different channel - count). - \return 0 if failed, otherwise returns 1 -**/ -unsigned char* - SOIL_load_image_from_memory - ( - const unsigned char *const buffer, - int buffer_length, - int *width, int *height, int *channels, - int force_channels - ); - -/** - Saves an image from an array of unsigned chars (RGBA) to disk - \return 0 if failed, otherwise returns 1 -**/ -int - SOIL_save_image - ( - const char *filename, - int image_type, - int width, int height, int channels, - const unsigned char *const data - ); - -/** - Frees the image data (note, this is just C's "free()"...this function is - present mostly so C++ programmers don't forget to use "free()" and call - "delete []" instead [8^) -**/ -void - SOIL_free_image_data - ( - unsigned char *img_data - ); - -/** - This function resturn a pointer to a string describing the last thing - that happened inside SOIL. It can be used to determine why an image - failed to load. -**/ -const char* - SOIL_last_result - ( - void - ); - - -#ifdef __cplusplus -} -#endif - -#endif /* HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY */ diff --git a/ext/SOIL/include/image_DXT.h b/ext/SOIL/include/image_DXT.h deleted file mode 100644 index 75f604f4..00000000 --- a/ext/SOIL/include/image_DXT.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - Jonathan Dummer - 2007-07-31-10.32 - - simple DXT compression / decompression code - - public domain -*/ - -#ifndef HEADER_IMAGE_DXT -#define HEADER_IMAGE_DXT - -/** - Converts an image from an array of unsigned chars (RGB or RGBA) to - DXT1 or DXT5, then saves the converted image to disk. - \return 0 if failed, otherwise returns 1 -**/ -int -save_image_as_DDS -( - const char *filename, - int width, int height, int channels, - const unsigned char *const data -); - -/** - take an image and convert it to DXT1 (no alpha) -**/ -unsigned char* -convert_image_to_DXT1 -( - const unsigned char *const uncompressed, - int width, int height, int channels, - int *out_size -); - -/** - take an image and convert it to DXT5 (with alpha) -**/ -unsigned char* -convert_image_to_DXT5 -( - const unsigned char *const uncompressed, - int width, int height, int channels, - int *out_size -); - -/** A bunch of DirectDraw Surface structures and flags **/ -typedef struct -{ - unsigned int dwMagic; - unsigned int dwSize; - unsigned int dwFlags; - unsigned int dwHeight; - unsigned int dwWidth; - unsigned int dwPitchOrLinearSize; - unsigned int dwDepth; - unsigned int dwMipMapCount; - unsigned int dwReserved1[ 11 ]; - - /* DDPIXELFORMAT */ - struct - { - unsigned int dwSize; - unsigned int dwFlags; - unsigned int dwFourCC; - unsigned int dwRGBBitCount; - unsigned int dwRBitMask; - unsigned int dwGBitMask; - unsigned int dwBBitMask; - unsigned int dwAlphaBitMask; - } - sPixelFormat; - - /* DDCAPS2 */ - struct - { - unsigned int dwCaps1; - unsigned int dwCaps2; - unsigned int dwDDSX; - unsigned int dwReserved; - } - sCaps; - unsigned int dwReserved2; -} -DDS_header ; - -/* the following constants were copied directly off the MSDN website */ - -/* The dwFlags member of the original DDSURFACEDESC2 structure - can be set to one or more of the following values. */ -#define DDSD_CAPS 0x00000001 -#define DDSD_HEIGHT 0x00000002 -#define DDSD_WIDTH 0x00000004 -#define DDSD_PITCH 0x00000008 -#define DDSD_PIXELFORMAT 0x00001000 -#define DDSD_MIPMAPCOUNT 0x00020000 -#define DDSD_LINEARSIZE 0x00080000 -#define DDSD_DEPTH 0x00800000 - -/* DirectDraw Pixel Format */ -#define DDPF_ALPHAPIXELS 0x00000001 -#define DDPF_FOURCC 0x00000004 -#define DDPF_RGB 0x00000040 - -/* The dwCaps1 member of the DDSCAPS2 structure can be - set to one or more of the following values. */ -#define DDSCAPS_COMPLEX 0x00000008 -#define DDSCAPS_TEXTURE 0x00001000 -#define DDSCAPS_MIPMAP 0x00400000 - -/* The dwCaps2 member of the DDSCAPS2 structure can be - set to one or more of the following values. */ -#define DDSCAPS2_CUBEMAP 0x00000200 -#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400 -#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800 -#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000 -#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000 -#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000 -#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000 -#define DDSCAPS2_VOLUME 0x00200000 - -#endif /* HEADER_IMAGE_DXT */ diff --git a/ext/SOIL/include/image_helper.h b/ext/SOIL/include/image_helper.h deleted file mode 100644 index 3fa2662f..00000000 --- a/ext/SOIL/include/image_helper.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - Jonathan Dummer - - Image helper functions - - MIT license -*/ - -#ifndef HEADER_IMAGE_HELPER -#define HEADER_IMAGE_HELPER - -#ifdef __cplusplus -extern "C" { -#endif - -/** - This function upscales an image. - Not to be used to create MIPmaps, - but to make it square, - or to make it a power-of-two sized. -**/ -int - up_scale_image - ( - const unsigned char* const orig, - int width, int height, int channels, - unsigned char* resampled, - int resampled_width, int resampled_height - ); - -/** - This function downscales an image. - Used for creating MIPmaps, - the incoming image should be a - power-of-two sized. -**/ -int - mipmap_image - ( - const unsigned char* const orig, - int width, int height, int channels, - unsigned char* resampled, - int block_size_x, int block_size_y - ); - -/** - This function takes the RGB components of the image - and scales each channel from [0,255] to [16,235]. - This makes the colors "Safe" for display on NTSC - displays. Note that this is _NOT_ a good idea for - loading images like normal- or height-maps! -**/ -int - scale_image_RGB_to_NTSC_safe - ( - unsigned char* orig, - int width, int height, int channels - ); - -/** - This function takes the RGB components of the image - and converts them into YCoCg. 3 components will be - re-ordered to CoYCg (for optimum DXT1 compression), - while 4 components will be ordered CoCgAY (for DXT5 - compression). -**/ -int - convert_RGB_to_YCoCg - ( - unsigned char* orig, - int width, int height, int channels - ); - -/** - This function takes the YCoCg components of the image - and converts them into RGB. See above. -**/ -int - convert_YCoCg_to_RGB - ( - unsigned char* orig, - int width, int height, int channels - ); - -/** - Converts an HDR image from an array - of unsigned chars (RGBE) to RGBdivA - \return 0 if failed, otherwise returns 1 -**/ -int - RGBE_to_RGBdivA - ( - unsigned char *image, - int width, int height, - int rescale_to_max - ); - -/** - Converts an HDR image from an array - of unsigned chars (RGBE) to RGBdivA2 - \return 0 if failed, otherwise returns 1 -**/ -int - RGBE_to_RGBdivA2 - ( - unsigned char *image, - int width, int height, - int rescale_to_max - ); - -#ifdef __cplusplus -} -#endif - -#endif /* HEADER_IMAGE_HELPER */ diff --git a/ext/SOIL/include/stbi_DDS_aug.h b/ext/SOIL/include/stbi_DDS_aug.h deleted file mode 100644 index c7da9f78..00000000 --- a/ext/SOIL/include/stbi_DDS_aug.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - adding DDS loading support to stbi -*/ - -#ifndef HEADER_STB_IMAGE_DDS_AUGMENTATION -#define HEADER_STB_IMAGE_DDS_AUGMENTATION - -// is it a DDS file? -extern int stbi_dds_test_memory (stbi_uc const *buffer, int len); - -extern stbi_uc *stbi_dds_load (char *filename, int *x, int *y, int *comp, int req_comp); -extern stbi_uc *stbi_dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); -#ifndef STBI_NO_STDIO -extern int stbi_dds_test_file (FILE *f); -extern stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -#endif - -// -// -//// end header file ///////////////////////////////////////////////////// -#endif // HEADER_STB_IMAGE_DDS_AUGMENTATION diff --git a/ext/SOIL/include/stbi_DDS_aug_c.h b/ext/SOIL/include/stbi_DDS_aug_c.h deleted file mode 100644 index f49407a7..00000000 --- a/ext/SOIL/include/stbi_DDS_aug_c.h +++ /dev/null @@ -1,511 +0,0 @@ - -/// DDS file support, does decoding, _not_ direct uploading -/// (use SOIL for that ;-) - -/// A bunch of DirectDraw Surface structures and flags -typedef struct { - unsigned int dwMagic; - unsigned int dwSize; - unsigned int dwFlags; - unsigned int dwHeight; - unsigned int dwWidth; - unsigned int dwPitchOrLinearSize; - unsigned int dwDepth; - unsigned int dwMipMapCount; - unsigned int dwReserved1[ 11 ]; - - // DDPIXELFORMAT - struct { - unsigned int dwSize; - unsigned int dwFlags; - unsigned int dwFourCC; - unsigned int dwRGBBitCount; - unsigned int dwRBitMask; - unsigned int dwGBitMask; - unsigned int dwBBitMask; - unsigned int dwAlphaBitMask; - } sPixelFormat; - - // DDCAPS2 - struct { - unsigned int dwCaps1; - unsigned int dwCaps2; - unsigned int dwDDSX; - unsigned int dwReserved; - } sCaps; - unsigned int dwReserved2; -} DDS_header ; - -// the following constants were copied directly off the MSDN website - -// The dwFlags member of the original DDSURFACEDESC2 structure -// can be set to one or more of the following values. -#define DDSD_CAPS 0x00000001 -#define DDSD_HEIGHT 0x00000002 -#define DDSD_WIDTH 0x00000004 -#define DDSD_PITCH 0x00000008 -#define DDSD_PIXELFORMAT 0x00001000 -#define DDSD_MIPMAPCOUNT 0x00020000 -#define DDSD_LINEARSIZE 0x00080000 -#define DDSD_DEPTH 0x00800000 - -// DirectDraw Pixel Format -#define DDPF_ALPHAPIXELS 0x00000001 -#define DDPF_FOURCC 0x00000004 -#define DDPF_RGB 0x00000040 - -// The dwCaps1 member of the DDSCAPS2 structure can be -// set to one or more of the following values. -#define DDSCAPS_COMPLEX 0x00000008 -#define DDSCAPS_TEXTURE 0x00001000 -#define DDSCAPS_MIPMAP 0x00400000 - -// The dwCaps2 member of the DDSCAPS2 structure can be -// set to one or more of the following values. -#define DDSCAPS2_CUBEMAP 0x00000200 -#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400 -#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800 -#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000 -#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000 -#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000 -#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000 -#define DDSCAPS2_VOLUME 0x00200000 - -static int dds_test(stbi *s) -{ - // check the magic number - if (get8(s) != 'D') return 0; - if (get8(s) != 'D') return 0; - if (get8(s) != 'S') return 0; - if (get8(s) != ' ') return 0; - // check header size - if (get32le(s) != 124) return 0; - return 1; -} -#ifndef STBI_NO_STDIO -int stbi_dds_test_file (FILE *f) -{ - stbi s; - int r,n = ftell(f); - start_file(&s,f); - r = dds_test(&s); - fseek(f,n,SEEK_SET); - return r; -} -#endif - -int stbi_dds_test_memory (stbi_uc const *buffer, int len) -{ - stbi s; - start_mem(&s,buffer, len); - return dds_test(&s); -} - -// helper functions -int stbi_convert_bit_range( int c, int from_bits, int to_bits ) -{ - int b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1); - return (b + (b >> from_bits)) >> from_bits; -} -void stbi_rgb_888_from_565( unsigned int c, int *r, int *g, int *b ) -{ - *r = stbi_convert_bit_range( (c >> 11) & 31, 5, 8 ); - *g = stbi_convert_bit_range( (c >> 05) & 63, 6, 8 ); - *b = stbi_convert_bit_range( (c >> 00) & 31, 5, 8 ); -} -void stbi_decode_DXT1_block( - unsigned char uncompressed[16*4], - unsigned char compressed[8] ) -{ - int next_bit = 4*8; - int i, r, g, b; - int c0, c1; - unsigned char decode_colors[4*4]; - // find the 2 primary colors - c0 = compressed[0] + (compressed[1] << 8); - c1 = compressed[2] + (compressed[3] << 8); - stbi_rgb_888_from_565( c0, &r, &g, &b ); - decode_colors[0] = r; - decode_colors[1] = g; - decode_colors[2] = b; - decode_colors[3] = 255; - stbi_rgb_888_from_565( c1, &r, &g, &b ); - decode_colors[4] = r; - decode_colors[5] = g; - decode_colors[6] = b; - decode_colors[7] = 255; - if( c0 > c1 ) - { - // no alpha, 2 interpolated colors - decode_colors[8] = (2*decode_colors[0] + decode_colors[4]) / 3; - decode_colors[9] = (2*decode_colors[1] + decode_colors[5]) / 3; - decode_colors[10] = (2*decode_colors[2] + decode_colors[6]) / 3; - decode_colors[11] = 255; - decode_colors[12] = (decode_colors[0] + 2*decode_colors[4]) / 3; - decode_colors[13] = (decode_colors[1] + 2*decode_colors[5]) / 3; - decode_colors[14] = (decode_colors[2] + 2*decode_colors[6]) / 3; - decode_colors[15] = 255; - } else - { - // 1 interpolated color, alpha - decode_colors[8] = (decode_colors[0] + decode_colors[4]) / 2; - decode_colors[9] = (decode_colors[1] + decode_colors[5]) / 2; - decode_colors[10] = (decode_colors[2] + decode_colors[6]) / 2; - decode_colors[11] = 255; - decode_colors[12] = 0; - decode_colors[13] = 0; - decode_colors[14] = 0; - decode_colors[15] = 0; - } - // decode the block - for( i = 0; i < 16*4; i += 4 ) - { - int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 4; - next_bit += 2; - uncompressed[i+0] = decode_colors[idx+0]; - uncompressed[i+1] = decode_colors[idx+1]; - uncompressed[i+2] = decode_colors[idx+2]; - uncompressed[i+3] = decode_colors[idx+3]; - } - // done -} -void stbi_decode_DXT23_alpha_block( - unsigned char uncompressed[16*4], - unsigned char compressed[8] ) -{ - int i, next_bit = 0; - // each alpha value gets 4 bits - for( i = 3; i < 16*4; i += 4 ) - { - uncompressed[i] = stbi_convert_bit_range( - (compressed[next_bit>>3] >> (next_bit&7)) & 15, - 4, 8 ); - next_bit += 4; - } -} -void stbi_decode_DXT45_alpha_block( - unsigned char uncompressed[16*4], - unsigned char compressed[8] ) -{ - int i, next_bit = 8*2; - unsigned char decode_alpha[8]; - // each alpha value gets 3 bits, and the 1st 2 bytes are the range - decode_alpha[0] = compressed[0]; - decode_alpha[1] = compressed[1]; - if( decode_alpha[0] > decode_alpha[1] ) - { - // 6 step intermediate - decode_alpha[2] = (6*decode_alpha[0] + 1*decode_alpha[1]) / 7; - decode_alpha[3] = (5*decode_alpha[0] + 2*decode_alpha[1]) / 7; - decode_alpha[4] = (4*decode_alpha[0] + 3*decode_alpha[1]) / 7; - decode_alpha[5] = (3*decode_alpha[0] + 4*decode_alpha[1]) / 7; - decode_alpha[6] = (2*decode_alpha[0] + 5*decode_alpha[1]) / 7; - decode_alpha[7] = (1*decode_alpha[0] + 6*decode_alpha[1]) / 7; - } else - { - // 4 step intermediate, pluss full and none - decode_alpha[2] = (4*decode_alpha[0] + 1*decode_alpha[1]) / 5; - decode_alpha[3] = (3*decode_alpha[0] + 2*decode_alpha[1]) / 5; - decode_alpha[4] = (2*decode_alpha[0] + 3*decode_alpha[1]) / 5; - decode_alpha[5] = (1*decode_alpha[0] + 4*decode_alpha[1]) / 5; - decode_alpha[6] = 0; - decode_alpha[7] = 255; - } - for( i = 3; i < 16*4; i += 4 ) - { - int idx = 0, bit; - bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; - idx += bit << 0; - ++next_bit; - bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; - idx += bit << 1; - ++next_bit; - bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; - idx += bit << 2; - ++next_bit; - uncompressed[i] = decode_alpha[idx & 7]; - } - // done -} -void stbi_decode_DXT_color_block( - unsigned char uncompressed[16*4], - unsigned char compressed[8] ) -{ - int next_bit = 4*8; - int i, r, g, b; - int c0, c1; - unsigned char decode_colors[4*3]; - // find the 2 primary colors - c0 = compressed[0] + (compressed[1] << 8); - c1 = compressed[2] + (compressed[3] << 8); - stbi_rgb_888_from_565( c0, &r, &g, &b ); - decode_colors[0] = r; - decode_colors[1] = g; - decode_colors[2] = b; - stbi_rgb_888_from_565( c1, &r, &g, &b ); - decode_colors[3] = r; - decode_colors[4] = g; - decode_colors[5] = b; - // Like DXT1, but no choicees: - // no alpha, 2 interpolated colors - decode_colors[6] = (2*decode_colors[0] + decode_colors[3]) / 3; - decode_colors[7] = (2*decode_colors[1] + decode_colors[4]) / 3; - decode_colors[8] = (2*decode_colors[2] + decode_colors[5]) / 3; - decode_colors[9] = (decode_colors[0] + 2*decode_colors[3]) / 3; - decode_colors[10] = (decode_colors[1] + 2*decode_colors[4]) / 3; - decode_colors[11] = (decode_colors[2] + 2*decode_colors[5]) / 3; - // decode the block - for( i = 0; i < 16*4; i += 4 ) - { - int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 3; - next_bit += 2; - uncompressed[i+0] = decode_colors[idx+0]; - uncompressed[i+1] = decode_colors[idx+1]; - uncompressed[i+2] = decode_colors[idx+2]; - } - // done -} -static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp) -{ - // all variables go up front - stbi_uc *dds_data = NULL; - stbi_uc block[16*4]; - stbi_uc compressed[8]; - int flags, DXT_family; - int has_alpha, has_mipmap; - int is_compressed, cubemap_faces; - int block_pitch, num_blocks; - DDS_header header; - int i, sz, cf; - // load the header - if( sizeof( DDS_header ) != 128 ) - { - return NULL; - } - getn( s, (stbi_uc*)(&header), 128 ); - // and do some checking - if( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) return NULL; - if( header.dwSize != 124 ) return NULL; - flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; - if( (header.dwFlags & flags) != flags ) return NULL; - /* According to the MSDN spec, the dwFlags should contain - DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if - uncompressed. Some DDS writers do not conform to the - spec, so I need to make my reader more tolerant */ - if( header.sPixelFormat.dwSize != 32 ) return NULL; - flags = DDPF_FOURCC | DDPF_RGB; - if( (header.sPixelFormat.dwFlags & flags) == 0 ) return NULL; - if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) return NULL; - // get the image data - s->img_x = header.dwWidth; - s->img_y = header.dwHeight; - s->img_n = 4; - is_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC; - has_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS; - has_mipmap = (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1); - cubemap_faces = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP; - /* I need cubemaps to have square faces */ - cubemap_faces &= (s->img_x == s->img_y); - cubemap_faces *= 5; - cubemap_faces += 1; - block_pitch = (s->img_x+3) >> 2; - num_blocks = block_pitch * ((s->img_y+3) >> 2); - /* let the user know what's going on */ - *x = s->img_x; - *y = s->img_y; - *comp = s->img_n; - /* is this uncompressed? */ - if( is_compressed ) - { - /* compressed */ - // note: header.sPixelFormat.dwFourCC is something like (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24)) - DXT_family = 1 + (header.sPixelFormat.dwFourCC >> 24) - '1'; - if( (DXT_family < 1) || (DXT_family > 5) ) return NULL; - /* check the expected size...oops, nevermind... - those non-compliant writers leave - dwPitchOrLinearSize == 0 */ - // passed all the tests, get the RAM for decoding - sz = (s->img_x)*(s->img_y)*4*cubemap_faces; - dds_data = (unsigned char*)malloc( sz ); - /* do this once for each face */ - for( cf = 0; cf < cubemap_faces; ++ cf ) - { - // now read and decode all the blocks - for( i = 0; i < num_blocks; ++i ) - { - // where are we? - int bx, by, bw=4, bh=4; - int ref_x = 4 * (i % block_pitch); - int ref_y = 4 * (i / block_pitch); - // get the next block's worth of compressed data, and decompress it - if( DXT_family == 1 ) - { - // DXT1 - getn( s, compressed, 8 ); - stbi_decode_DXT1_block( block, compressed ); - } else if( DXT_family < 4 ) - { - // DXT2/3 - getn( s, compressed, 8 ); - stbi_decode_DXT23_alpha_block ( block, compressed ); - getn( s, compressed, 8 ); - stbi_decode_DXT_color_block ( block, compressed ); - } else - { - // DXT4/5 - getn( s, compressed, 8 ); - stbi_decode_DXT45_alpha_block ( block, compressed ); - getn( s, compressed, 8 ); - stbi_decode_DXT_color_block ( block, compressed ); - } - // is this a partial block? - if( ref_x + 4 > s->img_x ) - { - bw = s->img_x - ref_x; - } - if( ref_y + 4 > s->img_y ) - { - bh = s->img_y - ref_y; - } - // now drop our decompressed data into the buffer - for( by = 0; by < bh; ++by ) - { - int idx = 4*((ref_y+by+cf*s->img_x)*s->img_x + ref_x); - for( bx = 0; bx < bw*4; ++bx ) - { - - dds_data[idx+bx] = block[by*16+bx]; - } - } - } - /* done reading and decoding the main image... - skip MIPmaps if present */ - if( has_mipmap ) - { - int block_size = 16; - if( DXT_family == 1 ) - { - block_size = 8; - } - for( i = 1; i < header.dwMipMapCount; ++i ) - { - int mx = s->img_x >> (i + 2); - int my = s->img_y >> (i + 2); - if( mx < 1 ) - { - mx = 1; - } - if( my < 1 ) - { - my = 1; - } - skip( s, mx*my*block_size ); - } - } - }/* per cubemap face */ - } else - { - /* uncompressed */ - DXT_family = 0; - s->img_n = 3; - if( has_alpha ) - { - s->img_n = 4; - } - *comp = s->img_n; - sz = s->img_x*s->img_y*s->img_n*cubemap_faces; - dds_data = (unsigned char*)malloc( sz ); - /* do this once for each face */ - for( cf = 0; cf < cubemap_faces; ++ cf ) - { - /* read the main image for this face */ - getn( s, &dds_data[cf*s->img_x*s->img_y*s->img_n], s->img_x*s->img_y*s->img_n ); - /* done reading and decoding the main image... - skip MIPmaps if present */ - if( has_mipmap ) - { - for( i = 1; i < header.dwMipMapCount; ++i ) - { - int mx = s->img_x >> i; - int my = s->img_y >> i; - if( mx < 1 ) - { - mx = 1; - } - if( my < 1 ) - { - my = 1; - } - skip( s, mx*my*s->img_n ); - } - } - } - /* data was BGR, I need it RGB */ - for( i = 0; i < sz; i += s->img_n ) - { - unsigned char temp = dds_data[i]; - dds_data[i] = dds_data[i+2]; - dds_data[i+2] = temp; - } - } - /* finished decompressing into RGBA, - adjust the y size if we have a cubemap - note: sz is already up to date */ - s->img_y *= cubemap_faces; - *y = s->img_y; - // did the user want something else, or - // see if all the alpha values are 255 (i.e. no transparency) - has_alpha = 0; - if( s->img_n == 4) - { - for( i = 3; (i < sz) && (has_alpha == 0); i += 4 ) - { - has_alpha |= (dds_data[i] < 255); - } - } - if( (req_comp <= 4) && (req_comp >= 1) ) - { - // user has some requirements, meet them - if( req_comp != s->img_n ) - { - dds_data = convert_format( dds_data, s->img_n, req_comp, s->img_x, s->img_y ); - *comp = s->img_n; - } - } else - { - // user had no requirements, only drop to RGB is no alpha - if( (has_alpha == 0) && (s->img_n == 4) ) - { - dds_data = convert_format( dds_data, 4, 3, s->img_x, s->img_y ); - *comp = 3; - } - } - // OK, done - return dds_data; -} - -#ifndef STBI_NO_STDIO -stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi s; - start_file(&s,f); - return dds_load(&s,x,y,comp,req_comp); -} - -stbi_uc *stbi_dds_load (char *filename, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *data; - FILE *f = fopen(filename, "rb"); - if (!f) return NULL; - data = stbi_dds_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return data; -} -#endif - -stbi_uc *stbi_dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi s; - start_mem(&s,buffer, len); - return dds_load(&s,x,y,comp,req_comp); -} diff --git a/ext/SOIL/src/SOIL.c b/ext/SOIL/src/SOIL.c deleted file mode 100644 index 4fcb1eb5..00000000 --- a/ext/SOIL/src/SOIL.c +++ /dev/null @@ -1,2025 +0,0 @@ -/* - Jonathan Dummer - 2007-07-26-10.36 - - Simple OpenGL Image Library - - Public Domain - using Sean Barret's stb_image as a base - - Thanks to: - * Sean Barret - for the awesome stb_image - * Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts - * everybody at gamedev.net -*/ - -#define SOIL_CHECK_FOR_GL_ERRORS 0 - -#ifdef WIN32 - #define WIN32_LEAN_AND_MEAN - #include - #include - #include -#elif defined(__APPLE__) || defined(__APPLE_CC__) - /* I can't test this Apple stuff! */ - #include - #include - #define APIENTRY -#else - #include - #include -#endif - -#include "SOIL.h" -#include "stb_image.h" -#include "image_helper.h" -#include "image_DXT.h" - -#include -#include - -/* error reporting */ -char *result_string_pointer = "SOIL initialized"; - -/* for loading cube maps */ -enum{ - SOIL_CAPABILITY_UNKNOWN = -1, - SOIL_CAPABILITY_NONE = 0, - SOIL_CAPABILITY_PRESENT = 1 -}; -static int has_cubemap_capability = SOIL_CAPABILITY_UNKNOWN; -int query_cubemap_capability( void ); -#define SOIL_TEXTURE_WRAP_R 0x8072 -#define SOIL_CLAMP_TO_EDGE 0x812F -#define SOIL_NORMAL_MAP 0x8511 -#define SOIL_REFLECTION_MAP 0x8512 -#define SOIL_TEXTURE_CUBE_MAP 0x8513 -#define SOIL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define SOIL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define SOIL_PROXY_TEXTURE_CUBE_MAP 0x851B -#define SOIL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -/* for non-power-of-two texture */ -static int has_NPOT_capability = SOIL_CAPABILITY_UNKNOWN; -int query_NPOT_capability( void ); -/* for texture rectangles */ -static int has_tex_rectangle_capability = SOIL_CAPABILITY_UNKNOWN; -int query_tex_rectangle_capability( void ); -#define SOIL_TEXTURE_RECTANGLE_ARB 0x84F5 -#define SOIL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 -/* for using DXT compression */ -static int has_DXT_capability = SOIL_CAPABILITY_UNKNOWN; -int query_DXT_capability( void ); -#define SOIL_RGB_S3TC_DXT1 0x83F0 -#define SOIL_RGBA_S3TC_DXT1 0x83F1 -#define SOIL_RGBA_S3TC_DXT3 0x83F2 -#define SOIL_RGBA_S3TC_DXT5 0x83F3 -typedef void (APIENTRY * P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid * data); -P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC soilGlCompressedTexImage2D = NULL; -unsigned int SOIL_direct_load_DDS( - const char *filename, - unsigned int reuse_texture_ID, - int flags, - int loading_as_cubemap ); -unsigned int SOIL_direct_load_DDS_from_memory( - const unsigned char *const buffer, - int buffer_length, - unsigned int reuse_texture_ID, - int flags, - int loading_as_cubemap ); -/* other functions */ -unsigned int - SOIL_internal_create_OGL_texture - ( - const unsigned char *const data, - int width, int height, int channels, - unsigned int reuse_texture_ID, - unsigned int flags, - unsigned int opengl_texture_type, - unsigned int opengl_texture_target, - unsigned int texture_check_size_enum - ); - -/* and the code magic begins here [8^) */ -unsigned int - SOIL_load_OGL_texture - ( - const char *filename, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ) -{ - /* variables */ - unsigned char* img; - int width, height, channels; - unsigned int tex_id; - /* does the user want direct uploading of the image as a DDS file? */ - if( flags & SOIL_FLAG_DDS_LOAD_DIRECT ) - { - /* 1st try direct loading of the image as a DDS file - note: direct uploading will only load what is in the - DDS file, no MIPmaps will be generated, the image will - not be flipped, etc. */ - tex_id = SOIL_direct_load_DDS( filename, reuse_texture_ID, flags, 0 ); - if( tex_id ) - { - /* hey, it worked!! */ - return tex_id; - } - } - /* try to load the image */ - img = SOIL_load_image( filename, &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* OK, make it a texture! */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - reuse_texture_ID, flags, - GL_TEXTURE_2D, GL_TEXTURE_2D, - GL_MAX_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - /* and return the handle, such as it is */ - return tex_id; -} - -unsigned int - SOIL_load_OGL_HDR_texture - ( - const char *filename, - int fake_HDR_format, - int rescale_to_max, - unsigned int reuse_texture_ID, - unsigned int flags - ) -{ - /* variables */ - unsigned char* img; - int width, height, channels; - unsigned int tex_id; - /* no direct uploading of the image as a DDS file */ - /* error check */ - if( (fake_HDR_format != SOIL_HDR_RGBE) && - (fake_HDR_format != SOIL_HDR_RGBdivA) && - (fake_HDR_format != SOIL_HDR_RGBdivA2) ) - { - result_string_pointer = "Invalid fake HDR format specified"; - return 0; - } - /* try to load the image (only the HDR type) */ - // TODO fix - //img = stbi__hdr_load( filename, &width, &height, &channels, 4 ); - /* channels holds the original number of channels, which may have been forced */ - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* the load worked, do I need to convert it? */ - if( fake_HDR_format == SOIL_HDR_RGBdivA ) - { - RGBE_to_RGBdivA( img, width, height, rescale_to_max ); - } else if( fake_HDR_format == SOIL_HDR_RGBdivA2 ) - { - RGBE_to_RGBdivA2( img, width, height, rescale_to_max ); - } - /* OK, make it a texture! */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - reuse_texture_ID, flags, - GL_TEXTURE_2D, GL_TEXTURE_2D, - GL_MAX_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - /* and return the handle, such as it is */ - return tex_id; -} - -unsigned int - SOIL_load_OGL_texture_from_memory - ( - const unsigned char *const buffer, - int buffer_length, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ) -{ - /* variables */ - unsigned char* img; - int width, height, channels; - unsigned int tex_id; - /* does the user want direct uploading of the image as a DDS file? */ - if( flags & SOIL_FLAG_DDS_LOAD_DIRECT ) - { - /* 1st try direct loading of the image as a DDS file - note: direct uploading will only load what is in the - DDS file, no MIPmaps will be generated, the image will - not be flipped, etc. */ - tex_id = SOIL_direct_load_DDS_from_memory( - buffer, buffer_length, - reuse_texture_ID, flags, 0 ); - if( tex_id ) - { - /* hey, it worked!! */ - return tex_id; - } - } - /* try to load the image */ - img = SOIL_load_image_from_memory( - buffer, buffer_length, - &width, &height, &channels, - force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* OK, make it a texture! */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - reuse_texture_ID, flags, - GL_TEXTURE_2D, GL_TEXTURE_2D, - GL_MAX_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - /* and return the handle, such as it is */ - return tex_id; -} - -unsigned int - SOIL_load_OGL_cubemap - ( - const char *x_pos_file, - const char *x_neg_file, - const char *y_pos_file, - const char *y_neg_file, - const char *z_pos_file, - const char *z_neg_file, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ) -{ - /* variables */ - unsigned char* img; - int width, height, channels; - unsigned int tex_id; - /* error checking */ - if( (x_pos_file == NULL) || - (x_neg_file == NULL) || - (y_pos_file == NULL) || - (y_neg_file == NULL) || - (z_pos_file == NULL) || - (z_neg_file == NULL) ) - { - result_string_pointer = "Invalid cube map files list"; - return 0; - } - /* capability checking */ - if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) - { - result_string_pointer = "No cube map capability present"; - return 0; - } - /* 1st face: try to load the image */ - img = SOIL_load_image( x_pos_file, &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, and create a texture ID if necessary */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - reuse_texture_ID, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_X, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - /* continue? */ - if( tex_id != 0 ) - { - /* 1st face: try to load the image */ - img = SOIL_load_image( x_neg_file, &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, but reuse the assigned texture ID */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - tex_id, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - } - /* continue? */ - if( tex_id != 0 ) - { - /* 1st face: try to load the image */ - img = SOIL_load_image( y_pos_file, &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, but reuse the assigned texture ID */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - tex_id, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - } - /* continue? */ - if( tex_id != 0 ) - { - /* 1st face: try to load the image */ - img = SOIL_load_image( y_neg_file, &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, but reuse the assigned texture ID */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - tex_id, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - } - /* continue? */ - if( tex_id != 0 ) - { - /* 1st face: try to load the image */ - img = SOIL_load_image( z_pos_file, &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, but reuse the assigned texture ID */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - tex_id, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - } - /* continue? */ - if( tex_id != 0 ) - { - /* 1st face: try to load the image */ - img = SOIL_load_image( z_neg_file, &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, but reuse the assigned texture ID */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - tex_id, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - } - /* and return the handle, such as it is */ - return tex_id; -} - -unsigned int - SOIL_load_OGL_cubemap_from_memory - ( - const unsigned char *const x_pos_buffer, - int x_pos_buffer_length, - const unsigned char *const x_neg_buffer, - int x_neg_buffer_length, - const unsigned char *const y_pos_buffer, - int y_pos_buffer_length, - const unsigned char *const y_neg_buffer, - int y_neg_buffer_length, - const unsigned char *const z_pos_buffer, - int z_pos_buffer_length, - const unsigned char *const z_neg_buffer, - int z_neg_buffer_length, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ) -{ - /* variables */ - unsigned char* img; - int width, height, channels; - unsigned int tex_id; - /* error checking */ - if( (x_pos_buffer == NULL) || - (x_neg_buffer == NULL) || - (y_pos_buffer == NULL) || - (y_neg_buffer == NULL) || - (z_pos_buffer == NULL) || - (z_neg_buffer == NULL) ) - { - result_string_pointer = "Invalid cube map buffers list"; - return 0; - } - /* capability checking */ - if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) - { - result_string_pointer = "No cube map capability present"; - return 0; - } - /* 1st face: try to load the image */ - img = SOIL_load_image_from_memory( - x_pos_buffer, x_pos_buffer_length, - &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, and create a texture ID if necessary */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - reuse_texture_ID, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_X, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - /* continue? */ - if( tex_id != 0 ) - { - /* 1st face: try to load the image */ - img = SOIL_load_image_from_memory( - x_neg_buffer, x_neg_buffer_length, - &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, but reuse the assigned texture ID */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - tex_id, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - } - /* continue? */ - if( tex_id != 0 ) - { - /* 1st face: try to load the image */ - img = SOIL_load_image_from_memory( - y_pos_buffer, y_pos_buffer_length, - &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, but reuse the assigned texture ID */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - tex_id, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - } - /* continue? */ - if( tex_id != 0 ) - { - /* 1st face: try to load the image */ - img = SOIL_load_image_from_memory( - y_neg_buffer, y_neg_buffer_length, - &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, but reuse the assigned texture ID */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - tex_id, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - } - /* continue? */ - if( tex_id != 0 ) - { - /* 1st face: try to load the image */ - img = SOIL_load_image_from_memory( - z_pos_buffer, z_pos_buffer_length, - &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, but reuse the assigned texture ID */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - tex_id, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - } - /* continue? */ - if( tex_id != 0 ) - { - /* 1st face: try to load the image */ - img = SOIL_load_image_from_memory( - z_neg_buffer, z_neg_buffer_length, - &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* upload the texture, but reuse the assigned texture ID */ - tex_id = SOIL_internal_create_OGL_texture( - img, width, height, channels, - tex_id, flags, - SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - /* and nuke the image data */ - SOIL_free_image_data( img ); - } - /* and return the handle, such as it is */ - return tex_id; -} - -unsigned int - SOIL_load_OGL_single_cubemap - ( - const char *filename, - const char face_order[6], - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ) -{ - /* variables */ - unsigned char* img; - int width, height, channels, i; - unsigned int tex_id = 0; - /* error checking */ - if( filename == NULL ) - { - result_string_pointer = "Invalid single cube map file name"; - return 0; - } - /* does the user want direct uploading of the image as a DDS file? */ - if( flags & SOIL_FLAG_DDS_LOAD_DIRECT ) - { - /* 1st try direct loading of the image as a DDS file - note: direct uploading will only load what is in the - DDS file, no MIPmaps will be generated, the image will - not be flipped, etc. */ - tex_id = SOIL_direct_load_DDS( filename, reuse_texture_ID, flags, 1 ); - if( tex_id ) - { - /* hey, it worked!! */ - return tex_id; - } - } - /* face order checking */ - for( i = 0; i < 6; ++i ) - { - if( (face_order[i] != 'N') && - (face_order[i] != 'S') && - (face_order[i] != 'W') && - (face_order[i] != 'E') && - (face_order[i] != 'U') && - (face_order[i] != 'D') ) - { - result_string_pointer = "Invalid single cube map face order"; - return 0; - }; - } - /* capability checking */ - if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) - { - result_string_pointer = "No cube map capability present"; - return 0; - } - /* 1st off, try to load the full image */ - img = SOIL_load_image( filename, &width, &height, &channels, force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* now, does this image have the right dimensions? */ - if( (width != 6*height) && - (6*width != height) ) - { - SOIL_free_image_data( img ); - result_string_pointer = "Single cubemap image must have a 6:1 ratio"; - return 0; - } - /* try the image split and create */ - tex_id = SOIL_create_OGL_single_cubemap( - img, width, height, channels, - face_order, reuse_texture_ID, flags - ); - /* nuke the temporary image data and return the texture handle */ - SOIL_free_image_data( img ); - return tex_id; -} - -unsigned int - SOIL_load_OGL_single_cubemap_from_memory - ( - const unsigned char *const buffer, - int buffer_length, - const char face_order[6], - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ) -{ - /* variables */ - unsigned char* img; - int width, height, channels, i; - unsigned int tex_id = 0; - /* error checking */ - if( buffer == NULL ) - { - result_string_pointer = "Invalid single cube map buffer"; - return 0; - } - /* does the user want direct uploading of the image as a DDS file? */ - if( flags & SOIL_FLAG_DDS_LOAD_DIRECT ) - { - /* 1st try direct loading of the image as a DDS file - note: direct uploading will only load what is in the - DDS file, no MIPmaps will be generated, the image will - not be flipped, etc. */ - tex_id = SOIL_direct_load_DDS_from_memory( - buffer, buffer_length, - reuse_texture_ID, flags, 1 ); - if( tex_id ) - { - /* hey, it worked!! */ - return tex_id; - } - } - /* face order checking */ - for( i = 0; i < 6; ++i ) - { - if( (face_order[i] != 'N') && - (face_order[i] != 'S') && - (face_order[i] != 'W') && - (face_order[i] != 'E') && - (face_order[i] != 'U') && - (face_order[i] != 'D') ) - { - result_string_pointer = "Invalid single cube map face order"; - return 0; - }; - } - /* capability checking */ - if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) - { - result_string_pointer = "No cube map capability present"; - return 0; - } - /* 1st off, try to load the full image */ - img = SOIL_load_image_from_memory( - buffer, buffer_length, - &width, &height, &channels, - force_channels ); - /* channels holds the original number of channels, which may have been forced */ - if( (force_channels >= 1) && (force_channels <= 4) ) - { - channels = force_channels; - } - if( NULL == img ) - { - /* image loading failed */ - result_string_pointer = stbi_failure_reason(); - return 0; - } - /* now, does this image have the right dimensions? */ - if( (width != 6*height) && - (6*width != height) ) - { - SOIL_free_image_data( img ); - result_string_pointer = "Single cubemap image must have a 6:1 ratio"; - return 0; - } - /* try the image split and create */ - tex_id = SOIL_create_OGL_single_cubemap( - img, width, height, channels, - face_order, reuse_texture_ID, flags - ); - /* nuke the temporary image data and return the texture handle */ - SOIL_free_image_data( img ); - return tex_id; -} - -unsigned int - SOIL_create_OGL_single_cubemap - ( - const unsigned char *const data, - int width, int height, int channels, - const char face_order[6], - unsigned int reuse_texture_ID, - unsigned int flags - ) -{ - /* variables */ - unsigned char* sub_img; - int dw, dh, sz, i; - unsigned int tex_id; - /* error checking */ - if( data == NULL ) - { - result_string_pointer = "Invalid single cube map image data"; - return 0; - } - /* face order checking */ - for( i = 0; i < 6; ++i ) - { - if( (face_order[i] != 'N') && - (face_order[i] != 'S') && - (face_order[i] != 'W') && - (face_order[i] != 'E') && - (face_order[i] != 'U') && - (face_order[i] != 'D') ) - { - result_string_pointer = "Invalid single cube map face order"; - return 0; - }; - } - /* capability checking */ - if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) - { - result_string_pointer = "No cube map capability present"; - return 0; - } - /* now, does this image have the right dimensions? */ - if( (width != 6*height) && - (6*width != height) ) - { - result_string_pointer = "Single cubemap image must have a 6:1 ratio"; - return 0; - } - /* which way am I stepping? */ - if( width > height ) - { - dw = height; - dh = 0; - } else - { - dw = 0; - dh = width; - } - sz = dw+dh; - sub_img = (unsigned char *)malloc( sz*sz*channels ); - /* do the splitting and uploading */ - tex_id = reuse_texture_ID; - for( i = 0; i < 6; ++i ) - { - int x, y, idx = 0; - unsigned int cubemap_target = 0; - /* copy in the sub-image */ - for( y = i*dh; y < i*dh+sz; ++y ) - { - for( x = i*dw*channels; x < (i*dw+sz)*channels; ++x ) - { - sub_img[idx++] = data[y*width*channels+x]; - } - } - /* what is my texture target? - remember, this coordinate system is - LHS if viewed from inside the cube! */ - switch( face_order[i] ) - { - case 'N': - cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z; - break; - case 'S': - cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z; - break; - case 'W': - cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X; - break; - case 'E': - cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X; - break; - case 'U': - cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y; - break; - case 'D': - cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y; - break; - } - /* upload it as a texture */ - tex_id = SOIL_internal_create_OGL_texture( - sub_img, sz, sz, channels, - tex_id, flags, - SOIL_TEXTURE_CUBE_MAP, - cubemap_target, - SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); - } - /* and nuke the image and sub-image data */ - SOIL_free_image_data( sub_img ); - /* and return the handle, such as it is */ - return tex_id; -} - -unsigned int - SOIL_create_OGL_texture - ( - const unsigned char *const data, - int width, int height, int channels, - unsigned int reuse_texture_ID, - unsigned int flags - ) -{ - /* wrapper function for 2D textures */ - return SOIL_internal_create_OGL_texture( - data, width, height, channels, - reuse_texture_ID, flags, - GL_TEXTURE_2D, GL_TEXTURE_2D, - GL_MAX_TEXTURE_SIZE ); -} - -#if SOIL_CHECK_FOR_GL_ERRORS -void check_for_GL_errors( const char *calling_location ) -{ - /* check for errors */ - GLenum err_code = glGetError(); - while( GL_NO_ERROR != err_code ) - { - printf( "OpenGL Error @ %s: %i", calling_location, err_code ); - err_code = glGetError(); - } -} -#else -void check_for_GL_errors( const char *calling_location ) -{ - /* no check for errors */ -} -#endif - -unsigned int - SOIL_internal_create_OGL_texture - ( - const unsigned char *const data, - int width, int height, int channels, - unsigned int reuse_texture_ID, - unsigned int flags, - unsigned int opengl_texture_type, - unsigned int opengl_texture_target, - unsigned int texture_check_size_enum - ) -{ - /* variables */ - unsigned char* img; - unsigned int tex_id; - unsigned int internal_texture_format = 0, original_texture_format = 0; - int DXT_mode = SOIL_CAPABILITY_UNKNOWN; - int max_supported_size; - /* If the user wants to use the texture rectangle I kill a few flags */ - if( flags & SOIL_FLAG_TEXTURE_RECTANGLE ) - { - /* well, the user asked for it, can we do that? */ - if( query_tex_rectangle_capability() == SOIL_CAPABILITY_PRESENT ) - { - /* only allow this if the user in _NOT_ trying to do a cubemap! */ - if( opengl_texture_type == GL_TEXTURE_2D ) - { - /* clean out the flags that cannot be used with texture rectangles */ - flags &= ~( - SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | - SOIL_FLAG_TEXTURE_REPEATS - ); - /* and change my target */ - opengl_texture_target = SOIL_TEXTURE_RECTANGLE_ARB; - opengl_texture_type = SOIL_TEXTURE_RECTANGLE_ARB; - } else - { - /* not allowed for any other uses (yes, I'm looking at you, cubemaps!) */ - flags &= ~SOIL_FLAG_TEXTURE_RECTANGLE; - } - - } else - { - /* can't do it, and that is a breakable offense (uv coords use pixels instead of [0,1]!) */ - result_string_pointer = "Texture Rectangle extension unsupported"; - return 0; - } - } - /* create a copy the image data */ - img = (unsigned char*)malloc( width*height*channels ); - memcpy( img, data, width*height*channels ); - /* does the user want me to invert the image? */ - if( flags & SOIL_FLAG_INVERT_Y ) - { - int i, j; - for( j = 0; j*2 < height; ++j ) - { - int index1 = j * width * channels; - int index2 = (height - 1 - j) * width * channels; - for( i = width * channels; i > 0; --i ) - { - unsigned char temp = img[index1]; - img[index1] = img[index2]; - img[index2] = temp; - ++index1; - ++index2; - } - } - } - /* does the user want me to scale the colors into the NTSC safe RGB range? */ - if( flags & SOIL_FLAG_NTSC_SAFE_RGB ) - { - scale_image_RGB_to_NTSC_safe( img, width, height, channels ); - } - /* does the user want me to convert from straight to pre-multiplied alpha? - (and do we even _have_ alpha?) */ - if( flags & SOIL_FLAG_MULTIPLY_ALPHA ) - { - int i; - switch( channels ) - { - case 2: - for( i = 0; i < 2*width*height; i += 2 ) - { - img[i] = (img[i] * img[i+1] + 128) >> 8; - } - break; - case 4: - for( i = 0; i < 4*width*height; i += 4 ) - { - img[i+0] = (img[i+0] * img[i+3] + 128) >> 8; - img[i+1] = (img[i+1] * img[i+3] + 128) >> 8; - img[i+2] = (img[i+2] * img[i+3] + 128) >> 8; - } - break; - default: - /* no other number of channels contains alpha data */ - break; - } - } - /* if the user can't support NPOT textures, make sure we force the POT option */ - if( (query_NPOT_capability() == SOIL_CAPABILITY_NONE) && - !(flags & SOIL_FLAG_TEXTURE_RECTANGLE) ) - { - /* add in the POT flag */ - flags |= SOIL_FLAG_POWER_OF_TWO; - } - /* how large of a texture can this OpenGL implementation handle? */ - /* texture_check_size_enum will be GL_MAX_TEXTURE_SIZE or SOIL_MAX_CUBE_MAP_TEXTURE_SIZE */ - glGetIntegerv( texture_check_size_enum, &max_supported_size ); - /* do I need to make it a power of 2? */ - if( - (flags & SOIL_FLAG_POWER_OF_TWO) || /* user asked for it */ - (flags & SOIL_FLAG_MIPMAPS) || /* need it for the MIP-maps */ - (width > max_supported_size) || /* it's too big, (make sure it's */ - (height > max_supported_size) ) /* 2^n for later down-sampling) */ - { - int new_width = 1; - int new_height = 1; - while( new_width < width ) - { - new_width *= 2; - } - while( new_height < height ) - { - new_height *= 2; - } - /* still? */ - if( (new_width != width) || (new_height != height) ) - { - /* yep, resize */ - unsigned char *resampled = (unsigned char*)malloc( channels*new_width*new_height ); - up_scale_image( - img, width, height, channels, - resampled, new_width, new_height ); - /* OJO this is for debug only! */ - /* - SOIL_save_image( "\\showme.bmp", SOIL_SAVE_TYPE_BMP, - new_width, new_height, channels, - resampled ); - */ - /* nuke the old guy, then point it at the new guy */ - SOIL_free_image_data( img ); - img = resampled; - width = new_width; - height = new_height; - } - } - /* now, if it is too large... */ - if( (width > max_supported_size) || (height > max_supported_size) ) - { - /* I've already made it a power of two, so simply use the MIPmapping - code to reduce its size to the allowable maximum. */ - unsigned char *resampled; - int reduce_block_x = 1, reduce_block_y = 1; - int new_width, new_height; - if( width > max_supported_size ) - { - reduce_block_x = width / max_supported_size; - } - if( height > max_supported_size ) - { - reduce_block_y = height / max_supported_size; - } - new_width = width / reduce_block_x; - new_height = height / reduce_block_y; - resampled = (unsigned char*)malloc( channels*new_width*new_height ); - /* perform the actual reduction */ - mipmap_image( img, width, height, channels, - resampled, reduce_block_x, reduce_block_y ); - /* nuke the old guy, then point it at the new guy */ - SOIL_free_image_data( img ); - img = resampled; - width = new_width; - height = new_height; - } - /* does the user want us to use YCoCg color space? */ - if( flags & SOIL_FLAG_CoCg_Y ) - { - /* this will only work with RGB and RGBA images */ - convert_RGB_to_YCoCg( img, width, height, channels ); - /* - save_image_as_DDS( "CoCg_Y.dds", width, height, channels, img ); - */ - } - /* create the OpenGL texture ID handle - (note: allowing a forced texture ID lets me reload a texture) */ - tex_id = reuse_texture_ID; - if( tex_id == 0 ) - { - glGenTextures( 1, &tex_id ); - } - check_for_GL_errors( "glGenTextures" ); - /* Note: sometimes glGenTextures fails (usually no OpenGL context) */ - if( tex_id ) - { - /* and what type am I using as the internal texture format? */ - switch( channels ) - { - case 1: - original_texture_format = GL_LUMINANCE; - break; - case 2: - original_texture_format = GL_LUMINANCE_ALPHA; - break; - case 3: - original_texture_format = GL_RGB; - break; - case 4: - original_texture_format = GL_RGBA; - break; - } - internal_texture_format = original_texture_format; - /* does the user want me to, and can I, save as DXT? */ - if( flags & SOIL_FLAG_COMPRESS_TO_DXT ) - { - DXT_mode = query_DXT_capability(); - if( DXT_mode == SOIL_CAPABILITY_PRESENT ) - { - /* I can use DXT, whether I compress it or OpenGL does */ - if( (channels & 1) == 1 ) - { - /* 1 or 3 channels = DXT1 */ - internal_texture_format = SOIL_RGB_S3TC_DXT1; - } else - { - /* 2 or 4 channels = DXT5 */ - internal_texture_format = SOIL_RGBA_S3TC_DXT5; - } - } - } - /* bind an OpenGL texture ID */ - glBindTexture( opengl_texture_type, tex_id ); - check_for_GL_errors( "glBindTexture" ); - /* upload the main image */ - if( DXT_mode == SOIL_CAPABILITY_PRESENT ) - { - /* user wants me to do the DXT conversion! */ - int DDS_size; - unsigned char *DDS_data = NULL; - if( (channels & 1) == 1 ) - { - /* RGB, use DXT1 */ - DDS_data = convert_image_to_DXT1( img, width, height, channels, &DDS_size ); - } else - { - /* RGBA, use DXT5 */ - DDS_data = convert_image_to_DXT5( img, width, height, channels, &DDS_size ); - } - if( DDS_data ) - { - soilGlCompressedTexImage2D( - opengl_texture_target, 0, - internal_texture_format, width, height, 0, - DDS_size, DDS_data ); - check_for_GL_errors( "glCompressedTexImage2D" ); - SOIL_free_image_data( DDS_data ); - /* printf( "Internal DXT compressor\n" ); */ - } else - { - /* my compression failed, try the OpenGL driver's version */ - glTexImage2D( - opengl_texture_target, 0, - internal_texture_format, width, height, 0, - original_texture_format, GL_UNSIGNED_BYTE, img ); - check_for_GL_errors( "glTexImage2D" ); - /* printf( "OpenGL DXT compressor\n" ); */ - } - } else - { - /* user want OpenGL to do all the work! */ - glTexImage2D( - opengl_texture_target, 0, - internal_texture_format, width, height, 0, - original_texture_format, GL_UNSIGNED_BYTE, img ); - check_for_GL_errors( "glTexImage2D" ); - /*printf( "OpenGL DXT compressor\n" ); */ - } - /* are any MIPmaps desired? */ - if( flags & SOIL_FLAG_MIPMAPS ) - { - int MIPlevel = 1; - int MIPwidth = (width+1) / 2; - int MIPheight = (height+1) / 2; - unsigned char *resampled = (unsigned char*)malloc( channels*MIPwidth*MIPheight ); - while( ((1< 0; --i ) - { - unsigned char temp = pixel_data[index1]; - pixel_data[index1] = pixel_data[index2]; - pixel_data[index2] = temp; - ++index1; - ++index2; - } - } - - /* save the image */ - save_result = SOIL_save_image( filename, image_type, width, height, 3, pixel_data); - - /* And free the memory */ - SOIL_free_image_data( pixel_data ); - return save_result; -} - -unsigned char* - SOIL_load_image - ( - const char *filename, - int *width, int *height, int *channels, - int force_channels - ) -{ - unsigned char *result = stbi_load( filename, - width, height, channels, force_channels ); - if( result == NULL ) - { - result_string_pointer = stbi_failure_reason(); - } else - { - result_string_pointer = "Image loaded"; - } - return result; -} - -unsigned char* - SOIL_load_image_from_memory - ( - const unsigned char *const buffer, - int buffer_length, - int *width, int *height, int *channels, - int force_channels - ) -{ - unsigned char *result = stbi_load_from_memory( - buffer, buffer_length, - width, height, channels, - force_channels ); - if( result == NULL ) - { - result_string_pointer = stbi_failure_reason(); - } else - { - result_string_pointer = "Image loaded from memory"; - } - return result; -} - -int - SOIL_save_image - ( - const char *filename, - int image_type, - int width, int height, int channels, - const unsigned char *const data - ) -{ - int save_result; - - /* error check */ - if( (width < 1) || (height < 1) || - (channels < 1) || (channels > 4) || - (data == NULL) || - (filename == NULL) ) - { - return 0; - } - if( image_type == SOIL_SAVE_TYPE_BMP ) - { - save_result = stbi_write_bmp( filename, - width, height, channels, (void*)data ); - } else - if( image_type == SOIL_SAVE_TYPE_TGA ) - { - save_result = stbi_write_tga( filename, - width, height, channels, (void*)data ); - } else - if( image_type == SOIL_SAVE_TYPE_DDS ) - { - save_result = save_image_as_DDS( filename, - width, height, channels, (const unsigned char *const)data ); - } else - { - save_result = 0; - } - if( save_result == 0 ) - { - result_string_pointer = "Saving the image failed"; - } else - { - result_string_pointer = "Image saved"; - } - return save_result; -} - -void - SOIL_free_image_data - ( - unsigned char *img_data - ) -{ - free( (void*)img_data ); -} - -const char* - SOIL_last_result - ( - void - ) -{ - return result_string_pointer; -} - -unsigned int SOIL_direct_load_DDS_from_memory( - const unsigned char *const buffer, - int buffer_length, - unsigned int reuse_texture_ID, - int flags, - int loading_as_cubemap ) -{ - /* variables */ - DDS_header header; - unsigned int buffer_index = 0; - unsigned int tex_ID = 0; - /* file reading variables */ - unsigned int S3TC_type = 0; - unsigned char *DDS_data; - unsigned int DDS_main_size; - unsigned int DDS_full_size; - unsigned int width, height; - int mipmaps, cubemap, uncompressed, block_size = 16; - unsigned int flag; - unsigned int cf_target, ogl_target_start, ogl_target_end; - unsigned int opengl_texture_type; - int i; - /* 1st off, does the filename even exist? */ - if( NULL == buffer ) - { - /* we can't do it! */ - result_string_pointer = "NULL buffer"; - return 0; - } - if( buffer_length < sizeof( DDS_header ) ) - { - /* we can't do it! */ - result_string_pointer = "DDS file was too small to contain the DDS header"; - return 0; - } - /* try reading in the header */ - memcpy ( (void*)(&header), (const void *)buffer, sizeof( DDS_header ) ); - buffer_index = sizeof( DDS_header ); - /* guilty until proven innocent */ - result_string_pointer = "Failed to read a known DDS header"; - /* validate the header (warning, "goto"'s ahead, shield your eyes!!) */ - flag = ('D'<<0)|('D'<<8)|('S'<<16)|(' '<<24); - if( header.dwMagic != flag ) {goto quick_exit;} - if( header.dwSize != 124 ) {goto quick_exit;} - /* I need all of these */ - flag = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; - if( (header.dwFlags & flag) != flag ) {goto quick_exit;} - /* According to the MSDN spec, the dwFlags should contain - DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if - uncompressed. Some DDS writers do not conform to the - spec, so I need to make my reader more tolerant */ - /* I need one of these */ - flag = DDPF_FOURCC | DDPF_RGB; - if( (header.sPixelFormat.dwFlags & flag) == 0 ) {goto quick_exit;} - if( header.sPixelFormat.dwSize != 32 ) {goto quick_exit;} - if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) {goto quick_exit;} - /* make sure it is a type we can upload */ - if( (header.sPixelFormat.dwFlags & DDPF_FOURCC) && - !( - (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24))) || - (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('3'<<24))) || - (header.sPixelFormat.dwFourCC == (('D'<<0)|('X'<<8)|('T'<<16)|('5'<<24))) - ) ) - { - goto quick_exit; - } - /* OK, validated the header, let's load the image data */ - result_string_pointer = "DDS header loaded and validated"; - width = header.dwWidth; - height = header.dwHeight; - uncompressed = 1 - (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC; - cubemap = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP; - if( uncompressed ) - { - S3TC_type = GL_RGB; - block_size = 3; - if( header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS ) - { - S3TC_type = GL_RGBA; - block_size = 4; - } - DDS_main_size = width * height * block_size; - } else - { - /* can we even handle direct uploading to OpenGL DXT compressed images? */ - if( query_DXT_capability() != SOIL_CAPABILITY_PRESENT ) - { - /* we can't do it! */ - result_string_pointer = "Direct upload of S3TC images not supported by the OpenGL driver"; - return 0; - } - /* well, we know it is DXT1/3/5, because we checked above */ - switch( (header.sPixelFormat.dwFourCC >> 24) - '0' ) - { - case 1: - S3TC_type = SOIL_RGBA_S3TC_DXT1; - block_size = 8; - break; - case 3: - S3TC_type = SOIL_RGBA_S3TC_DXT3; - block_size = 16; - break; - case 5: - S3TC_type = SOIL_RGBA_S3TC_DXT5; - block_size = 16; - break; - } - DDS_main_size = ((width+3)>>2)*((height+3)>>2)*block_size; - } - if( cubemap ) - { - /* does the user want a cubemap? */ - if( !loading_as_cubemap ) - { - /* we can't do it! */ - result_string_pointer = "DDS image was a cubemap"; - return 0; - } - /* can we even handle cubemaps with the OpenGL driver? */ - if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) - { - /* we can't do it! */ - result_string_pointer = "Direct upload of cubemap images not supported by the OpenGL driver"; - return 0; - } - ogl_target_start = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X; - ogl_target_end = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z; - opengl_texture_type = SOIL_TEXTURE_CUBE_MAP; - } else - { - /* does the user want a non-cubemap? */ - if( loading_as_cubemap ) - { - /* we can't do it! */ - result_string_pointer = "DDS image was not a cubemap"; - return 0; - } - ogl_target_start = GL_TEXTURE_2D; - ogl_target_end = GL_TEXTURE_2D; - opengl_texture_type = GL_TEXTURE_2D; - } - if( (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1) ) - { - int shift_offset; - mipmaps = header.dwMipMapCount - 1; - DDS_full_size = DDS_main_size; - if( uncompressed ) - { - /* uncompressed DDS, simple MIPmap size calculation */ - shift_offset = 0; - } else - { - /* compressed DDS, MIPmap size calculation is block based */ - shift_offset = 2; - } - for( i = 1; i <= mipmaps; ++ i ) - { - int w, h; - w = width >> (shift_offset + i); - h = height >> (shift_offset + i); - if( w < 1 ) - { - w = 1; - } - if( h < 1 ) - { - h = 1; - } - DDS_full_size += w*h*block_size; - } - } else - { - mipmaps = 0; - DDS_full_size = DDS_main_size; - } - DDS_data = (unsigned char*)malloc( DDS_full_size ); - /* got the image data RAM, create or use an existing OpenGL texture handle */ - tex_ID = reuse_texture_ID; - if( tex_ID == 0 ) - { - glGenTextures( 1, &tex_ID ); - } - /* bind an OpenGL texture ID */ - glBindTexture( opengl_texture_type, tex_ID ); - /* do this for each face of the cubemap! */ - for( cf_target = ogl_target_start; cf_target <= ogl_target_end; ++cf_target ) - { - if( buffer_index + DDS_full_size <= buffer_length ) - { - unsigned int byte_offset = DDS_main_size; - memcpy( (void*)DDS_data, (const void*)(&buffer[buffer_index]), DDS_full_size ); - buffer_index += DDS_full_size; - /* upload the main chunk */ - if( uncompressed ) - { - /* and remember, DXT uncompressed uses BGR(A), - so swap to RGB(A) for ALL MIPmap levels */ - for( i = 0; i < DDS_full_size; i += block_size ) - { - unsigned char temp = DDS_data[i]; - DDS_data[i] = DDS_data[i+2]; - DDS_data[i+2] = temp; - } - glTexImage2D( - cf_target, 0, - S3TC_type, width, height, 0, - S3TC_type, GL_UNSIGNED_BYTE, DDS_data ); - } else - { - soilGlCompressedTexImage2D( - cf_target, 0, - S3TC_type, width, height, 0, - DDS_main_size, DDS_data ); - } - /* upload the mipmaps, if we have them */ - for( i = 1; i <= mipmaps; ++i ) - { - int w, h, mip_size; - w = width >> i; - h = height >> i; - if( w < 1 ) - { - w = 1; - } - if( h < 1 ) - { - h = 1; - } - /* upload this mipmap */ - if( uncompressed ) - { - mip_size = w*h*block_size; - glTexImage2D( - cf_target, i, - S3TC_type, w, h, 0, - S3TC_type, GL_UNSIGNED_BYTE, &DDS_data[byte_offset] ); - } else - { - mip_size = ((w+3)/4)*((h+3)/4)*block_size; - soilGlCompressedTexImage2D( - cf_target, i, - S3TC_type, w, h, 0, - mip_size, &DDS_data[byte_offset] ); - } - /* and move to the next mipmap */ - byte_offset += mip_size; - } - /* it worked! */ - result_string_pointer = "DDS file loaded"; - } else - { - glDeleteTextures( 1, & tex_ID ); - tex_ID = 0; - cf_target = ogl_target_end + 1; - result_string_pointer = "DDS file was too small for expected image data"; - } - }/* end reading each face */ - SOIL_free_image_data( DDS_data ); - if( tex_ID ) - { - /* did I have MIPmaps? */ - if( mipmaps > 0 ) - { - /* instruct OpenGL to use the MIPmaps */ - glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - } else - { - /* instruct OpenGL _NOT_ to use the MIPmaps */ - glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - } - /* does the user want clamping, or wrapping? */ - if( flags & SOIL_FLAG_TEXTURE_REPEATS ) - { - glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT ); - glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT ); - glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT ); - } else - { - /* unsigned int clamp_mode = SOIL_CLAMP_TO_EDGE; */ - unsigned int clamp_mode = GL_CLAMP; - glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode ); - glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode ); - glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode ); - } - } - -quick_exit: - /* report success or failure */ - return tex_ID; -} - -unsigned int SOIL_direct_load_DDS( - const char *filename, - unsigned int reuse_texture_ID, - int flags, - int loading_as_cubemap ) -{ - FILE *f; - unsigned char *buffer; - size_t buffer_length, bytes_read; - unsigned int tex_ID = 0; - /* error checks */ - if( NULL == filename ) - { - result_string_pointer = "NULL filename"; - return 0; - } - f = fopen( filename, "rb" ); - if( NULL == f ) - { - /* the file doesn't seem to exist (or be open-able) */ - result_string_pointer = "Can not find DDS file"; - return 0; - } - fseek( f, 0, SEEK_END ); - buffer_length = ftell( f ); - fseek( f, 0, SEEK_SET ); - buffer = (unsigned char *) malloc( buffer_length ); - if( NULL == buffer ) - { - result_string_pointer = "malloc failed"; - fclose( f ); - return 0; - } - bytes_read = fread( (void*)buffer, 1, buffer_length, f ); - fclose( f ); - if( bytes_read < buffer_length ) - { - /* huh? */ - buffer_length = bytes_read; - } - /* now try to do the loading */ - tex_ID = SOIL_direct_load_DDS_from_memory( - (const unsigned char *const)buffer, buffer_length, - reuse_texture_ID, flags, loading_as_cubemap ); - SOIL_free_image_data( buffer ); - return tex_ID; -} - -int query_NPOT_capability( void ) -{ - /* check for the capability */ - if( has_NPOT_capability == SOIL_CAPABILITY_UNKNOWN ) - { - /* we haven't yet checked for the capability, do so */ - if( - (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ), - "GL_ARB_texture_non_power_of_two" ) ) - ) - { - /* not there, flag the failure */ - has_NPOT_capability = SOIL_CAPABILITY_NONE; - } else - { - /* it's there! */ - has_NPOT_capability = SOIL_CAPABILITY_PRESENT; - } - } - /* let the user know if we can do non-power-of-two textures or not */ - return has_NPOT_capability; -} - -int query_tex_rectangle_capability( void ) -{ - /* check for the capability */ - if( has_tex_rectangle_capability == SOIL_CAPABILITY_UNKNOWN ) - { - /* we haven't yet checked for the capability, do so */ - if( - (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ), - "GL_ARB_texture_rectangle" ) ) - && - (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ), - "GL_EXT_texture_rectangle" ) ) - && - (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ), - "GL_NV_texture_rectangle" ) ) - ) - { - /* not there, flag the failure */ - has_tex_rectangle_capability = SOIL_CAPABILITY_NONE; - } else - { - /* it's there! */ - has_tex_rectangle_capability = SOIL_CAPABILITY_PRESENT; - } - } - /* let the user know if we can do texture rectangles or not */ - return has_tex_rectangle_capability; -} - -int query_cubemap_capability( void ) -{ - /* check for the capability */ - if( has_cubemap_capability == SOIL_CAPABILITY_UNKNOWN ) - { - /* we haven't yet checked for the capability, do so */ - if( - (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ), - "GL_ARB_texture_cube_map" ) ) - && - (NULL == strstr( (char const*)glGetString( GL_EXTENSIONS ), - "GL_EXT_texture_cube_map" ) ) - ) - { - /* not there, flag the failure */ - has_cubemap_capability = SOIL_CAPABILITY_NONE; - } else - { - /* it's there! */ - has_cubemap_capability = SOIL_CAPABILITY_PRESENT; - } - } - /* let the user know if we can do cubemaps or not */ - return has_cubemap_capability; -} - -int query_DXT_capability( void ) -{ - /* check for the capability */ - if( has_DXT_capability == SOIL_CAPABILITY_UNKNOWN ) - { - /* we haven't yet checked for the capability, do so */ - if( NULL == strstr( - (char const*)glGetString( GL_EXTENSIONS ), - "GL_EXT_texture_compression_s3tc" ) ) - { - /* not there, flag the failure */ - has_DXT_capability = SOIL_CAPABILITY_NONE; - } else - { - /* and find the address of the extension function */ - P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = NULL; - #ifdef WIN32 - ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC) - wglGetProcAddress - ( - "glCompressedTexImage2DARB" - ); - #elif defined(__APPLE__) || defined(__APPLE_CC__) - /* I can't test this Apple stuff! */ - CFBundleRef bundle; - CFURLRef bundleURL = - CFURLCreateWithFileSystemPath( - kCFAllocatorDefault, - CFSTR("/System/Library/Frameworks/OpenGL.framework"), - kCFURLPOSIXPathStyle, - true ); - CFStringRef extensionName = - CFStringCreateWithCString( - kCFAllocatorDefault, - "glCompressedTexImage2DARB", - kCFStringEncodingASCII ); - bundle = CFBundleCreate( kCFAllocatorDefault, bundleURL ); - assert( bundle != NULL ); - ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC) - CFBundleGetFunctionPointerForName - ( - bundle, extensionName - ); - CFRelease( bundleURL ); - CFRelease( extensionName ); - CFRelease( bundle ); - #else - ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC) - glXGetProcAddressARB - ( - (const GLubyte *)"glCompressedTexImage2DARB" - ); - #endif - /* Flag it so no checks needed later */ - if( NULL == ext_addr ) - { - /* hmm, not good!! This should not happen, but does on my - laptop's VIA chipset. The GL_EXT_texture_compression_s3tc - spec requires that ARB_texture_compression be present too. - this means I can upload and have the OpenGL drive do the - conversion, but I can't use my own routines or load DDS files - from disk and upload them directly [8^( */ - has_DXT_capability = SOIL_CAPABILITY_NONE; - } else - { - /* all's well! */ - soilGlCompressedTexImage2D = ext_addr; - has_DXT_capability = SOIL_CAPABILITY_PRESENT; - } - } - } - /* let the user know if we can do DXT or not */ - return has_DXT_capability; -} diff --git a/ext/SOIL/src/image_DXT.c b/ext/SOIL/src/image_DXT.c deleted file mode 100644 index 4206a1bb..00000000 --- a/ext/SOIL/src/image_DXT.c +++ /dev/null @@ -1,632 +0,0 @@ -/* - Jonathan Dummer - 2007-07-31-10.32 - - simple DXT compression / decompression code - - public domain -*/ - -#include "image_DXT.h" -#include -#include -#include -#include - -/* set this =1 if you want to use the covarince matrix method... - which is better than my method of using standard deviations - overall, except on the infintesimal chance that the power - method fails for finding the largest eigenvector */ -#define USE_COV_MAT 1 - -/********* Function Prototypes *********/ -/* - Takes a 4x4 block of pixels and compresses it into 8 bytes - in DXT1 format (color only, no alpha). Speed is valued - over prettyness, at least for now. -*/ -void compress_DDS_color_block( - int channels, - const unsigned char *const uncompressed, - unsigned char compressed[8] ); -/* - Takes a 4x4 block of pixels and compresses the alpha - component it into 8 bytes for use in DXT5 DDS files. - Speed is valued over prettyness, at least for now. -*/ -void compress_DDS_alpha_block( - const unsigned char *const uncompressed, - unsigned char compressed[8] ); - -/********* Actual Exposed Functions *********/ -int - save_image_as_DDS - ( - const char *filename, - int width, int height, int channels, - const unsigned char *const data - ) -{ - /* variables */ - FILE *fout; - unsigned char *DDS_data; - DDS_header header; - int DDS_size; - /* error check */ - if( (NULL == filename) || - (width < 1) || (height < 1) || - (channels < 1) || (channels > 4) || - (data == NULL ) ) - { - return 0; - } - /* Convert the image */ - if( (channels & 1) == 1 ) - { - /* no alpha, just use DXT1 */ - DDS_data = convert_image_to_DXT1( data, width, height, channels, &DDS_size ); - } else - { - /* has alpha, so use DXT5 */ - DDS_data = convert_image_to_DXT5( data, width, height, channels, &DDS_size ); - } - /* save it */ - memset( &header, 0, sizeof( DDS_header ) ); - header.dwMagic = ('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24); - header.dwSize = 124; - header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_LINEARSIZE; - header.dwWidth = width; - header.dwHeight = height; - header.dwPitchOrLinearSize = DDS_size; - header.sPixelFormat.dwSize = 32; - header.sPixelFormat.dwFlags = DDPF_FOURCC; - if( (channels & 1) == 1 ) - { - header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('1' << 24); - } else - { - header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('5' << 24); - } - header.sCaps.dwCaps1 = DDSCAPS_TEXTURE; - /* write it out */ - fout = fopen( filename, "wb"); - fwrite( &header, sizeof( DDS_header ), 1, fout ); - fwrite( DDS_data, 1, DDS_size, fout ); - fclose( fout ); - /* done */ - free( DDS_data ); - return 1; -} - -unsigned char* convert_image_to_DXT1( - const unsigned char *const uncompressed, - int width, int height, int channels, - int *out_size ) -{ - unsigned char *compressed; - int i, j, x, y; - unsigned char ublock[16*3]; - unsigned char cblock[8]; - int index = 0, chan_step = 1; - int block_count = 0; - /* error check */ - *out_size = 0; - if( (width < 1) || (height < 1) || - (NULL == uncompressed) || - (channels < 1) || (channels > 4) ) - { - return NULL; - } - /* for channels == 1 or 2, I do not step forward for R,G,B values */ - if( channels < 3 ) - { - chan_step = 0; - } - /* get the RAM for the compressed image - (8 bytes per 4x4 pixel block) */ - *out_size = ((width+3) >> 2) * ((height+3) >> 2) * 8; - compressed = (unsigned char*)malloc( *out_size ); - /* go through each block */ - for( j = 0; j < height; j += 4 ) - { - for( i = 0; i < width; i += 4 ) - { - /* copy this block into a new one */ - int idx = 0; - int mx = 4, my = 4; - if( j+4 >= height ) - { - my = height - j; - } - if( i+4 >= width ) - { - mx = width - i; - } - for( y = 0; y < my; ++y ) - { - for( x = 0; x < mx; ++x ) - { - ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels]; - ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step]; - ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step]; - } - for( x = mx; x < 4; ++x ) - { - ublock[idx++] = ublock[0]; - ublock[idx++] = ublock[1]; - ublock[idx++] = ublock[2]; - } - } - for( y = my; y < 4; ++y ) - { - for( x = 0; x < 4; ++x ) - { - ublock[idx++] = ublock[0]; - ublock[idx++] = ublock[1]; - ublock[idx++] = ublock[2]; - } - } - /* compress the block */ - ++block_count; - compress_DDS_color_block( 3, ublock, cblock ); - /* copy the data from the block into the main block */ - for( x = 0; x < 8; ++x ) - { - compressed[index++] = cblock[x]; - } - } - } - return compressed; -} - -unsigned char* convert_image_to_DXT5( - const unsigned char *const uncompressed, - int width, int height, int channels, - int *out_size ) -{ - unsigned char *compressed; - int i, j, x, y; - unsigned char ublock[16*4]; - unsigned char cblock[8]; - int index = 0, chan_step = 1; - int block_count = 0, has_alpha; - /* error check */ - *out_size = 0; - if( (width < 1) || (height < 1) || - (NULL == uncompressed) || - (channels < 1) || ( channels > 4) ) - { - return NULL; - } - /* for channels == 1 or 2, I do not step forward for R,G,B vales */ - if( channels < 3 ) - { - chan_step = 0; - } - /* # channels = 1 or 3 have no alpha, 2 & 4 do have alpha */ - has_alpha = 1 - (channels & 1); - /* get the RAM for the compressed image - (16 bytes per 4x4 pixel block) */ - *out_size = ((width+3) >> 2) * ((height+3) >> 2) * 16; - compressed = (unsigned char*)malloc( *out_size ); - /* go through each block */ - for( j = 0; j < height; j += 4 ) - { - for( i = 0; i < width; i += 4 ) - { - /* local variables, and my block counter */ - int idx = 0; - int mx = 4, my = 4; - if( j+4 >= height ) - { - my = height - j; - } - if( i+4 >= width ) - { - mx = width - i; - } - for( y = 0; y < my; ++y ) - { - for( x = 0; x < mx; ++x ) - { - ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels]; - ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step]; - ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step]; - ublock[idx++] = - has_alpha * uncompressed[(j+y)*width*channels+(i+x)*channels+channels-1] - + (1-has_alpha)*255; - } - for( x = mx; x < 4; ++x ) - { - ublock[idx++] = ublock[0]; - ublock[idx++] = ublock[1]; - ublock[idx++] = ublock[2]; - ublock[idx++] = ublock[3]; - } - } - for( y = my; y < 4; ++y ) - { - for( x = 0; x < 4; ++x ) - { - ublock[idx++] = ublock[0]; - ublock[idx++] = ublock[1]; - ublock[idx++] = ublock[2]; - ublock[idx++] = ublock[3]; - } - } - /* now compress the alpha block */ - compress_DDS_alpha_block( ublock, cblock ); - /* copy the data from the compressed alpha block into the main buffer */ - for( x = 0; x < 8; ++x ) - { - compressed[index++] = cblock[x]; - } - /* then compress the color block */ - ++block_count; - compress_DDS_color_block( 4, ublock, cblock ); - /* copy the data from the compressed color block into the main buffer */ - for( x = 0; x < 8; ++x ) - { - compressed[index++] = cblock[x]; - } - } - } - return compressed; -} - -/********* Helper Functions *********/ -int convert_bit_range( int c, int from_bits, int to_bits ) -{ - int b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1); - return (b + (b >> from_bits)) >> from_bits; -} - -int rgb_to_565( int r, int g, int b ) -{ - return - (convert_bit_range( r, 8, 5 ) << 11) | - (convert_bit_range( g, 8, 6 ) << 05) | - (convert_bit_range( b, 8, 5 ) << 00); -} - -void rgb_888_from_565( unsigned int c, int *r, int *g, int *b ) -{ - *r = convert_bit_range( (c >> 11) & 31, 5, 8 ); - *g = convert_bit_range( (c >> 05) & 63, 6, 8 ); - *b = convert_bit_range( (c >> 00) & 31, 5, 8 ); -} - -void compute_color_line_STDEV( - const unsigned char *const uncompressed, - int channels, - float point[3], float direction[3] ) -{ - const float inv_16 = 1.0f / 16.0f; - int i; - float sum_r = 0.0f, sum_g = 0.0f, sum_b = 0.0f; - float sum_rr = 0.0f, sum_gg = 0.0f, sum_bb = 0.0f; - float sum_rg = 0.0f, sum_rb = 0.0f, sum_gb = 0.0f; - /* calculate all data needed for the covariance matrix - ( to compare with _rygdxt code) */ - for( i = 0; i < 16*channels; i += channels ) - { - sum_r += uncompressed[i+0]; - sum_rr += uncompressed[i+0] * uncompressed[i+0]; - sum_g += uncompressed[i+1]; - sum_gg += uncompressed[i+1] * uncompressed[i+1]; - sum_b += uncompressed[i+2]; - sum_bb += uncompressed[i+2] * uncompressed[i+2]; - sum_rg += uncompressed[i+0] * uncompressed[i+1]; - sum_rb += uncompressed[i+0] * uncompressed[i+2]; - sum_gb += uncompressed[i+1] * uncompressed[i+2]; - } - /* convert the sums to averages */ - sum_r *= inv_16; - sum_g *= inv_16; - sum_b *= inv_16; - /* and convert the squares to the squares of the value - avg_value */ - sum_rr -= 16.0f * sum_r * sum_r; - sum_gg -= 16.0f * sum_g * sum_g; - sum_bb -= 16.0f * sum_b * sum_b; - sum_rg -= 16.0f * sum_r * sum_g; - sum_rb -= 16.0f * sum_r * sum_b; - sum_gb -= 16.0f * sum_g * sum_b; - /* the point on the color line is the average */ - point[0] = sum_r; - point[1] = sum_g; - point[2] = sum_b; - #if USE_COV_MAT - /* - The following idea was from ryg. - (https://mollyrocket.com/forums/viewtopic.php?t=392) - The method worked great (less RMSE than mine) most of - the time, but had some issues handling some simple - boundary cases, like full green next to full red, - which would generate a covariance matrix like this: - - | 1 -1 0 | - | -1 1 0 | - | 0 0 0 | - - For a given starting vector, the power method can - generate all zeros! So no starting with {1,1,1} - as I was doing! This kind of error is still a - slight posibillity, but will be very rare. - */ - /* use the covariance matrix directly - (1st iteration, don't use all 1.0 values!) */ - sum_r = 1.0f; - sum_g = 2.718281828f; - sum_b = 3.141592654f; - direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; - direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; - direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; - /* 2nd iteration, use results from the 1st guy */ - sum_r = direction[0]; - sum_g = direction[1]; - sum_b = direction[2]; - direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; - direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; - direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; - /* 3rd iteration, use results from the 2nd guy */ - sum_r = direction[0]; - sum_g = direction[1]; - sum_b = direction[2]; - direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; - direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; - direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; - #else - /* use my standard deviation method - (very robust, a tiny bit slower and less accurate) */ - direction[0] = sqrt( sum_rr ); - direction[1] = sqrt( sum_gg ); - direction[2] = sqrt( sum_bb ); - /* which has a greater component */ - if( sum_gg > sum_rr ) - { - /* green has greater component, so base the other signs off of green */ - if( sum_rg < 0.0f ) - { - direction[0] = -direction[0]; - } - if( sum_gb < 0.0f ) - { - direction[2] = -direction[2]; - } - } else - { - /* red has a greater component */ - if( sum_rg < 0.0f ) - { - direction[1] = -direction[1]; - } - if( sum_rb < 0.0f ) - { - direction[2] = -direction[2]; - } - } - #endif -} - -void LSE_master_colors_max_min( - int *cmax, int *cmin, - int channels, - const unsigned char *const uncompressed ) -{ - int i, j; - /* the master colors */ - int c0[3], c1[3]; - /* used for fitting the line */ - float sum_x[] = { 0.0f, 0.0f, 0.0f }; - float sum_x2[] = { 0.0f, 0.0f, 0.0f }; - float dot_max = 1.0f, dot_min = -1.0f; - float vec_len2 = 0.0f; - float dot; - /* error check */ - if( (channels < 3) || (channels > 4) ) - { - return; - } - compute_color_line_STDEV( uncompressed, channels, sum_x, sum_x2 ); - vec_len2 = 1.0f / ( 0.00001f + - sum_x2[0]*sum_x2[0] + sum_x2[1]*sum_x2[1] + sum_x2[2]*sum_x2[2] ); - /* finding the max and min vector values */ - dot_max = - ( - sum_x2[0] * uncompressed[0] + - sum_x2[1] * uncompressed[1] + - sum_x2[2] * uncompressed[2] - ); - dot_min = dot_max; - for( i = 1; i < 16; ++i ) - { - dot = - ( - sum_x2[0] * uncompressed[i*channels+0] + - sum_x2[1] * uncompressed[i*channels+1] + - sum_x2[2] * uncompressed[i*channels+2] - ); - if( dot < dot_min ) - { - dot_min = dot; - } else if( dot > dot_max ) - { - dot_max = dot; - } - } - /* and the offset (from the average location) */ - dot = sum_x2[0]*sum_x[0] + sum_x2[1]*sum_x[1] + sum_x2[2]*sum_x[2]; - dot_min -= dot; - dot_max -= dot; - /* post multiply by the scaling factor */ - dot_min *= vec_len2; - dot_max *= vec_len2; - /* OK, build the master colors */ - for( i = 0; i < 3; ++i ) - { - /* color 0 */ - c0[i] = (int)(0.5f + sum_x[i] + dot_max * sum_x2[i]); - if( c0[i] < 0 ) - { - c0[i] = 0; - } else if( c0[i] > 255 ) - { - c0[i] = 255; - } - /* color 1 */ - c1[i] = (int)(0.5f + sum_x[i] + dot_min * sum_x2[i]); - if( c1[i] < 0 ) - { - c1[i] = 0; - } else if( c1[i] > 255 ) - { - c1[i] = 255; - } - } - /* down_sample (with rounding?) */ - i = rgb_to_565( c0[0], c0[1], c0[2] ); - j = rgb_to_565( c1[0], c1[1], c1[2] ); - if( i > j ) - { - *cmax = i; - *cmin = j; - } else - { - *cmax = j; - *cmin = i; - } -} - -void - compress_DDS_color_block - ( - int channels, - const unsigned char *const uncompressed, - unsigned char compressed[8] - ) -{ - /* variables */ - int i; - int next_bit; - int enc_c0, enc_c1; - int c0[4], c1[4]; - float color_line[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - float vec_len2 = 0.0f, dot_offset = 0.0f; - /* stupid order */ - int swizzle4[] = { 0, 2, 3, 1 }; - /* get the master colors */ - LSE_master_colors_max_min( &enc_c0, &enc_c1, channels, uncompressed ); - /* store the 565 color 0 and color 1 */ - compressed[0] = (enc_c0 >> 0) & 255; - compressed[1] = (enc_c0 >> 8) & 255; - compressed[2] = (enc_c1 >> 0) & 255; - compressed[3] = (enc_c1 >> 8) & 255; - /* zero out the compressed data */ - compressed[4] = 0; - compressed[5] = 0; - compressed[6] = 0; - compressed[7] = 0; - /* reconstitute the master color vectors */ - rgb_888_from_565( enc_c0, &c0[0], &c0[1], &c0[2] ); - rgb_888_from_565( enc_c1, &c1[0], &c1[1], &c1[2] ); - /* the new vector */ - vec_len2 = 0.0f; - for( i = 0; i < 3; ++i ) - { - color_line[i] = (float)(c1[i] - c0[i]); - vec_len2 += color_line[i] * color_line[i]; - } - if( vec_len2 > 0.0f ) - { - vec_len2 = 1.0f / vec_len2; - } - /* pre-proform the scaling */ - color_line[0] *= vec_len2; - color_line[1] *= vec_len2; - color_line[2] *= vec_len2; - /* compute the offset (constant) portion of the dot product */ - dot_offset = color_line[0]*c0[0] + color_line[1]*c0[1] + color_line[2]*c0[2]; - /* store the rest of the bits */ - next_bit = 8*4; - for( i = 0; i < 16; ++i ) - { - /* find the dot product of this color, to place it on the line - (should be [-1,1]) */ - int next_value = 0; - float dot_product = - color_line[0] * uncompressed[i*channels+0] + - color_line[1] * uncompressed[i*channels+1] + - color_line[2] * uncompressed[i*channels+2] - - dot_offset; - /* map to [0,3] */ - next_value = (int)( dot_product * 3.0f + 0.5f ); - if( next_value > 3 ) - { - next_value = 3; - } else if( next_value < 0 ) - { - next_value = 0; - } - /* OK, store this value */ - compressed[next_bit >> 3] |= swizzle4[ next_value ] << (next_bit & 7); - next_bit += 2; - } - /* done compressing to DXT1 */ -} - -void - compress_DDS_alpha_block - ( - const unsigned char *const uncompressed, - unsigned char compressed[8] - ) -{ - /* variables */ - int i; - int next_bit; - int a0, a1; - float scale_me; - /* stupid order */ - int swizzle8[] = { 1, 7, 6, 5, 4, 3, 2, 0 }; - /* get the alpha limits (a0 > a1) */ - a0 = a1 = uncompressed[3]; - for( i = 4+3; i < 16*4; i += 4 ) - { - if( uncompressed[i] > a0 ) - { - a0 = uncompressed[i]; - } else if( uncompressed[i] < a1 ) - { - a1 = uncompressed[i]; - } - } - /* store those limits, and zero the rest of the compressed dataset */ - compressed[0] = a0; - compressed[1] = a1; - /* zero out the compressed data */ - compressed[2] = 0; - compressed[3] = 0; - compressed[4] = 0; - compressed[5] = 0; - compressed[6] = 0; - compressed[7] = 0; - /* store the all of the alpha values */ - next_bit = 8*2; - scale_me = 7.9999f / (a0 - a1); - for( i = 3; i < 16*4; i += 4 ) - { - /* convert this alpha value to a 3 bit number */ - int svalue; - int value = (int)((uncompressed[i] - a1) * scale_me); - svalue = swizzle8[ value&7 ]; - /* OK, store this value, start with the 1st byte */ - compressed[next_bit >> 3] |= svalue << (next_bit & 7); - if( (next_bit & 7) > 5 ) - { - /* spans 2 bytes, fill in the start of the 2nd byte */ - compressed[1 + (next_bit >> 3)] |= svalue >> (8 - (next_bit & 7) ); - } - next_bit += 3; - } - /* done compressing to DXT1 */ -} diff --git a/ext/SOIL/src/image_helper.c b/ext/SOIL/src/image_helper.c deleted file mode 100644 index d22340f4..00000000 --- a/ext/SOIL/src/image_helper.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - Jonathan Dummer - - image helper functions - - MIT license -*/ - -#include "image_helper.h" -#include -#include - -/* Upscaling the image uses simple bilinear interpolation */ -int - up_scale_image - ( - const unsigned char* const orig, - int width, int height, int channels, - unsigned char* resampled, - int resampled_width, int resampled_height - ) -{ - float dx, dy; - int x, y, c; - - /* error(s) check */ - if ( (width < 1) || (height < 1) || - (resampled_width < 2) || (resampled_height < 2) || - (channels < 1) || - (NULL == orig) || (NULL == resampled) ) - { - /* signify badness */ - return 0; - } - /* - for each given pixel in the new map, find the exact location - from the original map which would contribute to this guy - */ - dx = (width - 1.0f) / (resampled_width - 1.0f); - dy = (height - 1.0f) / (resampled_height - 1.0f); - for ( y = 0; y < resampled_height; ++y ) - { - /* find the base y index and fractional offset from that */ - float sampley = y * dy; - int inty = (int)sampley; - /* if( inty < 0 ) { inty = 0; } else */ - if( inty > height - 2 ) { inty = height - 2; } - sampley -= inty; - for ( x = 0; x < resampled_width; ++x ) - { - float samplex = x * dx; - int intx = (int)samplex; - int base_index; - /* find the base x index and fractional offset from that */ - /* if( intx < 0 ) { intx = 0; } else */ - if( intx > width - 2 ) { intx = width - 2; } - samplex -= intx; - /* base index into the original image */ - base_index = (inty * width + intx) * channels; - for ( c = 0; c < channels; ++c ) - { - /* do the sampling */ - float value = 0.5f; - value += orig[base_index] - *(1.0f-samplex)*(1.0f-sampley); - value += orig[base_index+channels] - *(samplex)*(1.0f-sampley); - value += orig[base_index+width*channels] - *(1.0f-samplex)*(sampley); - value += orig[base_index+width*channels+channels] - *(samplex)*(sampley); - /* move to the next channel */ - ++base_index; - /* save the new value */ - resampled[y*resampled_width*channels+x*channels+c] = - (unsigned char)(value); - } - } - } - /* done */ - return 1; -} - -int - mipmap_image - ( - const unsigned char* const orig, - int width, int height, int channels, - unsigned char* resampled, - int block_size_x, int block_size_y - ) -{ - int mip_width, mip_height; - int i, j, c; - - /* error check */ - if( (width < 1) || (height < 1) || - (channels < 1) || (orig == NULL) || - (resampled == NULL) || - (block_size_x < 1) || (block_size_y < 1) ) - { - /* nothing to do */ - return 0; - } - mip_width = width / block_size_x; - mip_height = height / block_size_y; - if( mip_width < 1 ) - { - mip_width = 1; - } - if( mip_height < 1 ) - { - mip_height = 1; - } - for( j = 0; j < mip_height; ++j ) - { - for( i = 0; i < mip_width; ++i ) - { - for( c = 0; c < channels; ++c ) - { - const int index = (j*block_size_y)*width*channels + (i*block_size_x)*channels + c; - int sum_value; - int u,v; - int u_block = block_size_x; - int v_block = block_size_y; - int block_area; - /* do a bit of checking so we don't over-run the boundaries - (necessary for non-square textures!) */ - if( block_size_x * (i+1) > width ) - { - u_block = width - i*block_size_y; - } - if( block_size_y * (j+1) > height ) - { - v_block = height - j*block_size_y; - } - block_area = u_block*v_block; - /* for this pixel, see what the average - of all the values in the block are. - note: start the sum at the rounding value, not at 0 */ - sum_value = block_area >> 1; - for( v = 0; v < v_block; ++v ) - for( u = 0; u < u_block; ++u ) - { - sum_value += orig[index + v*width*channels + u*channels]; - } - resampled[j*mip_width*channels + i*channels + c] = sum_value / block_area; - } - } - } - return 1; -} - -int - scale_image_RGB_to_NTSC_safe - ( - unsigned char* orig, - int width, int height, int channels - ) -{ - const float scale_lo = 16.0f - 0.499f; - const float scale_hi = 235.0f + 0.499f; - int i, j; - int nc = channels; - unsigned char scale_LUT[256]; - /* error check */ - if( (width < 1) || (height < 1) || - (channels < 1) || (orig == NULL) ) - { - /* nothing to do */ - return 0; - } - /* set up the scaling Look Up Table */ - for( i = 0; i < 256; ++i ) - { - scale_LUT[i] = (unsigned char)((scale_hi - scale_lo) * i / 255.0f + scale_lo); - } - /* for channels = 2 or 4, ignore the alpha component */ - nc -= 1 - (channels & 1); - /* OK, go through the image and scale any non-alpha components */ - for( i = 0; i < width*height*channels; i += channels ) - { - for( j = 0; j < nc; ++j ) - { - orig[i+j] = scale_LUT[orig[i+j]]; - } - } - return 1; -} - -unsigned char clamp_byte( int x ) { return ( (x) < 0 ? (0) : ( (x) > 255 ? 255 : (x) ) ); } - -/* - This function takes the RGB components of the image - and converts them into YCoCg. 3 components will be - re-ordered to CoYCg (for optimum DXT1 compression), - while 4 components will be ordered CoCgAY (for DXT5 - compression). -*/ -int - convert_RGB_to_YCoCg - ( - unsigned char* orig, - int width, int height, int channels - ) -{ - int i; - /* error check */ - if( (width < 1) || (height < 1) || - (channels < 3) || (channels > 4) || - (orig == NULL) ) - { - /* nothing to do */ - return -1; - } - /* do the conversion */ - if( channels == 3 ) - { - for( i = 0; i < width*height*3; i += 3 ) - { - int r = orig[i+0]; - int g = (orig[i+1] + 1) >> 1; - int b = orig[i+2]; - int tmp = (2 + r + b) >> 2; - /* Co */ - orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) ); - /* Y */ - orig[i+1] = clamp_byte( g + tmp ); - /* Cg */ - orig[i+2] = clamp_byte( 128 + g - tmp ); - } - } else - { - for( i = 0; i < width*height*4; i += 4 ) - { - int r = orig[i+0]; - int g = (orig[i+1] + 1) >> 1; - int b = orig[i+2]; - unsigned char a = orig[i+3]; - int tmp = (2 + r + b) >> 2; - /* Co */ - orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) ); - /* Cg */ - orig[i+1] = clamp_byte( 128 + g - tmp ); - /* Alpha */ - orig[i+2] = a; - /* Y */ - orig[i+3] = clamp_byte( g + tmp ); - } - } - /* done */ - return 0; -} - -/* - This function takes the YCoCg components of the image - and converts them into RGB. See above. -*/ -int - convert_YCoCg_to_RGB - ( - unsigned char* orig, - int width, int height, int channels - ) -{ - int i; - /* error check */ - if( (width < 1) || (height < 1) || - (channels < 3) || (channels > 4) || - (orig == NULL) ) - { - /* nothing to do */ - return -1; - } - /* do the conversion */ - if( channels == 3 ) - { - for( i = 0; i < width*height*3; i += 3 ) - { - int co = orig[i+0] - 128; - int y = orig[i+1]; - int cg = orig[i+2] - 128; - /* R */ - orig[i+0] = clamp_byte( y + co - cg ); - /* G */ - orig[i+1] = clamp_byte( y + cg ); - /* B */ - orig[i+2] = clamp_byte( y - co - cg ); - } - } else - { - for( i = 0; i < width*height*4; i += 4 ) - { - int co = orig[i+0] - 128; - int cg = orig[i+1] - 128; - unsigned char a = orig[i+2]; - int y = orig[i+3]; - /* R */ - orig[i+0] = clamp_byte( y + co - cg ); - /* G */ - orig[i+1] = clamp_byte( y + cg ); - /* B */ - orig[i+2] = clamp_byte( y - co - cg ); - /* A */ - orig[i+3] = a; - } - } - /* done */ - return 0; -} - -float -find_max_RGBE -( - unsigned char *image, - int width, int height -) -{ - float max_val = 0.0f; - unsigned char *img = image; - int i, j; - for( i = width * height; i > 0; --i ) - { - /* float scale = powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ - float scale = ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); - for( j = 0; j < 3; ++j ) - { - if( img[j] * scale > max_val ) - { - max_val = img[j] * scale; - } - } - /* next pixel */ - img += 4; - } - return max_val; -} - -int -RGBE_to_RGBdivA -( - unsigned char *image, - int width, int height, - int rescale_to_max -) -{ - /* local variables */ - int i, iv; - unsigned char *img = image; - float scale = 1.0f; - /* error check */ - if( (!image) || (width < 1) || (height < 1) ) - { - return 0; - } - /* convert (note: no negative numbers, but 0.0 is possible) */ - if( rescale_to_max ) - { - scale = 255.0f / find_max_RGBE( image, width, height ); - } - for( i = width * height; i > 0; --i ) - { - /* decode this pixel, and find the max */ - float r,g,b,e, m; - /* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ - e = scale * ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); - r = e * img[0]; - g = e * img[1]; - b = e * img[2]; - m = (r > g) ? r : g; - m = (b > m) ? b : m; - /* and encode it into RGBdivA */ - iv = (m != 0.0f) ? (int)(255.0f / m) : 1.0f; - iv = (iv < 1) ? 1 : iv; - img[3] = (iv > 255) ? 255 : iv; - iv = (int)(img[3] * r + 0.5f); - img[0] = (iv > 255) ? 255 : iv; - iv = (int)(img[3] * g + 0.5f); - img[1] = (iv > 255) ? 255 : iv; - iv = (int)(img[3] * b + 0.5f); - img[2] = (iv > 255) ? 255 : iv; - /* and on to the next pixel */ - img += 4; - } - return 1; -} - -int -RGBE_to_RGBdivA2 -( - unsigned char *image, - int width, int height, - int rescale_to_max -) -{ - /* local variables */ - int i, iv; - unsigned char *img = image; - float scale = 1.0f; - /* error check */ - if( (!image) || (width < 1) || (height < 1) ) - { - return 0; - } - /* convert (note: no negative numbers, but 0.0 is possible) */ - if( rescale_to_max ) - { - scale = 255.0f * 255.0f / find_max_RGBE( image, width, height ); - } - for( i = width * height; i > 0; --i ) - { - /* decode this pixel, and find the max */ - float r,g,b,e, m; - /* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ - e = scale * ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); - r = e * img[0]; - g = e * img[1]; - b = e * img[2]; - m = (r > g) ? r : g; - m = (b > m) ? b : m; - /* and encode it into RGBdivA */ - iv = (m != 0.0f) ? (int)sqrtf( 255.0f * 255.0f / m ) : 1.0f; - iv = (iv < 1) ? 1 : iv; - img[3] = (iv > 255) ? 255 : iv; - iv = (int)(img[3] * img[3] * r / 255.0f + 0.5f); - img[0] = (iv > 255) ? 255 : iv; - iv = (int)(img[3] * img[3] * g / 255.0f + 0.5f); - img[1] = (iv > 255) ? 255 : iv; - iv = (int)(img[3] * img[3] * b / 255.0f + 0.5f); - img[2] = (iv > 255) ? 255 : iv; - /* and on to the next pixel */ - img += 4; - } - return 1; -} diff --git a/ext/bgfx b/ext/bgfx new file mode 160000 index 00000000..018bbc4e --- /dev/null +++ b/ext/bgfx @@ -0,0 +1 @@ +Subproject commit 018bbc4e9f14724ec93904efd61ae8d46dd7f804 diff --git a/ext/cgltf.h b/ext/cgltf.h index f18585c0..1032b841 100644 --- a/ext/cgltf.h +++ b/ext/cgltf.h @@ -1,7 +1,7 @@ /** * cgltf - a single-file glTF 2.0 parser written in C99. * - * Version: 1.0 + * Version: 1.1 * * Website: https://github.com/jkuhlmann/cgltf * @@ -35,8 +35,15 @@ * variable. * * `cgltf_result cgltf_load_buffers(const cgltf_options*, cgltf_data*, - * const char*)` can be optionally called to open and read buffer - * files using the `FILE*` APIs. + * const char* gltf_path)` can be optionally called to open and read buffer + * files using the `FILE*` APIs. The `gltf_path` argument is the path to + * the original glTF file, which allows the parser to resolve the path to + * buffer files. + * + * `cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, + * cgltf_size size, const char* base64, void** out_data)` decodes + * base64-encoded data content. Used internally by `cgltf_load_buffers()` + * and may be useful if you're not dealing with normal files. * * `cgltf_result cgltf_parse_file(const cgltf_options* options, const * char* path, cgltf_data** out_data)` can be used to open the given @@ -509,7 +516,10 @@ cgltf_result cgltf_parse_file( cgltf_result cgltf_load_buffers( const cgltf_options* options, cgltf_data* data, - const char* base_path); + const char* gltf_path); + + +cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data); cgltf_result cgltf_validate( cgltf_data* data); @@ -598,11 +608,13 @@ static const uint32_t GlbMagicBinChunk = 0x004E4942; static void* cgltf_default_alloc(void* user, cgltf_size size) { + (void)user; return malloc(size); } static void cgltf_default_free(void* user, void* ptr) { + (void)user; free(ptr); } @@ -832,18 +844,18 @@ static void cgltf_combine_paths(char* path, const char* base, const char* uri) } } -static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_size size, const char* uri, const char* base_path, void** out_data) +static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_size size, const char* uri, const char* gltf_path, void** out_data) { void* (*memory_alloc)(void*, cgltf_size) = options->memory_alloc ? options->memory_alloc : &cgltf_default_alloc; void (*memory_free)(void*, void*) = options->memory_free ? options->memory_free : &cgltf_default_free; - char* path = (char*)memory_alloc(options->memory_user_data, strlen(uri) + strlen(base_path) + 1); + char* path = (char*)memory_alloc(options->memory_user_data, strlen(uri) + strlen(gltf_path) + 1); if (!path) { return cgltf_result_out_of_memory; } - cgltf_combine_paths(path, base_path, uri); + cgltf_combine_paths(path, gltf_path, uri); FILE* file = fopen(path, "rb"); @@ -876,7 +888,7 @@ static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_s return cgltf_result_success; } -static cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data) +cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data) { void* (*memory_alloc)(void*, cgltf_size) = options->memory_alloc ? options->memory_alloc : &cgltf_default_alloc; void (*memory_free)(void*, void*) = options->memory_free ? options->memory_free : &cgltf_default_free; @@ -923,7 +935,7 @@ static cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf return cgltf_result_success; } -cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, const char* base_path) +cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, const char* gltf_path) { if (options == NULL) { @@ -974,7 +986,7 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, } else if (strstr(uri, "://") == NULL) { - cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, base_path, &data->buffers[i].data); + cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data); if (res != cgltf_result_success) { @@ -1396,7 +1408,7 @@ static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_typ case cgltf_component_type_r_32u: return *((const uint32_t*) in); case cgltf_component_type_r_32f: - return *((const float*) in); + return (cgltf_size)*((const float*) in); case cgltf_component_type_r_8: return *((const int8_t*) in); case cgltf_component_type_r_8u: @@ -1432,7 +1444,7 @@ static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_ty } } - return cgltf_component_read_index(in, component_type); + return (cgltf_float)cgltf_component_read_index(in, component_type); } static cgltf_size cgltf_num_components(cgltf_type type); @@ -1649,6 +1661,7 @@ static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* toke static int cgltf_parse_json_array(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, size_t element_size, void** out_array, cgltf_size* out_size) { + (void)json_chunk; CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY); if (*out_array) { @@ -1791,9 +1804,9 @@ static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* t return i; } - for (cgltf_size j = 0; j < out_prim->targets_count; ++j) + for (cgltf_size k = 0; k < out_prim->targets_count; ++k) { - i = cgltf_parse_json_attribute_list(options, tokens, i, json_chunk, &out_prim->targets[j].attributes, &out_prim->targets[j].attributes_count); + i = cgltf_parse_json_attribute_list(options, tokens, i, json_chunk, &out_prim->targets[k].attributes, &out_prim->targets[k].attributes_count); if (i < 0) { return i; @@ -2410,6 +2423,7 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_sampler* out_sampler) { + (void)options; CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); out_sampler->wrap_s = 10497; @@ -3468,6 +3482,7 @@ static int cgltf_parse_json_scenes(cgltf_options* options, jsmntok_t const* toke static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation_sampler* out_sampler) { + (void)options; CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); int size = tokens[i].size; @@ -3522,6 +3537,7 @@ static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t static int cgltf_parse_json_animation_channel(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation_channel* out_channel) { + (void)options; CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); int size = tokens[i].size; @@ -3767,7 +3783,16 @@ static cgltf_size cgltf_component_size(cgltf_component_type component_type) { static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type) { - return cgltf_component_size(component_type) * cgltf_num_components(type); + cgltf_size component_size = cgltf_component_size(component_type); + if (type == cgltf_type_mat2 && component_size == 1) + { + return 8 * component_size; + } + else if (type == cgltf_type_mat3 && (component_size == 1 || component_size == 2)) + { + return 12 * component_size; + } + return component_size * cgltf_num_components(type); } static int cgltf_fixup_pointers(cgltf_data* out_data); @@ -3913,7 +3938,7 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, cgltf_size size, cgltf_data** out_data) { - jsmn_parser parser = { 0 }; + jsmn_parser parser = { 0, 0, 0 }; if (options->json_token_count == 0) { diff --git a/ext/cmft/allocator.cpp b/ext/cmft/allocator.cpp deleted file mode 100644 index af41783e..00000000 --- a/ext/cmft/allocator.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014-2015 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#include - -namespace cmft -{ - CrtAllocator g_crtAllocator; - CrtStackAllocator g_crtStackAllocator; - - AllocatorI* g_allocator = &g_crtAllocator; - StackAllocatorI* g_stackAllocator = &g_crtStackAllocator; - - void setAllocator(AllocatorI* _allocator) - { - g_allocator = (NULL != _allocator) ? _allocator : &g_crtAllocator; - } - - void setStackAllocator(StackAllocatorI* _stackAllocator) - { - g_stackAllocator = (NULL != _stackAllocator) ? _stackAllocator : &g_crtStackAllocator; - } - -} // namespace cmft - -/* vim: set sw=4 ts=4 expandtab: */ diff --git a/ext/cmft/allocator.h b/ext/cmft/allocator.h deleted file mode 100644 index 06537edc..00000000 --- a/ext/cmft/allocator.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2014-2015 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#ifndef CMFT_ALLOCATOR_H_HEADER_GUARD -#define CMFT_ALLOCATOR_H_HEADER_GUARD - -#include // size_t - -#include -#include - -namespace cmft -{ - #ifndef CMFT_ALLOCATOR_DEBUG - # define CMFT_ALLOCATOR_DEBUG 0 - #endif // CMFT_ALLOCATOR_DEBUG - - #ifndef CMFT_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT - # define CMFT_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT 8 - #endif // CMFT_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT - - #if defined(_MSC_VER) - # define CMFT_NO_VTABLE __declspec(novtable) - #else - # define CMFT_NO_VTABLE - #endif - - struct CMFT_NO_VTABLE AllocatorI - { - virtual void* realloc(void* _ptr, size_t _size, size_t _align, const char* _file, size_t _line) = 0; - }; - - struct CMFT_NO_VTABLE StackAllocatorI : AllocatorI - { - virtual void push(const char* _file, size_t _line) = 0; - virtual void pop(const char* _file, size_t _line) = 0; - }; - - struct StackAllocatorScope - { - StackAllocatorScope(StackAllocatorI* _stackAlloc) : m_stack(_stackAlloc) - { - m_stack->push(0,0); - } - - ~StackAllocatorScope() - { - m_stack->pop(0,0); - } - - private: - StackAllocatorI* m_stack; - }; - - #if CMFT_ALLOCATOR_DEBUG - # define CMFT_ALLOC(_allocator, _size) (_allocator)->realloc(NULL, _size, 0, __FILE__, __LINE__) - # define CMFT_REALLOC(_allocator, _ptr, _size) (_allocator)->realloc(_ptr, _size, 0, __FILE__, __LINE__) - # define CMFT_FREE(_allocator, _ptr) (_allocator)->realloc(_ptr, 0, 0, __FILE__, __LINE__) - # define CMFT_ALIGNED_ALLOC(_allocator, _size, _align) (_allocator)->realloc(NULL, _size, _align, __FILE__, __LINE__) - # define CMFT_ALIGNED_REALLOC(_allocator, _ptr, _size, _align) (_allocator)->realloc(_ptr, _size, _align, __FILE__, __LINE__) - # define CMFT_ALIGNED_FREE(_allocator, _ptr, _align) (_allocator)->realloc(_ptr, 0, _align, __FILE__, __LINE__) - # define CMFT_PUSH(_stackAllocator) (_stackAllocator)->push(__FILE__, __LINE__) - # define CMFT_POP(_stackAllocator) (_stackAllocator)->pop(__FILE__, __LINE__) - #else - # define CMFT_ALLOC(_allocator, _size) (_allocator)->realloc(NULL, _size, 0, 0, 0) - # define CMFT_REALLOC(_allocator, _ptr, _size) (_allocator)->realloc(_ptr, _size, 0, 0, 0) - # define CMFT_FREE(_allocator, _ptr) (_allocator)->realloc(_ptr, 0, 0, 0, 0) - # define CMFT_ALIGNED_ALLOC(_allocator, _size, _align) (_allocator)->realloc(NULL, _size, _align, 0, 0) - # define CMFT_ALIGNED_REALLOC(_allocator, _ptr, _size, _align) (_allocator)->realloc(_ptr, _size, _align, 0, 0) - # define CMFT_ALIGNED_FREE(_allocator, _ptr, _align) (_allocator)->realloc(_ptr, 0, _align, 0, 0) - # define CMFT_PUSH(_stackAllocator) (_stackAllocator)->push(0, 0) - # define CMFT_POP(_stackAllocator) (_stackAllocator)->pop(0, 0) - #endif // CMFT_ALLOCATOR_DEBUG - - struct CrtAllocator : AllocatorI - { - virtual void* realloc(void* _ptr, size_t _size, size_t _align, const char* /*_file*/, size_t /*_line*/) - { - (void)_align; // Ignoring alignment for now. - - if (0 == _ptr) - { - return ::malloc(_size); - } - else if (0 == _size) - { - ::free(_ptr); - return NULL; - } - else - { - return ::realloc(_ptr, _size); - } - } - }; - extern CrtAllocator g_crtAllocator; - - struct CrtStackAllocator : StackAllocatorI - { - virtual void* realloc(void* _ptr, size_t _size, size_t _align, const char* /*_file*/, size_t /*_line*/) - { - (void)_align; // Ignoring alignment for now. - - if (0 == _ptr) - { - void* ptr = ::malloc(_size); - m_ptrs[m_curr++] = ptr; - return ptr; - } - else if (0 == _size) - { - ::free(_ptr); - return NULL; - } - else - { - void* ptr = ::realloc(_ptr, _size); - m_ptrs[m_curr++] = ptr; - return ptr; - } - } - - virtual void push(const char* /*_file*/, size_t /*_line*/) - { - m_frames[m_frameIdx++] = m_curr; - } - - virtual void pop(const char* /*_file*/, size_t /*_line*/) - { - uint16_t prev = m_frames[--m_frameIdx]; - for (uint16_t ii = prev, iiEnd = m_curr; ii < iiEnd; ++ii) - { - ::free(m_ptrs[ii]); - } - m_curr = prev; - } - - enum - { - MaxAllocations = 4096, - MaxFrames = 4096, - }; - - uint16_t m_curr; - uint16_t m_frameIdx; - void* m_ptrs[MaxAllocations]; - uint16_t m_frames[MaxAllocations]; - }; - extern CrtStackAllocator g_crtStackAllocator; - - extern AllocatorI* g_allocator; - extern StackAllocatorI* g_stackAllocator; - - void setAllocator(AllocatorI* _allocator); - void setStackAllocator(StackAllocatorI* _stackAllocator); -}; - -#endif // CMFT_ALLOCATOR_H_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ diff --git a/ext/cmft/common/cl.h b/ext/cmft/common/cl.h deleted file mode 100644 index 03db23cb..00000000 --- a/ext/cmft/common/cl.h +++ /dev/null @@ -1,938 +0,0 @@ -/* - * Copyright 2016 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -/* - * Copyright 2010-2015 Branimir Karadzic. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#ifndef CMFT_CL_H_HEADER_GUARD -#define CMFT_CL_H_HEADER_GUARD - -#include -#include - -/// To implement OpenCL dynamic loading, define CMFT_CL_IMPLEMENTATION and -/// #include into .cpp file. -/// -/// To use it, just #include without defining CMFT_CL_IMPLEMENTATION. -/// To load dynamic library call cmft::clLoad(), to unload it call cmft::clUnload. - -namespace cmft -{ - /// Load OpenCL dynamic library. - /// - /// Returns internal reference count. If library is not available - /// returns 0. - /// - int32_t clLoad(); - - /// Unload OpenCL dynamic library. - /// - /// Returns internal reference count. When reference count reaches 0 - /// library is fully unloaded. - /// - int32_t clUnload(); - -} // namespace cmft - -#if defined(CMFT_CL_IMPLEMENTATION) && defined(__OPENCL_CL_H) -# error message("CL/cl.h is already included, it cannot be included before bx/cl.h header when CMFT_CL_IMPLEMENTATION is defined!") -#endif // defined(CMFT_CL_IMPLEMENTATION) && defined(__OPENCL_CL_H) - -#ifndef __OPENCL_CL_H -#define __OPENCL_CL_H - -// CL/cl.h header begin ------------------------------------------------->8 - -/******************************************************************************* - * Copyright (c) 2008 - 2012 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and/or associated documentation files (the - * "Materials"), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - ******************************************************************************/ - -#ifdef __APPLE__ -#include -#else -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/******************************************************************************/ - -typedef struct _cl_platform_id * cl_platform_id; -typedef struct _cl_device_id * cl_device_id; -typedef struct _cl_context * cl_context; -typedef struct _cl_command_queue * cl_command_queue; -typedef struct _cl_mem * cl_mem; -typedef struct _cl_program * cl_program; -typedef struct _cl_kernel * cl_kernel; -typedef struct _cl_event * cl_event; -typedef struct _cl_sampler * cl_sampler; - -typedef cl_uint cl_bool; /* WARNING! Unlike cl_ types in cl_platform.h, cl_bool is not guaranteed to be the same size as the bool in kernels. */ -typedef cl_ulong cl_bitfield; -typedef cl_bitfield cl_device_type; -typedef cl_uint cl_platform_info; -typedef cl_uint cl_device_info; -typedef cl_bitfield cl_device_fp_config; -typedef cl_uint cl_device_mem_cache_type; -typedef cl_uint cl_device_local_mem_type; -typedef cl_bitfield cl_device_exec_capabilities; -typedef cl_bitfield cl_command_queue_properties; -typedef intptr_t cl_device_partition_property; -typedef cl_bitfield cl_device_affinity_domain; - -typedef intptr_t cl_context_properties; -typedef cl_uint cl_context_info; -typedef cl_uint cl_command_queue_info; -typedef cl_uint cl_channel_order; -typedef cl_uint cl_channel_type; -typedef cl_bitfield cl_mem_flags; -typedef cl_uint cl_mem_object_type; -typedef cl_uint cl_mem_info; -typedef cl_bitfield cl_mem_migration_flags; -typedef cl_uint cl_image_info; -typedef cl_uint cl_buffer_create_type; -typedef cl_uint cl_addressing_mode; -typedef cl_uint cl_filter_mode; -typedef cl_uint cl_sampler_info; -typedef cl_bitfield cl_map_flags; -typedef cl_uint cl_program_info; -typedef cl_uint cl_program_build_info; -typedef cl_uint cl_program_binary_type; -typedef cl_int cl_build_status; -typedef cl_uint cl_kernel_info; -typedef cl_uint cl_kernel_arg_info; -typedef cl_uint cl_kernel_arg_address_qualifier; -typedef cl_uint cl_kernel_arg_access_qualifier; -typedef cl_bitfield cl_kernel_arg_type_qualifier; -typedef cl_uint cl_kernel_work_group_info; -typedef cl_uint cl_event_info; -typedef cl_uint cl_command_type; -typedef cl_uint cl_profiling_info; - - -typedef struct _cl_image_format { - cl_channel_order image_channel_order; - cl_channel_type image_channel_data_type; -} cl_image_format; - -typedef struct _cl_image_desc { - cl_mem_object_type image_type; - size_t image_width; - size_t image_height; - size_t image_depth; - size_t image_array_size; - size_t image_row_pitch; - size_t image_slice_pitch; - cl_uint num_mip_levels; - cl_uint num_samples; - cl_mem buffer; -} cl_image_desc; - -typedef struct _cl_buffer_region { - size_t origin; - size_t size; -} cl_buffer_region; - - -/******************************************************************************/ - -/* Error Codes */ -#define CL_SUCCESS 0 -#define CL_DEVICE_NOT_FOUND -1 -#define CL_DEVICE_NOT_AVAILABLE -2 -#define CL_COMPILER_NOT_AVAILABLE -3 -#define CL_MEM_OBJECT_ALLOCATION_FAILURE -4 -#define CL_OUT_OF_RESOURCES -5 -#define CL_OUT_OF_HOST_MEMORY -6 -#define CL_PROFILING_INFO_NOT_AVAILABLE -7 -#define CL_MEM_COPY_OVERLAP -8 -#define CL_IMAGE_FORMAT_MISMATCH -9 -#define CL_IMAGE_FORMAT_NOT_SUPPORTED -10 -#define CL_BUILD_PROGRAM_FAILURE -11 -#define CL_MAP_FAILURE -12 -#define CL_MISALIGNED_SUB_BUFFER_OFFSET -13 -#define CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST -14 -#define CL_COMPILE_PROGRAM_FAILURE -15 -#define CL_LINKER_NOT_AVAILABLE -16 -#define CL_LINK_PROGRAM_FAILURE -17 -#define CL_DEVICE_PARTITION_FAILED -18 -#define CL_KERNEL_ARG_INFO_NOT_AVAILABLE -19 - -#define CL_INVALID_VALUE -30 -#define CL_INVALID_DEVICE_TYPE -31 -#define CL_INVALID_PLATFORM -32 -#define CL_INVALID_DEVICE -33 -#define CL_INVALID_CONTEXT -34 -#define CL_INVALID_QUEUE_PROPERTIES -35 -#define CL_INVALID_COMMAND_QUEUE -36 -#define CL_INVALID_HOST_PTR -37 -#define CL_INVALID_MEM_OBJECT -38 -#define CL_INVALID_IMAGE_FORMAT_DESCRIPTOR -39 -#define CL_INVALID_IMAGE_SIZE -40 -#define CL_INVALID_SAMPLER -41 -#define CL_INVALID_BINARY -42 -#define CL_INVALID_BUILD_OPTIONS -43 -#define CL_INVALID_PROGRAM -44 -#define CL_INVALID_PROGRAM_EXECUTABLE -45 -#define CL_INVALID_KERNEL_NAME -46 -#define CL_INVALID_KERNEL_DEFINITION -47 -#define CL_INVALID_KERNEL -48 -#define CL_INVALID_ARG_INDEX -49 -#define CL_INVALID_ARG_VALUE -50 -#define CL_INVALID_ARG_SIZE -51 -#define CL_INVALID_KERNEL_ARGS -52 -#define CL_INVALID_WORK_DIMENSION -53 -#define CL_INVALID_WORK_GROUP_SIZE -54 -#define CL_INVALID_WORK_ITEM_SIZE -55 -#define CL_INVALID_GLOBAL_OFFSET -56 -#define CL_INVALID_EVENT_WAIT_LIST -57 -#define CL_INVALID_EVENT -58 -#define CL_INVALID_OPERATION -59 -#define CL_INVALID_GL_OBJECT -60 -#define CL_INVALID_BUFFER_SIZE -61 -#define CL_INVALID_MIP_LEVEL -62 -#define CL_INVALID_GLOBAL_WORK_SIZE -63 -#define CL_INVALID_PROPERTY -64 -#define CL_INVALID_IMAGE_DESCRIPTOR -65 -#define CL_INVALID_COMPILER_OPTIONS -66 -#define CL_INVALID_LINKER_OPTIONS -67 -#define CL_INVALID_DEVICE_PARTITION_COUNT -68 - -/* OpenCL Version */ -#define CL_VERSION_1_0 1 -#define CL_VERSION_1_1 1 -#define CL_VERSION_1_2 1 - -/* cl_bool */ -#define CL_FALSE 0 -#define CL_TRUE 1 -#define CL_BLOCKING CL_TRUE -#define CL_NON_BLOCKING CL_FALSE - -/* cl_platform_info */ -#define CL_PLATFORM_PROFILE 0x0900 -#define CL_PLATFORM_VERSION 0x0901 -#define CL_PLATFORM_NAME 0x0902 -#define CL_PLATFORM_VENDOR 0x0903 -#define CL_PLATFORM_EXTENSIONS 0x0904 - -/* cl_device_type - bitfield */ -#define CL_DEVICE_TYPE_DEFAULT (1 << 0) -#define CL_DEVICE_TYPE_CPU (1 << 1) -#define CL_DEVICE_TYPE_GPU (1 << 2) -#define CL_DEVICE_TYPE_ACCELERATOR (1 << 3) -#define CL_DEVICE_TYPE_CUSTOM (1 << 4) -#define CL_DEVICE_TYPE_ALL 0xFFFFFFFF - -/* cl_device_info */ -#define CL_DEVICE_TYPE 0x1000 -#define CL_DEVICE_VENDOR_ID 0x1001 -#define CL_DEVICE_MAX_COMPUTE_UNITS 0x1002 -#define CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS 0x1003 -#define CL_DEVICE_MAX_WORK_GROUP_SIZE 0x1004 -#define CL_DEVICE_MAX_WORK_ITEM_SIZES 0x1005 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR 0x1006 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT 0x1007 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT 0x1008 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG 0x1009 -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT 0x100A -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE 0x100B -#define CL_DEVICE_MAX_CLOCK_FREQUENCY 0x100C -#define CL_DEVICE_ADDRESS_BITS 0x100D -#define CL_DEVICE_MAX_READ_IMAGE_ARGS 0x100E -#define CL_DEVICE_MAX_WRITE_IMAGE_ARGS 0x100F -#define CL_DEVICE_MAX_MEM_ALLOC_SIZE 0x1010 -#define CL_DEVICE_IMAGE2D_MAX_WIDTH 0x1011 -#define CL_DEVICE_IMAGE2D_MAX_HEIGHT 0x1012 -#define CL_DEVICE_IMAGE3D_MAX_WIDTH 0x1013 -#define CL_DEVICE_IMAGE3D_MAX_HEIGHT 0x1014 -#define CL_DEVICE_IMAGE3D_MAX_DEPTH 0x1015 -#define CL_DEVICE_IMAGE_SUPPORT 0x1016 -#define CL_DEVICE_MAX_PARAMETER_SIZE 0x1017 -#define CL_DEVICE_MAX_SAMPLERS 0x1018 -#define CL_DEVICE_MEM_BASE_ADDR_ALIGN 0x1019 -#define CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE 0x101A -#define CL_DEVICE_SINGLE_FP_CONFIG 0x101B -#define CL_DEVICE_GLOBAL_MEM_CACHE_TYPE 0x101C -#define CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE 0x101D -#define CL_DEVICE_GLOBAL_MEM_CACHE_SIZE 0x101E -#define CL_DEVICE_GLOBAL_MEM_SIZE 0x101F -#define CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE 0x1020 -#define CL_DEVICE_MAX_CONSTANT_ARGS 0x1021 -#define CL_DEVICE_LOCAL_MEM_TYPE 0x1022 -#define CL_DEVICE_LOCAL_MEM_SIZE 0x1023 -#define CL_DEVICE_ERROR_CORRECTION_SUPPORT 0x1024 -#define CL_DEVICE_PROFILING_TIMER_RESOLUTION 0x1025 -#define CL_DEVICE_ENDIAN_LITTLE 0x1026 -#define CL_DEVICE_AVAILABLE 0x1027 -#define CL_DEVICE_COMPILER_AVAILABLE 0x1028 -#define CL_DEVICE_EXECUTION_CAPABILITIES 0x1029 -#define CL_DEVICE_QUEUE_PROPERTIES 0x102A -#define CL_DEVICE_NAME 0x102B -#define CL_DEVICE_VENDOR 0x102C -#define CL_DRIVER_VERSION 0x102D -#define CL_DEVICE_PROFILE 0x102E -#define CL_DEVICE_VERSION 0x102F -#define CL_DEVICE_EXTENSIONS 0x1030 -#define CL_DEVICE_PLATFORM 0x1031 -#define CL_DEVICE_DOUBLE_FP_CONFIG 0x1032 -/* 0x1033 reserved for CL_DEVICE_HALF_FP_CONFIG */ -#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF 0x1034 -#define CL_DEVICE_HOST_UNIFIED_MEMORY 0x1035 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR 0x1036 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT 0x1037 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_INT 0x1038 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG 0x1039 -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT 0x103A -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE 0x103B -#define CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF 0x103C -#define CL_DEVICE_OPENCL_C_VERSION 0x103D -#define CL_DEVICE_LINKER_AVAILABLE 0x103E -#define CL_DEVICE_BUILT_IN_KERNELS 0x103F -#define CL_DEVICE_IMAGE_MAX_BUFFER_SIZE 0x1040 -#define CL_DEVICE_IMAGE_MAX_ARRAY_SIZE 0x1041 -#define CL_DEVICE_PARENT_DEVICE 0x1042 -#define CL_DEVICE_PARTITION_MAX_SUB_DEVICES 0x1043 -#define CL_DEVICE_PARTITION_PROPERTIES 0x1044 -#define CL_DEVICE_PARTITION_AFFINITY_DOMAIN 0x1045 -#define CL_DEVICE_PARTITION_TYPE 0x1046 -#define CL_DEVICE_REFERENCE_COUNT 0x1047 -#define CL_DEVICE_PREFERRED_INTEROP_USER_SYNC 0x1048 -#define CL_DEVICE_PRINTF_BUFFER_SIZE 0x1049 -#define CL_DEVICE_IMAGE_PITCH_ALIGNMENT 0x104A -#define CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT 0x104B - -/* cl_device_fp_config - bitfield */ -#define CL_FP_DENORM (1 << 0) -#define CL_FP_INF_NAN (1 << 1) -#define CL_FP_ROUND_TO_NEAREST (1 << 2) -#define CL_FP_ROUND_TO_ZERO (1 << 3) -#define CL_FP_ROUND_TO_INF (1 << 4) -#define CL_FP_FMA (1 << 5) -#define CL_FP_SOFT_FLOAT (1 << 6) -#define CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT (1 << 7) - -/* cl_device_mem_cache_type */ -#define CL_NONE 0x0 -#define CL_READ_ONLY_CACHE 0x1 -#define CL_READ_WRITE_CACHE 0x2 - -/* cl_device_local_mem_type */ -#define CL_LOCAL 0x1 -#define CL_GLOBAL 0x2 - -/* cl_device_exec_capabilities - bitfield */ -#define CL_EXEC_KERNEL (1 << 0) -#define CL_EXEC_NATIVE_KERNEL (1 << 1) - -/* cl_command_queue_properties - bitfield */ -#define CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE (1 << 0) -#define CL_QUEUE_PROFILING_ENABLE (1 << 1) - -/* cl_context_info */ -#define CL_CONTEXT_REFERENCE_COUNT 0x1080 -#define CL_CONTEXT_DEVICES 0x1081 -#define CL_CONTEXT_PROPERTIES 0x1082 -#define CL_CONTEXT_NUM_DEVICES 0x1083 - -/* cl_context_properties */ -#define CL_CONTEXT_PLATFORM 0x1084 -#define CL_CONTEXT_INTEROP_USER_SYNC 0x1085 - -/* cl_device_partition_property */ -#define CL_DEVICE_PARTITION_EQUALLY 0x1086 -#define CL_DEVICE_PARTITION_BY_COUNTS 0x1087 -#define CL_DEVICE_PARTITION_BY_COUNTS_LIST_END 0x0 -#define CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN 0x1088 - -/* cl_device_affinity_domain */ -#define CL_DEVICE_AFFINITY_DOMAIN_NUMA (1 << 0) -#define CL_DEVICE_AFFINITY_DOMAIN_L4_CACHE (1 << 1) -#define CL_DEVICE_AFFINITY_DOMAIN_L3_CACHE (1 << 2) -#define CL_DEVICE_AFFINITY_DOMAIN_L2_CACHE (1 << 3) -#define CL_DEVICE_AFFINITY_DOMAIN_L1_CACHE (1 << 4) -#define CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE (1 << 5) - -/* cl_command_queue_info */ -#define CL_QUEUE_CONTEXT 0x1090 -#define CL_QUEUE_DEVICE 0x1091 -#define CL_QUEUE_REFERENCE_COUNT 0x1092 -#define CL_QUEUE_PROPERTIES 0x1093 - -/* cl_mem_flags - bitfield */ -#define CL_MEM_READ_WRITE (1 << 0) -#define CL_MEM_WRITE_ONLY (1 << 1) -#define CL_MEM_READ_ONLY (1 << 2) -#define CL_MEM_USE_HOST_PTR (1 << 3) -#define CL_MEM_ALLOC_HOST_PTR (1 << 4) -#define CL_MEM_COPY_HOST_PTR (1 << 5) -// reserved (1 << 6) -#define CL_MEM_HOST_WRITE_ONLY (1 << 7) -#define CL_MEM_HOST_READ_ONLY (1 << 8) -#define CL_MEM_HOST_NO_ACCESS (1 << 9) - -/* cl_mem_migration_flags - bitfield */ -#define CL_MIGRATE_MEM_OBJECT_HOST (1 << 0) -#define CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED (1 << 1) - -/* cl_channel_order */ -#define CL_R 0x10B0 -#define CL_A 0x10B1 -#define CL_RG 0x10B2 -#define CL_RA 0x10B3 -#define CL_RGB 0x10B4 -#define CL_RGBA 0x10B5 -#define CL_BGRA 0x10B6 -#define CL_ARGB 0x10B7 -#define CL_INTENSITY 0x10B8 -#define CL_LUMINANCE 0x10B9 -#define CL_Rx 0x10BA -#define CL_RGx 0x10BB -#define CL_RGBx 0x10BC -#define CL_DEPTH 0x10BD -#define CL_DEPTH_STENCIL 0x10BE - -/* cl_channel_type */ -#define CL_SNORM_INT8 0x10D0 -#define CL_SNORM_INT16 0x10D1 -#define CL_UNORM_INT8 0x10D2 -#define CL_UNORM_INT16 0x10D3 -#define CL_UNORM_SHORT_565 0x10D4 -#define CL_UNORM_SHORT_555 0x10D5 -#define CL_UNORM_INT_101010 0x10D6 -#define CL_SIGNED_INT8 0x10D7 -#define CL_SIGNED_INT16 0x10D8 -#define CL_SIGNED_INT32 0x10D9 -#define CL_UNSIGNED_INT8 0x10DA -#define CL_UNSIGNED_INT16 0x10DB -#define CL_UNSIGNED_INT32 0x10DC -#define CL_HALF_FLOAT 0x10DD -#define CL_FLOAT 0x10DE -#define CL_UNORM_INT24 0x10DF - -/* cl_mem_object_type */ -#define CL_MEM_OBJECT_BUFFER 0x10F0 -#define CL_MEM_OBJECT_IMAGE2D 0x10F1 -#define CL_MEM_OBJECT_IMAGE3D 0x10F2 -#define CL_MEM_OBJECT_IMAGE2D_ARRAY 0x10F3 -#define CL_MEM_OBJECT_IMAGE1D 0x10F4 -#define CL_MEM_OBJECT_IMAGE1D_ARRAY 0x10F5 -#define CL_MEM_OBJECT_IMAGE1D_BUFFER 0x10F6 - -/* cl_mem_info */ -#define CL_MEM_TYPE 0x1100 -#define CL_MEM_FLAGS 0x1101 -#define CL_MEM_SIZE 0x1102 -#define CL_MEM_HOST_PTR 0x1103 -#define CL_MEM_MAP_COUNT 0x1104 -#define CL_MEM_REFERENCE_COUNT 0x1105 -#define CL_MEM_CONTEXT 0x1106 -#define CL_MEM_ASSOCIATED_MEMOBJECT 0x1107 -#define CL_MEM_OFFSET 0x1108 - -/* cl_image_info */ -#define CL_IMAGE_FORMAT 0x1110 -#define CL_IMAGE_ELEMENT_SIZE 0x1111 -#define CL_IMAGE_ROW_PITCH 0x1112 -#define CL_IMAGE_SLICE_PITCH 0x1113 -#define CL_IMAGE_WIDTH 0x1114 -#define CL_IMAGE_HEIGHT 0x1115 -#define CL_IMAGE_DEPTH 0x1116 -#define CL_IMAGE_ARRAY_SIZE 0x1117 -#define CL_IMAGE_BUFFER 0x1118 -#define CL_IMAGE_NUM_MIP_LEVELS 0x1119 -#define CL_IMAGE_NUM_SAMPLES 0x111A - -/* cl_addressing_mode */ -#define CL_ADDRESS_NONE 0x1130 -#define CL_ADDRESS_CLAMP_TO_EDGE 0x1131 -#define CL_ADDRESS_CLAMP 0x1132 -#define CL_ADDRESS_REPEAT 0x1133 -#define CL_ADDRESS_MIRRORED_REPEAT 0x1134 - -/* cl_filter_mode */ -#define CL_FILTER_NEAREST 0x1140 -#define CL_FILTER_LINEAR 0x1141 - -/* cl_sampler_info */ -#define CL_SAMPLER_REFERENCE_COUNT 0x1150 -#define CL_SAMPLER_CONTEXT 0x1151 -#define CL_SAMPLER_NORMALIZED_COORDS 0x1152 -#define CL_SAMPLER_ADDRESSING_MODE 0x1153 -#define CL_SAMPLER_FILTER_MODE 0x1154 - -/* cl_map_flags - bitfield */ -#define CL_MAP_READ (1 << 0) -#define CL_MAP_WRITE (1 << 1) -#define CL_MAP_WRITE_INVALIDATE_REGION (1 << 2) - -/* cl_program_info */ -#define CL_PROGRAM_REFERENCE_COUNT 0x1160 -#define CL_PROGRAM_CONTEXT 0x1161 -#define CL_PROGRAM_NUM_DEVICES 0x1162 -#define CL_PROGRAM_DEVICES 0x1163 -#define CL_PROGRAM_SOURCE 0x1164 -#define CL_PROGRAM_BINARY_SIZES 0x1165 -#define CL_PROGRAM_BINARIES 0x1166 -#define CL_PROGRAM_NUM_KERNELS 0x1167 -#define CL_PROGRAM_KERNEL_NAMES 0x1168 - -/* cl_program_build_info */ -#define CL_PROGRAM_BUILD_STATUS 0x1181 -#define CL_PROGRAM_BUILD_OPTIONS 0x1182 -#define CL_PROGRAM_BUILD_LOG 0x1183 -#define CL_PROGRAM_BINARY_TYPE 0x1184 - -/* cl_program_binary_type */ -#define CL_PROGRAM_BINARY_TYPE_NONE 0x0 -#define CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT 0x1 -#define CL_PROGRAM_BINARY_TYPE_LIBRARY 0x2 -#define CL_PROGRAM_BINARY_TYPE_EXECUTABLE 0x4 - -/* cl_build_status */ -#define CL_BUILD_SUCCESS 0 -#define CL_BUILD_NONE -1 -#define CL_BUILD_ERROR -2 -#define CL_BUILD_IN_PROGRESS -3 - -/* cl_kernel_info */ -#define CL_KERNEL_FUNCTION_NAME 0x1190 -#define CL_KERNEL_NUM_ARGS 0x1191 -#define CL_KERNEL_REFERENCE_COUNT 0x1192 -#define CL_KERNEL_CONTEXT 0x1193 -#define CL_KERNEL_PROGRAM 0x1194 -#define CL_KERNEL_ATTRIBUTES 0x1195 - -/* cl_kernel_arg_info */ -#define CL_KERNEL_ARG_ADDRESS_QUALIFIER 0x1196 -#define CL_KERNEL_ARG_ACCESS_QUALIFIER 0x1197 -#define CL_KERNEL_ARG_TYPE_NAME 0x1198 -#define CL_KERNEL_ARG_TYPE_QUALIFIER 0x1199 -#define CL_KERNEL_ARG_NAME 0x119A - -/* cl_kernel_arg_address_qualifier */ -#define CL_KERNEL_ARG_ADDRESS_GLOBAL 0x119B -#define CL_KERNEL_ARG_ADDRESS_LOCAL 0x119C -#define CL_KERNEL_ARG_ADDRESS_CONSTANT 0x119D -#define CL_KERNEL_ARG_ADDRESS_PRIVATE 0x119E - -/* cl_kernel_arg_access_qualifier */ -#define CL_KERNEL_ARG_ACCESS_READ_ONLY 0x11A0 -#define CL_KERNEL_ARG_ACCESS_WRITE_ONLY 0x11A1 -#define CL_KERNEL_ARG_ACCESS_READ_WRITE 0x11A2 -#define CL_KERNEL_ARG_ACCESS_NONE 0x11A3 - -/* cl_kernel_arg_type_qualifer */ -#define CL_KERNEL_ARG_TYPE_NONE 0 -#define CL_KERNEL_ARG_TYPE_CONST (1 << 0) -#define CL_KERNEL_ARG_TYPE_RESTRICT (1 << 1) -#define CL_KERNEL_ARG_TYPE_VOLATILE (1 << 2) - -/* cl_kernel_work_group_info */ -#define CL_KERNEL_WORK_GROUP_SIZE 0x11B0 -#define CL_KERNEL_COMPILE_WORK_GROUP_SIZE 0x11B1 -#define CL_KERNEL_LOCAL_MEM_SIZE 0x11B2 -#define CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE 0x11B3 -#define CL_KERNEL_PRIVATE_MEM_SIZE 0x11B4 -#define CL_KERNEL_GLOBAL_WORK_SIZE 0x11B5 - -/* cl_event_info */ -#define CL_EVENT_COMMAND_QUEUE 0x11D0 -#define CL_EVENT_COMMAND_TYPE 0x11D1 -#define CL_EVENT_REFERENCE_COUNT 0x11D2 -#define CL_EVENT_COMMAND_EXECUTION_STATUS 0x11D3 -#define CL_EVENT_CONTEXT 0x11D4 - -/* cl_command_type */ -#define CL_COMMAND_NDRANGE_KERNEL 0x11F0 -#define CL_COMMAND_TASK 0x11F1 -#define CL_COMMAND_NATIVE_KERNEL 0x11F2 -#define CL_COMMAND_READ_BUFFER 0x11F3 -#define CL_COMMAND_WRITE_BUFFER 0x11F4 -#define CL_COMMAND_COPY_BUFFER 0x11F5 -#define CL_COMMAND_READ_IMAGE 0x11F6 -#define CL_COMMAND_WRITE_IMAGE 0x11F7 -#define CL_COMMAND_COPY_IMAGE 0x11F8 -#define CL_COMMAND_COPY_IMAGE_TO_BUFFER 0x11F9 -#define CL_COMMAND_COPY_BUFFER_TO_IMAGE 0x11FA -#define CL_COMMAND_MAP_BUFFER 0x11FB -#define CL_COMMAND_MAP_IMAGE 0x11FC -#define CL_COMMAND_UNMAP_MEM_OBJECT 0x11FD -#define CL_COMMAND_MARKER 0x11FE -#define CL_COMMAND_ACQUIRE_GL_OBJECTS 0x11FF -#define CL_COMMAND_RELEASE_GL_OBJECTS 0x1200 -#define CL_COMMAND_READ_BUFFER_RECT 0x1201 -#define CL_COMMAND_WRITE_BUFFER_RECT 0x1202 -#define CL_COMMAND_COPY_BUFFER_RECT 0x1203 -#define CL_COMMAND_USER 0x1204 -#define CL_COMMAND_BARRIER 0x1205 -#define CL_COMMAND_MIGRATE_MEM_OBJECTS 0x1206 -#define CL_COMMAND_FILL_BUFFER 0x1207 -#define CL_COMMAND_FILL_IMAGE 0x1208 - -/* command execution status */ -#define CL_COMPLETE 0x0 -#define CL_RUNNING 0x1 -#define CL_SUBMITTED 0x2 -#define CL_QUEUED 0x3 - -/* cl_buffer_create_type */ -#define CL_BUFFER_CREATE_TYPE_REGION 0x1220 - -/* cl_profiling_info */ -#define CL_PROFILING_COMMAND_QUEUED 0x1280 -#define CL_PROFILING_COMMAND_SUBMIT 0x1281 -#define CL_PROFILING_COMMAND_START 0x1282 -#define CL_PROFILING_COMMAND_END 0x1283 - -#ifdef __cplusplus -} //extern "C" -#endif - -// BK - CL/cl.h header end --------------------------------------------------->8 - -// 1.1 -typedef cl_int (CL_API_CALL* PFNCLGETPLATFORMIDSPROC)(cl_uint, cl_platform_id*, cl_uint*); -typedef cl_int (CL_API_CALL* PFNCLGETPLATFORMINFOPROC)(cl_platform_id, cl_platform_info, size_t, void*, size_t*); -typedef cl_int (CL_API_CALL* PFNCLGETDEVICEINFOPROC)(cl_device_id, cl_device_info, size_t, void*, size_t*); -typedef cl_int (CL_API_CALL* PFNCLGETDEVICEIDSPROC)(cl_platform_id, cl_device_type, cl_uint, cl_device_id*, cl_uint*); -typedef cl_context (CL_API_CALL* PFNCLCREATECONTEXTPROC)(const cl_context_properties*, cl_uint, const cl_device_id*, void (CL_CALLBACK*)(const char*, const void*, size_t, void*), void*, cl_int*); -typedef cl_context (CL_API_CALL* PFNCLCREATECONTEXTFROMTYPEPROC)(const cl_context_properties *, cl_device_type, void (CL_CALLBACK*)(const char*, const void*, size_t, void*), void*, cl_int*); -typedef cl_int (CL_API_CALL* PFNCLRETAINCONTEXTPROC)(cl_context); -typedef cl_int (CL_API_CALL* PFNCLRELEASECONTEXTPROC)(cl_context); -typedef cl_int (CL_API_CALL* PFNCLGETCONTEXTINFOPROC)(cl_context, cl_context_info, size_t, void*, size_t*); -typedef cl_command_queue (CL_API_CALL* PFNCLCREATECOMMANDQUEUEPROC)(cl_context, cl_device_id, cl_command_queue_properties, cl_int*); -typedef cl_int (CL_API_CALL* PFNCLRETAINCOMMANDQUEUEPROC)(cl_command_queue); -typedef cl_int (CL_API_CALL* PFNCLRELEASECOMMANDQUEUEPROC)(cl_command_queue); -typedef cl_int (CL_API_CALL* PFNCLGETCOMMANDQUEUEINFOPROC)(cl_command_queue, cl_command_queue_info, size_t, void*, size_t*); -typedef cl_mem (CL_API_CALL* PFNCLCREATEBUFFERPROC)(cl_context, cl_mem_flags, size_t, void*, cl_int*); -typedef cl_int (CL_API_CALL* PFNCLRETAINMEMOBJECTPROC)(cl_mem); -typedef cl_int (CL_API_CALL* PFNCLRELEASEMEMOBJECTPROC)(cl_mem); -typedef cl_int (CL_API_CALL* PFNCLGETSUPPORTEDIMAGEFORMATSPROC)(cl_context, cl_mem_flags, cl_mem_object_type, cl_uint, cl_image_format*, cl_uint*); -typedef cl_int (CL_API_CALL* PFNCLGETMEMOBJECTINFOPROC)(cl_mem, cl_mem_info, size_t, void*, size_t*); -typedef cl_int (CL_API_CALL* PFNCLGETIMAGEINFOPROC)(cl_mem, cl_image_info, size_t, void*, size_t*); -typedef cl_sampler (CL_API_CALL* PFNCLCREATESAMPLERPROC)(cl_context, cl_bool, cl_addressing_mode, cl_filter_mode, cl_int*); -typedef cl_int (CL_API_CALL* PFNCLRETAINSAMPLERPROC)(cl_sampler); -typedef cl_int (CL_API_CALL* PFNCLRELEASESAMPLERPROC)(cl_sampler); -typedef cl_int (CL_API_CALL* PFNCLGETSAMPLERINFOPROC)(cl_sampler, cl_sampler_info, size_t, void*, size_t*); -typedef cl_program (CL_API_CALL* PFNCLCREATEPROGRAMWITHSOURCEPROC)(cl_context, cl_uint, const char**, const size_t*, cl_int*); -typedef cl_program (CL_API_CALL* PFNCLCREATEPROGRAMWITHBINARYPROC)(cl_context, cl_uint, const cl_device_id*, const size_t*, const unsigned char**, cl_int*, cl_int*); -typedef cl_int (CL_API_CALL* PFNCLRETAINPROGRAMPROC)(cl_program); -typedef cl_int (CL_API_CALL* PFNCLRELEASEPROGRAMPROC)(cl_program); -typedef cl_int (CL_API_CALL* PFNCLBUILDPROGRAMPROC)(cl_program, cl_uint, const cl_device_id *, const char *, void (CL_CALLBACK*)(cl_program, void*), void*); -typedef cl_int (CL_API_CALL* PFNCLGETPROGRAMINFOPROC)(cl_program, cl_program_info, size_t, void*, size_t*); -typedef cl_int (CL_API_CALL* PFNCLGETPROGRAMBUILDINFOPROC)(cl_program, cl_device_id, cl_program_build_info, size_t, void*, size_t*); -typedef cl_kernel (CL_API_CALL* PFNCLCREATEKERNELPROC)(cl_program, const char*, cl_int*); -typedef cl_int (CL_API_CALL* PFNCLCREATEKERNELSINPROGRAMPROC)(cl_program, cl_uint, cl_kernel*, cl_uint*); -typedef cl_int (CL_API_CALL* PFNCLRETAINKERNELPROC)(cl_kernel); -typedef cl_int (CL_API_CALL* PFNCLRELEASEKERNELPROC)(cl_kernel); -typedef cl_int (CL_API_CALL* PFNCLSETKERNELARGPROC)(cl_kernel, cl_uint, size_t, const void*); -typedef cl_int (CL_API_CALL* PFNCLGETKERNELINFOPROC)(cl_kernel, cl_kernel_info, size_t, void*, size_t*); -typedef cl_int (CL_API_CALL* PFNCLGETKERNELWORKGROUPINFOPROC)(cl_kernel, cl_device_id, cl_kernel_work_group_info, size_t, void*, size_t*); -typedef cl_int (CL_API_CALL* PFNCLWAITFOREVENTSPROC)(cl_uint, const cl_event*); -typedef cl_int (CL_API_CALL* PFNCLGETEVENTINFOPROC)(cl_event, cl_event_info, size_t, void*, size_t*); -typedef cl_int (CL_API_CALL* PFNCLRETAINEVENTPROC)(cl_event); -typedef cl_int (CL_API_CALL* PFNCLRELEASEEVENTPROC)(cl_event); -typedef cl_int (CL_API_CALL* PFNCLGETEVENTPROFILINGINFOPROC)(cl_event, cl_profiling_info, size_t, void*, size_t*); -typedef cl_int (CL_API_CALL* PFNCLFLUSHPROC)(cl_command_queue); -typedef cl_int (CL_API_CALL* PFNCLFINISHPROC)(cl_command_queue); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEREADBUFFERPROC)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEWRITEBUFFERPROC)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUECOPYBUFFERPROC)(cl_command_queue, cl_mem, cl_mem, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEREADIMAGEPROC)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEWRITEIMAGEPROC)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUECOPYIMAGEPROC)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUECOPYIMAGETOBUFFERPROC)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, size_t, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUECOPYBUFFERTOIMAGEPROC)(cl_command_queue, cl_mem, cl_mem, size_t, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); -typedef void (CL_API_CALL* PFNCLENQUEUEMAPBUFFERPROC)(cl_command_queue, cl_mem, cl_bool, cl_map_flags, size_t, size_t, cl_uint, const cl_event*, cl_event*, cl_int*); -typedef void (CL_API_CALL* PFNCLENQUEUEMAPIMAGEPROC)(cl_command_queue, cl_mem, cl_bool, cl_map_flags, const size_t *, const size_t *, size_t *, size_t *, cl_uint, const cl_event *, cl_event *, cl_int*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEUNMAPMEMOBJECTPROC)(cl_command_queue, cl_mem, void*, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUENDRANGEKERNELPROC)(cl_command_queue, cl_kernel, cl_uint, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUETASKPROC)(cl_command_queue, cl_kernel, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUENATIVEKERNELPROC)(cl_command_queue, void (CL_CALLBACK*)(void*), void*, size_t, cl_uint, const cl_mem*, const void**, cl_uint, const cl_event*, cl_event*); - -// 1.1 -typedef cl_mem (CL_API_CALL* PFNCLCREATEIMAGE2DPROC)(cl_context, cl_mem_flags, const cl_image_format*, size_t, size_t, size_t, void*, cl_int*); -typedef cl_mem (CL_API_CALL* PFNCLCREATEIMAGE3DPROC)(cl_context, cl_mem_flags, const cl_image_format*, size_t, size_t, size_t, size_t, size_t, void*, cl_int*); -typedef cl_mem (CL_API_CALL* PFNCLCREATESUBBUFFERPROC)(cl_mem, cl_mem_flags, cl_buffer_create_type, const void*, cl_int*); -typedef cl_int (CL_API_CALL* PFNCLSETMEMOBJECTDESTRUCTORCALLBACKPROC)(cl_mem, void (CL_CALLBACK*)(cl_mem, void*), void*); -typedef cl_event (CL_API_CALL* PFNCLCREATEUSEREVENTPROC)(cl_context, cl_int*); -typedef cl_int (CL_API_CALL* PFNCLSETUSEREVENTSTATUSPROC)(cl_event, cl_int); -typedef cl_int (CL_API_CALL* PFNCLSETEVENTCALLBACKPROC)(cl_event, cl_int, void (CL_CALLBACK*)(cl_event, cl_int, void*), void*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEREADBUFFERRECTPROC)(cl_command_queue, cl_mem, cl_bool, const size_t *, const size_t *, const size_t *, size_t, size_t, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEWRITEBUFFERRECTPROC)(cl_command_queue, cl_mem, cl_bool, const size_t *, const size_t *, const size_t *, size_t, size_t, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUECOPYBUFFERRECTPROC)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*); - -// 1.2 -typedef cl_int (CL_API_CALL* PFNCLCREATESUBDEVICESPROC)(cl_device_id, const cl_device_partition_property*, cl_uint, cl_device_id*, cl_uint*); -typedef cl_int (CL_API_CALL* PFNCLRETAINDEVICEPROC)(cl_device_id); -typedef cl_int (CL_API_CALL* PFNCLRELEASEDEVICEPROC)(cl_device_id); -typedef cl_mem (CL_API_CALL* PFNCLCREATEIMAGEPROC)(cl_context, cl_mem_flags, const cl_image_format*, const cl_image_desc*, void*, cl_int*); -typedef cl_program (CL_API_CALL* PFNCLCREATEPROGRAMWITHBUILTINKERNELSPROC)(cl_context, cl_uint, const cl_device_id*, const char*, cl_int*); -typedef cl_int (CL_API_CALL* PFNCLCOMPILEPROGRAMPROC)(cl_program, cl_uint, const cl_device_id*, const char*, cl_uint, const cl_program*, const char**, void (CL_CALLBACK*)(cl_program, void*), void*); -typedef cl_program (CL_API_CALL* PFNCLLINKPROGRAMPROC)(cl_context, cl_uint, const cl_device_id*, const char*, cl_uint, const cl_program*, void (CL_CALLBACK*)(cl_program, void*), void*, cl_int*); -typedef cl_int (CL_API_CALL* PFNCLUNLOADPLATFORMCOMPILERPROC)(cl_platform_id); -typedef cl_int (CL_API_CALL* PFNCLGETKERNELARGINFOPROC)(cl_kernel, cl_uint, cl_kernel_arg_info, size_t, void*, size_t*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEFILLBUFFERPROC)(cl_command_queue, cl_mem, const void*, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event *); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEFILLIMAGEPROC)(cl_command_queue, cl_mem, const void*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEMIGRATEMEMOBJECTSPROC)(cl_command_queue, cl_uint, const cl_mem*, cl_mem_migration_flags, cl_uint, const cl_event *, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEMARKERWITHWAITLISTPROC)(cl_command_queue, cl_uint, const cl_event*, cl_event*); -typedef cl_int (CL_API_CALL* PFNCLENQUEUEBARRIERWITHWAITLISTPROC)(cl_command_queue, cl_uint, const cl_event *, cl_event*); - -#define CMFT_CL_IMPORT_ALL_10 \ - /* Platform API */ \ - CMFT_CL_IMPORT_10(false, PFNCLGETPLATFORMIDSPROC, clGetPlatformIDs); \ - CMFT_CL_IMPORT_10(false, PFNCLGETPLATFORMINFOPROC, clGetPlatformInfo); \ - /* Device APIs */ \ - CMFT_CL_IMPORT_10(false, PFNCLGETDEVICEIDSPROC, clGetDeviceIDs); \ - CMFT_CL_IMPORT_10(false, PFNCLGETDEVICEINFOPROC, clGetDeviceInfo); \ - /* Context APIs */ \ - CMFT_CL_IMPORT_10(false, PFNCLCREATECONTEXTPROC, clCreateContext); \ - CMFT_CL_IMPORT_10(false, PFNCLCREATECONTEXTFROMTYPEPROC, clCreateContextFromType); \ - CMFT_CL_IMPORT_10(false, PFNCLRETAINCONTEXTPROC, clRetainContext); \ - CMFT_CL_IMPORT_10(false, PFNCLRELEASECONTEXTPROC, clReleaseContext); \ - CMFT_CL_IMPORT_10(false, PFNCLGETCONTEXTINFOPROC, clGetContextInfo); \ - /* Command Queue APIs */ \ - CMFT_CL_IMPORT_10(false, PFNCLCREATECOMMANDQUEUEPROC, clCreateCommandQueue); \ - CMFT_CL_IMPORT_10(false, PFNCLRETAINCOMMANDQUEUEPROC, clRetainCommandQueue); \ - CMFT_CL_IMPORT_10(false, PFNCLRELEASECOMMANDQUEUEPROC, clReleaseCommandQueue); \ - CMFT_CL_IMPORT_10(false, PFNCLGETCOMMANDQUEUEINFOPROC, clGetCommandQueueInfo); \ - /* Memory Object APIs */ \ - CMFT_CL_IMPORT_10(false, PFNCLCREATEBUFFERPROC, clCreateBuffer); \ - CMFT_CL_IMPORT_10(false, PFNCLRETAINMEMOBJECTPROC, clRetainMemObject); \ - CMFT_CL_IMPORT_10(false, PFNCLRELEASEMEMOBJECTPROC, clReleaseMemObject); \ - CMFT_CL_IMPORT_10(false, PFNCLGETSUPPORTEDIMAGEFORMATSPROC, clGetSupportedImageFormats); \ - CMFT_CL_IMPORT_10(false, PFNCLGETMEMOBJECTINFOPROC, clGetMemObjectInfo); \ - CMFT_CL_IMPORT_10(false, PFNCLGETIMAGEINFOPROC, clGetImageInfo); \ - /* Sampler APIs */ \ - CMFT_CL_IMPORT_10(false, PFNCLCREATESAMPLERPROC, clCreateSampler); \ - CMFT_CL_IMPORT_10(false, PFNCLRETAINSAMPLERPROC, clRetainSampler); \ - CMFT_CL_IMPORT_10(false, PFNCLRELEASESAMPLERPROC, clReleaseSampler); \ - CMFT_CL_IMPORT_10(false, PFNCLGETSAMPLERINFOPROC, clGetSamplerInfo); \ - /* Program Object APIs */ \ - CMFT_CL_IMPORT_10(false, PFNCLCREATEPROGRAMWITHSOURCEPROC, clCreateProgramWithSource); \ - CMFT_CL_IMPORT_10(false, PFNCLCREATEPROGRAMWITHBINARYPROC, clCreateProgramWithBinary); \ - CMFT_CL_IMPORT_10(false, PFNCLRETAINPROGRAMPROC, clRetainProgram); \ - CMFT_CL_IMPORT_10(false, PFNCLRELEASEPROGRAMPROC, clReleaseProgram); \ - CMFT_CL_IMPORT_10(false, PFNCLBUILDPROGRAMPROC, clBuildProgram); \ - CMFT_CL_IMPORT_10(false, PFNCLGETPROGRAMINFOPROC, clGetProgramInfo); \ - CMFT_CL_IMPORT_10(false, PFNCLGETPROGRAMBUILDINFOPROC, clGetProgramBuildInfo); \ - /* Kernel Object APIs */ \ - CMFT_CL_IMPORT_10(false, PFNCLCREATEKERNELPROC, clCreateKernel); \ - CMFT_CL_IMPORT_10(false, PFNCLCREATEKERNELSINPROGRAMPROC, clCreateKernelsInProgram); \ - CMFT_CL_IMPORT_10(false, PFNCLRETAINKERNELPROC, clRetainKernel); \ - CMFT_CL_IMPORT_10(false, PFNCLRELEASEKERNELPROC, clReleaseKernel); \ - CMFT_CL_IMPORT_10(false, PFNCLSETKERNELARGPROC, clSetKernelArg); \ - CMFT_CL_IMPORT_10(false, PFNCLGETKERNELINFOPROC, clGetKernelInfo); \ - CMFT_CL_IMPORT_10(false, PFNCLGETKERNELWORKGROUPINFOPROC, clGetKernelWorkGroupInfo); \ - /* Event Object APIs */ \ - CMFT_CL_IMPORT_10(false, PFNCLWAITFOREVENTSPROC, clWaitForEvents); \ - CMFT_CL_IMPORT_10(false, PFNCLGETEVENTINFOPROC, clGetEventInfo); \ - CMFT_CL_IMPORT_10(false, PFNCLRETAINEVENTPROC, clRetainEvent); \ - CMFT_CL_IMPORT_10(false, PFNCLRELEASEEVENTPROC, clReleaseEvent); \ - /* Profiling APIs */ \ - CMFT_CL_IMPORT_10(false, PFNCLGETEVENTPROFILINGINFOPROC, clGetEventProfilingInfo); \ - /* Flush and Finish APIs */ \ - CMFT_CL_IMPORT_10(false, PFNCLFLUSHPROC, clFlush); \ - CMFT_CL_IMPORT_10(false, PFNCLFINISHPROC, clFinish); \ - /* Enqueued Commands APIs */ \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUEREADBUFFERPROC, clEnqueueReadBuffer); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUEWRITEBUFFERPROC, clEnqueueWriteBuffer); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUECOPYBUFFERPROC, clEnqueueCopyBuffer); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUEREADIMAGEPROC, clEnqueueReadImage); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUEWRITEIMAGEPROC, clEnqueueWriteImage); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUECOPYIMAGEPROC, clEnqueueCopyImage); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUECOPYIMAGETOBUFFERPROC, clEnqueueCopyImageToBuffer); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUEMAPBUFFERPROC, clEnqueueMapBuffer); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUEMAPIMAGEPROC, clEnqueueMapImage); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUEUNMAPMEMOBJECTPROC, clEnqueueUnmapMemObject); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUENDRANGEKERNELPROC, clEnqueueNDRangeKernel); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUETASKPROC, clEnqueueTask); \ - CMFT_CL_IMPORT_10(false, PFNCLENQUEUENATIVEKERNELPROC, clEnqueueNativeKernel); \ - \ - CMFT_CL_IMPORT_END - -#define CMFT_CL_IMPORT_ALL_11 \ - /* Memory Object APIs */ \ - CMFT_CL_IMPORT_11(false, PFNCLCREATEIMAGE2DPROC, clCreateImage2D); \ - CMFT_CL_IMPORT_11(false, PFNCLCREATEIMAGE3DPROC, clCreateImage3D); \ - CMFT_CL_IMPORT_11(false, PFNCLCREATESUBBUFFERPROC, clCreateSubBuffer); \ - CMFT_CL_IMPORT_11(false, PFNCLSETMEMOBJECTDESTRUCTORCALLBACKPROC, clSetMemObjectDestructorCallback); \ - /* Event Object APIs */ \ - CMFT_CL_IMPORT_11(false, PFNCLCREATEUSEREVENTPROC, clCreateUserEvent); \ - CMFT_CL_IMPORT_11(false, PFNCLSETUSEREVENTSTATUSPROC, clSetUserEventStatus); \ - CMFT_CL_IMPORT_11(false, PFNCLSETEVENTCALLBACKPROC, clSetEventCallback); \ - /* Enqueued Commands APIs */ \ - CMFT_CL_IMPORT_11(false, PFNCLENQUEUEREADBUFFERRECTPROC, clEnqueueReadBufferRect); \ - CMFT_CL_IMPORT_11(false, PFNCLENQUEUEWRITEBUFFERRECTPROC, clEnqueueWriteBufferRect); \ - CMFT_CL_IMPORT_11(false, PFNCLENQUEUECOPYBUFFERRECTPROC, clEnqueueCopyBufferRect); \ - \ - CMFT_CL_IMPORT_END - -#define CMFT_CL_IMPORT_ALL_12 \ - /* Device APIs */ \ - CMFT_CL_IMPORT_12(false, PFNCLCREATESUBDEVICESPROC, clCreateSubDevices); \ - CMFT_CL_IMPORT_12(false, PFNCLRETAINDEVICEPROC, clRetainDevice); \ - CMFT_CL_IMPORT_12(false, PFNCLRELEASEDEVICEPROC, clReleaseDevice); \ - CMFT_CL_IMPORT_12(false, PFNCLCREATEIMAGEPROC, clCreateImage); \ - /* Program Object APIs */ \ - CMFT_CL_IMPORT_12(false, PFNCLCREATEPROGRAMWITHBUILTINKERNELSPROC, clCreateProgramWithBuiltInKernels); \ - CMFT_CL_IMPORT_12(false, PFNCLCOMPILEPROGRAMPROC, clCompileProgram); \ - CMFT_CL_IMPORT_12(false, PFNCLLINKPROGRAMPROC, clLinkProgram); \ - CMFT_CL_IMPORT_12(false, PFNCLUNLOADPLATFORMCOMPILERPROC, clUnloadPlatformCompiler); \ - /* Kernel Object APIs */ \ - CMFT_CL_IMPORT_12(false, PFNCLGETKERNELARGINFOPROC, clGetKernelArgInfo); \ - /* Enqueued Commands APIs */ \ - CMFT_CL_IMPORT_12(false, PFNCLENQUEUEFILLBUFFERPROC, clEnqueueFillBuffer); \ - CMFT_CL_IMPORT_12(false, PFNCLENQUEUEFILLIMAGEPROC, clEnqueueFillImage); \ - CMFT_CL_IMPORT_12(false, PFNCLENQUEUEMIGRATEMEMOBJECTSPROC, clEnqueueMigrateMemObjects); \ - CMFT_CL_IMPORT_12(false, PFNCLENQUEUEMARKERWITHWAITLISTPROC, clEnqueueMarkerWithWaitList); \ - CMFT_CL_IMPORT_12(false, PFNCLENQUEUEBARRIERWITHWAITLISTPROC, clEnqueueBarrierWithWaitList); \ - \ - CMFT_CL_IMPORT_END - -#define CMFT_CL_IMPORT_ALL \ - CMFT_CL_IMPORT_ALL_10 \ - CMFT_CL_IMPORT_ALL_11 \ - CMFT_CL_IMPORT_ALL_12 \ - \ - CMFT_CL_IMPORT_END - -#define CMFT_CL_IMPORT_10(_optional, _proto, _func) CMFT_CL_IMPORT(10, _optional, _proto, _func) -#define CMFT_CL_IMPORT_11(_optional, _proto, _func) CMFT_CL_IMPORT(11, _optional, _proto, _func) -#define CMFT_CL_IMPORT_12(_optional, _proto, _func) CMFT_CL_IMPORT(12, _optional, _proto, _func) -#define CMFT_CL_IMPORT_END - -#define CMFT_CL_IMPORT(_version, _optional, _proto, _func) extern "C" _proto _func -CMFT_CL_IMPORT_ALL -#undef CMFT_CL_IMPORT - -#if defined(CMFT_CL_IMPLEMENTATION) -extern "C" -{ -#define CMFT_CL_IMPORT(_version, _optional, _proto, _func) _proto _func -CMFT_CL_IMPORT_ALL -#undef CMFT_CL_IMPORT -}; - -#include "os.h" - -namespace cmft -{ - struct OpenCLContext - { - OpenCLContext() - : m_handle(NULL) - , m_refCount(0) - { - } - - int32_t load() - { - if (NULL != m_handle) - { - int32_t ref = ++m_refCount; - return ref; - } - - const char* filePath = -#if CMFT_PLATFORM_LINUX - "libOpenCL.so" -#elif CMFT_PLATFORM_APPLE - "/Library/Frameworks/OpenCL.framework/OpenCL" -#elif CMFT_PLATFORM_WINDOWS - "opencl.dll" -#else - "??? unknown OpenCL platform ???" -#endif // CMFT_PLATFORM_ - ; - - m_handle = cmft::dlopen(filePath); - if (NULL == m_handle) - { - fprintf(stderr, "Unable to find OpenCL '%s' dynamic library.\n", filePath); - return 0; - } - - m_refCount = 1; - -#define CMFT_CL_IMPORT(_version, _optional, _proto, _func) _func = (_proto)cmft::dlsym(m_handle, #_func) - CMFT_CL_IMPORT_ALL -#undef CMFT_CL_IMPORT - - return 1; - } - - int32_t unload() - { - const bool check = m_refCount > 0 && NULL != m_handle; - if (!check) - { - fprintf(stderr, "OpenCL is not loaded.\n"); - } - - int32_t ref = --m_refCount; - if (0 == ref) - { - dlclose(m_handle); - m_handle = NULL; - } - - return ref; - } - - void* m_handle; - int32_t m_refCount; - }; - - static OpenCLContext s_ctx; - - int32_t clLoad() - { - return s_ctx.load(); - } - - int32_t clUnload() - { - return s_ctx.unload(); - } - -} // namespace cmft - -#undef CMFT_CL_IMPORT_ALL -#undef CMFT_CL_IMPORT_ALL_10 -#undef CMFT_CL_IMPORT_ALL_11 -#undef CMFT_CL_IMPORT_ALL_12 -#undef CMFT_CL_IMPORT_END - -#endif // defined(CMFT_CL_IMPLEMENTATION) - -#endif // __OPENCL_CL_H - -#endif // CMFT_CL_H_HEADER_GUARD - diff --git a/ext/cmft/common/commandline.h b/ext/cmft/common/commandline.h deleted file mode 100644 index c7f93abe..00000000 --- a/ext/cmft/common/commandline.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2016 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#ifndef CMFT_COMMANDLINE_H_HEADER_GUARD -#define CMFT_COMMANDLINE_H_HEADER_GUARD - -namespace cmft -{ - /* - * Adapted from: https://github.com/bkaradzic/bx/include/bx/commandline.h - * - * Copyright 2010-2016 Branimir Karadzic. All rights reserved. - * License: https://github.com/bkaradzic/bx#license-bsd-2-clause - */ - - struct CommandLine - { - CommandLine(int _argc, char const* const* _argv) - : m_argc(_argc) - , m_argv(_argv) - { - } - - const char* findOption(const char* _long, const char* _default) const - { - const char* result = find(0, '\0', _long, 1); - return result == NULL ? _default : result; - } - - const char* findOption(const char _short, const char* _long, const char* _default) const - { - const char* result = find(0, _short, _long, 1); - return result == NULL ? _default : result; - } - - const char* findOption(const char* _long, int _numParams = 1) const - { - const char* result = find(0, '\0', _long, _numParams); - return result; - } - - const char* findOption(const char _short, const char* _long = NULL, int _numParams = 1) const - { - const char* result = find(0, _short, _long, _numParams); - return result; - } - - const char* findOption(int _skip, const char _short, const char* _long = NULL, int _numParams = 1) const - { - const char* result = find(_skip, _short, _long, _numParams); - return result; - } - - bool hasArg(const char _short, const char* _long = NULL) const - { - const char* arg = findOption(_short, _long, 0); - return NULL != arg; - } - - bool hasArg(const char* _long) const - { - const char* arg = findOption('\0', _long, 0); - return NULL != arg; - } - - bool hasArg(const char*& _value, const char _short, const char* _long = NULL) const - { - const char* arg = findOption(_short, _long, 1); - _value = arg; - return NULL != arg; - } - - bool hasArg(int& _value, const char _short, const char* _long = NULL) const - { - const char* arg = findOption(_short, _long, 1); - if (NULL != arg) - { - _value = atoi(arg); - return true; - } - - return false; - } - - bool hasArg(unsigned int& _value, const char _short, const char* _long = NULL) const - { - const char* arg = findOption(_short, _long, 1); - if (NULL != arg) - { - _value = atoi(arg); - return true; - } - - return false; - } - - bool hasArg(float& _value, const char _short, const char* _long = NULL) const - { - const char* arg = findOption(_short, _long, 1); - if (NULL != arg) - { - _value = float(atof(arg)); - return true; - } - - return false; - } - - bool hasArg(double& _value, const char _short, const char* _long = NULL) const - { - const char* arg = findOption(_short, _long, 1); - if (NULL != arg) - { - _value = atof(arg); - return true; - } - - return false; - } - - bool hasArg(bool& _value, const char _short, const char* _long = NULL) const - { - const char* arg = findOption(_short, _long, 1); - if (NULL != arg) - { - if ('0' == *arg || (0 == stricmp(arg, "false") ) ) - { - _value = false; - } - else if ('0' != *arg || (0 == stricmp(arg, "true") ) ) - { - _value = true; - } - - return true; - } - - return false; - } - - private: - const char* find(int _skip, const char _short, const char* _long, int _numParams) const - { - for (int ii = 0; ii < m_argc; ++ii) - { - const char* arg = m_argv[ii]; - if ('-' == *arg) - { - ++arg; - if (_short == *arg) - { - if (1 == strlen(arg) ) - { - if (0 == _skip) - { - if (0 == _numParams) - { - return ""; - } - else if (ii+_numParams < m_argc - && '-' != *m_argv[ii+1] ) - { - return m_argv[ii+1]; - } - - return NULL; - } - - --_skip; - ii += _numParams; - } - } - else if (NULL != _long - && '-' == *arg - && 0 == stricmp(arg+1, _long) ) - { - if (0 == _skip) - { - if (0 == _numParams) - { - return ""; - } - else if (ii+_numParams < m_argc - && '-' != *m_argv[ii+1] ) - { - return m_argv[ii+1]; - } - - return NULL; - } - - --_skip; - ii += _numParams; - } - } - } - - return NULL; - } - - int m_argc; - char const* const* m_argv; - }; -} - -#endif // CMFT_COMMANDLINE_H_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ diff --git a/ext/cmft/common/config.h b/ext/cmft/common/config.h deleted file mode 100644 index d0bca8fa..00000000 --- a/ext/cmft/common/config.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright 2014-2015 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#ifndef CMFT_CONFIG_H_HEADER_GUARD -#define CMFT_CONFIG_H_HEADER_GUARD - -#include //abort() -#include //stderr -#include // PrintFunc - -// Config. -//----- - -// This flags can also be specified in the build tool by defining CMFT_CUSTOM_CONFIG. -#ifndef CMFT_CUSTOM_CONFIG - // Output messages. - #define CMFT_ENABLE_INFO_MESSAGES 1 - #define CMFT_ENABLE_WARNINGS 1 - #define CMFT_ENABLE_PROGRESS_REPORT 0 - - // Flush output. - #define CMFT_ALWAYS_FLUSH_OUTPUT 0 - - // Checks. - #define CMFT_ENABLE_CL_CHECK 0 - #define CMFT_ENABLE_DEBUG_CHECK 0 - #define CMFT_ENABLE_FILE_ERROR_CHECK 0 - #define CMFT_ENABLE_MEMORY_ALLOC_CHECK 0 -#endif // CMFT_CUSTOM_CONFIG - -// When CMFT_TEST_BUILD is 0, 'src/cmft_cli/cmft_cli.h' gets executed. -// When CMFT_TEST_BUILD is 1, 'src/tests/test.h' gets executed. -#define CMFT_TEST_BUILD 0 - -// Implementation. -//----- - -// Flush output. -#ifndef CMFT_ALWAYS_FLUSH_OUTPUT - #define CMFT_ALWAYS_FLUSH_OUTPUT 0 -#endif //CMFT_ALWAYS_FLUSH_OUTPUT - -#if CMFT_ALWAYS_FLUSH_OUTPUT - #define CMFT_FLUSH_OUTPUT() do { fflush(stdout); fflush(stderr); } while(0) -#else - #define CMFT_FLUSH_OUTPUT() do {} while(0) -#endif - -// Cmft progress. -#ifndef CMFT_ENABLE_PROGRESS_REPORT - #define CMFT_ENABLE_PROGRESS_REPORT 0 -#endif - -#if CMFT_ENABLE_PROGRESS_REPORT - #define CMFT_PROGRESS(_format, ...) \ - do \ - { \ - printf(_format "\n", ##__VA_ARGS__); \ - CMFT_FLUSH_OUTPUT(); \ - } while(0) -#else - #define CMFT_PROGRESS(...) do {} while(0) -#endif - -// Cmft info. -#ifndef CMFT_ENABLE_INFO_MESSAGES - #define CMFT_ENABLE_INFO_MESSAGES 0 -#endif - -#if CMFT_ENABLE_INFO_MESSAGES - #define INFO _INFO -#else - #define INFO(...) do {} while(0) -#endif - -namespace cmft { extern PrintFunc printfInfo; } -#define _INFO(_format, ...) \ -do \ -{ \ - if (NULL != cmft::printfInfo) \ - { \ - cmft::printfInfo("CMFT info: " _format "\n", ##__VA_ARGS__); \ - } \ -} while(0) - -// Cmft warning. -#ifndef CMFT_ENABLE_WARNINGS - #define CMFT_ENABLE_WARNINGS 0 -#endif - -#if CMFT_ENABLE_WARNINGS - #define WARN _WARN -#else - #define WARN(...) do {} while(0) -#endif - -namespace cmft { extern PrintFunc printfWarning; } -#define _WARN(_format, ...) \ -do \ -{ \ - if (NULL != cmft::printfWarning) \ - { \ - cmft::printfWarning("CMFT WARNING: " _format "\n", ##__VA_ARGS__); \ - } \ -} while(0) - -// File error check. -#ifndef CMFT_ENABLE_FILE_ERROR_CHECK - #define CMFT_ENABLE_FILE_ERROR_CHECK 0 -#endif - -#if CMFT_ENABLE_FILE_ERROR_CHECK - #define FERROR_CHECK _FERROR_CHECK -#else - #define FERROR_CHECK(_fp) do {} while(0) -#endif - -#define _FERROR_CHECK(_fp) \ -do \ -{ \ - if (ferror(_fp)) \ - { \ - fprintf(stderr, "CMFT FILE I/O ERROR " _FILE_LINE_ ".\n"); \ - CMFT_FLUSH_OUTPUT(); \ - } \ -} while(0) - -// Memory alloc check. -#ifndef CMFT_ENABLE_MEMORY_ALLOC_CHECK - #define CMFT_ENABLE_MEMORY_ALLOC_CHECK 0 -#endif - -#if CMFT_ENABLE_MEMORY_ALLOC_CHECK - #define MALLOC_CHECK _MALLOC_CHECK -#else - #define MALLOC_CHECK(_fp) do {} while(0) -#endif - -#define _MALLOC_CHECK(_ptr) \ -do \ -{ \ - if (NULL == _ptr) \ - { \ - fprintf(stderr, "CMFT MEMORY ALLOC ERROR " _FILE_LINE_ ".\n"); \ - CMFT_FLUSH_OUTPUT(); \ - } \ -} while(0) - -// Debug check. -#ifndef CMFT_ENABLE_DEBUG_CHECK - #define CMFT_ENABLE_DEBUG_CHECK 0 -#endif - -#if CMFT_ENABLE_DEBUG_CHECK - #define DEBUG_CHECK _DEBUG_CHECK -#else - #define DEBUG_CHECK(_condition, ...) do {} while(0) -#endif - -#define _DEBUG_CHECK(_condition, _format, ...) \ -do \ -{ \ - if (!(_condition)) \ - { \ - fprintf(stderr, "CMFT DEBUG CHECK " _FILE_LINE_ ": " _format "\n", ##__VA_ARGS__); \ - CMFT_FLUSH_OUTPUT(); \ - abort(); \ - } \ -} while(0) - -// CL check. -#ifndef CMFT_ENABLE_CL_CHECK - #define CMFT_ENABLE_CL_CHECK 0 -#endif - -#if CMFT_ENABLE_CL_CHECK - #define CL_CHECK _CL_CHECK - #define CL_CHECK_ERR _CL_CHECK_ERR -#else - #define CL_CHECK(_expr) _expr - #define CL_CHECK_ERR(_expr) BX_UNUSED(_expr) -#endif - -#define _CL_CHECK(_expr) \ - do \ - { \ - cl_int err = _expr; \ - if (CL_SUCCESS != err) \ - { \ - fprintf(stderr, "CMFT OpenCL Error: '%s' returned %d!\n", #_expr, (int)err); \ - CMFT_FLUSH_OUTPUT(); \ - abort(); \ - } \ - } while (0) - -#define _CL_CHECK_ERR(_err) \ - if (CL_SUCCESS != _err) \ - { \ - fprintf(stderr, "CMFT OpenCL Error: %d!\n", (int)_err); \ - CMFT_FLUSH_OUTPUT(); \ - abort(); \ - } - -#endif //CMFT_CONFIG_H_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ diff --git a/ext/cmft/common/fpumath.h b/ext/cmft/common/fpumath.h deleted file mode 100644 index 0756e906..00000000 --- a/ext/cmft/common/fpumath.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2011-2014 Branimir Karadzic. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -// FPU math lib - -#ifndef FPU_MATH_H_HEADER_GUARD -#define FPU_MATH_H_HEADER_GUARD - -#define _USE_MATH_DEFINES -#include -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#if defined(_MSC_VER) -inline float fminf(float _a, float _b) -{ - return _a < _b ? _a : _b; -} - -inline float fmaxf(float _a, float _b) -{ - return _a > _b ? _a : _b; -} -#endif // BX_COMPILER_MSVC - -inline float toRad(float _deg) -{ - return _deg * float(M_PI / 180.0); -} - -inline float toDeg(float _rad) -{ - return _rad * float(180.0 / M_PI); -} - -inline float fclamp(float _a, float _min, float _max) -{ - return fminf(fmaxf(_a, _min), _max); -} - -inline float fsaturate(float _a) -{ - return fclamp(_a, 0.0f, 1.0f); -} - -inline float flerp(float _a, float _b, float _t) -{ - return _a + (_b - _a) * _t; -} - -inline float fsign(float _a) -{ - return _a < 0.0f ? -1.0f : 1.0f; -} - -inline void vec3Move(float* __restrict _result, const float* __restrict _a) -{ - _result[0] = _a[0]; - _result[1] = _a[1]; - _result[2] = _a[2]; -} - -inline void vec3Abs(float* __restrict _result, const float* __restrict _a) -{ - _result[0] = fabsf(_a[0]); - _result[1] = fabsf(_a[1]); - _result[2] = fabsf(_a[2]); -} - -inline void vec3Neg(float* __restrict _result, const float* __restrict _a) -{ - _result[0] = -_a[0]; - _result[1] = -_a[1]; - _result[2] = -_a[2]; -} - -inline void vec3Add(float* __restrict _result, const float* __restrict _a, const float* __restrict _b) -{ - _result[0] = _a[0] + _b[0]; - _result[1] = _a[1] + _b[1]; - _result[2] = _a[2] + _b[2]; -} - -inline void vec3Sub(float* __restrict _result, const float* __restrict _a, const float* __restrict _b) -{ - _result[0] = _a[0] - _b[0]; - _result[1] = _a[1] - _b[1]; - _result[2] = _a[2] - _b[2]; -} - -inline void vec3Mul(float* __restrict _result, const float* __restrict _a, const float* __restrict _b) -{ - _result[0] = _a[0] * _b[0]; - _result[1] = _a[1] * _b[1]; - _result[2] = _a[2] * _b[2]; -} - -inline void vec3Mul(float* __restrict _result, const float* __restrict _a, float _b) -{ - _result[0] = _a[0] * _b; - _result[1] = _a[1] * _b; - _result[2] = _a[2] * _b; -} - -inline float vec3Dot(const float* __restrict _a, const float* __restrict _b) -{ - return _a[0]*_b[0] + _a[1]*_b[1] + _a[2]*_b[2]; -} - -inline void vec3Cross(float* __restrict _result, const float* __restrict _a, const float* __restrict _b) -{ - _result[0] = _a[1]*_b[2] - _a[2]*_b[1]; - _result[1] = _a[2]*_b[0] - _a[0]*_b[2]; - _result[2] = _a[0]*_b[1] - _a[1]*_b[0]; -} - -inline float vec3Length(const float* _a) -{ - return sqrtf(vec3Dot(_a, _a) ); -} - -inline float vec3Norm(float* __restrict _result, const float* __restrict _a) -{ - const float len = vec3Length(_a); - const float invLen = 1.0f/len; - _result[0] = _a[0] * invLen; - _result[1] = _a[1] * invLen; - _result[2] = _a[2] * invLen; - return len; -} - -#endif // FPU_MATH_H_HEADER_GUARD diff --git a/ext/cmft/common/halffloat.h b/ext/cmft/common/halffloat.h deleted file mode 100644 index bef18f33..00000000 --- a/ext/cmft/common/halffloat.h +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright 2016 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -/* - * Copyright 2010-2016 Branimir Karadzic. All rights reserved. - * License: https://github.com/bkaradzic/bx#license-bsd-2-clause - */ - -// Copyright 2006 Mike Acton -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE - -#ifndef CMFT_HALFLOAT_H_HEADER_GUARD -#define CMFT_HALFLOAT_H_HEADER_GUARD - -#include "platform.h" -#include - -#if CMFT_COMPILER_MSVC -# if CMFT_PLATFORM_WINDOWS -# include // math.h is included because VS bitches: - // warning C4985: 'ceil': attributes not present on previous declaration. - // must be included before intrin.h. -# include -# pragma intrinsic(_BitScanForward) -# pragma intrinsic(_BitScanReverse) -# if CMFT_ARCH_64BIT -# pragma intrinsic(_BitScanForward64) -# pragma intrinsic(_BitScanReverse64) -# endif // CMFT_ARCH_64BIT -# endif // CMFT_PLATFORM_WINDOWS -#endif // CMFT_COMPILER_MSVC - -#define CMFT_HALF_FLOAT_ZERO UINT16_C(0) -#define CMFT_HALF_FLOAT_HALF UINT16_C(0x3800) -#define CMFT_HALF_FLOAT_ONE UINT16_C(0x3c00) -#define CMFT_HALF_FLOAT_TWO UINT16_C(0x4000) - -namespace cmft -{ - inline uint32_t uint32_li(uint32_t _a) - { - return _a; - } - - inline uint32_t uint32_dec(uint32_t _a) - { - return _a - 1; - } - - inline uint32_t uint32_inc(uint32_t _a) - { - return _a + 1; - } - - inline uint32_t uint32_not(uint32_t _a) - { - return ~_a; - } - - inline uint32_t uint32_neg(uint32_t _a) - { - return -(int32_t)_a; - } - - inline uint32_t uint32_ext(uint32_t _a) - { - return ( (int32_t)_a)>>31; - } - - inline uint32_t uint32_and(uint32_t _a, uint32_t _b) - { - return _a & _b; - } - - inline uint32_t uint32_andc(uint32_t _a, uint32_t _b) - { - return _a & ~_b; - } - - inline uint32_t uint32_xor(uint32_t _a, uint32_t _b) - { - return _a ^ _b; - } - - inline uint32_t uint32_xorl(uint32_t _a, uint32_t _b) - { - return !_a != !_b; - } - - inline uint32_t uint32_or(uint32_t _a, uint32_t _b) - { - return _a | _b; - } - - inline uint32_t uint32_orc(uint32_t _a, uint32_t _b) - { - return _a | ~_b; - } - - inline uint32_t uint32_sll(uint32_t _a, int _sa) - { - return _a << _sa; - } - - inline uint32_t uint32_srl(uint32_t _a, int _sa) - { - return _a >> _sa; - } - - inline uint32_t uint32_sra(uint32_t _a, int _sa) - { - return ( (int32_t)_a) >> _sa; - } - - inline uint32_t uint32_rol(uint32_t _a, int _sa) - { - return ( _a << _sa) | (_a >> (32-_sa) ); - } - - inline uint32_t uint32_ror(uint32_t _a, int _sa) - { - return ( _a >> _sa) | (_a << (32-_sa) ); - } - - inline uint32_t uint32_add(uint32_t _a, uint32_t _b) - { - return _a + _b; - } - - inline uint32_t uint32_sub(uint32_t _a, uint32_t _b) - { - return _a - _b; - } - - inline uint32_t uint32_mul(uint32_t _a, uint32_t _b) - { - return _a * _b; - } - - inline uint32_t uint32_div(uint32_t _a, uint32_t _b) - { - return (_a / _b); - } - - inline uint32_t uint32_mod(uint32_t _a, uint32_t _b) - { - return (_a % _b); - } - - inline uint32_t uint32_cmpeq(uint32_t _a, uint32_t _b) - { - return -(_a == _b); - } - - inline uint32_t uint32_cmpneq(uint32_t _a, uint32_t _b) - { - return -(_a != _b); - } - - inline uint32_t uint32_cmplt(uint32_t _a, uint32_t _b) - { - return -(_a < _b); - } - - inline uint32_t uint32_cmple(uint32_t _a, uint32_t _b) - { - return -(_a <= _b); - } - - inline uint32_t uint32_cmpgt(uint32_t _a, uint32_t _b) - { - return -(_a > _b); - } - - inline uint32_t uint32_cmpge(uint32_t _a, uint32_t _b) - { - return -(_a >= _b); - } - - inline uint32_t uint32_setnz(uint32_t _a) - { - return -!!_a; - } - - inline uint32_t uint32_satadd(uint32_t _a, uint32_t _b) - { - const uint32_t add = uint32_add(_a, _b); - const uint32_t lt = uint32_cmplt(add, _a); - const uint32_t result = uint32_or(add, lt); - - return result; - } - - inline uint32_t uint32_satsub(uint32_t _a, uint32_t _b) - { - const uint32_t sub = uint32_sub(_a, _b); - const uint32_t le = uint32_cmple(sub, _a); - const uint32_t result = uint32_and(sub, le); - - return result; - } - - inline uint32_t uint32_satmul(uint32_t _a, uint32_t _b) - { - const uint64_t mul = (uint64_t)_a * (uint64_t)_b; - const uint32_t hi = mul >> 32; - const uint32_t nz = uint32_setnz(hi); - const uint32_t result = uint32_or(uint32_t(mul), nz); - - return result; - } - - inline uint32_t uint32_sels(uint32_t test, uint32_t _a, uint32_t _b) - { - const uint32_t mask = uint32_ext(test); - const uint32_t sel_a = uint32_and(_a, mask); - const uint32_t sel_b = uint32_andc(_b, mask); - const uint32_t result = uint32_or(sel_a, sel_b); - - return (result); - } - - inline uint32_t uint32_selb(uint32_t _mask, uint32_t _a, uint32_t _b) - { - const uint32_t sel_a = uint32_and(_a, _mask); - const uint32_t sel_b = uint32_andc(_b, _mask); - const uint32_t result = uint32_or(sel_a, sel_b); - - return (result); - } - - inline uint32_t uint32_imin(uint32_t _a, uint32_t _b) - { - const uint32_t a_sub_b = uint32_sub(_a, _b); - const uint32_t result = uint32_sels(a_sub_b, _a, _b); - - return result; - } - - inline uint32_t uint32_imax(uint32_t _a, uint32_t _b) - { - const uint32_t b_sub_a = uint32_sub(_b, _a); - const uint32_t result = uint32_sels(b_sub_a, _a, _b); - - return result; - } - - inline uint32_t uint32_min(uint32_t _a, uint32_t _b) - { - return _a > _b ? _b : _a; - } - - inline uint32_t uint32_min(uint32_t _a, uint32_t _b, uint32_t _c) - { - return uint32_min(_a, uint32_min(_b, _c) ); - } - - inline uint32_t uint32_max(uint32_t _a, uint32_t _b) - { - return _a > _b ? _a : _b; - } - - inline uint32_t uint32_max(uint32_t _a, uint32_t _b, uint32_t _c) - { - return uint32_max(_a, uint32_max(_b, _c) ); - } - - inline uint32_t uint32_clamp(uint32_t _a, uint32_t _min, uint32_t _max) - { - const uint32_t tmp = uint32_max(_a, _min); - const uint32_t result = uint32_min(tmp, _max); - - return result; - } - - inline uint32_t uint32_iclamp(uint32_t _a, uint32_t _min, uint32_t _max) - { - const uint32_t tmp = uint32_imax(_a, _min); - const uint32_t result = uint32_imin(tmp, _max); - - return result; - } - - inline uint32_t uint32_incwrap(uint32_t _val, uint32_t _min, uint32_t _max) - { - const uint32_t inc = uint32_inc(_val); - const uint32_t max_diff = uint32_sub(_max, _val); - const uint32_t neg_max_diff = uint32_neg(max_diff); - const uint32_t max_or = uint32_or(max_diff, neg_max_diff); - const uint32_t max_diff_nz = uint32_ext(max_or); - const uint32_t result = uint32_selb(max_diff_nz, inc, _min); - - return result; - } - - inline uint32_t uint32_decwrap(uint32_t _val, uint32_t _min, uint32_t _max) - { - const uint32_t dec = uint32_dec(_val); - const uint32_t min_diff = uint32_sub(_min, _val); - const uint32_t neg_min_diff = uint32_neg(min_diff); - const uint32_t min_or = uint32_or(min_diff, neg_min_diff); - const uint32_t min_diff_nz = uint32_ext(min_or); - const uint32_t result = uint32_selb(min_diff_nz, dec, _max); - - return result; - } - - /// Count number of bits set. - inline uint32_t uint32_cntbits(uint32_t _val) - { - #if CMFT_COMPILER_GCC || CMFT_COMPILER_CLANG - return __builtin_popcount(_val); - #elif CMFT_COMPILER_MSVC && CMFT_PLATFORM_WINDOWS - return __popcnt(_val); - #else - return uint32_cntbits_ref(_val); - #endif // CMFT_COMPILER_ - } - - inline uint32_t uint32_cntlz_ref(uint32_t _val) - { - const uint32_t tmp0 = uint32_srl(_val, 1); - const uint32_t tmp1 = uint32_or(tmp0, _val); - const uint32_t tmp2 = uint32_srl(tmp1, 2); - const uint32_t tmp3 = uint32_or(tmp2, tmp1); - const uint32_t tmp4 = uint32_srl(tmp3, 4); - const uint32_t tmp5 = uint32_or(tmp4, tmp3); - const uint32_t tmp6 = uint32_srl(tmp5, 8); - const uint32_t tmp7 = uint32_or(tmp6, tmp5); - const uint32_t tmp8 = uint32_srl(tmp7, 16); - const uint32_t tmp9 = uint32_or(tmp8, tmp7); - const uint32_t tmpA = uint32_not(tmp9); - const uint32_t result = uint32_cntbits(tmpA); - - return result; - } - - /// Count number of leading zeros. - inline uint32_t uint32_cntlz(uint32_t _val) - { - #if CMFT_COMPILER_GCC || CMFT_COMPILER_CLANG - return __builtin_clz(_val); - #elif CMFT_COMPILER_MSVC && CMFT_PLATFORM_WINDOWS - unsigned long index; - _BitScanReverse(&index, _val); - return 31 - index; - #else - return uint32_cntlz_ref(_val); - #endif // CMFT_COMPILER_ - } - - inline float halfToFloat(uint16_t _a) - { - const uint32_t h_e_mask = uint32_li(0x00007c00); - const uint32_t h_m_mask = uint32_li(0x000003ff); - const uint32_t h_s_mask = uint32_li(0x00008000); - const uint32_t h_f_s_pos_offset = uint32_li(0x00000010); - const uint32_t h_f_e_pos_offset = uint32_li(0x0000000d); - const uint32_t h_f_bias_offset = uint32_li(0x0001c000); - const uint32_t f_e_mask = uint32_li(0x7f800000); - const uint32_t f_m_mask = uint32_li(0x007fffff); - const uint32_t h_f_e_denorm_bias = uint32_li(0x0000007e); - const uint32_t h_f_m_denorm_sa_bias = uint32_li(0x00000008); - const uint32_t f_e_pos = uint32_li(0x00000017); - const uint32_t h_e_mask_minus_one = uint32_li(0x00007bff); - const uint32_t h_e = uint32_and(_a, h_e_mask); - const uint32_t h_m = uint32_and(_a, h_m_mask); - const uint32_t h_s = uint32_and(_a, h_s_mask); - const uint32_t h_e_f_bias = uint32_add(h_e, h_f_bias_offset); - const uint32_t h_m_nlz = uint32_cntlz(h_m); - const uint32_t f_s = uint32_sll(h_s, h_f_s_pos_offset); - const uint32_t f_e = uint32_sll(h_e_f_bias, h_f_e_pos_offset); - const uint32_t f_m = uint32_sll(h_m, h_f_e_pos_offset); - const uint32_t f_em = uint32_or(f_e, f_m); - const uint32_t h_f_m_sa = uint32_sub(h_m_nlz, h_f_m_denorm_sa_bias); - const uint32_t f_e_denorm_unpacked = uint32_sub(h_f_e_denorm_bias, h_f_m_sa); - const uint32_t h_f_m = uint32_sll(h_m, h_f_m_sa); - const uint32_t f_m_denorm = uint32_and(h_f_m, f_m_mask); - const uint32_t f_e_denorm = uint32_sll(f_e_denorm_unpacked, f_e_pos); - const uint32_t f_em_denorm = uint32_or(f_e_denorm, f_m_denorm); - const uint32_t f_em_nan = uint32_or(f_e_mask, f_m); - const uint32_t is_e_eqz_msb = uint32_dec(h_e); - const uint32_t is_m_nez_msb = uint32_neg(h_m); - const uint32_t is_e_flagged_msb = uint32_sub(h_e_mask_minus_one, h_e); - const uint32_t is_zero_msb = uint32_andc(is_e_eqz_msb, is_m_nez_msb); - const uint32_t is_inf_msb = uint32_andc(is_e_flagged_msb, is_m_nez_msb); - const uint32_t is_denorm_msb = uint32_and(is_m_nez_msb, is_e_eqz_msb); - const uint32_t is_nan_msb = uint32_and(is_e_flagged_msb, is_m_nez_msb); - const uint32_t is_zero = uint32_ext(is_zero_msb); - const uint32_t f_zero_result = uint32_andc(f_em, is_zero); - const uint32_t f_denorm_result = uint32_sels(is_denorm_msb, f_em_denorm, f_zero_result); - const uint32_t f_inf_result = uint32_sels(is_inf_msb, f_e_mask, f_denorm_result); - const uint32_t f_nan_result = uint32_sels(is_nan_msb, f_em_nan, f_inf_result); - const uint32_t f_result = uint32_or(f_s, f_nan_result); - - union { uint32_t ui; float flt; } utof; - utof.ui = f_result; - return utof.flt; - } - - inline uint16_t halfFromFloat(float _a) - { - union { uint32_t ui; float flt; } ftou; - ftou.flt = _a; - - const uint32_t one = uint32_li(0x00000001); - const uint32_t f_s_mask = uint32_li(0x80000000); - const uint32_t f_e_mask = uint32_li(0x7f800000); - const uint32_t f_m_mask = uint32_li(0x007fffff); - const uint32_t f_m_hidden_bit = uint32_li(0x00800000); - const uint32_t f_m_round_bit = uint32_li(0x00001000); - const uint32_t f_snan_mask = uint32_li(0x7fc00000); - const uint32_t f_e_pos = uint32_li(0x00000017); - const uint32_t h_e_pos = uint32_li(0x0000000a); - const uint32_t h_e_mask = uint32_li(0x00007c00); - const uint32_t h_snan_mask = uint32_li(0x00007e00); - const uint32_t h_e_mask_value = uint32_li(0x0000001f); - const uint32_t f_h_s_pos_offset = uint32_li(0x00000010); - const uint32_t f_h_bias_offset = uint32_li(0x00000070); - const uint32_t f_h_m_pos_offset = uint32_li(0x0000000d); - const uint32_t h_nan_min = uint32_li(0x00007c01); - const uint32_t f_h_e_biased_flag = uint32_li(0x0000008f); - const uint32_t f_s = uint32_and(ftou.ui, f_s_mask); - const uint32_t f_e = uint32_and(ftou.ui, f_e_mask); - const uint16_t h_s = (uint16_t)uint32_srl(f_s, f_h_s_pos_offset); - const uint32_t f_m = uint32_and(ftou.ui, f_m_mask); - const uint16_t f_e_amount = (uint16_t)uint32_srl(f_e, f_e_pos); - const uint32_t f_e_half_bias = uint32_sub(f_e_amount, f_h_bias_offset); - const uint32_t f_snan = uint32_and(ftou.ui, f_snan_mask); - const uint32_t f_m_round_mask = uint32_and(f_m, f_m_round_bit); - const uint32_t f_m_round_offset = uint32_sll(f_m_round_mask, one); - const uint32_t f_m_rounded = uint32_add(f_m, f_m_round_offset); - const uint32_t f_m_denorm_sa = uint32_sub(one, f_e_half_bias); - const uint32_t f_m_with_hidden = uint32_or(f_m_rounded, f_m_hidden_bit); - const uint32_t f_m_denorm = uint32_srl(f_m_with_hidden, f_m_denorm_sa); - const uint32_t h_m_denorm = uint32_srl(f_m_denorm, f_h_m_pos_offset); - const uint32_t f_m_rounded_overflow = uint32_and(f_m_rounded, f_m_hidden_bit); - const uint32_t m_nan = uint32_srl(f_m, f_h_m_pos_offset); - const uint32_t h_em_nan = uint32_or(h_e_mask, m_nan); - const uint32_t h_e_norm_overflow_offset = uint32_inc(f_e_half_bias); - const uint32_t h_e_norm_overflow = uint32_sll(h_e_norm_overflow_offset, h_e_pos); - const uint32_t h_e_norm = uint32_sll(f_e_half_bias, h_e_pos); - const uint32_t h_m_norm = uint32_srl(f_m_rounded, f_h_m_pos_offset); - const uint32_t h_em_norm = uint32_or(h_e_norm, h_m_norm); - const uint32_t is_h_ndenorm_msb = uint32_sub(f_h_bias_offset, f_e_amount); - const uint32_t is_f_e_flagged_msb = uint32_sub(f_h_e_biased_flag, f_e_half_bias); - const uint32_t is_h_denorm_msb = uint32_not(is_h_ndenorm_msb); - const uint32_t is_f_m_eqz_msb = uint32_dec(f_m); - const uint32_t is_h_nan_eqz_msb = uint32_dec(m_nan); - const uint32_t is_f_inf_msb = uint32_and(is_f_e_flagged_msb, is_f_m_eqz_msb); - const uint32_t is_f_nan_underflow_msb = uint32_and(is_f_e_flagged_msb, is_h_nan_eqz_msb); - const uint32_t is_e_overflow_msb = uint32_sub(h_e_mask_value, f_e_half_bias); - const uint32_t is_h_inf_msb = uint32_or(is_e_overflow_msb, is_f_inf_msb); - const uint32_t is_f_nsnan_msb = uint32_sub(f_snan, f_snan_mask); - const uint32_t is_m_norm_overflow_msb = uint32_neg(f_m_rounded_overflow); - const uint32_t is_f_snan_msb = uint32_not(is_f_nsnan_msb); - const uint32_t h_em_overflow_result = uint32_sels(is_m_norm_overflow_msb, h_e_norm_overflow, h_em_norm); - const uint32_t h_em_nan_result = uint32_sels(is_f_e_flagged_msb, h_em_nan, h_em_overflow_result); - const uint32_t h_em_nan_underflow_result = uint32_sels(is_f_nan_underflow_msb, h_nan_min, h_em_nan_result); - const uint32_t h_em_inf_result = uint32_sels(is_h_inf_msb, h_e_mask, h_em_nan_underflow_result); - const uint32_t h_em_denorm_result = uint32_sels(is_h_denorm_msb, h_m_denorm, h_em_inf_result); - const uint32_t h_em_snan_result = uint32_sels(is_f_snan_msb, h_snan_mask, h_em_denorm_result); - const uint32_t h_result = uint32_or(h_s, h_em_snan_result); - - return (uint16_t)(h_result); - } -} - -#endif // CMFT_HALFLOAT_H_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ diff --git a/ext/cmft/common/handlealloc.h b/ext/cmft/common/handlealloc.h deleted file mode 100644 index 9c09013d..00000000 --- a/ext/cmft/common/handlealloc.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2016 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#ifndef CMFT_HANDLEALLOC_H_HEADER_GUARD -#define CMFT_HANDLEALLOC_H_HEADER_GUARD - -#include - -#ifdef max -# undef max -#endif // max - -#ifdef min -# undef min -#endif // max - -namespace cmft -{ - template - struct HandleAllocImpl : HandleAllocStorageTy - { - /// Expected interface: - /// struct HandleAllocStorageTemplate - /// { - /// typedef typename bestfit_type::type HandleType; - /// HandleType* handles(); - /// HandleType* indices(); - /// HandleType max(); - /// }; - typedef typename HandleAllocStorageTy::HandleType HandleTy; - using HandleAllocStorageTy::handles; - using HandleAllocStorageTy::indices; - using HandleAllocStorageTy::max; - - HandleAllocImpl() : HandleAllocStorageTy() - { - } - - void init() - { - m_numHandles = 0; - for (HandleTy ii = 0, end = max(); ii < end; ++ii) - { - handles()[ii] = ii; - } - } - - HandleTy alloc() - { - const HandleTy index = m_numHandles++; - const HandleTy handle = handles()[index]; - indices()[handle] = index; - - return handle; - } - - bool contains(uint32_t _handle) - { - HandleTy index = indices()[_handle]; - - return (index < m_numHandles && handles()[index] == _handle); - } - - void free(uint32_t _handle) - { - HandleTy index = indices()[_handle]; - - if (index < m_numHandles && handles()[index] == _handle) - { - --m_numHandles; - HandleTy temp = handles()[m_numHandles]; - handles()[m_numHandles] = _handle; - indices()[temp] = index; - handles()[index] = temp; - } - } - - HandleTy getHandleAt(uint32_t _idx) - { - return handles()[_idx]; - } - - HandleTy getIdxOf(uint32_t _handle) - { - return indices()[_handle]; - } - - void reset() - { - m_numHandles = 0; - } - - HandleTy count() - { - return m_numHandles; - } - - private: - HandleTy m_numHandles; - }; - - template - struct HandleAllocStorageT - { - typedef uint16_t HandleType; - - HandleType* handles() - { - return m_handles; - } - - HandleType* indices() - { - return m_indices; - } - - HandleType max() const - { - return MaxHandlesT; - } - - private: - HandleType m_handles[MaxHandlesT]; - HandleType m_indices[MaxHandlesT]; - }; - - template - struct HandleAllocT : HandleAllocImpl< HandleAllocStorageT > - { - typedef HandleAllocImpl< HandleAllocStorageT > Base; - - HandleAllocT() - { - Base::init(); - } - }; -} - -#endif // CMFT_HANDLEALLOC_H_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ - diff --git a/ext/cmft/common/os.h b/ext/cmft/common/os.h deleted file mode 100644 index e7091704..00000000 --- a/ext/cmft/common/os.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2016 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -/* - * Copyright 2010-2016 Branimir Karadzic. All rights reserved. - * License: https://github.com/bkaradzic/bx#license-bsd-2-clause - */ - -// Copyright 2006 Mike Acton -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE - -#ifndef CMFT_OS_H_HEADER_GUARD -#define CMFT_OS_H_HEADER_GUARD - -#include "platform.h" -#include - -#if CMFT_PLATFORM_WINDOWS -# include -#elif CMFT_PLATFORM_LINUX || CMFT_PLATFORM_APPLE -# include // sched_yield -# if CMFT_PLATFORM_APPLE -# include // mach_port_t -# endif // CMFT_PLATFORM_* -# -# include // dlopen, dlclose, dlsym -# -# if CMFT_PLATFORM_LINUX -# include // syscall -# include -# endif // CMFT_PLATFORM_LINUX -#endif // CMFT_PLATFORM_ - -namespace cmft -{ - inline void* dlopen(const char* _filePath) - { - #if CMFT_PLATFORM_WINDOWS - return (void*)::LoadLibraryA(_filePath); - #else - return ::dlopen(_filePath, RTLD_LOCAL|RTLD_LAZY); - #endif // CMFT_PLATFORM_ - } - - inline void dlclose(void* _handle) - { - #if CMFT_PLATFORM_WINDOWS - ::FreeLibrary( (HMODULE)_handle); - #else - ::dlclose(_handle); - #endif // CMFT_PLATFORM_ - } - - inline void* dlsym(void* _handle, const char* _symbol) - { - #if CMFT_PLATFORM_WINDOWS - return (void*)::GetProcAddress( (HMODULE)_handle, _symbol); - #else - return ::dlsym(_handle, _symbol); - #endif // CMFT_PLATFORM_ - } -} - -#endif // CMFT_OS_H_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ - diff --git a/ext/cmft/common/platform.h b/ext/cmft/common/platform.h deleted file mode 100644 index b98b0c82..00000000 --- a/ext/cmft/common/platform.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2016 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#ifndef CMFT_PLATFORM_HEADER_GUARD -#define CMFT_PLATFORM_HEADER_GUARD - -/// Pre-defined C/C++ Compiler Macros: http://sourceforge.net/p/predef/wiki/Home/ - -//------------------------------------------------------------ -// Options. -//------------------------------------------------------------ - -#define CMFT_COMPILER_MSVC 0 -#define CMFT_COMPILER_GCC 0 -#define CMFT_COMPILER_CLANG 0 - -#define CMFT_ARCH_32BIT 0 -#define CMFT_ARCH_64BIT 0 - -#define CMFT_PTR_SIZE 0 - -#define CMFT_PLATFORM_LINUX 0 -#define CMFT_PLATFORM_APPLE 0 -#define CMFT_PLATFORM_WINDOWS 0 - -#define CMFT_PLATFORM_UNIX 0 -#define CMFT_PLATFORM_POSIX 0 - -#define CMFT_CPP11 0 -#define CMFT_CPP14 0 - -//------------------------------------------------------------ -// Impl. -//------------------------------------------------------------ - -#if defined(_WIN32) || defined(_WIN64) -# undef CMFT_COMPILER_MSVC -# define CMFT_COMPILER_MSVC 1 -#elif defined(__GNUC__) -# undef CMFT_COMPILER_GCC -# define CMFT_COMPILER_GCC 1 -#elif defined(__clang__) -# undef CMFT_COMPILER_CLANG -# define CMFT_COMPILER_CLANG 1 -#endif - -#if (0 \ - || defined (__amd64__) \ - || defined (__amd64) \ - || defined (__x86_64__) \ - || defined (__x86_64) \ - || defined (_M_X64) \ - || defined (_M_AMD64) ) -# undef CMFT_ARCH_64BIT -# define CMFT_ARCH_64BIT 1 -# undef CMFT_PTR_SIZE -# define CMFT_PTR_SIZE 8 -#elif (0 \ - || defined(i386) \ - || defined(__i386) \ - || defined(__i386__) \ - || defined(__i386) \ - || defined(__IA32__) \ - || defined(_M_I86) \ - || defined(_M_IX86) \ - || defined(_X86_) \ - || defined(__X86__) ) -# undef CMFT_ARCH_32BIT -# define CMFT_ARCH_32BIT 1 -# undef CMFT_PTR_SIZE -# define CMFT_PTR_SIZE 4 -#else -# error Unsupported platform! -#endif - -#if (0 \ - || defined(__linux__) \ - || defined(linux) \ - || defined(__linux) \ - || defined(__gnu_linux__) ) -# undef CMFT_PLATFORM_LINUX -# define CMFT_PLATFORM_LINUX 1 -#elif (0 \ - || defined(__APPLE__) \ - || defined(macintosh) \ - || defined(Macintosh) ) -# undef CMFT_PLATFORM_APPLE -# define CMFT_PLATFORM_APPLE 1 -#elif (0 \ - || defined(_WIN16) \ - || defined(_WIN32) \ - || defined(_WIN64) \ - || defined(__WIN32__) \ - || defined(__TOS_WIN__) \ - || defined(__WINDOWS__) ) -# undef CMFT_PLATFORM_WINDOWS -# define CMFT_PLATFORM_WINDOWS 1 -#endif - -#if defined(__unix__) || defined(__unix) -# undef CMFT_PLATFORM_UNIX -# define CMFT_PLATFORM_UNIX 1 -#endif - -#undef CMFT_PLATFORM_POSIX -#define CMFT_PLATFORM_POSIX (CMFT_PLATFORM_LINUX || CMFT_PLATFORM_APPLE || CMFT_PLATFORM_UNIX) - -#undef CMFT_CPP11 -#define CMFT_CPP11 (__cplusplus >= 201103L) -#undef CMFT_CPP14 -#define CMFT_CPP14 (__cplusplus >= 201402L) - -#endif // CMFT_PLATFORM_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ - diff --git a/ext/cmft/common/print.cpp b/ext/cmft/common/print.cpp deleted file mode 100644 index 346adbcb..00000000 --- a/ext/cmft/common/print.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2014-2015 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#include "config.h" -#include -#include // ::printf - -namespace cmft -{ - PrintFunc printfWarning = ::printf; - PrintFunc printfInfo = ::printf; - - void setWarningPrintf(PrintFunc _printf) - { - printfWarning = _printf; - } - - void setInfoPrintf(PrintFunc _printf) - { - printfInfo = _printf; - } - -} // namespace cmft - -/* vim: set sw=4 ts=4 expandtab: */ diff --git a/ext/cmft/common/timer.h b/ext/cmft/common/timer.h deleted file mode 100644 index 3701c23b..00000000 --- a/ext/cmft/common/timer.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2016 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -/* - * Adapted from: https://github.com/bkaradzic/bx/include/bx/timer.h - * Copyright 2010-2016 Branimir Karadzic. All rights reserved. - * License: https://github.com/bkaradzic/bx#license-bsd-2-clause - */ -#ifndef CMFT_OS_H_HEADER_GUARD -#define CMFT_OS_H_HEADER_GUARD - -#include "platform.h" -#include - -#if CMFT_PLATFORM_WINDOWS -# include -#else -# include // gettimeofday -#endif // CMFT_PLATFORM_ - -namespace cmft -{ - inline int64_t getHPCounter() - { - #if CMFT_PLATFORM_WINDOWS - LARGE_INTEGER li; - // Performance counter value may unexpectedly leap forward - // http://support.microsoft.com/kb/274323 - QueryPerformanceCounter(&li); - int64_t i64 = li.QuadPart; - #else - struct timeval now; - gettimeofday(&now, 0); - int64_t i64 = now.tv_sec*INT64_C(1000000) + now.tv_usec; - #endif // CMFT_PLATFORM_ - - return i64; - } - - inline int64_t getHPFrequency() - { - #if CMFT_PLATFORM_WINDOWS - LARGE_INTEGER li; - QueryPerformanceFrequency(&li); - return li.QuadPart; - #else - return INT64_C(1000000); - #endif // CMFT_PLATFORM_ - } -} - -#endif // CMFT_OS_H_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ - diff --git a/ext/cmft/common/utils.h b/ext/cmft/common/utils.h deleted file mode 100644 index 43cce0a6..00000000 --- a/ext/cmft/common/utils.h +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright 2016 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#ifndef CMFT_CMFT_UTILS_H_HEADER_GUARD -#define CMFT_CMFT_UTILS_H_HEADER_GUARD - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(_WIN32) -# include -# define alloca _alloca -#else /* Unix */ -# include -#endif // defined(_WIN32) - -#include "platform.h" - -namespace cmft -{ - // Macros. - //----- - - #define CMFT_PATH_LEN 4096 - - #define RLOG2 1.4426950408889634f - - #define CMFT_MIN(_a, _b) ((_a)<(_b)?(_a):(_b)) - #define CMFT_MAX(_a, _b) ((_a)>(_b)?(_a):(_b)) - #define CMFT_CLAMP(_val, _min, _max) (CMFT_MIN(CMFT_MAX(_val, _min), _max)) - - #define CMFT_UNUSED(_expr) for (;;) { (void)(true ? (void)0 : ((void)(_expr))); break; } - - #define CMFT_STRINGIZE(_x) CMFT_STRINGIZE_(_x) - #define CMFT_STRINGIZE_(_x) #_x - - #define CMFT_CONCATENATE(_x, _y) CMFT_CONCATENATE_(_x, _y) - #define CMFT_CONCATENATE_(_x, _y) _x ## _y - - #define _FILE_LINE_ " " __FILE__ "(" CMFT_STRINGIZE(__LINE__) ")" - - #define CMFT_MAKEFOURCC(_a, _b, _c, _d) \ - ( ((uint32_t)(uint8_t)(_a)) \ - | ((uint32_t)(uint8_t)(_b) << 8) \ - | ((uint32_t)(uint8_t)(_c) << 16) \ - | ((uint32_t)(uint8_t)(_d) << 24) \ - ) - - #define CMFT_COUNTOF(arr) (sizeof(arr)/sizeof(0[arr])) - - // Pragma macros. - //----- - - #if CMFT_COMPILER_CLANG - # define CMFT_PRAGMA_DIAGNOSTIC_PUSH_CLANG_() _Pragma("clang diagnostic push") - # define CMFT_PRAGMA_DIAGNOSTIC_POP_CLANG_() _Pragma("clang diagnostic pop") - # define CMFT_PRAGMA_DIAGNOSTIC_IGNORED_CLANG(_x) _Pragma(CMFT_STRINGIZE(clang diagnostic ignored _x)) - #else - # define CMFT_PRAGMA_DIAGNOSTIC_PUSH_CLANG_() - # define CMFT_PRAGMA_DIAGNOSTIC_POP_CLANG_() - # define CMFT_PRAGMA_DIAGNOSTIC_IGNORED_CLANG(_x) - #endif // CMFT_COMPILER_CLANG - - #if CMFT_COMPILER_GCC - # define CMFT_PRAGMA_DIAGNOSTIC_PUSH_GCC_() _Pragma("GCC diagnostic push") - # define CMFT_PRAGMA_DIAGNOSTIC_POP_GCC_() _Pragma("GCC diagnostic pop") - # define CMFT_PRAGMA_DIAGNOSTIC_IGNORED_GCC(_x) _Pragma(CMFT_STRINGIZE(GCC diagnostic ignored _x)) - #else - # define CMFT_PRAGMA_DIAGNOSTIC_PUSH_GCC_() - # define CMFT_PRAGMA_DIAGNOSTIC_POP_GCC_() - # define CMFT_PRAGMA_DIAGNOSTIC_IGNORED_GCC(_x) - #endif // CMFT_COMPILER_GCC - - #if CMFT_COMPILER_MSVC - # define CMFT_PRAGMA_DIAGNOSTIC_PUSH_MSVC_() __pragma(warning(push)) - # define CMFT_PRAGMA_DIAGNOSTIC_POP_MSVC_() __pragma(warning(pop)) - # define CMFT_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(_x) __pragma(warning(disable:_x)) - #else - # define CMFT_PRAGMA_DIAGNOSTIC_PUSH_MSVC_() - # define CMFT_PRAGMA_DIAGNOSTIC_POP_MSVC_() - # define CMFT_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(_x) - #endif // CMFT_COMPILER_CLANG - - #if CMFT_COMPILER_CLANG - # define CMFT_PRAGMA_DIAGNOSTIC_PUSH CMFT_PRAGMA_DIAGNOSTIC_PUSH_CLANG_ - # define CMFT_PRAGMA_DIAGNOSTIC_POP CMFT_PRAGMA_DIAGNOSTIC_POP_CLANG_ - # define CMFT_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC CMFT_PRAGMA_DIAGNOSTIC_IGNORED_CLANG - #elif CMFT_COMPILER_GCC - # define CMFT_PRAGMA_DIAGNOSTIC_PUSH CMFT_PRAGMA_DIAGNOSTIC_PUSH_GCC_ - # define CMFT_PRAGMA_DIAGNOSTIC_POP CMFT_PRAGMA_DIAGNOSTIC_POP_GCC_ - # define CMFT_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC CMFT_PRAGMA_DIAGNOSTIC_IGNORED_GCC - #elif CMFT_COMPILER_MSVC - # define CMFT_PRAGMA_DIAGNOSTIC_PUSH CMFT_PRAGMA_DIAGNOSTIC_PUSH_MSVC_ - # define CMFT_PRAGMA_DIAGNOSTIC_POP CMFT_PRAGMA_DIAGNOSTIC_POP_MSVC_ - # define CMFT_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC(_x) - #endif // CMFT_COMPILER_ - - // Value. - //----- - - static inline float utof(uint32_t _u32) { return float(int32_t(_u32)); } - static inline uint32_t ftou(float _f) { return uint32_t(int32_t(_f)); } - - template - static inline void swap(Ty _a, Ty _b) - { - Ty c = _a; - _a = _b; - _b = c; - } - - static inline void swap(uint8_t* __restrict _a, uint8_t* __restrict _b, uint32_t _size) - { - uint8_t* c = (uint8_t*)alloca(_size); - memcpy( c, _a, _size); - memcpy(_a, _b, _size); - memcpy(_b, c, _size); - } - - static inline void swap(uint8_t* __restrict _a, uint8_t* __restrict _b, uint8_t* __restrict _tmp, uint32_t _size) - { - uint8_t* c = _tmp; - memcpy( c, _a, _size); - memcpy(_a, _b, _size); - memcpy(_b, c, _size); - } - - // Math. - //----- - - static inline float log2f(float _val) - { - return logf(_val)*RLOG2; - } - - static inline bool equals(float _a, float _b, float _epsilon = FLT_EPSILON) - { - return fabsf(_a - _b) < _epsilon; - } - - // Align. - //----- - - static inline uint32_t align(uint32_t _val, uint32_t _alignPwrTwo) - { - const uint32_t mask = _alignPwrTwo-UINT32_C(1); - return (_val+mask)&(~mask); - } - - static inline uint32_t alignf(float _val, uint32_t _align) - { - return uint32_t(_val/float(int32_t(_align)))*_align; - } - - // File. - //----- - - static inline long int fsize(FILE* _file) - { - long int pos = ftell(_file); - fseek(_file, 0L, SEEK_END); - long int size = ftell(_file); - fseek(_file, pos, SEEK_SET); - return size; - } - - // String. - //----- - - /// Case insensitive string compare. - inline int32_t stricmp(const char* _a, const char* _b) - { - #if defined(_MSC_VER) - return ::_stricmp(_a, _b); - #else - return ::strcasecmp(_a, _b); - #endif // BX_COMPILER_ - } - - static inline void strscpy(char* _dst, const char* _src, size_t _dstSize) - { - _dst[0] = '\0'; - if (NULL != _src) - { - strncat(_dst, _src, _dstSize-1); - } - } - - template - static inline void stracpy(char (&_dst)[DstSize], const char* _src) - { - strscpy(_dst, _src, DstSize); - } - - /// Notice: do NOT use return value of this function for memory deallocation! - static inline char* trim(char* _str) - { - char* beg = _str; - char* end = _str + strlen(_str)-1; - - // Point to the first non-whitespace character. - while (isspace(*beg)) { ++beg; } - - // If end is reached (_str contained all spaces), return. - if ('\0' == *beg) - { - return beg; - } - - // Point to the last non-whitespace character. - while (isspace(*end)) { --end; } - - // Add string terminator after non-whitespace character. - end[1] = '\0'; - - return beg; - } - - /// Find substring in string. Case insensitive. - inline const char* stristr(const char* _str, const char* _find) - { - const char* ptr = _str; - - for (size_t len = strlen(_str), searchLen = strlen(_find) - ; len >= searchLen - ; ++ptr, --len) - { - // Find start of the string. - while (tolower(*ptr) != tolower(*_find) ) - { - ++ptr; - --len; - - // Search pattern lenght can't be longer than the string. - if (searchLen > len) - { - return NULL; - } - } - - // Set pointers. - const char* string = ptr; - const char* search = _find; - - // Start comparing. - while (tolower(*string++) == tolower(*search++) ) - { - // If end of the 'search' string is reached, all characters match. - if ('\0' == *search) - { - return ptr; - } - } - } - - return NULL; - } - - /// Find substring in string. Case insensitive. Limit search to _max. - inline const char* stristr(const char* _str, const char* _find, size_t _max) - { - const char* ptr = _str; - - size_t stringLen = strnlen(_str, _max); - const size_t findLen = strlen(_find); - - for (; stringLen >= findLen; ++ptr, --stringLen) - { - // Find start of the string. - while (tolower(*ptr) != tolower(*_find) ) - { - ++ptr; - --stringLen; - - // Search pattern lenght can't be longer than the string. - if (findLen > stringLen) - { - return NULL; - } - } - - // Set pointers. - const char* string = ptr; - const char* search = _find; - - // Start comparing. - while (tolower(*string++) == tolower(*search++) ) - { - // If end of the 'search' string is reached, all characters match. - if ('\0' == *search) - { - return ptr; - } - } - } - - return NULL; - } - - /// Appends src to string dst of size siz (unlike strncat, siz is the - /// full size of dst, not space left). At most siz-1 characters - /// will be copied. Always NUL terminates (unless siz <= strlen(dst)). - /// Returns strlen(src) + MIN(siz, strlen(initial dst)). - /// If retval >= siz, truncation occurred. - inline size_t strlcat(char* _dst, const char* _src, size_t _siz) - { - char* dd = _dst; - const char *s = _src; - size_t nn = _siz; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (nn-- != 0 && *dd != '\0') - { - dd++; - } - - dlen = dd - _dst; - nn = _siz - dlen; - - if (nn == 0) - { - return(dlen + strlen(s)); - } - - while (*s != '\0') - { - if (nn != 1) - { - *dd++ = *s; - nn--; - } - s++; - } - *dd = '\0'; - - return(dlen + (s - _src)); /* count does not include NUL */ - } - - /// Find substring in string. Limit search to _size. - inline const char* strnstr(const char* _str, const char* _find, size_t _size) - { - char first = *_find; - if ('\0' == first) - { - return _str; - } - - const char* cmp = _find + 1; - size_t len = strlen(cmp); - do - { - for (char match = *_str++; match != first && 0 < _size; match = *_str++, --_size) - { - if ('\0' == match) - { - return NULL; - } - } - - if (0 == _size) - { - return NULL; - } - - } while (0 != strncmp(_str, cmp, len) ); - - return --_str; - } - - /// Find end of line. Retuns pointer to new line terminator. - inline const char* streol(const char* _str) - { - for (; '\0' != *_str; _str += strnlen(_str, 1024) ) - { - const char* eol = strnstr(_str, "\r\n", 1024); - if (NULL != eol) - { - return eol; - } - - eol = strnstr(_str, "\n", 1024); - if (NULL != eol) - { - return eol; - } - } - - return _str; - } - - /// Find new line. Returns pointer after new line terminator. - inline const char* strnl(const char* _str) - { - for (; '\0' != *_str; _str += strnlen(_str, 1024) ) - { - const char* eol = strnstr(_str, "\r\n", 1024); - if (NULL != eol) - { - return eol + 2; - } - - eol = strnstr(_str, "\n", 1024); - if (NULL != eol) - { - return eol + 1; - } - } - - return _str; - } - - static inline void strtolower(char* _out, char* _in) - { - while (*_in) { *_out++ = (char)tolower(*_in++); } - *_out = '\0'; - } - - static inline void strtoupper(char* _out, char* _in) - { - while (*_in) { *_out++ = (char)toupper(*_in++); } - *_out = '\0'; - } - - static inline void strtolower(char* _str) - { - for (; *_str; ++_str) - { - *_str = (char)tolower(*_str); - } - } - - static inline void strtoupper(char* _str) - { - for (; *_str; ++_str) - { - *_str = (char)toupper(*_str); - } - } - - static inline int32_t vsnprintf(char* _str, size_t _count, const char* _format, va_list _argList) - { - #if CMFT_COMPILER_MSVC - int32_t len = ::vsnprintf_s(_str, _count, size_t(-1), _format, _argList); - return -1 == len ? ::_vscprintf(_format, _argList) : len; - #else - return ::vsnprintf(_str, _count, _format, _argList); - #endif // CMFT_COMPILER_MSVC - } - - static inline int32_t snprintf(char* _str, size_t _count, const char* _format, ...) - { - va_list argList; - va_start(argList, _format); - int32_t len = vsnprintf(_str, _count, _format, argList); - va_end(argList); - return len; - } - - // Path. - //----- - - /// Gets file name without extension from file path. Examples: - /// /tmp/foo.c -> foo - /// C:\\tmp\\foo.c -> foo - static inline bool basename(char* _out, size_t _outSize, const char* _filePath) - { - const char* begin; - const char* end; - - const char* ptr; - begin = NULL != (ptr = strrchr(_filePath, '\\')) ? ++ptr - : NULL != (ptr = strrchr(_filePath, '/' )) ? ++ptr - : _filePath - ; - - end = NULL != (ptr = strrchr(_filePath, '.')) ? ptr : strrchr(_filePath, '\0'); - - if (NULL != begin && NULL != end) - { - const size_t size = CMFT_MIN(size_t(end-begin)+1, _outSize); - cmft::strscpy(_out, begin, size); - return true; - } - - return false; - } - - // Endianess. - //----- - - inline uint16_t endianSwap(uint16_t _in) - { - return (_in>>8) | (_in<<8); - } - - inline uint32_t endianSwap(uint32_t _in) - { - return (_in>>24) | (_in<<24) - | ((_in&0x00ff0000)>>8) | ((_in&0x0000ff00)<<8) - ; - } - - inline uint64_t endianSwap(uint64_t _in) - { - return (_in>>56) | (_in<<56) - | ((_in&UINT64_C(0x00ff000000000000))>>40) | ((_in&UINT64_C(0x000000000000ff00))<<40) - | ((_in&UINT64_C(0x0000ff0000000000))>>24) | ((_in&UINT64_C(0x0000000000ff0000))<<24) - | ((_in&UINT64_C(0x000000ff00000000))>>8 ) | ((_in&UINT64_C(0x00000000ff000000))<<8 ) - ; - } - - // Scope. - //----- - - struct ScopeFclose - { - ScopeFclose(FILE* _fp) { m_fp = _fp; } - ~ScopeFclose() { if (NULL != m_fp) { fclose(m_fp); } } - - private: - FILE* m_fp; - }; -} - -#endif // CMFT_CMFT_UTILS_H_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ diff --git a/ext/cmft/cubemaputils.h b/ext/cmft/cubemaputils.h deleted file mode 100644 index 81a5a5a4..00000000 --- a/ext/cmft/cubemaputils.h +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright 2014-2015 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#ifndef CMFT_CUBEMAPUTILS_H_HEADER_GUARD -#define CMFT_CUBEMAPUTILS_H_HEADER_GUARD - -#include "common/fpumath.h" - -namespace cmft -{ - #define CMFT_PI 3.14159265358979323846f - #define CMFT_RPI 0.31830988618379067153f - #define CMFT_2PI 6.28318530717958647692f - #define CMFT_DEGTORAD 0.01745329251994329576f - #define CMFT_RADTODEG 57.2957795130823208767f - - /// - /// - /// +----------+ - /// | +---->+x | - /// | | | - /// | | +y | - /// |+z 2 | - /// +----------+----------+----------+----------+ - /// | +---->+z | +---->+x | +---->-z | +---->-x | - /// | | | | | | | | | - /// | | -x | | +z | | +x | | -z | - /// |-y 1 |-y 4 |-y 0 |-y 5 | - /// +----------+----------+----------+----------+ - /// | +---->+x | - /// | | | - /// | | -y | - /// |-z 3 | - /// +----------+ - /// - static const float s_faceUvVectors[6][3][3] = - { - { // +x face - { 0.0f, 0.0f, -1.0f }, // u -> -z - { 0.0f, -1.0f, 0.0f }, // v -> -y - { 1.0f, 0.0f, 0.0f }, // +x face - }, - { // -x face - { 0.0f, 0.0f, 1.0f }, // u -> +z - { 0.0f, -1.0f, 0.0f }, // v -> -y - { -1.0f, 0.0f, 0.0f }, // -x face - }, - { // +y face - { 1.0f, 0.0f, 0.0f }, // u -> +x - { 0.0f, 0.0f, 1.0f }, // v -> +z - { 0.0f, 1.0f, 0.0f }, // +y face - }, - { // -y face - { 1.0f, 0.0f, 0.0f }, // u -> +x - { 0.0f, 0.0f, -1.0f }, // v -> -z - { 0.0f, -1.0f, 0.0f }, // -y face - }, - { // +z face - { 1.0f, 0.0f, 0.0f }, // u -> +x - { 0.0f, -1.0f, 0.0f }, // v -> -y - { 0.0f, 0.0f, 1.0f }, // +z face - }, - { // -z face - { -1.0f, 0.0f, 0.0f }, // u -> -x - { 0.0f, -1.0f, 0.0f }, // v -> -y - { 0.0f, 0.0f, -1.0f }, // -z face - } - }; - - enum - { - CMFT_FACE_POS_X = 0, - CMFT_FACE_NEG_X = 1, - CMFT_FACE_POS_Y = 2, - CMFT_FACE_NEG_Y = 3, - CMFT_FACE_POS_Z = 4, - CMFT_FACE_NEG_Z = 5, - }; - - enum - { - CMFT_EDGE_LEFT = 0, - CMFT_EDGE_RIGHT = 1, - CMFT_EDGE_TOP = 2, - CMFT_EDGE_BOTTOM = 3, - }; - - /// - /// --> U _____ - /// | | | - /// v | +Y | - /// V _____|_____|_____ _____ - /// | | | | | - /// | -X | +Z | +X | -Z | - /// |_____|_____|_____|_____| - /// | | - /// | -Y | - /// |_____| - /// - /// Neighbour faces in order: left, right, top, bottom. - /// FaceEdge is the edge that belongs to the neighbour face. - static const struct CubeFaceNeighbour - { - uint8_t m_faceIdx; - uint8_t m_faceEdge; - } s_cubeFaceNeighbours[6][4] = - { - { //POS_X - { CMFT_FACE_POS_Z, CMFT_EDGE_RIGHT }, - { CMFT_FACE_NEG_Z, CMFT_EDGE_LEFT }, - { CMFT_FACE_POS_Y, CMFT_EDGE_RIGHT }, - { CMFT_FACE_NEG_Y, CMFT_EDGE_RIGHT }, - }, - { //NEG_X - { CMFT_FACE_NEG_Z, CMFT_EDGE_RIGHT }, - { CMFT_FACE_POS_Z, CMFT_EDGE_LEFT }, - { CMFT_FACE_POS_Y, CMFT_EDGE_LEFT }, - { CMFT_FACE_NEG_Y, CMFT_EDGE_LEFT }, - }, - { //POS_Y - { CMFT_FACE_NEG_X, CMFT_EDGE_TOP }, - { CMFT_FACE_POS_X, CMFT_EDGE_TOP }, - { CMFT_FACE_NEG_Z, CMFT_EDGE_TOP }, - { CMFT_FACE_POS_Z, CMFT_EDGE_TOP }, - }, - { //NEG_Y - { CMFT_FACE_NEG_X, CMFT_EDGE_BOTTOM }, - { CMFT_FACE_POS_X, CMFT_EDGE_BOTTOM }, - { CMFT_FACE_POS_Z, CMFT_EDGE_BOTTOM }, - { CMFT_FACE_NEG_Z, CMFT_EDGE_BOTTOM }, - }, - { //POS_Z - { CMFT_FACE_NEG_X, CMFT_EDGE_RIGHT }, - { CMFT_FACE_POS_X, CMFT_EDGE_LEFT }, - { CMFT_FACE_POS_Y, CMFT_EDGE_BOTTOM }, - { CMFT_FACE_NEG_Y, CMFT_EDGE_TOP }, - }, - { //NEG_Z - { CMFT_FACE_POS_X, CMFT_EDGE_RIGHT }, - { CMFT_FACE_NEG_X, CMFT_EDGE_LEFT }, - { CMFT_FACE_POS_Y, CMFT_EDGE_TOP }, - { CMFT_FACE_NEG_Y, CMFT_EDGE_BOTTOM }, - } - }; - - /// _u and _v should be center adressing and in [-1.0+invSize..1.0-invSize] range. - static inline void texelCoordToVec(float* _out3f, float _u, float _v, uint8_t _faceId) - { - // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. - _out3f[0] = s_faceUvVectors[_faceId][0][0] * _u + s_faceUvVectors[_faceId][1][0] * _v + s_faceUvVectors[_faceId][2][0]; - _out3f[1] = s_faceUvVectors[_faceId][0][1] * _u + s_faceUvVectors[_faceId][1][1] * _v + s_faceUvVectors[_faceId][2][1]; - _out3f[2] = s_faceUvVectors[_faceId][0][2] * _u + s_faceUvVectors[_faceId][1][2] * _v + s_faceUvVectors[_faceId][2][2]; - - // Normalize. - const float invLen = 1.0f/sqrtf(_out3f[0]*_out3f[0] + _out3f[1]*_out3f[1] + _out3f[2]*_out3f[2]); - _out3f[0] *= invLen; - _out3f[1] *= invLen; - _out3f[2] *= invLen; - } - - /// Notice: _faceSize should not be equal to one! - static inline float warpFixupFactor(float _faceSize) - { - // Edge fixup. - // Based on Nvtt : http://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvtt/CubeSurface.cpp - if (_faceSize == 1.0f) - { - return 1.0f; - } - - const float fs = _faceSize; - const float fsmo = fs - 1.0f; - return (fs*fs) / (fsmo*fsmo*fsmo); - } - - /// _u and _v should be center adressing and in [-1.0+invSize..1.0-invSize] range. - static inline void texelCoordToVecWarp(float* _out3f, float _u, float _v, uint8_t _faceId, float _warpFixup) - { - _u = (_warpFixup * _u*_u*_u) + _u; - _v = (_warpFixup * _v*_v*_v) + _v; - - texelCoordToVec(_out3f, _u, _v, _faceId); - } - - /// _u and _v are in [0.0 .. 1.0] range. - static inline void vecToTexelCoord(float& _u, float& _v, uint8_t& _faceIdx, const float* _vec) - { - const float absVec[3] = - { - fabsf(_vec[0]), - fabsf(_vec[1]), - fabsf(_vec[2]), - }; - const float max = fmaxf(fmaxf(absVec[0], absVec[1]), absVec[2]); - - // Get face id (max component == face vector). - if (max == absVec[0]) - { - _faceIdx = (_vec[0] >= 0.0f) ? uint8_t(CMFT_FACE_POS_X) : uint8_t(CMFT_FACE_NEG_X); - } - else if (max == absVec[1]) - { - _faceIdx = (_vec[1] >= 0.0f) ? uint8_t(CMFT_FACE_POS_Y) : uint8_t(CMFT_FACE_NEG_Y); - } - else //if (max == absVec[2]) - { - _faceIdx = (_vec[2] >= 0.0f) ? uint8_t(CMFT_FACE_POS_Z) : uint8_t(CMFT_FACE_NEG_Z); - } - - // Divide by max component. - float faceVec[3]; - vec3Mul(faceVec, _vec, 1.0f/max); - - // Project other two components to face uv basis. - _u = (vec3Dot(s_faceUvVectors[_faceIdx][0], faceVec) + 1.0f) * 0.5f; - _v = (vec3Dot(s_faceUvVectors[_faceIdx][1], faceVec) + 1.0f) * 0.5f; - } - - static inline void latLongFromVec(float& _u, float& _v, const float _vec[3]) - { - const float phi = atan2f(_vec[0], _vec[2]); - const float theta = acosf(_vec[1]); - - _u = (CMFT_PI + phi)*(0.5f/CMFT_PI); - _v = theta*CMFT_RPI; - } - - static inline void vecFromLatLong(float _vec[3], float _u, float _v) - { - const float phi = _u * CMFT_2PI; - const float theta = _v * CMFT_PI; - - _vec[0] = -sinf(theta)*sinf(phi); - _vec[1] = cosf(theta); - _vec[2] = -sinf(theta)*cosf(phi); - } - - // Assume normalized _vec. - // Output is on [0, 1] for each component - static inline void octantFromVec(float& _u, float& _v, const float _vec[3]) - { - // Project the sphere onto the octahedron, and then onto the xy plane. - float dot = fabsf(_vec[0]) + fabsf(_vec[1]) + fabsf(_vec[2]); - float px = _vec[0] / dot; - float py = _vec[2] / dot; - - // Reflect the folds of the lower hemisphere over the diagonals. - if (_vec[1] <= 0.0f) - { - _u = ((1.0f - fabsf(py)) * fsign(px)); - _v = ((1.0f - fabsf(px)) * fsign(py)); - } - else - { - _u = px; - _v = py; - } - - _u = _u * 0.5f + 0.5f; - _v = _v * 0.5f + 0.5f; - } - - static inline void vecFromOctant(float _vec[3], float _u, float _v) - { - _u = _u*2.0f - 1.0f; - _v = _v*2.0f - 1.0f; - - _vec[1] = 1.0f - fabsf(_u) - fabsf(_v); - - if (_vec[1] < 0.0f) - { - _vec[0] = (1.0f - fabsf(_v)) * fsign(_u); - _vec[2] = (1.0f - fabsf(_u)) * fsign(_v); - } - else - { - _vec[0] = _u; - _vec[2] = _v; - } - - const float invLen = 1.0f/vec3Length(_vec); - _vec[0] *= invLen; - _vec[1] *= invLen; - _vec[2] *= invLen; - } - - /// http://www.mpia-hd.mpg.de/~mathar/public/mathar20051002.pdf - /// http://www.rorydriscoll.com/2012/01/15/cubemap-texel-solid-angle/ - static inline float areaElement(float _x, float _y) - { - return atan2f(_x*_y, sqrtf(_x*_x + _y*_y + 1.0f)); - } - - /// _u and _v should be center adressing and in [-1.0+invSize..1.0-invSize] range. - static inline float texelSolidAngle(float _u, float _v, float _invFaceSize) - { - // Specify texel area. - const float x0 = _u - _invFaceSize; - const float x1 = _u + _invFaceSize; - const float y0 = _v - _invFaceSize; - const float y1 = _v + _invFaceSize; - - // Compute solid angle of texel area. - const float solidAngle = areaElement(x1, y1) - - areaElement(x0, y1) - - areaElement(x1, y0) - + areaElement(x0, y0) - ; - - return solidAngle; - } - -} // namespace cmft - -#endif //CMFT_CUBEMAPUTILS_H_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ diff --git a/ext/cmft/image.cpp b/ext/cmft/image.cpp deleted file mode 100644 index b2e38619..00000000 --- a/ext/cmft/image.cpp +++ /dev/null @@ -1,5948 +0,0 @@ -/* - * Copyright 2014-2016 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#include -#include - -#include "common/config.h" -#include "common/utils.h" -#include "common/halffloat.h" -#include "stb_image.h" - -#include "cubemaputils.h" - -#include - -namespace cmft -{ - // Read/write. - //----- - - struct RwError - { - enum Enum - { - None, - Open, - Read, - Write, - Eof, - }; - }; - - struct RwType - { - enum Enum - { - Memory, - FilePath, - }; - }; - - struct Rw - { - uint8_t m_error; - uint8_t m_type; - union - { - struct - { - const char* m_path; - FILE* m_file; - }; - - struct - { - void* m_mem; - size_t m_size; - size_t m_offset; - }; - }; - }; - - struct Whence - { - enum Enum - { - Begin, - Current, - End, - }; - }; - - typedef int64_t (*RwSeekFn)(Rw* _rw, int64_t _offset, Whence::Enum _whence); - typedef size_t (*RwReadFn)(Rw* _rw, void* _data, size_t _size); - - void rwInit(Rw* _rw, const char* _path); - void rwInit(Rw* _rw, FILE* _file); - void rwInit(Rw* _rw, void* _mem, size_t _size); - bool rwFileOpen(Rw* _rw, const char* _mode = "rb"); - bool rwFileOpened(const Rw* _rw); - void rwFileClose(Rw* _rw); - uint8_t rwGetError(Rw* _rw); - void rwClearError(Rw* _rw); - RwSeekFn rwSeekFnFor(const Rw* _rw); - RwReadFn rwReadFnFor(const Rw* _rw); - - struct RwScopeFileClose - { - RwScopeFileClose(Rw* _rw, bool _condition = true) - { - m_rw = _rw; - m_condition = _condition; - } - - ~RwScopeFileClose() - { - if (m_condition) - { - rwFileClose(m_rw); - } - } - private: - Rw* m_rw; - bool m_condition; - }; - - void rwInit(Rw* _rw, void* _mem, size_t _size) - { - _rw->m_error = RwError::None; - _rw->m_type = RwType::Memory; - _rw->m_mem = _mem; - _rw->m_size = _size; - } - - void rwInit(Rw* _rw, FILE* _file) - { - _rw->m_error = RwError::None; - _rw->m_type = RwType::FilePath; - _rw->m_path = NULL; - _rw->m_file = _file; - } - - void rwInit(Rw* _rw, const char* _path) - { - _rw->m_error = RwError::None; - _rw->m_type = RwType::FilePath; - _rw->m_path = _path; - _rw->m_file = NULL; - } - - bool rwFileOpen(Rw* _rw, const char* _mode) - { - if (RwType::FilePath == _rw->m_type - && NULL == _rw->m_file) - { - FILE* file = fopen(_rw->m_path, _mode); - if (NULL != file) - { - _rw->m_error = 0; - _rw->m_file = file; - - return true; - } - else - { - _rw->m_error = RwError::Open; // Error opening file. - - return false; - } - } - - return false; - } - - bool rwFileOpened(const Rw* _rw) - { - return (NULL != _rw->m_file); - } - - void rwFileClose(Rw* _rw) - { - if (NULL != _rw->m_file) - { - int result = fclose(_rw->m_file); - if (0 == result) - { - _rw->m_file = NULL; - } - else - { - _rw->m_error = RwError::Eof; // Error closing file. - } - } - } - - uint8_t rwGetError(Rw* _rw) - { - return _rw->m_error; - } - - void rwClearError(Rw* _rw) - { - _rw->m_error = 0; - } - - #if CMFT_COMPILER_MSVC - # define fseeko64 _fseeki64 - # define ftello64 _ftelli64 - #elif CMFT_PLATFORM_APPLE - # define fseeko64 fseeko - # define ftello64 ftello - #endif // CMFT_ - - int64_t rwSeekFile(Rw* _rw, int64_t _offset = 0, Whence::Enum _whence = Whence::Current) - { - fseeko64(_rw->m_file, _offset, _whence); - return ftello64(_rw->m_file); - } - - int64_t rwSeekMem(Rw* _rw, int64_t _offset = 0, Whence::Enum _whence = Whence::Current) - { - int64_t offset; - if (Whence::Begin == _whence) - { - offset = _offset; - } - else if (Whence::Current == _whence) - { - offset = int64_t(_rw->m_offset) + _offset; - } - else /*.if (Whence::End == _whence).*/ - { - offset = int64_t(_rw->m_size) - _offset; - } - offset = CMFT_CLAMP(offset, 0, int64_t(_rw->m_size)); - - _rw->m_offset = offset; - - return offset; - } - - RwSeekFn rwSeekFnFor(const Rw* _rw) - { - if (RwType::Memory == _rw->m_type) - { - return rwSeekMem; - } - else - { - return rwSeekFile; - } - } - - size_t rwReadFile(Rw* _src, void* _data, size_t _size) - { - const size_t size = fread(_data, 1, _size, _src->m_file); - if (size != _size) - { - if (0 != feof(_src->m_file)) - { - _src->m_error = RwError::Eof; - } - else if (0 != ferror(_src->m_file)) - { - _src->m_error = RwError::Read; - } - } - - return size; - } - - size_t rwReadMem(Rw* _rw, void* _data, size_t _size) - { - const size_t remainder = _rw->m_size - _rw->m_offset; - const size_t sizeToRead = _size < remainder ? _size : remainder; - if (_size != sizeToRead) - { - _rw->m_error = RwError::Read; // Size truncated. - } - _rw->m_offset += sizeToRead; - - memcpy(_data, _rw->m_mem, sizeToRead); - - return sizeToRead; - } - - RwReadFn rwReadFnFor(const Rw* _rw) - { - if (RwType::Memory == _rw->m_type) - { - return rwReadMem; - } - else - { - return rwReadFile; - } - } - - // Texture format string. - //----- - - static const char* s_textureFormatStr[TextureFormat::Count] = - { - "BGR8", //BGR8 - "RGB8", //RGB8 - "RGB16", //RGB16 - "RGB16F", //RGB16F - "RGB32F", //RGB32F - "RGBE", //RGBE - "BGRA8", //BGRA8 - "RGBA8", //RGBA8 - "RGBA16", //RGBA16 - "RGBA16F", //RGBA16F - "RGBA32F", //RGBA32F - "RGBM", //RGBM - }; - - const char* getTextureFormatStr(TextureFormat::Enum _format) - { - DEBUG_CHECK(_format < TextureFormat::Count, "Reading array out of bounds!"); - return s_textureFormatStr[uint8_t(_format)]; - } - - // Image file type extension. - //----- - - static const char* s_imageFileTypeExtension[ImageFileType::Count] = - { - ".dds", //DDS - ".ktx", //KTX - ".tga", //TGA - ".hdr", //HDR - }; - - const char* getFilenameExtensionStr(ImageFileType::Enum _ft) - { - DEBUG_CHECK(_ft < ImageFileType::Count, "Reading array out of bounds!"); - return s_imageFileTypeExtension[uint8_t(_ft)]; - } - - // Image file type name. - //----- - - static const char* s_imageFileTypeName[ImageFileType::Count] = - { - "DDS", //DDS - "KTX", //KTX - "TGA", //TGA - "HDR", //HDR - }; - - const char* getFileTypeStr(ImageFileType::Enum _ft) - { - DEBUG_CHECK(_ft < ImageFileType::Count, "Reading array out of bounds!"); - return s_imageFileTypeName[uint8_t(_ft)]; - } - - // Image output type name. - //----- - - static const char* s_outputTypeStr[OutputType::Count] = - { - "LatLong", - "Cubemap", - "HCross", - "VCross", - "HStrip", - "VStrip", - "FaceList", - "Octant", - }; - - const char* getOutputTypeStr(OutputType::Enum _outputType) - { - DEBUG_CHECK(_outputType < OutputType::Count, "Reading array out of bounds!"); - return s_outputTypeStr[uint8_t(_outputType)]; - } - - // Cubemap faceId names. - //----- - - static const char* s_cubemapFaceIdStr[6] = - { - "posx", - "negx", - "posy", - "negy", - "posz", - "negz", - }; - - const char* getCubemapFaceIdStr(uint8_t _face) - { - DEBUG_CHECK(_face < 6, "Reading array out of bounds!"); - return s_cubemapFaceIdStr[_face]; - } - - - // Valid output types. - //----- - - static const OutputType::Enum s_ddsValidOutputTypes[] = - { - OutputType::LatLong, - OutputType::Cubemap, - OutputType::HCross, - OutputType::VCross, - OutputType::HStrip, - OutputType::VStrip, - OutputType::FaceList, - OutputType::Octant, - OutputType::Null, - }; - - static const OutputType::Enum s_ktxValidOutputTypes[] = - { - OutputType::LatLong, - OutputType::Cubemap, - OutputType::HCross, - OutputType::VCross, - OutputType::HStrip, - OutputType::VStrip, - OutputType::FaceList, - OutputType::Octant, - OutputType::Null, - }; - - static const OutputType::Enum s_tgaValidOutputTypes[] = - { - OutputType::LatLong, - OutputType::HCross, - OutputType::VCross, - OutputType::HStrip, - OutputType::VStrip, - OutputType::FaceList, - OutputType::Octant, - OutputType::Null, - }; - - static const OutputType::Enum s_hdrValidOutputTypes[] = - { - OutputType::LatLong, - OutputType::HCross, - OutputType::VCross, - OutputType::HStrip, - OutputType::VStrip, - OutputType::FaceList, - OutputType::Octant, - OutputType::Null, - }; - - const OutputType::Enum* getValidOutputTypes(ImageFileType::Enum _fileType) - { - if (ImageFileType::DDS == _fileType) - { - return s_ddsValidOutputTypes; - } - else if (ImageFileType::KTX == _fileType) - { - return s_ktxValidOutputTypes; - } - else if (ImageFileType::TGA == _fileType) - { - return s_tgaValidOutputTypes; - } - else if (ImageFileType::HDR == _fileType) - { - return s_hdrValidOutputTypes; - } - else - { - return NULL; - } - } - - void getValidOutputTypesStr(char* _str, ImageFileType::Enum _fileType) - { - const OutputType::Enum* validOutputTypes = getValidOutputTypes(_fileType); - if (NULL == validOutputTypes) - { - _str[0] = '\0'; - return; - } - - uint8_t ii = 0; - OutputType::Enum curr; - if (OutputType::Null != (curr = validOutputTypes[ii++])) - { - strcpy(_str, getOutputTypeStr(curr)); - } - while (OutputType::Null != (curr = validOutputTypes[ii++])) - { - strcat(_str, " "); - strcat(_str, getOutputTypeStr(curr)); - } - } - - static bool contains(OutputType::Enum _format, const OutputType::Enum* _formatList) - { - OutputType::Enum curr; - uint8_t ii = 0; - while (OutputType::Null != (curr = _formatList[ii++])) - { - if (curr == _format) - { - return true; - } - } - - return false; - }; - - bool checkValidOutputType(ImageFileType::Enum _fileType, OutputType::Enum _outputType) - { - if (ImageFileType::DDS == _fileType) - { - return contains(_outputType, s_ddsValidOutputTypes); - } - else if (ImageFileType::KTX == _fileType) - { - return contains(_outputType, s_ktxValidOutputTypes); - } - else if (ImageFileType::TGA == _fileType) - { - return contains(_outputType, s_tgaValidOutputTypes); - } - else if (ImageFileType::HDR == _fileType) - { - return contains(_outputType, s_hdrValidOutputTypes); - } - - return false; - } - - // Valid texture formats. - //----- - - static const TextureFormat::Enum s_ddsValidFormats[] = - { - TextureFormat::BGR8, - TextureFormat::BGRA8, - TextureFormat::RGBA16, - TextureFormat::RGBA16F, - TextureFormat::RGBA32F, - TextureFormat::RGBM, - TextureFormat::Null, - }; - - static const TextureFormat::Enum s_ktxValidFormats[] = - { - TextureFormat::RGB8, - TextureFormat::RGB16, - TextureFormat::RGB16F, - TextureFormat::RGB32F, - TextureFormat::RGBA8, - TextureFormat::RGBA16, - TextureFormat::RGBA16F, - TextureFormat::RGBA32F, - TextureFormat::Null, - }; - - static const TextureFormat::Enum s_tgaValidFormats[] = - { - TextureFormat::BGR8, - TextureFormat::BGRA8, - TextureFormat::RGBM, - TextureFormat::Null, - }; - - static const TextureFormat::Enum s_hdrValidFormats[] = - { - TextureFormat::RGBE, - TextureFormat::Null, - }; - - const TextureFormat::Enum* getValidTextureFormats(ImageFileType::Enum _fileType) - { - if (ImageFileType::DDS == _fileType) - { - return s_ddsValidFormats; - } - else if (ImageFileType::KTX == _fileType) - { - return s_ktxValidFormats; - } - else if (ImageFileType::TGA == _fileType) - { - return s_tgaValidFormats; - } - else if (ImageFileType::HDR == _fileType) - { - return s_hdrValidFormats; - } - else - { - return NULL; - } - } - - void getValidTextureFormatsStr(char* _str, ImageFileType::Enum _fileType) - { - const TextureFormat::Enum* validFormatsList = getValidTextureFormats(_fileType); - if (NULL == validFormatsList) - { - _str[0] = '\0'; - return; - } - - uint8_t ii = 0; - TextureFormat::Enum curr; - if (TextureFormat::Null != (curr = validFormatsList[ii++])) - { - strcpy(_str, getTextureFormatStr(curr)); - } - while (TextureFormat::Null != (curr = validFormatsList[ii++])) - { - strcat(_str, " "); - strcat(_str, getTextureFormatStr(curr)); - } - } - - static bool contains(TextureFormat::Enum _format, const TextureFormat::Enum* _formatList) - { - TextureFormat::Enum curr; - uint8_t ii = 0; - while (TextureFormat::Null != (curr = _formatList[ii++])) - { - if (curr == _format) - { - return true; - } - } - - return false; - }; - - bool checkValidTextureFormat(ImageFileType::Enum _fileType, TextureFormat::Enum _textureFormat) - { - if (ImageFileType::DDS == _fileType) - { - return contains(_textureFormat, s_ddsValidFormats); - } - else if (ImageFileType::KTX == _fileType) - { - return contains(_textureFormat, s_ktxValidFormats); - } - else if (ImageFileType::TGA == _fileType) - { - return contains(_textureFormat, s_tgaValidFormats); - } - else if (ImageFileType::HDR == _fileType) - { - return contains(_textureFormat, s_hdrValidFormats); - } - - return false; - } - - // Image data info. - //----- - - struct PixelDataType - { - enum Enum - { - UINT8, - UINT16, - UINT32, - HALF_FLOAT, - FLOAT, - - Count, - }; - }; - - static const ImageDataInfo s_imageDataInfo[TextureFormat::Count] = - { - { 3, 3, 0, PixelDataType::UINT8 }, //BGR8 - { 3, 3, 0, PixelDataType::UINT8 }, //RGB8 - { 6, 3, 0, PixelDataType::UINT16 }, //RGB16 - { 6, 3, 0, PixelDataType::HALF_FLOAT }, //RGB16F - { 12, 3, 0, PixelDataType::FLOAT }, //RGB32F - { 4, 4, 0, PixelDataType::UINT8 }, //RGBE - { 4, 4, 1, PixelDataType::UINT8 }, //BGRA8 - { 4, 4, 1, PixelDataType::UINT8 }, //RGBA8 - { 8, 4, 1, PixelDataType::UINT16 }, //RGBA16 - { 8, 4, 1, PixelDataType::HALF_FLOAT }, //RGBA16F - { 16, 4, 1, PixelDataType::FLOAT }, //RGBA32F - }; - - const ImageDataInfo& getImageDataInfo(TextureFormat::Enum _format) - { - DEBUG_CHECK(_format < TextureFormat::Count, "Reading array out of bounds!"); - return s_imageDataInfo[_format]; - } - - uint8_t getNaturalAlignment(TextureFormat::Enum _format) - { - const uint8_t bytesPerPixel = getImageDataInfo(_format).m_bytesPerPixel; - const uint8_t numChannels = getImageDataInfo(_format).m_numChanels; - - return bytesPerPixel/numChannels; - } - - // HDR format. - //----- - - #define HDR_VALID_PROGRAMTYPE 0x01 - #define HDR_VALID_GAMMA 0x02 - #define HDR_VALID_EXPOSURE 0x04 - #define HDR_MAGIC CMFT_MAKEFOURCC('#','?','R','A') - #define HDR_MAGIC_FULL "#?RADIANCE" - #define HDR_MAGIC_LEN 10 - - struct HdrHeader - { - int m_valid; - float m_gamma; - float m_exposure; - }; - - // TGA format. - //----- - - #define TGA_HEADER_SIZE 18 - #define TGA_ID { 'T', 'R', 'U', 'E', 'V', 'I', 'S', 'I', 'O', 'N', '-', 'X', 'F', 'I', 'L', 'E', '.', '\0' } - #define TGA_ID_LEN 18 - #define TGA_FOOTER_SIZE 26 - - #define TGA_IT_NOIMAGE 0x0 - #define TGA_IT_COLORMAPPED 0x1 - #define TGA_IT_RGB 0x2 - #define TGA_IT_BW 0x3 - #define TGA_IT_RLE 0x8 - - #define TGA_DESC_HORIZONTAL 0x10 - #define TGA_DESC_VERTICAL 0x20 - - struct TgaHeader - { - uint8_t m_idLength; - uint8_t m_colorMapType; - uint8_t m_imageType; - int16_t m_colorMapOrigin; - int16_t m_colorMapLength; - uint8_t m_colorMapDepth; - int16_t m_xOrigin; - int16_t m_yOrigin; - uint16_t m_width; - uint16_t m_height; - uint8_t m_bitsPerPixel; - uint8_t m_imageDescriptor; - }; - - struct TgaFooter - { - uint32_t m_extensionOffset; - uint32_t m_developerOffset; - uint8_t m_signature[18]; - }; - - // DDS format. - //----- - - #define DDS_MAGIC CMFT_MAKEFOURCC('D', 'D', 'S', ' ') - #define DDS_HEADER_SIZE 124 - #define DDS_IMAGE_DATA_OFFSET (DDS_HEADER_SIZE + 4) - #define DDS_PIXELFORMAT_SIZE 32 - #define DDS_DX10_HEADER_SIZE 20 - - #define DDS_DXT1 CMFT_MAKEFOURCC('D', 'X', 'T', '1') - #define DDS_DXT2 CMFT_MAKEFOURCC('D', 'X', 'T', '2') - #define DDS_DXT3 CMFT_MAKEFOURCC('D', 'X', 'T', '3') - #define DDS_DXT4 CMFT_MAKEFOURCC('D', 'X', 'T', '4') - #define DDS_DXT5 CMFT_MAKEFOURCC('D', 'X', 'T', '5') - #define DDS_ATI1 CMFT_MAKEFOURCC('A', 'T', 'I', '1') - #define DDS_BC4U CMFT_MAKEFOURCC('B', 'C', '4', 'U') - #define DDS_ATI2 CMFT_MAKEFOURCC('A', 'T', 'I', '2') - #define DDS_BC5U CMFT_MAKEFOURCC('B', 'C', '5', 'U') - - #define DDS_DX10 CMFT_MAKEFOURCC('D', 'X', '1', '0') - - #define D3DFMT_R8G8B8 20 - #define D3DFMT_A8R8G8B8 21 - #define D3DFMT_X8R8G8B8 22 - #define D3DFMT_A8B8G8R8 32 - #define D3DFMT_X8B8G8R8 33 - #define D3DFMT_A16B16G16R16 36 - #define D3DFMT_A16B16G16R16F 113 - #define D3DFMT_A32B32G32R32F 116 - - #define DDSD_CAPS 0x00000001 - #define DDSD_HEIGHT 0x00000002 - #define DDSD_WIDTH 0x00000004 - #define DDSD_PITCH 0x00000008 - #define DDSD_PIXELFORMAT 0x00001000 - #define DDSD_MIPMAPCOUNT 0x00020000 - #define DDSD_LINEARSIZE 0x00080000 - #define DDSD_DEPTH 0x00800000 - - #define DDPF_ALPHAPIXELS 0x00000001 - #define DDPF_ALPHA 0x00000002 - #define DDPF_FOURCC 0x00000004 - #define DDPF_INDEXED 0x00000020 - #define DDPF_RGB 0x00000040 - #define DDPF_YUV 0x00000200 - #define DDPF_LUMINANCE 0x00020000 - #define DDPF_RGBA (DDPF_RGB|DDPF_ALPHAPIXELS) - #define DDPF_LUMINANCEA (DDPF_LUMINANCE|DDPF_ALPHAPIXELS) - #define DDS_PF_BC_24 0x00100000 - #define DDS_PF_BC_32 0x00200000 - #define DDS_PF_BC_48 0x00400000 - - #define DDSCAPS_COMPLEX 0x00000008 - #define DDSCAPS_TEXTURE 0x00001000 - #define DDSCAPS_MIPMAP 0x00400000 - - #define DDSCAPS2_CUBEMAP 0x00000200 - #define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400 - #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800 - #define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000 - #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000 - #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000 - #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000 - - #define DDS_CUBEMAP_ALLFACES ( DDSCAPS2_CUBEMAP_POSITIVEX|DDSCAPS2_CUBEMAP_NEGATIVEX \ - | DDSCAPS2_CUBEMAP_POSITIVEY|DDSCAPS2_CUBEMAP_NEGATIVEY \ - | DDSCAPS2_CUBEMAP_POSITIVEZ|DDSCAPS2_CUBEMAP_NEGATIVEZ ) - - #define DDSCAPS2_VOLUME 0x00200000 - - #define DXGI_FORMAT_UNKNOWN 0 - #define DXGI_FORMAT_R32G32B32A32_FLOAT 2 - #define DXGI_FORMAT_R16G16B16A16_FLOAT 10 - #define DXGI_FORMAT_R16G16B16A16_UINT 12 - #define DXGI_FORMAT_R8G8B8A8_UNORM 28 - #define DXGI_FORMAT_R8G8B8A8_UINT 30 - #define DXGI_FORMAT_B8G8R8A8_UNORM 87 - #define DXGI_FORMAT_B8G8R8X8_UNORM 88 - #define DXGI_FORMAT_B8G8R8A8_TYPELESS 90 - - #define DDS_DIMENSION_TEXTURE1D 2 - #define DDS_DIMENSION_TEXTURE2D 3 - #define DDS_DIMENSION_TEXTURE3D 4 - - #define DDS_ALPHA_MODE_UNKNOWN 0x0 - #define DDS_ALPHA_MODE_STRAIGHT 0x1 - #define DDS_ALPHA_MODE_PREMULTIPLIED 0x2 - #define DDS_ALPHA_MODE_OPAQUE 0x3 - #define DDS_ALPHA_MODE_CUSTOM 0x4 - - #define D3D10_RESOURCE_MISC_GENERATE_MIPS 0x1L - #define D3D10_RESOURCE_MISC_SHARED 0x2L - #define D3D10_RESOURCE_MISC_TEXTURECUBE 0x4L - #define D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX 0x10L - #define D3D10_RESOURCE_MISC_GDI_COMPATIBLE 0x20L - - struct DdsPixelFormat - { - uint32_t m_size; - uint32_t m_flags; - uint32_t m_fourcc; - uint32_t m_rgbBitCount; - uint32_t m_rBitMask; - uint32_t m_gBitMask; - uint32_t m_bBitMask; - uint32_t m_aBitMask; - }; - - struct DdsHeader - { - uint32_t m_size; - uint32_t m_flags; - uint32_t m_height; - uint32_t m_width; - uint32_t m_pitchOrLinearSize; - uint32_t m_depth; - uint32_t m_mipMapCount; - uint32_t m_reserved1[11]; - DdsPixelFormat m_pixelFormat; - uint32_t m_caps; - uint32_t m_caps2; - uint32_t m_caps3; - uint32_t m_caps4; - uint32_t m_reserved2; - }; - - struct DdsHeaderDxt10 - { - uint32_t m_dxgiFormat; - uint32_t m_resourceDimension; - uint32_t m_miscFlags; - uint32_t m_arraySize; - uint32_t m_miscFlags2; - }; - - static const DdsPixelFormat s_ddsPixelFormat[] = - { - { sizeof(DdsPixelFormat), DDPF_RGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 }, //BGR8 - { sizeof(DdsPixelFormat), DDPF_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, //BGRA8 - { sizeof(DdsPixelFormat), DDPF_FOURCC, DDS_DX10, 64, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, //RGBA16 - { sizeof(DdsPixelFormat), DDPF_FOURCC, D3DFMT_A16B16G16R16F, 64, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, //RGBA16F - { sizeof(DdsPixelFormat), DDPF_FOURCC, D3DFMT_A32B32G32R32F, 128, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, //RGBA32F - }; - - static inline const DdsPixelFormat& getDdsPixelFormat(TextureFormat::Enum _format) - { - DEBUG_CHECK(checkValidTextureFormat(ImageFileType::DDS, _format), "Not a valid DDS texture format!"); - if (TextureFormat::BGR8 == _format) { return s_ddsPixelFormat[0]; } - else if (TextureFormat::BGRA8 == _format) { return s_ddsPixelFormat[1]; } - else if (TextureFormat::RGBA16 == _format) { return s_ddsPixelFormat[2]; } - else if (TextureFormat::RGBA16F == _format) { return s_ddsPixelFormat[3]; } - else/*(TextureFormat::RGBA32F == _format)*/ { return s_ddsPixelFormat[4]; } - } - - static inline uint8_t getDdsDxgiFormat(TextureFormat::Enum _format) - { - if (TextureFormat::RGBA16 == _format) { return DXGI_FORMAT_R16G16B16A16_UINT; } - else if (TextureFormat::RGBA16F == _format) { return DXGI_FORMAT_R16G16B16A16_FLOAT; } - else if (TextureFormat::RGBA32F == _format) { return DXGI_FORMAT_R32G32B32A32_FLOAT; } - else { return DXGI_FORMAT_UNKNOWN; } - } - - static const struct TranslateDdsPfBitCount - { - uint32_t m_bitCount; - uint32_t m_flag; - } s_translateDdsPfBitCount[] = - { - { 24, DDS_PF_BC_24 }, - { 32, DDS_PF_BC_32 }, - { 48, DDS_PF_BC_48 }, - }; - - static const struct TranslateDdsFormat - { - uint32_t m_format; - TextureFormat::Enum m_textureFormat; - - } s_translateDdsFormat[] = - { - { D3DFMT_R8G8B8, TextureFormat::BGR8 }, - { D3DFMT_A8R8G8B8, TextureFormat::BGRA8 }, - { D3DFMT_A16B16G16R16, TextureFormat::RGBA16 }, - { D3DFMT_A16B16G16R16F, TextureFormat::RGBA16F }, - { D3DFMT_A32B32G32R32F, TextureFormat::RGBA32F }, - { DDS_PF_BC_24|DDPF_RGB, TextureFormat::BGR8 }, - { DDS_PF_BC_32|DDPF_RGBA, TextureFormat::BGRA8 }, - { DDS_PF_BC_48|DDPF_RGB, TextureFormat::RGB16 }, - }; - - static const struct TranslateDdsDxgiFormat - { - uint8_t m_dxgiFormat; - TextureFormat::Enum m_textureFormat; - - } s_translateDdsDxgiFormat[] = - { - { DXGI_FORMAT_R16G16B16A16_UINT, TextureFormat::RGBA16 }, - { DXGI_FORMAT_R16G16B16A16_FLOAT, TextureFormat::RGBA16F }, - { DXGI_FORMAT_R32G32B32A32_FLOAT, TextureFormat::RGBA32F }, - }; - - // KTX format. - //----- - - #define KTX_MAGIC { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A } - #define KTX_MAGIC_SHORT 0x58544BAB - #define KTX_MAGIC_LEN 12 - #define KTX_ENDIAN_REF 0x04030201 - #define KTX_ENDIAN_REF_REV 0x01020304 - #define KTX_HEADER_SIZE 52 - #define KTX_UNPACK_ALIGNMENT 4 - - // GL data type. - #define GL_BYTE 0x1400 - #define GL_UNSIGNED_BYTE 0x1401 - #define GL_SHORT 0x1402 - #define GL_UNSIGNED_SHORT 0x1403 - #define GL_INT 0x1404 - #define GL_UNSIGNED_INT 0x1405 - #define GL_FLOAT 0x1406 - #define GL_HALF_FLOAT 0x140B - #define GL_FIXED 0x140C - - // GL pixel format. - #define GL_RGB 0x1907 - #define GL_RGBA 0x1908 - - #define GL_RGBA32F 0x8814 - #define GL_RGB32F 0x8815 - #define GL_RGBA16F 0x881A - #define GL_RGB16F 0x881B - #define GL_RGBA32UI 0x8D70 - #define GL_RGB32UI 0x8D71 - #define GL_RGBA16UI 0x8D76 - #define GL_RGB16UI 0x8D77 - #define GL_RGBA8UI 0x8D7C - #define GL_RGB8UI 0x8D7D - #define GL_RGBA32I 0x8D82 - #define GL_RGB32I 0x8D83 - #define GL_RGBA16I 0x8D88 - #define GL_RGB16I 0x8D89 - #define GL_RGBA8I 0x8D8E - #define GL_RGB8I 0x8D8F - - struct KtxHeader - { - uint32_t m_endianness; - uint32_t m_glType; - uint32_t m_glTypeSize; - uint32_t m_glFormat; - uint32_t m_glInternalFormat; - uint32_t m_glBaseInternalFormat; - uint32_t m_pixelWidth; - uint32_t m_pixelHeight; - uint32_t m_pixelDepth; - uint32_t m_numArrayElements; - uint32_t m_numFaces; - uint32_t m_numMips; - uint32_t m_bytesKeyValue; - }; - - struct GlSizedInternalFormat - { - uint32_t m_glInternalFormat; - uint32_t m_glFormat; - }; - - static const GlSizedInternalFormat s_glSizedInternalFormats[TextureFormat::Count] = - { - { 0, 0 }, //BGR8 - { GL_RGB8UI, GL_RGB }, //RGB8 - { GL_RGB16UI, GL_RGB }, //RGB16 - { GL_RGB16F, GL_RGB }, //RGB16F - { GL_RGB32F, GL_RGB }, //RGB32F - { 0, 0 }, //RGBE - { 0, 0 }, //BGRA8 - { GL_RGBA8UI, GL_RGBA }, //RGBA8 - { GL_RGBA16UI, GL_RGBA }, //RGBA16 - { GL_RGBA16F, GL_RGBA }, //RGBA16F - { GL_RGBA32F, GL_RGBA }, //RGBA32F - }; - - static const GlSizedInternalFormat& getGlSizedInternalFormat(TextureFormat::Enum _format) - { - DEBUG_CHECK(_format < TextureFormat::Count, "Reading array out of bounds!"); - return s_glSizedInternalFormats[_format]; - } - - static const uint32_t s_pixelDataTypeToGlType[PixelDataType::Count] = - { - GL_UNSIGNED_BYTE, // UINT8 - GL_UNSIGNED_SHORT, // UINT16 - GL_UNSIGNED_INT, // UINT32 - GL_HALF_FLOAT, // HALF_FLOAT - GL_FLOAT, // FLOAT - }; - - static uint32_t pixelDataTypeToGlType(PixelDataType::Enum _pdt) - { - DEBUG_CHECK(_pdt < PixelDataType::Count, "Reading array out of bounds!"); - return s_pixelDataTypeToGlType[_pdt]; - } - - static const struct TranslateKtxFormat - { - uint32_t m_glInternalFormat; - TextureFormat::Enum m_textureFormat; - - } s_translateKtxFormat[] = - { - { GL_RGB, TextureFormat::RGB8 }, - { GL_RGB8UI, TextureFormat::RGB8 }, - { GL_RGB16UI, TextureFormat::RGB16 }, - { GL_RGB16F, TextureFormat::RGB16F }, - { GL_RGB32F, TextureFormat::RGB32F }, - { GL_RGBA, TextureFormat::RGBA8 }, - { GL_RGBA8UI, TextureFormat::RGBA8 }, - { GL_RGBA16UI, TextureFormat::RGBA16 }, - { GL_RGBA16F, TextureFormat::RGBA16F }, - { GL_RGBA32F, TextureFormat::RGBA32F }, - }; - - // Image -> format headers/footers. - //----- - - // Notice: creates proper dds headers only for uncompressed formats. - void ddsHeaderFromImage(DdsHeader& _ddsHeader, DdsHeaderDxt10* _ddsHeaderDxt10, const Image& _image) - { - const DdsPixelFormat& ddsPixelFormat = getDdsPixelFormat(_image.m_format); - - const uint32_t bytesPerPixel = getImageDataInfo(_image.m_format).m_bytesPerPixel; - const bool hasMipMaps = _image.m_numMips > 1; - const bool hasMultipleFaces = _image.m_numFaces > 0; - const bool isCubemap = _image.m_numFaces == 6; - - if (DDS_DX10 == ddsPixelFormat.m_fourcc) - { - if (NULL != _ddsHeaderDxt10) - { - _ddsHeaderDxt10->m_dxgiFormat = getDdsDxgiFormat(_image.m_format); - DEBUG_CHECK(0 != _ddsHeaderDxt10->m_dxgiFormat, "Dxt10 format should not be 0."); - _ddsHeaderDxt10->m_resourceDimension = DDS_DIMENSION_TEXTURE2D; - _ddsHeaderDxt10->m_miscFlags = isCubemap ? D3D10_RESOURCE_MISC_TEXTURECUBE : 0; - _ddsHeaderDxt10->m_arraySize = 1; - _ddsHeaderDxt10->m_miscFlags2 = 0; - } - else - { - WARN("Dds header dxt10 is required but it is NULL."); - } - } - - memset(&_ddsHeader, 0, sizeof(DdsHeader)); - _ddsHeader.m_size = DDS_HEADER_SIZE; - _ddsHeader.m_flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT - | (hasMipMaps ? DDSD_MIPMAPCOUNT : 0) - | DDSD_PITCH - ; - _ddsHeader.m_height = _image.m_height; - _ddsHeader.m_width = _image.m_width; - _ddsHeader.m_pitchOrLinearSize = _image.m_width * bytesPerPixel; - _ddsHeader.m_mipMapCount = _image.m_numMips; - memcpy(&_ddsHeader.m_pixelFormat, &ddsPixelFormat, sizeof(DdsPixelFormat)); - _ddsHeader.m_caps = DDSCAPS_TEXTURE - | (hasMipMaps ? DDSCAPS_MIPMAP : 0) - | ((hasMipMaps | hasMultipleFaces) ? DDSCAPS_COMPLEX : 0) - ; - _ddsHeader.m_caps2 = (isCubemap ? DDSCAPS2_CUBEMAP | DDS_CUBEMAP_ALLFACES : 0); - } - - void printDdsHeader(const DdsHeader& _ddsHeader) - { - printf("ddsHeader.m_size = %u\n" - "ddsHeader.m_flags = %u\n" - "ddsHeader.m_height = %u\n" - "ddsHeader.m_width = %u\n" - "ddsHeader.m_pitchOrLinearSize = %u\n" - "ddsHeader.m_depth = %u\n" - "ddsHeader.m_mipMapCount = %u\n" - "ddsHeader.m_reserved1[0] = %u\n" - "ddsHeader.m_pixelFormat.m_size = %u\n" - "ddsHeader.m_pixelFormat.m_flags = %u\n" - "ddsHeader.m_pixelFormat.m_fourcc = %u\n" - "ddsHeader.m_pixelFormat.m_rgbBitCount = %u\n" - "ddsHeader.m_pixelFormat.m_rBitMask = %u\n" - "ddsHeader.m_pixelFormat.m_gBitMask = %u\n" - "ddsHeader.m_pixelFormat.m_bBitMask = %u\n" - "ddsHeader.m_pixelFormat.m_aBitMask = %u\n" - "ddsHeader.m_caps = %u\n" - "ddsHeader.m_caps2 = %u\n" - "ddsHeader.m_caps3 = %u\n" - "ddsHeader.m_caps4 = %u\n" - "ddsHeader.m_reserved2 = %u\n" - , _ddsHeader.m_size - , _ddsHeader.m_flags - , _ddsHeader.m_height - , _ddsHeader.m_width - , _ddsHeader.m_pitchOrLinearSize - , _ddsHeader.m_depth - , _ddsHeader.m_mipMapCount - , _ddsHeader.m_reserved1[0] - , _ddsHeader.m_pixelFormat.m_size - , _ddsHeader.m_pixelFormat.m_flags - , _ddsHeader.m_pixelFormat.m_fourcc - , _ddsHeader.m_pixelFormat.m_rgbBitCount - , _ddsHeader.m_pixelFormat.m_rBitMask - , _ddsHeader.m_pixelFormat.m_gBitMask - , _ddsHeader.m_pixelFormat.m_bBitMask - , _ddsHeader.m_pixelFormat.m_aBitMask - , _ddsHeader.m_caps - , _ddsHeader.m_caps2 - , _ddsHeader.m_caps3 - , _ddsHeader.m_caps4 - , _ddsHeader.m_reserved2 - ); - } - - void printDdsHeaderDxt10(const DdsHeaderDxt10& _ddsHeaderDxt10) - { - printf("ddsHeaderDxt10.m_dxgiFormat = %u\n" - "ddsHeaderDxt10.m_resourceDimension = %u\n" - "ddsHeaderDxt10.m_miscFlags = %u\n" - "ddsHeaderDxt10.m_arraySize = %u\n" - "ddsHeaderDxt10.m_miscFlags2 = %u\n" - , _ddsHeaderDxt10.m_dxgiFormat - , _ddsHeaderDxt10.m_resourceDimension - , _ddsHeaderDxt10.m_miscFlags - , _ddsHeaderDxt10.m_arraySize - , _ddsHeaderDxt10.m_miscFlags2 - ); - } - - void ktxHeaderFromImage(KtxHeader& _ktxHeader, const Image& _image) - { - const ImageDataInfo& imageDataInfo = getImageDataInfo(_image.m_format); - - _ktxHeader.m_endianness = KTX_ENDIAN_REF; - _ktxHeader.m_glType = pixelDataTypeToGlType((PixelDataType::Enum)imageDataInfo.m_pixelType); - _ktxHeader.m_glTypeSize = (imageDataInfo.m_bytesPerPixel/imageDataInfo.m_numChanels); - _ktxHeader.m_glFormat = getGlSizedInternalFormat(_image.m_format).m_glFormat; - _ktxHeader.m_glInternalFormat = getGlSizedInternalFormat(_image.m_format).m_glInternalFormat; - _ktxHeader.m_glBaseInternalFormat = _ktxHeader.m_glFormat; - _ktxHeader.m_pixelWidth = _image.m_width; - _ktxHeader.m_pixelHeight = _image.m_height; - _ktxHeader.m_pixelDepth = 0; - _ktxHeader.m_numArrayElements = 0; - _ktxHeader.m_numFaces = _image.m_numFaces; - _ktxHeader.m_numMips = _image.m_numMips; - _ktxHeader.m_bytesKeyValue = 0; - - DEBUG_CHECK(_ktxHeader.m_glTypeSize == 1 - || _ktxHeader.m_glTypeSize == 2 - || _ktxHeader.m_glTypeSize == 4 - , "Invalid ktx header glTypeSize." - ); - DEBUG_CHECK(0 != _image.m_numMips, "Mips count cannot be 0."); - } - - void printKtxHeader(const KtxHeader& _ktxHeader) - { - printf("ktxHeader.m_endianness = %u\n" - "ktxHeader.m_glType = %u\n" - "ktxHeader.m_glTypeSize = %u\n" - "ktxHeader.m_glFormat = %u\n" - "ktxHeader.m_glInternalFormat = %u\n" - "ktxHeader.m_glBaseInternal = %u\n" - "ktxHeader.m_pixelWidth = %u\n" - "ktxHeader.m_pixelHeight = %u\n" - "ktxHeader.m_pixelDepth = %u\n" - "ktxHeader.m_numArrayElements = %u\n" - "ktxHeader.m_numFaces = %u\n" - "ktxHeader.m_numMips = %u\n" - "ktxHeader.m_bytesKeyValue = %u\n" - , _ktxHeader.m_endianness - , _ktxHeader.m_glType - , _ktxHeader.m_glTypeSize - , _ktxHeader.m_glFormat - , _ktxHeader.m_glInternalFormat - , _ktxHeader.m_glBaseInternalFormat - , _ktxHeader.m_pixelWidth - , _ktxHeader.m_pixelHeight - , _ktxHeader.m_pixelDepth - , _ktxHeader.m_numArrayElements - , _ktxHeader.m_numFaces - , _ktxHeader.m_numMips - , _ktxHeader.m_bytesKeyValue - ); - } - - void tgaHeaderFromImage(TgaHeader& _tgaHeader, const Image& _image, uint8_t _mip) - { - memset(&_tgaHeader, 0, sizeof(TgaHeader)); - _tgaHeader.m_idLength = 0; - _tgaHeader.m_colorMapType = 0; - _tgaHeader.m_imageType = TGA_IT_RGB; - _tgaHeader.m_xOrigin = 0; - _tgaHeader.m_yOrigin = 0; - _tgaHeader.m_width = uint16_t(CMFT_MAX(1, _image.m_width >> _mip)); - _tgaHeader.m_height = uint16_t(CMFT_MAX(1, _image.m_height >> _mip)); - _tgaHeader.m_bitsPerPixel = getImageDataInfo(_image.m_format).m_bytesPerPixel*8; - _tgaHeader.m_imageDescriptor = (getImageDataInfo(_image.m_format).m_hasAlpha ? 0x8 : 0x0); - } - - void printTgaHeader(const TgaHeader& _tgaHeader) - { - printf("tgaHeader.m_idLength = %u\n" - "tgaHeader.m_colorMapType = %u\n" - "tgaHeader.m_imageType = %u\n" - "tgaHeader.m_colorMapOrigin = %d\n" - "tgaHeader.m_colorMapLength = %d\n" - "tgaHeader.m_colorMapDepth = %u\n" - "tgaHeader.m_xOrigin = %d\n" - "tgaHeader.m_yOrigin = %d\n" - "tgaHeader.m_width = %u\n" - "tgaHeader.m_height = %u\n" - "tgaHeader.m_bitsPerPixel = %u\n" - "tgaHeader.m_imageDescriptor = %u\n" - , _tgaHeader.m_idLength - , _tgaHeader.m_colorMapType - , _tgaHeader.m_imageType - , _tgaHeader.m_colorMapOrigin - , _tgaHeader.m_colorMapLength - , _tgaHeader.m_colorMapDepth - , _tgaHeader.m_xOrigin - , _tgaHeader.m_yOrigin - , _tgaHeader.m_width - , _tgaHeader.m_height - , _tgaHeader.m_bitsPerPixel - , _tgaHeader.m_imageDescriptor - ); - } - - void hdrHeaderFromImage(HdrHeader& _hdrHeader, const Image& _image) - { - CMFT_UNUSED(_image); - - memset(&_hdrHeader, 0, sizeof(HdrHeader)); - _hdrHeader.m_valid = HDR_VALID_GAMMA | HDR_VALID_EXPOSURE; - _hdrHeader.m_gamma = 1.0f; - _hdrHeader.m_exposure = 1.0f; - } - - void printHdrHeader(const HdrHeader& _hdrHeader) - { - printf("hdrHeader.m_valid = %d\n" - "hdrHeader.m_gamma = %f\n" - "hdrHeader.m_exposure = %f\n" - , _hdrHeader.m_valid - , _hdrHeader.m_gamma - , _hdrHeader.m_exposure - ); - } - - // Image. - //----- - - void imageCreate(Image& _image, uint32_t _width, uint32_t _height, uint32_t _rgba, uint8_t _numMips, uint8_t _numFaces, TextureFormat::Enum _format, AllocatorI* _allocator) - { - const uint8_t numFaces = _numFaces > 0 ? _numFaces : 1; - const uint8_t numMips = _numMips > 0 ? _numMips : 1; - - // Alloc data. - const uint32_t bytesPerPixel = 4 /*numChannels*/ * 4 /*bytesPerChannel*/; - uint32_t dstDataSize = 0; - for (uint8_t mip = 0; mip < numMips; ++mip) - { - const uint32_t mipWidth = CMFT_MAX(UINT32_C(1), _width >> mip); - const uint32_t mipHeight = CMFT_MAX(UINT32_C(1), _height >> mip); - dstDataSize += mipWidth * mipHeight * bytesPerPixel; - } - dstDataSize *= numFaces; - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - // Get color in rgba32f format. - float color[4]; - toRgba32f(color, TextureFormat::RGBA8, &_rgba); - - // Fill data with specified color. - float* dstPtr = (float*)dstData; - const float* end = (float*)((uint8_t*)dstData + dstDataSize); - for (;dstPtr < end; dstPtr+=4) - { - dstPtr[0] = color[0]; - dstPtr[1] = color[1]; - dstPtr[2] = color[2]; - dstPtr[3] = color[3]; - } - - // Fill image structure. - Image result; - result.m_data = dstData; - result.m_width = _width; - result.m_height = _height; - result.m_dataSize = dstDataSize; - result.m_format = TextureFormat::RGBA32F; - result.m_numMips = numMips; - result.m_numFaces = numFaces; - - // Convert result to source format. - if (TextureFormat::RGBA8 == _format) - { - imageMove(_image, result, _allocator); - } - else - { - imageConvert(_image, _format, result, _allocator); - imageUnload(result, _allocator); - } - } - - void imageUnload(Image& _image, AllocatorI* _allocator) - { - if (_image.m_data) - { - CMFT_FREE(_allocator, _image.m_data); - _image.m_data = NULL; - } - } - - void imageMove(Image& _dst, Image& _src, AllocatorI* _allocator) - { - imageUnload(_dst, _allocator); - _dst.m_data = _src.m_data; - _dst.m_width = _src.m_width; - _dst.m_height = _src.m_height; - _dst.m_dataSize = _src.m_dataSize; - _dst.m_format = _src.m_format; - _dst.m_numMips = _src.m_numMips; - _dst.m_numFaces = _src.m_numFaces; - - _src.m_data = NULL; - } - - void imageCopy(Image& _dst, const Image& _src, AllocatorI* _allocator) - { - imageUnload(_dst, _allocator); - - _dst.m_data = CMFT_ALLOC(_allocator, _src.m_dataSize); - MALLOC_CHECK(_dst.m_data); - memcpy(_dst.m_data, _src.m_data, _src.m_dataSize); - _dst.m_width = _src.m_width; - _dst.m_height = _src.m_height; - _dst.m_dataSize = _src.m_dataSize; - _dst.m_format = _src.m_format; - _dst.m_numMips = _src.m_numMips; - _dst.m_numFaces = _src.m_numFaces; - } - - uint32_t imageGetNumPixels(const Image& _image) - { - DEBUG_CHECK(0 != _image.m_numMips, "Mips count cannot be 0."); - DEBUG_CHECK(0 != _image.m_numFaces, "Face count cannot be 0."); - - uint32_t count = 0; - for (uint8_t mip = 0; mip < _image.m_numMips; ++mip) - { - const uint32_t width = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - count += width * height; - } - count *= _image.m_numFaces; - - return count; - } - - void imageGetMipOffsets(uint32_t _offsets[CUBE_FACE_NUM][MAX_MIP_NUM], const Image& _image) - { - const uint32_t bytesPerPixel = getImageDataInfo(_image.m_format).m_bytesPerPixel; - - uint32_t offset = 0; - for (uint8_t face = 0; face < _image.m_numFaces; ++face) - { - for (uint8_t mip = 0; mip < _image.m_numMips; ++mip) - { - _offsets[face][mip] = offset; - - const uint32_t width = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - offset += width * height * bytesPerPixel; - } - } - } - - void imageGetFaceOffsets(uint32_t _faceOffsets[CUBE_FACE_NUM], const Image& _image) - { - const uint32_t bytesPerPixel = getImageDataInfo(_image.m_format).m_bytesPerPixel; - - uint32_t offset = 0; - for (uint8_t face = 0; face < _image.m_numFaces; ++face) - { - _faceOffsets[face] = offset; - - for (uint8_t mip = 0; mip < _image.m_numMips; ++mip) - { - const uint32_t width = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - offset += width * height * bytesPerPixel; - } - } - } - - // To rgba32f. - //----- - - inline void bgr8ToRgba32f(float* _rgba32f, const uint8_t* _bgr8) - { - _rgba32f[0] = float(_bgr8[2]) * (1.0f/255.0f); - _rgba32f[1] = float(_bgr8[1]) * (1.0f/255.0f); - _rgba32f[2] = float(_bgr8[0]) * (1.0f/255.0f); - _rgba32f[3] = 1.0f; - } - - inline void bgra8ToRgba32f(float* _rgba32f, const uint8_t* _bgra8) - { - _rgba32f[0] = float(_bgra8[2]) * (1.0f/255.0f); - _rgba32f[1] = float(_bgra8[1]) * (1.0f/255.0f); - _rgba32f[2] = float(_bgra8[0]) * (1.0f/255.0f); - _rgba32f[3] = float(_bgra8[3]) * (1.0f/255.0f); - } - - inline void rgb8ToRgba32f(float* _rgba32f, const uint8_t* _rgb8) - { - _rgba32f[0] = float(_rgb8[0]) * (1.0f/255.0f); - _rgba32f[1] = float(_rgb8[1]) * (1.0f/255.0f); - _rgba32f[2] = float(_rgb8[2]) * (1.0f/255.0f); - _rgba32f[3] = 1.0f; - } - - inline void rgba8ToRgba32f(float* _rgba32f, const uint8_t* _rgba8) - { - _rgba32f[0] = float(_rgba8[0]) * (1.0f/255.0f); - _rgba32f[1] = float(_rgba8[1]) * (1.0f/255.0f); - _rgba32f[2] = float(_rgba8[2]) * (1.0f/255.0f); - _rgba32f[3] = float(_rgba8[3]) * (1.0f/255.0f); - } - - inline void rgb16ToRgba32f(float* _rgba32f, const uint16_t* _rgb16) - { - _rgba32f[0] = float(_rgb16[0]) * (1.0f/65535.0f); - _rgba32f[1] = float(_rgb16[1]) * (1.0f/65535.0f); - _rgba32f[2] = float(_rgb16[2]) * (1.0f/65535.0f); - _rgba32f[3] = 1.0f; - } - - inline void rgba16ToRgba32f(float* _rgba32f, const uint16_t* _rgba16) - { - _rgba32f[0] = float(_rgba16[0]) * (1.0f/65535.0f); - _rgba32f[1] = float(_rgba16[1]) * (1.0f/65535.0f); - _rgba32f[2] = float(_rgba16[2]) * (1.0f/65535.0f); - _rgba32f[3] = float(_rgba16[3]) * (1.0f/65535.0f); - } - - inline void rgb16fToRgba32f(float* _rgba32f, const uint16_t* _rgb16f) - { - _rgba32f[0] = cmft::halfToFloat(_rgb16f[0]); - _rgba32f[1] = cmft::halfToFloat(_rgb16f[1]); - _rgba32f[2] = cmft::halfToFloat(_rgb16f[2]); - _rgba32f[3] = 1.0f; - } - - inline void rgba16fToRgba32f(float* _rgba32f, const uint16_t* _rgba16f) - { - _rgba32f[0] = cmft::halfToFloat(_rgba16f[0]); - _rgba32f[1] = cmft::halfToFloat(_rgba16f[1]); - _rgba32f[2] = cmft::halfToFloat(_rgba16f[2]); - _rgba32f[3] = cmft::halfToFloat(_rgba16f[3]); - } - - inline void rgb32fToRgba32f(float* _rgba32f, const float* _rgb32f) - { - _rgba32f[0] = _rgb32f[0]; - _rgba32f[1] = _rgb32f[1]; - _rgba32f[2] = _rgb32f[2]; - _rgba32f[3] = 1.0f; - } - - inline void rgba32fToRgba32f(float* _dst, const float* _src) - { - memcpy(_dst, _src, 4*sizeof(float)); - } - - inline void rgbeToRgba32f(float* _rgba32f, const uint8_t* _rgbe) - { - if (_rgbe[3]) - { - const float exp = ldexp(1.0f, _rgbe[3] - (128+8)); - _rgba32f[0] = float(_rgbe[0]) * exp; - _rgba32f[1] = float(_rgbe[1]) * exp; - _rgba32f[2] = float(_rgbe[2]) * exp; - _rgba32f[3] = 1.0f; - } - else - { - _rgba32f[0] = 0.0f; - _rgba32f[1] = 0.0f; - _rgba32f[2] = 0.0f; - _rgba32f[3] = 1.0f; - } - } - - void toRgba32f(float _rgba32f[4], TextureFormat::Enum _srcFormat, const void* _src) - { - switch(_srcFormat) - { - case TextureFormat::BGR8: bgr8ToRgba32f(_rgba32f, (const uint8_t*)_src); break; - case TextureFormat::RGB8: rgb8ToRgba32f(_rgba32f, (const uint8_t*)_src); break; - case TextureFormat::RGB16: rgb16ToRgba32f(_rgba32f, (const uint16_t*)_src); break; - case TextureFormat::RGB16F: rgb16fToRgba32f(_rgba32f, (const uint16_t*)_src); break; - case TextureFormat::RGB32F: rgb32fToRgba32f(_rgba32f, (const float*)_src); break; - case TextureFormat::RGBE: rgbeToRgba32f(_rgba32f, (const uint8_t*)_src); break; - case TextureFormat::BGRA8: bgra8ToRgba32f(_rgba32f, (const uint8_t*)_src); break; - case TextureFormat::RGBA8: rgba8ToRgba32f(_rgba32f, (const uint8_t*)_src); break; - case TextureFormat::RGBA16: rgba16ToRgba32f(_rgba32f, (const uint16_t*)_src); break; - case TextureFormat::RGBA16F: rgba16fToRgba32f(_rgba32f, (const uint16_t*)_src); break; - case TextureFormat::RGBA32F: rgba32fToRgba32f(_rgba32f, (const float*)_src); break; - default: DEBUG_CHECK(false, "Unknown image format."); - }; - } - - void imageToRgba32f(Image& _dst, const Image& _src, AllocatorI* _allocator) - { - // Alloc dst data. - const uint32_t pixelCount = imageGetNumPixels(_src); - const uint8_t dstBytesPerPixel = getImageDataInfo(TextureFormat::RGBA32F).m_bytesPerPixel; - const uint32_t dataSize = pixelCount*dstBytesPerPixel; - void* data = CMFT_ALLOC(_allocator, dataSize); - MALLOC_CHECK(data); - - // Get total number of channels. - const uint8_t numChannelsPerPixel = getImageDataInfo(TextureFormat::RGBA32F).m_numChanels; - const uint32_t totalNumChannels = pixelCount*numChannelsPerPixel; - - // Convert each channel. - float* dst = (float*)data; - const float* end = (float*)dst + totalNumChannels; - switch(_src.m_format) - { - case TextureFormat::BGR8: - { - const uint8_t* src = (const uint8_t*)_src.m_data; - - for (;dst < end; dst+=4, src+=3) - { - bgr8ToRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGB8: - { - const uint8_t* src = (const uint8_t*)_src.m_data; - - for (;dst < end; dst+=4, src+=3) - { - rgb8ToRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGB16: - { - const uint16_t* src = (const uint16_t*)_src.m_data; - - for (;dst < end; dst+=4, src+=3) - { - rgb16ToRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGB16F: - { - const uint16_t* src = (const uint16_t*)_src.m_data; - - for (;dst < end; dst+=4, src+=3) - { - rgb16fToRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGB32F: - { - const float* src = (const float*)_src.m_data; - - for (;dst < end; dst+=4, src+=3) - { - rgb32fToRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGBE: - { - const uint8_t* src = (const uint8_t*)_src.m_data; - - for (;dst < end; dst+=4, src+=4) - { - rgbeToRgba32f(dst, src); - } - } - break; - - case TextureFormat::BGRA8: - { - const uint8_t* src = (const uint8_t*)_src.m_data; - - for (;dst < end; dst+=4, src+=4) - { - bgra8ToRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGBA8: - { - const uint8_t* src = (const uint8_t*)_src.m_data; - - for (;dst < end; dst+=4, src+=4) - { - rgba8ToRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGBA16: - { - const uint16_t* src = (const uint16_t*)_src.m_data; - - for (;dst < end; dst+=4, src+=4) - { - rgba16ToRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGBA16F: - { - const uint16_t* src = (const uint16_t*)_src.m_data; - - for (;dst < end; dst+=4, src+=4) - { - rgba16fToRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGBA32F: - { - // Copy data. - memcpy(data, _src.m_data, dataSize); - } - break; - - default: - { - DEBUG_CHECK(false, "Unknown image format."); - } - break; - }; - - // Fill image structure. - Image result; - result.m_data = data; - result.m_width = _src.m_width; - result.m_height = _src.m_height; - result.m_dataSize = dataSize; - result.m_format = TextureFormat::RGBA32F; - result.m_numMips = _src.m_numMips; - result.m_numFaces = _src.m_numFaces; - - // Fill image structure. - imageMove(_dst, result, _allocator); - } - - void imageToRgba32f(Image& _image, AllocatorI* _allocator) - { - Image tmp; - imageToRgba32f(tmp, _image, _allocator); - imageMove(_image, tmp, _allocator); - } - - // From Rgba32f. - //----- - - inline void bgr8FromRgba32f(uint8_t* _bgr8, const float* _rgba32f) - { - _bgr8[2] = uint8_t(CMFT_CLAMP(_rgba32f[0], 0.0f, 1.0f) * 255.0f); - _bgr8[1] = uint8_t(CMFT_CLAMP(_rgba32f[1], 0.0f, 1.0f) * 255.0f); - _bgr8[0] = uint8_t(CMFT_CLAMP(_rgba32f[2], 0.0f, 1.0f) * 255.0f); - } - - inline void bgra8FromRgba32f(uint8_t* _bgra8, const float* _rgba32f) - { - _bgra8[2] = uint8_t(CMFT_CLAMP(_rgba32f[0], 0.0f, 1.0f) * 255.0f); - _bgra8[1] = uint8_t(CMFT_CLAMP(_rgba32f[1], 0.0f, 1.0f) * 255.0f); - _bgra8[0] = uint8_t(CMFT_CLAMP(_rgba32f[2], 0.0f, 1.0f) * 255.0f); - _bgra8[3] = uint8_t(CMFT_CLAMP(_rgba32f[3], 0.0f, 1.0f) * 255.0f); - } - - inline void rgb8FromRgba32f(uint8_t* _rgb8, const float* _rgba32f) - { - _rgb8[0] = uint8_t(CMFT_CLAMP(_rgba32f[0], 0.0f, 1.0f) * 255.0f); - _rgb8[1] = uint8_t(CMFT_CLAMP(_rgba32f[1], 0.0f, 1.0f) * 255.0f); - _rgb8[2] = uint8_t(CMFT_CLAMP(_rgba32f[2], 0.0f, 1.0f) * 255.0f); - } - - inline void rgba8FromRgba32f(uint8_t* _rgba8, const float* _rgba32f) - { - _rgba8[0] = uint8_t(CMFT_CLAMP(_rgba32f[0], 0.0f, 1.0f) * 255.0f); - _rgba8[1] = uint8_t(CMFT_CLAMP(_rgba32f[1], 0.0f, 1.0f) * 255.0f); - _rgba8[2] = uint8_t(CMFT_CLAMP(_rgba32f[2], 0.0f, 1.0f) * 255.0f); - _rgba8[3] = uint8_t(CMFT_CLAMP(_rgba32f[3], 0.0f, 1.0f) * 255.0f); - } - - inline void rgb16FromRgba32f(uint16_t* _rgb16, const float* _rgba32f) - { - _rgb16[0] = uint16_t(CMFT_CLAMP(_rgba32f[0], 0.0f, 1.0f) * 65535.0f); - _rgb16[1] = uint16_t(CMFT_CLAMP(_rgba32f[1], 0.0f, 1.0f) * 65535.0f); - _rgb16[2] = uint16_t(CMFT_CLAMP(_rgba32f[2], 0.0f, 1.0f) * 65535.0f); - } - - inline void rgba16FromRgba32f(uint16_t* _rgba16, const float* _rgba32f) - { - _rgba16[0] = uint16_t(CMFT_CLAMP(_rgba32f[0], 0.0f, 1.0f) * 65535.0f); - _rgba16[1] = uint16_t(CMFT_CLAMP(_rgba32f[1], 0.0f, 1.0f) * 65535.0f); - _rgba16[2] = uint16_t(CMFT_CLAMP(_rgba32f[2], 0.0f, 1.0f) * 65535.0f); - _rgba16[3] = uint16_t(CMFT_CLAMP(_rgba32f[3], 0.0f, 1.0f) * 65535.0f); - } - - inline void rgb16fFromRgba32f(uint16_t* _rgb16f, const float* _rgba32f) - { - _rgb16f[0] = cmft::halfFromFloat(_rgba32f[0]); - _rgb16f[1] = cmft::halfFromFloat(_rgba32f[1]); - _rgb16f[2] = cmft::halfFromFloat(_rgba32f[2]); - } - - inline void rgba16fFromRgba32f(uint16_t* _rgba16f, const float* _rgba32f) - { - _rgba16f[0] = cmft::halfFromFloat(_rgba32f[0]); - _rgba16f[1] = cmft::halfFromFloat(_rgba32f[1]); - _rgba16f[2] = cmft::halfFromFloat(_rgba32f[2]); - _rgba16f[3] = cmft::halfFromFloat(_rgba32f[3]); - } - - inline void rgb32fFromRgba32f(float* _rgb32f, const float* _rgba32f) - { - _rgb32f[0] = _rgba32f[0]; - _rgb32f[1] = _rgba32f[1]; - _rgb32f[2] = _rgba32f[2]; - } - - inline void rgba32fFromRgba32f(float* _dst, const float* _src) - { - memcpy(_dst, _src, 4*sizeof(float)); - } - - inline void rgbeFromRgba32f(uint8_t* _rgbe, const float* _rgba32f) - { - const float maxVal = CMFT_MAX(CMFT_MAX(_rgba32f[0], _rgba32f[1]), _rgba32f[2]); - const float exp = ceilf(cmft::log2f(maxVal)); - const float toRgb8 = 255.0f * 1.0f/ldexp(1.0f, int(exp)); //ldexp -> exp2 (c++11 - ) - _rgbe[0] = uint8_t(_rgba32f[0] * toRgb8); - _rgbe[1] = uint8_t(_rgba32f[1] * toRgb8); - _rgbe[2] = uint8_t(_rgba32f[2] * toRgb8); - _rgbe[3] = uint8_t(exp+128.0f); - } - - void fromRgba32f(void* _out, TextureFormat::Enum _format, const float _rgba32f[4]) - { - switch(_format) - { - case TextureFormat::BGR8: bgr8FromRgba32f((uint8_t*)_out, _rgba32f); break; - case TextureFormat::RGB8: rgb8FromRgba32f((uint8_t*)_out, _rgba32f); break; - case TextureFormat::RGB16: rgb16FromRgba32f((uint16_t*)_out, _rgba32f); break; - case TextureFormat::RGB16F: rgb16fFromRgba32f((uint16_t*)_out, _rgba32f); break; - case TextureFormat::RGB32F: rgb32fFromRgba32f((float*)_out, _rgba32f); break; - case TextureFormat::RGBE: rgbeFromRgba32f((uint8_t*)_out, _rgba32f); break; - case TextureFormat::BGRA8: bgra8FromRgba32f((uint8_t*)_out, _rgba32f); break; - case TextureFormat::RGBA8: rgba8FromRgba32f((uint8_t*)_out, _rgba32f); break; - case TextureFormat::RGBA16: rgba16FromRgba32f((uint16_t*)_out, _rgba32f); break; - case TextureFormat::RGBA16F: rgba16fFromRgba32f((uint16_t*)_out, _rgba32f); break; - case TextureFormat::RGBA32F: rgba32fFromRgba32f((float*)_out, _rgba32f); break; - default: DEBUG_CHECK(false, "Unknown image format."); - }; - } - - void imageFromRgba32f(Image& _dst, TextureFormat::Enum _dstFormat, const Image& _src, AllocatorI* _allocator) - { - DEBUG_CHECK(TextureFormat::RGBA32F == _src.m_format, "Source image is not in RGBA32F format!"); - - // Alloc dst data. - const uint32_t pixelCount = imageGetNumPixels(_src); - const uint8_t dstBytesPerPixel = getImageDataInfo(_dstFormat).m_bytesPerPixel; - const uint32_t dstDataSize = pixelCount*dstBytesPerPixel; - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - // Get total number of channels. - const uint8_t srcNumChannels = getImageDataInfo(_src.m_format).m_numChanels; - const uint32_t totalNumChannels = pixelCount*srcNumChannels; - - // Convert data. - const float* src = (const float*)_src.m_data; - const float* end = (const float*)_src.m_data + totalNumChannels; - switch(_dstFormat) - { - case TextureFormat::BGR8: - { - uint8_t* dst = (uint8_t*)dstData; - - for (;src < end; src+=4, dst+=3) - { - bgr8FromRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGB8: - { - uint8_t* dst = (uint8_t*)dstData; - - for (;src < end; src+=4, dst+=3) - { - rgb8FromRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGB16: - { - uint16_t* dst = (uint16_t*)dstData; - - for (;src < end; src+=4, dst+=3) - { - rgb16FromRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGB16F: - { - uint16_t* dst = (uint16_t*)dstData; - - for (;src < end; src+=4, dst+=3) - { - rgb16fFromRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGB32F: - { - float* dst = (float*)dstData; - - for (;src < end; src+=4, dst+=3) - { - rgb32fFromRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGBE: - { - uint8_t* dst = (uint8_t*)dstData; - - for (;src < end; src+=4, dst+=4) - { - rgbeFromRgba32f(dst, src); - } - } - break; - - case TextureFormat::BGRA8: - { - uint8_t* dst = (uint8_t*)dstData; - - for (;src < end; src+=4, dst+=4) - { - bgra8FromRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGBA8: - { - uint8_t* dst = (uint8_t*)dstData; - - for (;src < end; src+=4, dst+=4) - { - rgba8FromRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGBA16: - { - uint16_t* dst = (uint16_t*)dstData; - - for (;src < end; src+=4, dst+=4) - { - rgba16FromRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGBA16F: - { - uint16_t* dst = (uint16_t*)dstData; - - for (;src < end; src+=4, dst+=4) - { - rgba16fFromRgba32f(dst, src); - } - } - break; - - case TextureFormat::RGBA32F: - { - float* dst = (float*)dstData; - - for (;src < end; src+=4, dst+=4) - { - rgba32fFromRgba32f(dst, src); - } - } - break; - - default: - { - DEBUG_CHECK(false, "Unknown image format."); - } - break; - }; - - // Fill image structure. - Image result; - result.m_data = dstData; - result.m_width = _src.m_width; - result.m_height = _src.m_height; - result.m_dataSize = dstDataSize; - result.m_format = _dstFormat; - result.m_numMips = _src.m_numMips; - result.m_numFaces = _src.m_numFaces; - - // Output. - imageMove(_dst, result, _allocator); - } - - void imageFromRgba32f(Image& _image, TextureFormat::Enum _textureFormat, AllocatorI* _allocator) - { - Image tmp; - imageFromRgba32f(tmp, _textureFormat, _image, _allocator); - imageMove(_image, tmp, _allocator); - } - - void imageConvert(Image& _dst, TextureFormat::Enum _dstFormat, const Image& _src, AllocatorI* _allocator) - { - // Image _src to rgba32f. - ImageSoftRef imageRgba32f; - if (TextureFormat::RGBA32F == _src.m_format) - { - imageRef(imageRgba32f, _src); - } - else - { - imageToRgba32f(imageRgba32f, _src, _allocator); - } - - // Image rgba32f to _dst. - if (TextureFormat::RGBA32F == _dstFormat) - { - imageUnload(_dst, _allocator); - if (imageRgba32f.m_isRef) - { - imageCopy(_dst, imageRgba32f, _allocator); - } - else - { - imageMove(_dst, imageRgba32f, _allocator); - } - - } - else - { - imageUnload(_dst, _allocator); - imageFromRgba32f(_dst, _dstFormat, imageRgba32f, _allocator); - } - - // Cleanup. - imageUnload(imageRgba32f, _allocator); - } - - void imageConvert(Image& _image, TextureFormat::Enum _format, AllocatorI* _allocator) - { - if (_format != _image.m_format) - { - Image tmp; - imageConvert(tmp, _format, _image, _allocator); - imageMove(_image, tmp, _allocator); - } - } - - void imageGetPixel(void* _out, TextureFormat::Enum _format, uint32_t _x, uint32_t _y, uint8_t _face, uint8_t _mip, const Image& _image) - { - // Input check. - DEBUG_CHECK(_x < _image.m_width, "Invalid input parameters. X coord bigger than image width."); - DEBUG_CHECK(_y < _image.m_height, "Invalid input parameters. Y coord bigger than image height."); - DEBUG_CHECK(_face < _image.m_numFaces, "Invalid input parameters. Requesting pixel from non-existing face."); - DEBUG_CHECK(_mip < _image.m_numMips, "Invalid input parameters. Requesting pixel from non-existing mip level."); - - const uint32_t bytesPerPixel = getImageDataInfo(_image.m_format).m_bytesPerPixel; - const uint32_t pitch = _image.m_width * bytesPerPixel; - - // Get face and mip offset. - uint32_t offset = 0; - for (uint8_t face = 0; face < _face; ++face) - { - for (uint8_t mip = 0, end = _mip+1; mip < end; ++mip) - { - const uint32_t width = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - offset += width * height * bytesPerPixel; - } - } - - const void* src = (const void*)((const uint8_t*)_image.m_data + offset + _y*pitch + _x*bytesPerPixel); - - // Output. - if (_image.m_format == _format) - { - // Image is already in requested format, just copy data. - memcpy(_out, src, bytesPerPixel); - } - else if (_image.m_format == TextureFormat::RGBA32F) - { - // Image is in rgba32f format. Transform to output format. - fromRgba32f(_out, _format, (const float*)src); - } - else - { - // Image is in some other format. - // Transform to rgba32f and then back to requested output format. - float buf[4]; - toRgba32f(buf, _image.m_format, src); - fromRgba32f(_out, _format, buf); - } - } - - void imageCubemapGetPixel(void* _out, TextureFormat::Enum _format, float _dir[3], uint8_t _mip, const Image& _image) - { - float uu; - float vv; - uint8_t face; - vecToTexelCoord(uu, vv, face, _dir); - - const float sizeMinusOne = float(int32_t(_image.m_width-1)); - const int32_t xx = int32_t(uu*sizeMinusOne); - const int32_t yy = int32_t(vv*sizeMinusOne); - - imageGetPixel(_out, _format, xx, yy, face, _mip, _image); - } - - // Notice: this is the most trivial image resampling implementation. Use this only for testing/debugging purposes! - void imageResize(Image& _dst, uint32_t _width, uint32_t _height, const Image& _src, AllocatorI* _allocator) - { - // Operation is done in rgba32f format. - ImageSoftRef imageRgba32f; - imageRefOrConvert(imageRgba32f, TextureFormat::RGBA32F, _src, _allocator); - - // Alloc dst data. - const uint32_t bytesPerPixel = 4 /*numChannels*/ * 4 /*bytesPerChannel*/; - uint32_t dstDataSize = 0; - uint32_t dstOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - for (uint8_t face = 0; face < imageRgba32f.m_numFaces; ++face) - { - for (uint8_t mip = 0; mip < imageRgba32f.m_numMips; ++mip) - { - dstOffsets[face][mip] = dstDataSize; - const uint32_t dstMipWidth = CMFT_MAX(UINT32_C(1), _width >> mip); - const uint32_t dstMipHeight = CMFT_MAX(UINT32_C(1), _height >> mip); - dstDataSize += dstMipWidth * dstMipHeight * bytesPerPixel; - } - } - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - // Get source offsets. - uint32_t srcOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(srcOffsets, imageRgba32f); - - // Resample. - for (uint8_t face = 0; face < imageRgba32f.m_numFaces; ++face) - { - for (uint8_t mip = 0; mip < imageRgba32f.m_numMips; ++mip) - { - const uint8_t srcMip = CMFT_MIN(mip, uint8_t(_src.m_numMips-1)); - const uint32_t srcMipWidth = CMFT_MAX(UINT32_C(1), imageRgba32f.m_width >> srcMip); - const uint32_t srcMipHeight = CMFT_MAX(UINT32_C(1), imageRgba32f.m_height >> srcMip); - const uint32_t srcMipPitch = srcMipWidth * bytesPerPixel; - const uint8_t* srcMipData = (const uint8_t*)imageRgba32f.m_data + srcOffsets[face][srcMip]; - - const uint32_t dstMipWidth = CMFT_MAX(UINT32_C(1), _width >> mip); - const uint32_t dstMipHeight = CMFT_MAX(UINT32_C(1), _height >> mip); - const uint32_t dstMipPitch = dstMipWidth * bytesPerPixel; - - const float dstToSrcRatioXf = cmft::utof(srcMipWidth) /cmft::utof(dstMipWidth); - const float dstToSrcRatioYf = cmft::utof(srcMipHeight)/cmft::utof(dstMipHeight); - const uint32_t dstToSrcRatioX = cmft::ftou(dstToSrcRatioXf); - const uint32_t dstToSrcRatioY = cmft::ftou(dstToSrcRatioYf); - - uint8_t* dstMipData = (uint8_t*)dstData + dstOffsets[face][mip]; - - for (int32_t yDst = 0; yDst < int32_t(dstMipHeight); ++yDst) - { - uint8_t* dstFaceRow = (uint8_t*)dstMipData + yDst*dstMipPitch; - - for (int32_t xDst = 0; xDst < int32_t(dstMipWidth); ++xDst) - { - float* dstFaceColumn = (float*)((uint8_t*)dstFaceRow + xDst*bytesPerPixel); - - float color[3] = { 0.0f, 0.0f, 0.0f }; - uint32_t weight = 0; - - uint32_t ySrc = cmft::ftou(float(yDst)*dstToSrcRatioYf); - uint32_t const ySrcEnd = ySrc + CMFT_MAX(1, dstToSrcRatioY); - for (; ySrc < ySrcEnd; ++ySrc) - { - const uint8_t* srcRowData = (const uint8_t*)srcMipData + ySrc*srcMipPitch; - - uint32_t xSrc = cmft::ftou(float(xDst)*dstToSrcRatioXf); - uint32_t const xSrcEnd = xSrc + CMFT_MAX(1, dstToSrcRatioX); - for (; xSrc < xSrcEnd; ++xSrc) - { - const float* srcColumnData = (const float*)((const uint8_t*)srcRowData + xSrc*bytesPerPixel); - color[0] += srcColumnData[0]; - color[1] += srcColumnData[1]; - color[2] += srcColumnData[2]; - weight++; - } - } - - const float invWeight = 1.0f/cmft::utof(CMFT_MAX(weight, UINT32_C(1))); - dstFaceColumn[0] = color[0] * invWeight; - dstFaceColumn[1] = color[1] * invWeight; - dstFaceColumn[2] = color[2] * invWeight; - dstFaceColumn[3] = 1.0f; - } - } - } - } - - // Fill image structure. - Image result; - result.m_width = _width; - result.m_height = _height; - result.m_dataSize = dstDataSize; - result.m_format = TextureFormat::RGBA32F; - result.m_numMips = imageRgba32f.m_numMips; - result.m_numFaces = imageRgba32f.m_numFaces; - result.m_data = dstData; - - // Convert result to source format. - if (TextureFormat::RGBA32F == _src.m_format) - { - imageMove(_dst, result, _allocator); - } - else - { - imageConvert(_dst, (TextureFormat::Enum)_src.m_format, result, _allocator); - imageUnload(result, _allocator); - } - - // Cleanup. - imageUnload(imageRgba32f, _allocator); - } - - void imageResize(Image& _image, uint32_t _width, uint32_t _height, AllocatorI* _allocator) - { - Image tmp; - imageResize(tmp, _width, _height, _image, _allocator); - imageMove(_image, tmp, _allocator); - } - - static inline void faceSizeToWH(uint32_t& _width, uint32_t& _height, uint32_t _faceSize, const cmft::Image& _image) - { - if (cmft::imageIsLatLong(_image)) - { - _width = _faceSize*4; - _height = _faceSize*2; - } - else if (imageIsCubeCross(_image, true)) - { - const float aspect = float(int32_t(_image.m_width))/float(int32_t(_image.m_height)); - const bool isVertical = cmft::equals(aspect, 3.0f/4.0f, 0.0001f); - if (isVertical) - { - _width = _faceSize*3; - _height = _faceSize*4; - } - else // isHorizontal - { - _width = _faceSize*4; - _height = _faceSize*3; - } - } - else if (imageIsHStrip(_image)) - { - _width = _faceSize*6; - _height = _faceSize; - } - else if (imageIsVStrip(_image)) - { - _width = _faceSize; - _height = _faceSize*6; - } - else // Cubemap. - { - _width = _faceSize; - _height = _faceSize; - } - } - - void imageResize(Image& _dst, uint32_t _faceSize, const Image& _src, AllocatorI* _allocator) - { - uint32_t width, height; - faceSizeToWH(width, height, _faceSize, _src); - imageResize(_dst, width, height, _src, _allocator); - } - - void imageResize(Image& _image, uint32_t _faceSize, AllocatorI* _allocator) - { - uint32_t width, height; - faceSizeToWH(width, height, _faceSize, _image); - imageResize(_image, width, height, _allocator); - } - - uint32_t imageGetCubemapFaceSize(const Image& _image) - { - if (cmft::imageIsLatLong(_image)) - { - return _image.m_width>>2; - } - else if (imageIsHStrip(_image)) - { - return _image.m_height; - } - else if (imageIsCubeCross(_image, true)) - { - const float aspect = float(int32_t(_image.m_width))/float(int32_t(_image.m_height)); - const bool isVertical = cmft::equals(aspect, 3.0f/4.0f, 0.0001f); - if (isVertical) - { - return _image.m_height>>2; - } - else // isHorizontal. - { - return _image.m_width>>2; - } - } - else // Image is vstrip or cubemap. - { - return _image.m_width; - } - } - - void imageTransformUseMacroInstead(Image* _image, ...) - { - va_list argList; - va_start(argList, _image); - imageTransformArg(*_image, argList); - va_end(argList); - } - - void imageTransformArg(Image& _image, va_list _argList) - { - uint32_t op = va_arg(_argList, uint32_t); - if (UINT32_MAX != op) - { - const uint32_t bytesPerPixel = getImageDataInfo(_image.m_format).m_bytesPerPixel; - - uint32_t offsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(offsets, _image); - - uint8_t* tmp = (uint8_t*)alloca(bytesPerPixel * _image.m_width); - - for (uint8_t ii = 0; op != UINT32_MAX; ++ii, op = va_arg(_argList, uint32_t)) - { - const uint16_t imageOp = (op&IMAGE_OP_MASK); - const uint8_t imageFace = (op&IMAGE_FACE_MASK)>>IMAGE_FACE_SHIFT; - - if (imageOp&IMAGE_OP_ROT_90) - { - if (_image.m_width == _image.m_height) - { - for (uint8_t mip = 0; mip < _image.m_numMips; ++mip) - { - const uint32_t width = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - const uint32_t pitch = width * bytesPerPixel; - - uint8_t* facePtr = (uint8_t*)_image.m_data + offsets[imageFace][mip]; - for (uint32_t yy = 0, yyEnd = height-1; yy < height; ++yy, --yyEnd) - { - uint8_t* rowPtr = (uint8_t*)facePtr + yy*pitch; - uint8_t* columnPtr = (uint8_t*)facePtr + yyEnd*bytesPerPixel; - for (uint32_t xx = 0, xxEnd = width-1; xx < width; ++xx, --xxEnd) - { - if (xx < yyEnd) - { - uint8_t* aa = (uint8_t*)rowPtr + xx*bytesPerPixel; - uint8_t* bb = (uint8_t*)columnPtr + xxEnd*pitch; - cmft::swap(aa, bb, tmp, bytesPerPixel); - } - } - } - - // Flip X. - for (uint32_t yy = 0, yyEnd = height-1; yy < yyEnd; ++yy, --yyEnd) - { - uint8_t* rowPtr = (uint8_t*)facePtr + pitch*yy; - uint8_t* rowPtrEnd = (uint8_t*)facePtr + pitch*yyEnd; - cmft::swap(rowPtr, rowPtrEnd, tmp, pitch); - } - } - } - else - { - WARN("Because image data transformation is done in place, " - "rotation operations work only when image width is equal to image height."); - } - } - - if (imageOp&IMAGE_OP_ROT_180) - { - if (_image.m_width == _image.m_height) - { - for (uint8_t mip = 0; mip < _image.m_numMips; ++mip) - { - const uint32_t width = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - const uint32_t pitch = width * bytesPerPixel; - - uint8_t* facePtr = (uint8_t*)_image.m_data + offsets[imageFace][mip]; - uint32_t yy = 0, yyEnd = height-1; - for (; yy < yyEnd; ++yy, --yyEnd) - { - uint8_t* rowPtr = (uint8_t*)facePtr + pitch*yy; - uint8_t* rowPtrEnd = (uint8_t*)facePtr + pitch*yyEnd; - for (uint32_t xx = 0, xxEnd = width-1; xx < width; ++xx, --xxEnd) - { - uint8_t* aa = (uint8_t*)rowPtr + bytesPerPixel*xx; - uint8_t* bb = (uint8_t*)rowPtrEnd + bytesPerPixel*xxEnd; - cmft::swap(aa, bb, tmp, bytesPerPixel); - } - } - - // Handle middle line as special case. - if (yy == yyEnd) - { - uint8_t* rowPtr = (uint8_t*)facePtr + pitch*yy; - for (uint32_t xx = 0, xxEnd = width-1; xx < xxEnd; ++xx, --xxEnd) - { - uint8_t* aa = (uint8_t*)rowPtr + bytesPerPixel*xx; - uint8_t* bb = (uint8_t*)rowPtr + bytesPerPixel*xxEnd; - cmft::swap(aa, bb, tmp, bytesPerPixel); - } - } - } - } - else - { - WARN("Because image data transformation is done in place, " - "rotation operations work only when image width is equal to image height." - ); - } - } - - if (imageOp&IMAGE_OP_ROT_270) - { - if (_image.m_width == _image.m_height) - { - for (uint8_t mip = 0; mip < _image.m_numMips; ++mip) - { - const uint32_t width = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - const uint32_t pitch = width * bytesPerPixel; - - uint8_t* facePtr = (uint8_t*)_image.m_data + offsets[imageFace][mip]; - for (uint32_t yy = 0; yy < height; ++yy) - { - uint8_t* rowPtr = (uint8_t*)facePtr + yy*pitch; - uint8_t* columnPtr = (uint8_t*)facePtr + yy*bytesPerPixel; - for (uint32_t xx = 0; xx < width; ++xx) - { - if (xx > yy) - { - uint8_t* aa = (uint8_t*)rowPtr + xx*bytesPerPixel; - uint8_t* bb = (uint8_t*)columnPtr + xx*pitch; - cmft::swap(aa, bb, tmp, bytesPerPixel); - } - } - } - - // Flip X. - for (uint32_t yy = 0, yyEnd = height-1; yy < yyEnd; ++yy, --yyEnd) - { - uint8_t* rowPtr = (uint8_t*)facePtr + pitch*yy; - uint8_t* rowPtrEnd = (uint8_t*)facePtr + pitch*yyEnd; - cmft::swap(rowPtr, rowPtrEnd, tmp, pitch); - } - } - } - else - { - WARN("Because image data transformation is done in place, " - "rotation operations work only when image width is equal to image height." - ); - } - } - - if (imageOp&IMAGE_OP_FLIP_X) - { - for (uint8_t mip = 0; mip < _image.m_numMips; ++mip) - { - const uint32_t width = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - const uint32_t pitch = width * bytesPerPixel; - - uint8_t* facePtr = (uint8_t*)_image.m_data + offsets[imageFace][mip]; - for (uint32_t yy = 0, yyEnd = height-1; yy < yyEnd; ++yy, --yyEnd) - { - uint8_t* rowPtr = (uint8_t*)facePtr + pitch*yy; - uint8_t* rowPtrEnd = (uint8_t*)facePtr + pitch*yyEnd; - cmft::swap(rowPtr, rowPtrEnd, tmp, pitch); - } - } - } - - if (imageOp&IMAGE_OP_FLIP_Y) - { - for (uint8_t mip = 0; mip < _image.m_numMips; ++mip) - { - const uint32_t width = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - const uint32_t pitch = width * bytesPerPixel; - - uint8_t* facePtr = (uint8_t*)_image.m_data + offsets[imageFace][mip]; - for (uint32_t yy = 0; yy < height; ++yy) - { - uint8_t* rowPtr = (uint8_t*)facePtr + pitch*yy; - for (uint32_t xx = 0, xxEnd = width-1; xx < xxEnd; ++xx, --xxEnd) - { - uint8_t* columnPtr = (uint8_t*)rowPtr + bytesPerPixel*xx; - uint8_t* columnPtrEnd = (uint8_t*)rowPtr + bytesPerPixel*xxEnd; - cmft::swap(columnPtr, columnPtrEnd, tmp, bytesPerPixel); - } - } - } - } - } - } - } - - void imageGenerateMipMapChain(Image& _image, uint8_t _numMips, AllocatorI* _allocator) - { - // Processing is done in rgba32f format. - ImageHardRef imageRgba32f; - imageRefOrConvert(imageRgba32f, TextureFormat::RGBA32F, _image, _allocator); - - // Calculate dataSize and offsets for the entire mip map chain. - uint32_t dstOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - uint32_t dstDataSize = 0; - uint8_t mipCount = 0; - const uint8_t maxMipNum = CMFT_MIN(_numMips, uint8_t(MAX_MIP_NUM)); - const uint32_t bytesPerPixel = 4 /*numChannels*/ * 4 /*bytesPerChannel*/; - for (uint8_t face = 0; face < imageRgba32f.m_numFaces; ++face) - { - uint32_t width = 0; - uint32_t height = 0; - - for (mipCount = 0; (mipCount < maxMipNum) && (width != 1) && (height != 1); ++mipCount) - { - dstOffsets[face][mipCount] = dstDataSize; - width = CMFT_MAX(UINT32_C(1), imageRgba32f.m_width >> mipCount); - height = CMFT_MAX(UINT32_C(1), imageRgba32f.m_height >> mipCount); - - dstDataSize += width * height * bytesPerPixel; - } - } - - // Alloc data. - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - // Get source offsets. - uint32_t srcOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(srcOffsets, imageRgba32f); - - // Generate mip chain. - for (uint8_t face = 0; face < imageRgba32f.m_numFaces; ++face) - { - for (uint8_t mip = 0; mip < mipCount; ++mip) - { - const uint32_t width = CMFT_MAX(UINT32_C(1), imageRgba32f.m_width >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), imageRgba32f.m_height >> mip); - const uint32_t pitch = width * bytesPerPixel; - - uint8_t* dstMipData = (uint8_t*)dstData + dstOffsets[face][mip]; - const uint8_t* srcMipData = (const uint8_t*)imageRgba32f.m_data + srcOffsets[face][mip]; - - // If mip is present, copy data. - if (mip < imageRgba32f.m_numMips) - { - for (uint32_t yy = 0; yy < height; ++yy) - { - uint8_t* dst = (uint8_t*)dstMipData + yy*pitch; - const uint8_t* src = (const uint8_t*)srcMipData + yy*pitch; - memcpy(dst, src, pitch); - } - } - // Else generate it. - else - { - const uint8_t parentMip = mip - 1; - const uint32_t parentWidth = CMFT_MAX(UINT32_C(1), imageRgba32f.m_width >> parentMip); - const uint32_t parentPitch = parentWidth * bytesPerPixel; - const uint8_t* parentMipData = (const uint8_t*)dstData + dstOffsets[face][parentMip]; - - for (uint32_t yy = 0; yy < height; ++yy) - { - uint8_t* dstRowData = (uint8_t*)dstMipData + pitch*yy; - for (uint32_t xx = 0; xx < width; ++xx) - { - float* dstColumnData = (float*)((uint8_t*)dstRowData + xx*bytesPerPixel); - - float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - for (uint32_t yParent = yy*2, yEnd = yParent+2; yParent < yEnd; ++yParent) - { - const uint8_t* parentRowData = (const uint8_t*)parentMipData + parentPitch*yParent; - for (uint32_t xParent = xx*2, xEnd = xParent+2; xParent < xEnd; ++xParent) - { - const float* parentColumnData = (const float*)((const uint8_t*)parentRowData + xParent*bytesPerPixel); - color[0] += parentColumnData[0]; - color[1] += parentColumnData[1]; - color[2] += parentColumnData[2]; - color[3] += parentColumnData[3]; - } - } - - dstColumnData[0] = color[0] * 0.25f; - dstColumnData[1] = color[1] * 0.25f; - dstColumnData[2] = color[2] * 0.25f; - dstColumnData[3] = color[3] * 0.25f; - } - } - } - } - } - - // Fill image structure. - Image result; - result.m_width = imageRgba32f.m_width; - result.m_height = imageRgba32f.m_height; - result.m_dataSize = dstDataSize; - result.m_format = imageRgba32f.m_format; - result.m_numMips = mipCount; - result.m_numFaces = imageRgba32f.m_numFaces; - result.m_data = dstData; - - // Convert result to source format. - if (TextureFormat::RGBA32F == (TextureFormat::Enum)_image.m_format) - { - imageMove(_image, result, _allocator); - } - else - { - imageConvert(_image, (TextureFormat::Enum)_image.m_format, result, _allocator); - imageUnload(result, _allocator); - } - - // Cleanup. - imageUnload(imageRgba32f, _allocator); - } - - // From: http://chilliant.blogspot.pt/2012/08/srgb-approximations-for-hlsl.html - float ToSRGBApprox(float v) - { - float S1 = sqrtf( v ); - float S2 = sqrtf( S1 ); - float S3 = sqrtf( S2 ); - float sRGB = 0.585122381f * S1 + 0.783140355f * S2 - 0.368262736f * S3; - return sRGB; - } - - void imageEncodeRGBM(Image& _image, AllocatorI* _allocator) - { - // Operation is done in rgba32f format. - ImageHardRef imageRgba32f; - imageRefOrConvert(imageRgba32f, TextureFormat::RGBA32F, _image, _allocator); - - // Iterate through image channels and apply gamma function. - float* channel = (float*)imageRgba32f.m_data; - const float* end = (const float*)((const uint8_t*)imageRgba32f.m_data + imageRgba32f.m_dataSize); - - float rgbm[4]; - for (; channel < end; channel += 4) - { - // convert to gamma space before encoding - channel[0] = ToSRGBApprox(channel[0]); - channel[1] = ToSRGBApprox(channel[1]); - channel[2] = ToSRGBApprox(channel[2]); - channel[3] = ToSRGBApprox(channel[3]); - - memcpy( rgbm, channel, 4*sizeof(float) ); - - rgbm[0] /= 6.0f; - rgbm[1] /= 6.0f; - rgbm[2] /= 6.0f; - - float m = fsaturate(fmaxf(fmaxf(rgbm[0], rgbm[1]), fmaxf(rgbm[2], 1e-6f))); - m = ceil(rgbm[3] * 255.0f) / 255.0f; - rgbm[0] /= m; - rgbm[1] /= m; - rgbm[2] /= m; - rgbm[3] = m; - - channel[0] = rgbm[0]; - channel[1] = rgbm[1]; - channel[2] = rgbm[2]; - channel[3] = rgbm[3]; - } - - // Convert to BGRA8 format as final. Overrides any format the user asks - if (imageRgba32f.isCopy()) - { - imageConvert(_image, TextureFormat::BGRA8, imageRgba32f, _allocator); - } - - // Cleanup. - imageUnload(imageRgba32f, _allocator); - } - - void imageApplyGamma(Image& _image, float _gammaPow, AllocatorI* _allocator) - { - // Do nothing if _gammaPow is ~= 1.0f. - if (cmft::equals(_gammaPow, 1.0, 0.0001f)) - { - return; - } - - // Operation is done in rgba32f format. - ImageHardRef imageRgba32f; - imageRefOrConvert(imageRgba32f, TextureFormat::RGBA32F, _image, _allocator); - - // Iterate through image channels and apply gamma function. - float* channel = (float*)imageRgba32f.m_data; - const float* end = (const float*)((const uint8_t*)imageRgba32f.m_data + imageRgba32f.m_dataSize); - - for (;channel < end; channel+=4) - { - channel[0] = powf(channel[0], _gammaPow); - channel[1] = powf(channel[1], _gammaPow); - channel[2] = powf(channel[2], _gammaPow); - //channel[3] = leave alpha channel as is. - } - - // If image was converted, convert back to original format. - if (imageRgba32f.isCopy()) - { - imageConvert(_image, (TextureFormat::Enum)_image.m_format, imageRgba32f, _allocator); - } - - // Cleanup. - imageUnload(imageRgba32f, _allocator); - } - - void imageClamp(Image& _dst, const Image& _src, AllocatorI* _allocator) - { - // Get a copy in rgba32f format. - Image imageRgba32f; - imageConvert(imageRgba32f, TextureFormat::RGBA32F, _src, _allocator); - - // Iterate through image channels and clamp to [0.0-1.0] range. - float* channel = (float*)imageRgba32f.m_data; - const float* end = (const float*)((const uint8_t*)imageRgba32f.m_data + imageRgba32f.m_dataSize); - - for (;channel < end; channel+=4) - { - channel[0] = CMFT_CLAMP(channel[0], 0.0f, 1.0f); - channel[1] = CMFT_CLAMP(channel[1], 0.0f, 1.0f); - channel[2] = CMFT_CLAMP(channel[2], 0.0f, 1.0f); - channel[3] = CMFT_CLAMP(channel[3], 0.0f, 1.0f); - } - - // Move or convert to original format. - if (TextureFormat::RGBA32F == _src.m_format) - { - imageMove(_dst, imageRgba32f, _allocator); - } - else - { - imageConvert(_dst, (TextureFormat::Enum)_src.m_format, imageRgba32f, _allocator); - imageUnload(imageRgba32f, _allocator); - } - } - - void imageClamp(Image& _image, AllocatorI* _allocator) - { - // Operation is done in rgba32f format. - ImageHardRef imageRgba32f; - imageRefOrConvert(imageRgba32f, TextureFormat::RGBA32F, _image, _allocator); - - // Iterate through image channels and clamp to [0.0-1.0] range. - float* channel = (float*)imageRgba32f.m_data; - const float* end = (const float*)((const uint8_t*)imageRgba32f.m_data + imageRgba32f.m_dataSize); - - for (;channel < end; channel+=4) - { - channel[0] = CMFT_CLAMP(channel[0], 0.0f, 1.0f); - channel[1] = CMFT_CLAMP(channel[1], 0.0f, 1.0f); - channel[2] = CMFT_CLAMP(channel[2], 0.0f, 1.0f); - channel[3] = CMFT_CLAMP(channel[3], 0.0f, 1.0f); - } - - // If image was converted, convert back to original format. - if (imageRgba32f.isCopy()) - { - imageConvert(_image, (TextureFormat::Enum)_image.m_format, imageRgba32f, _allocator); - } - - // Cleanup. - imageUnload(imageRgba32f, _allocator); - } - - bool imageIsCubemap(const Image& _image) - { - return (6 == _image.m_numFaces) && (_image.m_width == _image.m_height); - } - - bool imageIsLatLong(const Image& _image) - { - const float aspect = (float)(int32_t)_image.m_width/(float)(int32_t)_image.m_height; - return cmft::equals(aspect, 2.0f, 0.00001f); - } - - bool imageIsHStrip(const Image& _image) - { - return (_image.m_width == 6*_image.m_height); - } - - bool imageIsVStrip(const Image& _image) - { - return (6*_image.m_width == _image.m_height); - } - - bool imageIsOctant(const Image& _image) - { - return (_image.m_width == _image.m_height); - } - - bool imageValidCubemapFaceList(const Image _faceList[6]) - { - const uint32_t size = _faceList[0].m_width; - const uint8_t numMips = _faceList[0].m_numMips; - for (uint8_t face = 0; face < 6; ++face) - { - if (_faceList[face].m_width != _faceList[face].m_height - || size != _faceList[face].m_width - || numMips != _faceList[face].m_numMips) - { - return false; - } - } - return true; - } - - bool imageIsCubeCross(const Image& _image, bool _fastCheck) - { - // Check face count. - if (1 != _image.m_numFaces) - { - return false; - } - - // Check aspect. - const float aspect = (float)(int32_t)_image.m_width/(float)(int32_t)_image.m_height; - const bool isVertical = cmft::equals(aspect, 3.0f/4.0f, 0.0001f); - const bool isHorizontal = cmft::equals(aspect, 4.0f/3.0f, 0.0001f); - - if (!isVertical && !isHorizontal) - { - return false; - } - - // Aspect ratio is valid. - if (_fastCheck) - { - return true; - } - - // Define key points. - const uint32_t bytesPerPixel = getImageDataInfo(_image.m_format).m_bytesPerPixel; - const uint32_t imagePitch = _image.m_width * bytesPerPixel; - - const uint32_t faceSize = cmft::alignf((float)(int32_t)_image.m_width / (isVertical ? 3.0f : 4.0f), bytesPerPixel); - const uint32_t facePitch = faceSize * bytesPerPixel; - const uint32_t rowDataSize = imagePitch * faceSize; - - const uint32_t halfFacePitch = cmft::alignf((float)(int32_t)facePitch / 2.0f, bytesPerPixel); - const uint32_t halfRowDataSize = cmft::alignf((float)(int32_t)rowDataSize / 2.0f, bytesPerPixel); - - uint32_t keyPointsOffsets[6]; - if (isVertical) - { - // ___ ___ ___ - // | | | | -> rowDataSize - // |___|___|___| - // - // ___ -> facePitch - // - // . -> keyPoint - // ___ - // . |Y+ | . - // ___|___|___ - // |X- |Z+ |X+ | - // |___|___|___| - // . |Y- | . - // |___| - // . |Z- | . - // |___| - // - const uint32_t leftCenter = halfRowDataSize + halfFacePitch; - const uint32_t rightCenter = halfRowDataSize + 5*halfFacePitch; - const uint32_t firstRow = 0; - const uint32_t thirdRow = 2*rowDataSize; - const uint32_t fourthRow = 3*rowDataSize; - keyPointsOffsets[0] = leftCenter + firstRow; //+x - keyPointsOffsets[1] = rightCenter + firstRow; //-x - keyPointsOffsets[2] = leftCenter + thirdRow; //+y - keyPointsOffsets[3] = rightCenter + thirdRow; //-y - keyPointsOffsets[4] = leftCenter + fourthRow; //+z - keyPointsOffsets[5] = rightCenter + fourthRow; //-z - } - else - { - // ___ - // . |+Y | . . - // ___|___|___ ___ - // |-X |+Z |+X |-Z | - // |___|___|___|___| - // . |-Y | . . - // |___| - // - const uint32_t center0 = halfRowDataSize + halfFacePitch; - const uint32_t center1 = halfRowDataSize + 5*halfFacePitch; - const uint32_t center2 = halfRowDataSize + 7*halfFacePitch; - const uint32_t firstRow = 0; - const uint32_t thirdRow = 2*rowDataSize; - keyPointsOffsets[0] = firstRow + center0; //+x - keyPointsOffsets[1] = firstRow + center1; //-x - keyPointsOffsets[2] = firstRow + center2; //+y - keyPointsOffsets[3] = thirdRow + center0; //-y - keyPointsOffsets[4] = thirdRow + center1; //+z - keyPointsOffsets[5] = thirdRow + center2; //-z - } - - // Check key points. - bool result = true; - switch(_image.m_format) - { - case TextureFormat::BGR8: - case TextureFormat::RGB8: - case TextureFormat::BGRA8: - case TextureFormat::RGBA8: - { - for (uint8_t key = 0; (true == result) && (key < 6); ++key) - { - const uint8_t* point = (const uint8_t*)_image.m_data + keyPointsOffsets[key]; - const bool tap0 = point[0] < 2; - const bool tap1 = point[1] < 2; - const bool tap2 = point[2] < 2; - result &= (tap0 & tap1 & tap2); - } - } - break; - - case TextureFormat::RGB16: - case TextureFormat::RGBA16: - { - for (uint8_t key = 0; (true == result) && (key < 6); ++key) - { - const uint16_t* point = (const uint16_t*)((const uint8_t*)_image.m_data + keyPointsOffsets[key]); - const bool tap0 = point[0] < 2; - const bool tap1 = point[1] < 2; - const bool tap2 = point[2] < 2; - result &= (tap0 & tap1 & tap2); - } - } - break; - - case TextureFormat::RGB16F: - case TextureFormat::RGBA16F: - { - for (uint8_t key = 0; (true == result) && (key < 6); ++key) - { - const uint16_t* point = (const uint16_t*)((const uint8_t*)_image.m_data + keyPointsOffsets[key]); - const bool tap0 = cmft::halfToFloat(point[0]) < 0.01f; - const bool tap1 = cmft::halfToFloat(point[1]) < 0.01f; - const bool tap2 = cmft::halfToFloat(point[2]) < 0.01f; - result &= (tap0 & tap1 & tap2); - } - } - break; - - case TextureFormat::RGB32F: - case TextureFormat::RGBA32F: - { - for (uint8_t key = 0; (true == result) && (key < 6); ++key) - { - const float* point = (const float*)((const uint8_t*)_image.m_data + keyPointsOffsets[key]); - const bool tap0 = point[0] < 0.01f; - const bool tap1 = point[1] < 0.01f; - const bool tap2 = point[2] < 0.01f; - result &= (tap0 & tap1 & tap2); - } - } - break; - - case TextureFormat::RGBE: - { - for (uint8_t key = 0; (true == result) && (key < 6); ++key) - { - const uint8_t* point = (const uint8_t*)_image.m_data + keyPointsOffsets[key]; - const float exp = ldexp(1.0f, point[3] - (128+8)); - const bool tap0 = float(point[0])*exp < 0.01f; - const bool tap1 = float(point[1])*exp < 0.01f; - const bool tap2 = float(point[2])*exp < 0.01f; - result &= (tap0 & tap1 & tap2); - } - } - break; - - default: - { - DEBUG_CHECK(false, "Unknown image format."); - result = false; - } - break; - }; - - return result; - } - - bool imageIsEnvironmentMap(const Image& _image, bool _fastCheck) - { - return imageIsCubemap(_image) - || imageIsLatLong(_image) - || imageIsHStrip(_image) - || imageIsVStrip(_image) - || imageIsCubeCross(_image, _fastCheck); - } - - bool imageCubemapFromCross(Image& _dst, const Image& _src, AllocatorI* _allocator) - { - // Checking image aspect. - const float aspect = (float)(int32_t)_src.m_width/(float)(int32_t)_src.m_height; - const bool isVertical = cmft::equals(aspect, 3.0f/4.0f, 0.0001f); - const bool isHorizontal = cmft::equals(aspect, 4.0f/3.0f, 0.0001f); - - if (!isVertical && !isHorizontal) - { - return false; - } - - // Get sizes. - const uint32_t srcBytesPerPixel = getImageDataInfo(_src.m_format).m_bytesPerPixel; - const uint32_t imagePitch = _src.m_width * srcBytesPerPixel; - const uint32_t faceSize = isVertical ? (_src.m_width+2)/3 : (_src.m_width+3)/4; - const uint32_t facePitch = faceSize * srcBytesPerPixel; - const uint32_t faceDataSize = facePitch * faceSize; - const uint32_t rowDataSize = imagePitch * faceSize; - - // Alloc data. - const uint32_t dstDataSize = faceDataSize * CUBE_FACE_NUM; - void* data = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(data); - - // Setup offsets. - uint32_t faceOffsets[6]; - if (isVertical) - { - // ___ ___ ___ - // | | | | -> rowDataSize - // |___|___|___| - // - // ___ -> facePitch - // - // ___ - // |+Y | - // ___|___|___ - // |-X |+Z |+X | - // |___|___|___| - // |-Y | - // |___| - // |-Z | - // |___| - // - faceOffsets[0] = rowDataSize + 2*facePitch; //+x - faceOffsets[1] = rowDataSize; //-x - faceOffsets[2] = facePitch; //+y - faceOffsets[3] = 2*rowDataSize + facePitch; //-y - faceOffsets[4] = rowDataSize + facePitch; //+z - faceOffsets[5] = 3*rowDataSize + facePitch; //-z - } - else - { - // ___ - // |+Y | - // ___|___|___ ___ - // |-X |+Z |+X |-Z | - // |___|___|___|___| - // |-Y | - // |___| - // - faceOffsets[0] = rowDataSize + 2*facePitch; //+x - faceOffsets[1] = rowDataSize; //-x - faceOffsets[2] = facePitch; //+y - faceOffsets[3] = 2*rowDataSize + facePitch; //-y - faceOffsets[4] = rowDataSize + facePitch; //+z - faceOffsets[5] = rowDataSize + 3*facePitch; //-z - } - - // Copy data. - for (uint8_t face = 0; face < 6; ++face) - { - const uint8_t* srcFaceData = (const uint8_t*)_src.m_data + faceOffsets[face]; - uint8_t* dstFaceData = (uint8_t*)data + faceDataSize*face; - for (uint32_t yy = 0; yy < faceSize; ++yy) - { - memcpy(&dstFaceData[facePitch*yy], &srcFaceData[imagePitch*yy], facePitch); - } - } - - // Fill image structure. - Image result; - result.m_width = faceSize; - result.m_height = faceSize; - result.m_dataSize = dstDataSize; - result.m_format = _src.m_format; - result.m_numMips = 1; - result.m_numFaces = 6; - result.m_data = data; - - // Transform -Z face properly. - if (isVertical) - { - imageTransform(result, IMAGE_FACE_NEGATIVEZ | IMAGE_OP_FLIP_X | IMAGE_OP_FLIP_Y); - } - - // Output. - imageMove(_dst, result, _allocator); - - return true; - } - - bool imageCubemapFromCross(Image& _image, AllocatorI* _allocator) - { - Image tmp; - if (imageCubemapFromCross(tmp, _image, _allocator)) - { - imageMove(_image, tmp, _allocator); - return true; - } - - return false; - } - - bool imageCubemapFromLatLong(Image& _dst, const Image& _src, bool _useBilinearInterpolation, AllocatorI* _allocator) - { - if (!imageIsLatLong(_src)) - { - return false; - } - - // Conversion is done in rgba32f format. - ImageSoftRef imageRgba32f; - imageRefOrConvert(imageRgba32f, TextureFormat::RGBA32F, _src, _allocator); - - // Alloc data. - const uint32_t bytesPerPixel = 4 /*numChannels*/ * 4 /*bytesPerChannel*/; - const uint32_t dstFaceSize = (imageRgba32f.m_height+1)/2; - const uint32_t dstPitch = dstFaceSize * bytesPerPixel; - const uint32_t dstFaceDataSize = dstPitch * dstFaceSize; - const uint32_t dstDataSize = dstFaceDataSize * CUBE_FACE_NUM; - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - // Get source parameters. - const float srcWidthMinusOne = float(int32_t(imageRgba32f.m_width-1)); - const float srcHeightMinusOne = float(int32_t(imageRgba32f.m_height-1)); - const uint32_t srcPitch = imageRgba32f.m_width * bytesPerPixel; - const float invDstFaceSizef = 1.0f/float(dstFaceSize); - - // Iterate over destination image (cubemap). - for (uint8_t face = 0; face < 6; ++face) - { - uint8_t* dstFaceData = (uint8_t*)dstData + face*dstFaceDataSize; - for (uint32_t yy = 0; yy < dstFaceSize; ++yy) - { - uint8_t* dstRowData = (uint8_t*)dstFaceData + yy*dstPitch; - for (uint32_t xx = 0; xx < dstFaceSize; ++xx) - { - float* dstColumnData = (float*)((uint8_t*)dstRowData + xx*bytesPerPixel); - - // Cubemap (u,v) on current face. - const float uu = 2.0f*xx*invDstFaceSizef-1.0f; - const float vv = 2.0f*yy*invDstFaceSizef-1.0f; - - // Get cubemap vector (x,y,z) from (u,v,faceIdx). - float vec[3]; - texelCoordToVec(vec, uu, vv, face); - - // Convert cubemap vector (x,y,z) to latlong (u,v). - float xSrcf; - float ySrcf; - latLongFromVec(xSrcf, ySrcf, vec); - - // Convert from [0..1] to [0..(size-1)] range. - xSrcf *= srcWidthMinusOne; - ySrcf *= srcHeightMinusOne; - - // Sample from latlong (u,v). - if (_useBilinearInterpolation) - { - const uint32_t x0 = cmft::ftou(xSrcf); - const uint32_t y0 = cmft::ftou(ySrcf); - const uint32_t x1 = CMFT_MIN(x0+1, imageRgba32f.m_width-1); - const uint32_t y1 = CMFT_MIN(y0+1, imageRgba32f.m_height-1); - - const float *src0 = (const float*)((const uint8_t*)imageRgba32f.m_data + y0*srcPitch + x0*bytesPerPixel); - const float *src1 = (const float*)((const uint8_t*)imageRgba32f.m_data + y0*srcPitch + x1*bytesPerPixel); - const float *src2 = (const float*)((const uint8_t*)imageRgba32f.m_data + y1*srcPitch + x0*bytesPerPixel); - const float *src3 = (const float*)((const uint8_t*)imageRgba32f.m_data + y1*srcPitch + x1*bytesPerPixel); - - const float tx = xSrcf - float(int32_t(x0)); - const float ty = ySrcf - float(int32_t(y0)); - const float invTx = 1.0f - tx; - const float invTy = 1.0f - ty; - - float p0[3]; - float p1[3]; - float p2[3]; - float p3[3]; - vec3Mul(p0, src0, invTx*invTy); - vec3Mul(p1, src1, tx*invTy); - vec3Mul(p2, src2, invTx* ty); - vec3Mul(p3, src3, tx* ty); - - const float rr = p0[0] + p1[0] + p2[0] + p3[0]; - const float gg = p0[1] + p1[1] + p2[1] + p3[1]; - const float bb = p0[2] + p1[2] + p2[2] + p3[2]; - - dstColumnData[0] = rr; - dstColumnData[1] = gg; - dstColumnData[2] = bb; - dstColumnData[3] = 1.0f; - } - else - { - const uint32_t xSrc = cmft::ftou(xSrcf); - const uint32_t ySrc = cmft::ftou(ySrcf); - const float *src = (const float*)((const uint8_t*)imageRgba32f.m_data + ySrc*srcPitch + xSrc*bytesPerPixel); - - dstColumnData[0] = src[0]; - dstColumnData[1] = src[1]; - dstColumnData[2] = src[2]; - dstColumnData[3] = 1.0f; - } - - } - } - } - - // Fill image structure. - Image result; - result.m_width = dstFaceSize; - result.m_height = dstFaceSize; - result.m_dataSize = dstDataSize; - result.m_format = TextureFormat::RGBA32F; - result.m_numMips = 1; - result.m_numFaces = 6; - result.m_data = dstData; - - // Convert result to source format. - if (TextureFormat::RGBA32F == _src.m_format) - { - imageMove(_dst, result, _allocator); - } - else - { - imageConvert(_dst, (TextureFormat::Enum)_src.m_format, result, _allocator); - imageUnload(result, _allocator); - } - - // Cleanup. - imageUnload(imageRgba32f, _allocator); - - return true; - } - - bool imageCubemapFromLatLong(Image& _image, bool _useBilinearInterpolation, AllocatorI* _allocator) - { - Image tmp; - if (imageCubemapFromLatLong(tmp, _image, _useBilinearInterpolation, _allocator)) - { - imageMove(_image, tmp, _allocator); - return true; - } - - return false; - } - - bool imageLatLongFromCubemap(Image& _dst, const Image& _src, bool _useBilinearInterpolation, AllocatorI* _allocator) - { - // Input check. - if (!imageIsCubemap(_src)) - { - return false; - } - - // Conversion is done in rgba32f format. - ImageSoftRef imageRgba32f; - imageRefOrConvert(imageRgba32f, TextureFormat::RGBA32F, _src, _allocator); - - // Alloc data. - const uint32_t bytesPerPixel = 4 /*numChannels*/ * 4 /*bytesPerChannel*/; - const uint32_t dstHeight = imageRgba32f.m_height*2; - const uint32_t dstWidth = imageRgba32f.m_height*4; - uint32_t dstDataSize = 0; - uint32_t dstMipOffsets[MAX_MIP_NUM]; - for (uint8_t mip = 0; mip < imageRgba32f.m_numMips; ++mip) - { - dstMipOffsets[mip] = dstDataSize; - const uint32_t dstMipWidth = CMFT_MAX(UINT32_C(1), dstWidth >> mip); - const uint32_t dstMipHeight = CMFT_MAX(UINT32_C(1), dstHeight >> mip); - dstDataSize += dstMipWidth * dstMipHeight * bytesPerPixel; - } - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - // Get source image parameters. - uint32_t srcOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(srcOffsets, imageRgba32f); - - // Iterate over destination image (latlong). - for (uint8_t mip = 0; mip < imageRgba32f.m_numMips; ++mip) - { - const uint32_t dstMipWidth = CMFT_MAX(UINT32_C(1), dstWidth >> mip); - const uint32_t dstMipHeight = CMFT_MAX(UINT32_C(1), dstHeight >> mip); - const uint32_t dstMipPitch = dstMipWidth * bytesPerPixel; - const float invDstWidthf = 1.0f/float(dstMipWidth-1); - const float invDstHeightf = 1.0f/float(dstMipHeight-1); - - const uint32_t srcMipSize = CMFT_MAX(UINT32_C(1), imageRgba32f.m_width >> mip); - const uint32_t srcPitch = srcMipSize * bytesPerPixel; - - const uint32_t srcMipSizeMinOne = srcMipSize-1; - const float srcMipSizeMinOnef = cmft::utof(srcMipSizeMinOne); - - uint8_t* dstMipData = (uint8_t*)dstData + dstMipOffsets[mip]; - for (uint32_t yy = 0; yy < dstMipHeight; ++yy) - { - uint8_t* dstRowData = (uint8_t*)dstMipData + yy*dstMipPitch; - for (uint32_t xx = 0; xx < dstMipWidth; ++xx) - { - float* dstColumnData = (float*)((uint8_t*)dstRowData + xx*bytesPerPixel); - - // Latlong (x,y). - const float xDst = cmft::utof(xx)*invDstWidthf; - const float yDst = cmft::utof(yy)*invDstHeightf; - - // Get cubemap vector (x,y,z) coresponding to latlong (x,y). - float vec[3]; - vecFromLatLong(vec, xDst, yDst); - - // Get cubemap (u,v,faceIdx) from cubemap vector (x,y,z). - float xSrcf; - float ySrcf; - uint8_t faceIdx; - vecToTexelCoord(xSrcf, ySrcf, faceIdx, vec); - - // Convert from [0..1] to [0..(size-1)] range. - xSrcf *= srcMipSizeMinOnef; - ySrcf *= srcMipSizeMinOnef; - - // Sample from cubemap (u,v, faceIdx). - if (_useBilinearInterpolation) - { - const uint32_t x0 = cmft::ftou(xSrcf); - const uint32_t y0 = cmft::ftou(ySrcf); - const uint32_t x1 = CMFT_MIN(x0+1, srcMipSizeMinOne); - const uint32_t y1 = CMFT_MIN(y0+1, srcMipSizeMinOne); - - const uint8_t* srcFaceData = (const uint8_t*)imageRgba32f.m_data + srcOffsets[faceIdx][mip]; - const float *src0 = (const float*)((const uint8_t*)srcFaceData + y0*srcPitch + x0*bytesPerPixel); - const float *src1 = (const float*)((const uint8_t*)srcFaceData + y0*srcPitch + x1*bytesPerPixel); - const float *src2 = (const float*)((const uint8_t*)srcFaceData + y1*srcPitch + x0*bytesPerPixel); - const float *src3 = (const float*)((const uint8_t*)srcFaceData + y1*srcPitch + x1*bytesPerPixel); - - const float tx = xSrcf - float(int32_t(x0)); - const float ty = ySrcf - float(int32_t(y0)); - const float invTx = 1.0f - tx; - const float invTy = 1.0f - ty; - - float p0[3]; - float p1[3]; - float p2[3]; - float p3[3]; - vec3Mul(p0, src0, invTx*invTy); - vec3Mul(p1, src1, tx*invTy); - vec3Mul(p2, src2, invTx* ty); - vec3Mul(p3, src3, tx* ty); - - const float rr = p0[0] + p1[0] + p2[0] + p3[0]; - const float gg = p0[1] + p1[1] + p2[1] + p3[1]; - const float bb = p0[2] + p1[2] + p2[2] + p3[2]; - - dstColumnData[0] = rr; - dstColumnData[1] = gg; - dstColumnData[2] = bb; - dstColumnData[3] = 1.0f; - } - else - { - const uint32_t xSrc = cmft::ftou(xSrcf); - const uint32_t ySrc = cmft::ftou(ySrcf); - - const uint8_t* srcFaceData = (const uint8_t*)imageRgba32f.m_data + srcOffsets[faceIdx][mip]; - const float *src = (const float*)((const uint8_t*)srcFaceData + ySrc*srcPitch + xSrc*bytesPerPixel); - - dstColumnData[0] = src[0]; - dstColumnData[1] = src[1]; - dstColumnData[2] = src[2]; - dstColumnData[3] = 1.0f; - } - } - } - } - - // Fill image structure. - Image result; - result.m_width = dstWidth; - result.m_height = dstHeight; - result.m_dataSize = dstDataSize; - result.m_format = TextureFormat::RGBA32F; - result.m_numMips = imageRgba32f.m_numMips; - result.m_numFaces = 1; - result.m_data = dstData; - - // Convert back to source format. - if (TextureFormat::RGBA32F == _src.m_format) - { - imageMove(_dst, result, _allocator); - } - else - { - imageConvert(_dst, (TextureFormat::Enum)_src.m_format, result, _allocator); - imageUnload(result, _allocator); - } - - // Cleanup. - imageUnload(imageRgba32f, _allocator); - - return true; - } - - bool imageLatLongFromCubemap(Image& _cubemap, bool _useBilinearInterpolation, AllocatorI* _allocator) - { - Image tmp; - if (imageLatLongFromCubemap(tmp, _cubemap, _useBilinearInterpolation, _allocator)) - { - imageMove(_cubemap, tmp, _allocator); - return true; - } - - return false; - } - - bool imageStripFromCubemap(Image& _dst, const Image& _src, bool _vertical, AllocatorI* _allocator) - { - // Input check. - if(!imageIsCubemap(_src)) - { - return false; - } - - // Calculate destination offsets and alloc data. - uint32_t dstDataSize = 0; - uint32_t dstMipOffsets[MAX_MIP_NUM]; - const uint32_t dstWidth = _vertical ? _src.m_width : _src.m_width*6; - const uint32_t dstHeight = _vertical ? _src.m_width*6 : _src.m_width ; - const uint32_t bytesPerPixel = getImageDataInfo(_src.m_format).m_bytesPerPixel; - for (uint8_t mip = 0; mip < _src.m_numMips; ++mip) - { - dstMipOffsets[mip] = dstDataSize; - const uint32_t mipWidth = CMFT_MAX(UINT32_C(1), dstWidth >> mip); - const uint32_t mipHeight = CMFT_MAX(UINT32_C(1), dstHeight >> mip); - - dstDataSize += mipWidth * mipHeight * bytesPerPixel; - } - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - // Get source image offsets. - uint32_t srcOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(srcOffsets, _src); - - for (uint8_t face = 0; face < 6; ++face) - { - for (uint8_t mip = 0; mip < _src.m_numMips; ++mip) - { - // Get src data ptr for current mip and face. - const uint8_t* srcFaceData = (const uint8_t*)_src.m_data + srcOffsets[face][mip]; - - // Get dst ptr for current mip level. - uint8_t* dstMipData = (uint8_t*)dstData + dstMipOffsets[mip]; - - const uint32_t mipFaceSize = CMFT_MAX(UINT32_C(1), _src.m_width >> mip); - const uint32_t mipFacePitch = mipFaceSize * bytesPerPixel; - // - // Horizontal strip. - // - // .__................ ___ -> FacePitch - // . . . . . . . - // ................... - // - // - // - // Vertical strip. - // ___ - // | | - // |___| ___ - // . . | | -> FaceDataSize - // ..... |___| - // . . - // ..... - // . . - // ..... - // . . - // ..... - // . . - // ..... - // - // To get to the desired face in the strip, advance by: - // - (mipFacePitch * faceIdx) for hstrip - // - (mipFaceDataSize * faceIdx) for vstrip - // Note: mipFaceDataSize == mipFacePitch * mipFaceSize. - const uint32_t advance = _vertical ? mipFacePitch * mipFaceSize : mipFacePitch; - uint8_t* dstFaceData = (uint8_t*)dstMipData + advance*face; - - const uint32_t dstMipSize = CMFT_MAX(UINT32_C(1), dstWidth >> mip); - const uint32_t dstMipPitch = dstMipSize*bytesPerPixel; - - for (uint32_t yy = 0; yy < mipFaceSize; ++yy) - { - const uint8_t* srcRowData = (const uint8_t*)srcFaceData + yy*mipFacePitch; - uint8_t* dstRowData = (uint8_t*)dstFaceData + yy*dstMipPitch; - - memcpy(dstRowData, srcRowData, mipFacePitch); - } - } - } - - // Fill image structure. - Image result; - result.m_width = dstWidth; - result.m_height = dstHeight; - result.m_dataSize = dstDataSize; - result.m_format = _src.m_format; - result.m_numMips = _src.m_numMips; - result.m_numFaces = 1; - result.m_data = dstData; - - // Output. - imageMove(_dst, result, _allocator); - - return true; - } - - bool imageStripFromCubemap(Image& _cubemap, bool _vertical, AllocatorI* _allocator) - { - Image tmp; - if (imageStripFromCubemap(tmp, _cubemap, _vertical, _allocator)) - { - imageMove(_cubemap, tmp, _allocator); - return true; - } - - return false; - } - - bool imageCubemapFromStrip(Image& _dst, const Image& _src, AllocatorI* _allocator) - { - // Input check. - const bool isVertical = imageIsVStrip(_src); - const bool isHorizontal = imageIsHStrip(_src); - if(!isVertical && !isHorizontal) - { - return false; - } - - // Calculate destination offsets and alloc data. - uint32_t dstDataSize = 0; - uint32_t dstOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - const uint32_t dstSize = isHorizontal ? _src.m_height : _src.m_width; - const uint32_t bytesPerPixel = getImageDataInfo(_src.m_format).m_bytesPerPixel; - for (uint8_t face = 0; face < 6; ++face) - { - for (uint8_t mip = 0; mip < _src.m_numMips; ++mip) - { - dstOffsets[face][mip] = dstDataSize; - const uint32_t mipSize = CMFT_MAX(UINT32_C(1), dstSize >> mip); - - dstDataSize += mipSize * mipSize * bytesPerPixel; - } - } - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - uint32_t srcOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(srcOffsets, _src); - - for (uint8_t face = 0; face < 6; ++face) - { - for (uint8_t mip = 0; mip < _src.m_numMips; ++mip) - { - // Get dst data ptr for current mip and face. - uint8_t* dstFaceData = (uint8_t*)dstData + dstOffsets[face][mip]; - - // Get src ptr for current mip level. - const uint8_t* srcMipData = (const uint8_t*)_src.m_data + srcOffsets[0][mip]; - - // Advance by (dstPitch * faceIdx) to get to the desired face in the strip. - const uint32_t dstMipSize = CMFT_MAX(UINT32_C(1), dstSize >> mip); - const uint32_t dstMipPitch = dstMipSize * bytesPerPixel; - const uint8_t* srcFaceData = (const uint8_t*)srcMipData + dstMipPitch*face; - - const uint32_t srcMipPitch = dstMipPitch*6; - - for (uint32_t yy = 0; yy < dstMipSize; ++yy) - { - const uint8_t* srcRowData = (const uint8_t*)srcFaceData + yy*srcMipPitch; - uint8_t* dstRowData = (uint8_t*)dstFaceData + yy*dstMipPitch; - - memcpy(dstRowData, srcRowData, dstMipPitch); - } - } - } - - // Fill image structure. - Image result; - result.m_width = dstSize; - result.m_height = dstSize; - result.m_dataSize = dstDataSize; - result.m_format = _src.m_format; - result.m_numMips = _src.m_numMips; - result.m_numFaces = 6; - result.m_data = dstData; - - // Output. - imageMove(_dst, result, _allocator); - - return true; - } - - bool imageCubemapFromStrip(Image& _image, AllocatorI* _allocator) - { - Image tmp; - if (imageCubemapFromStrip(tmp, _image, _allocator)) - { - imageMove(_image, tmp, _allocator); - return true; - } - - return false; - } - - bool imageFaceListFromCubemap(Image _faceList[6], const Image& _cubemap, AllocatorI* _allocator) - { - // Input check. - if(!imageIsCubemap(_cubemap)) - { - return false; - } - - // Get destination sizes and offsets. - uint32_t dstDataSize = 0; - uint32_t dstMipOffsets[MAX_MIP_NUM]; - const uint8_t bytesPerPixel = getImageDataInfo(_cubemap.m_format).m_bytesPerPixel; - for (uint8_t mip = 0; mip < _cubemap.m_numMips; ++mip) - { - dstMipOffsets[mip] = dstDataSize; - const uint32_t mipSize = CMFT_MAX(UINT32_C(1), _cubemap.m_width >> mip); - dstDataSize += mipSize * mipSize * bytesPerPixel; - } - - // Get source offsets. - uint32_t cubemapOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(cubemapOffsets, _cubemap); - - for (uint8_t face = 0; face < 6; ++face) - { - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - for (uint8_t mip = 0; mip < _cubemap.m_numMips; ++mip) - { - const uint8_t* srcFaceData = (const uint8_t*)_cubemap.m_data + cubemapOffsets[face][mip]; - uint8_t* dstFaceData = (uint8_t*)dstData + dstMipOffsets[mip]; - - const uint32_t mipFaceSize = CMFT_MAX(UINT32_C(1), _cubemap.m_width >> mip); - const uint32_t mipPitch = mipFaceSize * bytesPerPixel; - - for (uint32_t yy = 0; yy < mipFaceSize; ++yy) - { - const uint8_t* srcRowData = (const uint8_t*)srcFaceData + yy*mipPitch; - uint8_t* dstRowData = (uint8_t*)dstFaceData + yy*mipPitch; - - memcpy(dstRowData, srcRowData, mipPitch); - } - } - - // Fill image structure. - Image result; - result.m_width = _cubemap.m_width; - result.m_height = _cubemap.m_height; - result.m_dataSize = dstDataSize; - result.m_format = _cubemap.m_format; - result.m_numMips = _cubemap.m_numMips; - result.m_numFaces = 1; - result.m_data = dstData; - - // Output. - imageMove(_faceList[face], result, _allocator); - } - - return true; - } - - bool imageCubemapFromFaceList(Image& _cubemap, const Image _faceList[6], AllocatorI* _allocator) - { - // Input check. - if (!imageValidCubemapFaceList(_faceList)) - { - return false; - } - - // Get source offsets. - uint32_t srcOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(srcOffsets, _faceList[0]); - const uint32_t bytesPerPixel = getImageDataInfo(_faceList[0].m_format).m_bytesPerPixel; - - // Alloc destination data. - const uint32_t dstDataSize = _faceList[0].m_dataSize * 6; - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - // Copy data. - uint32_t destinationOffset = 0; - for (uint8_t face = 0; face < 6; ++face) - { - const uint8_t* srcFaceData = (const uint8_t*)_faceList[face].m_data; - for (uint8_t mip = 0; mip < _faceList[0].m_numMips; ++mip) - { - const uint8_t* srcMipData = (const uint8_t*)srcFaceData + srcOffsets[0][mip]; - uint8_t* dstMipData = (uint8_t*)dstData + destinationOffset; - - const uint32_t mipFaceSize = CMFT_MAX(UINT32_C(1), _faceList[0].m_width >> mip); - const uint32_t mipPitch = mipFaceSize * bytesPerPixel; - const uint32_t mipFaceDataSize = mipPitch * mipFaceSize; - - destinationOffset += mipFaceDataSize; - - for (uint32_t yy = 0; yy < mipFaceSize; ++yy) - { - const uint8_t* srcRowData = (const uint8_t*)srcMipData + yy*mipPitch; - uint8_t* dstRowData = (uint8_t*)dstMipData + yy*mipPitch; - - memcpy(dstRowData, srcRowData, mipPitch); - } - } - } - - // Fill image structure. - Image result; - result.m_width = _faceList[0].m_width; - result.m_height = _faceList[0].m_height; - result.m_dataSize = dstDataSize; - result.m_format = _faceList[0].m_format; - result.m_numMips = _faceList[0].m_numMips; - result.m_numFaces = 6; - result.m_data = dstData; - - // Output. - imageMove(_cubemap, result, _allocator); - - return true; - } - - bool imageCrossFromCubemap(Image& _dst, const Image& _src, bool _vertical, AllocatorI* _allocator) - { - // Input check. - if(!imageIsCubemap(_src)) - { - return false; - } - - // Copy source image. - Image srcCpy; - imageCopy(srcCpy, _src, _allocator); - - // Transform -z image face properly. - if (_vertical) - { - imageTransform(srcCpy, IMAGE_FACE_NEGATIVEZ | IMAGE_OP_FLIP_X | IMAGE_OP_FLIP_Y); - } - - // Calculate destination offsets and alloc data. - uint32_t dstDataSize = 0; - uint32_t dstMipOffsets[MAX_MIP_NUM]; - const uint32_t dstWidth = (_vertical?3:4) * srcCpy.m_width; - const uint32_t dstHeight = (_vertical?4:3) * srcCpy.m_width; - const uint32_t bytesPerPixel = getImageDataInfo(srcCpy.m_format).m_bytesPerPixel; - for (uint8_t mip = 0; mip < srcCpy.m_numMips; ++mip) - { - dstMipOffsets[mip] = dstDataSize; - const uint32_t mipWidth = CMFT_MAX(UINT32_C(1), dstWidth >> mip); - const uint32_t mipHeight = CMFT_MAX(UINT32_C(1), dstHeight >> mip); - - dstDataSize += mipWidth * mipHeight * bytesPerPixel; - } - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - // Get black pixel. - void* blackPixel = alloca(bytesPerPixel); - const float blackPixelRgba32f[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - fromRgba32f(blackPixel, TextureFormat::Enum(srcCpy.m_format), blackPixelRgba32f); - - // Fill with black. - for (uint8_t mip = 0; mip < srcCpy.m_numMips; ++mip) - { - const uint32_t mipWidth = CMFT_MAX(UINT32_C(1), dstWidth >> mip); - const uint32_t mipHeight = CMFT_MAX(UINT32_C(1), dstHeight >> mip); - const uint32_t mipPitch = mipWidth*bytesPerPixel; - - uint8_t* dstMipData = (uint8_t*)dstData + dstMipOffsets[mip]; - for (uint32_t yy = 0; yy < mipHeight; ++yy) - { - uint8_t* dstRowData = (uint8_t*)dstMipData + yy*mipPitch; - for (uint32_t xx = 0; xx < mipWidth; ++xx) - { - uint8_t* dstColumnData = (uint8_t*)dstRowData + xx*bytesPerPixel; - memcpy(dstColumnData, blackPixel, bytesPerPixel); - } - } - } - - // Get source offsets. - uint32_t srcOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(srcOffsets, srcCpy); - - for (uint8_t mip = 0; mip < srcCpy.m_numMips; ++mip) - { - const uint32_t srcWidth = CMFT_MAX(UINT32_C(1), srcCpy.m_width >> mip); - const uint32_t srcPitch = srcWidth * bytesPerPixel; - - const uint32_t mipWidth = CMFT_MAX(UINT32_C(1), dstWidth >> mip); - const uint32_t mipPitch = mipWidth * bytesPerPixel; - - const uint32_t denominator = (_vertical?3:4); - const uint32_t faceSize = mipWidth / denominator; - - const uint32_t oneFacePitch = (mipPitch) / denominator; - const uint32_t twoFacePitch = (2*mipPitch) / denominator; - const uint32_t threeFacePitch = (3*mipPitch) / denominator; - - const uint32_t oneRowDataSize = (mipPitch*mipWidth) / denominator; - const uint32_t twoRowDataSize = (2*mipPitch*mipWidth) / denominator; - const uint32_t threeRowDataSize = (3*mipPitch*mipWidth) / denominator; - - // Destination offsets. - uint32_t faceOffsets[6]; - if (_vertical) - { - // ___ ___ ___ - // | | | | -> rowDataSize - // |___|___|___| - // - // ___ -> facePitch - // - // ___ - // |Y+ | - // ___|___|___ - // |X- |Z+ |X+ | - // |___|___|___| - // |Y- | - // |___| - // |Z- | - // |___| - // - faceOffsets[0] = oneRowDataSize + twoFacePitch; //+x - faceOffsets[1] = oneRowDataSize; //-x - faceOffsets[2] = oneFacePitch; //+y - faceOffsets[3] = twoRowDataSize + oneFacePitch; //-y - faceOffsets[4] = oneRowDataSize + oneFacePitch; //+z - faceOffsets[5] = threeRowDataSize + oneFacePitch; //-z - } - else - { - // ___ - // |+Y | - // ___|___|___ ___ - // |-X |+Z |+X |-Z | - // |___|___|___|___| - // |-Y | - // |___| - // - faceOffsets[0] = oneRowDataSize + twoFacePitch; //+x - faceOffsets[1] = oneRowDataSize; //-x - faceOffsets[2] = oneFacePitch; //+y - faceOffsets[3] = twoRowDataSize + oneFacePitch; //-y - faceOffsets[4] = oneRowDataSize + oneFacePitch; //+z - faceOffsets[5] = oneRowDataSize + threeFacePitch; //-z - } - - uint8_t* dstMipData = (uint8_t*)dstData + dstMipOffsets[mip]; - for (uint8_t face = 0; face < 6; ++face) - { - uint8_t* dstFaceData = (uint8_t*)dstMipData + faceOffsets[face]; - const uint8_t* srcFaceData = (uint8_t*)srcCpy.m_data + srcOffsets[face][mip]; - for (uint32_t yy = 0; yy < faceSize; ++yy) - { - uint8_t* dstRowData = (uint8_t*)dstFaceData + yy*mipPitch; - const uint8_t* srcRowData = (const uint8_t*)srcFaceData + yy*srcPitch; - - memcpy(dstRowData, srcRowData, oneFacePitch); - } - } - } - - // Fill image structure. - Image result; - result.m_width = dstWidth; - result.m_height = dstHeight; - result.m_dataSize = dstDataSize; - result.m_format = srcCpy.m_format; - result.m_numMips = srcCpy.m_numMips; - result.m_numFaces = 1; - result.m_data = dstData; - - // Output. - imageMove(_dst, result, _allocator); - - // Cleanup. - imageUnload(srcCpy, _allocator); - - return true; - } - - bool imageCrossFromCubemap(Image& _image, bool _vertical, AllocatorI* _allocator) - { - Image tmp; - if (imageCrossFromCubemap(tmp, _image, _vertical, _allocator)) - { - imageMove(_image, tmp, _allocator); - return true; - } - - return false; - } - - bool imageToCubemap(Image& _dst, const Image& _src, AllocatorI* _allocator) - { - if (imageIsCubemap(_src)) - { - imageCopy(_dst, _src, _allocator); - return true; - } - else if (imageCubemapFromCross(_dst, _src, _allocator) - || imageCubemapFromLatLong(_dst, _src, true, _allocator) - || imageCubemapFromStrip(_dst, _src, _allocator)) - { - return true; - } - - return false; - } - - bool imageToCubemap(Image& _image, AllocatorI* _allocator) - { - if (!imageIsCubemap(_image)) - { - if (imageIsCubeCross(_image, true)) - { - imageCubemapFromCross(_image, _allocator); - } - else if (imageIsLatLong(_image)) - { - imageCubemapFromLatLong(_image, true, _allocator); - } - else if (imageIsHStrip(_image) || imageIsVStrip(_image)) - { - imageCubemapFromStrip(_image, _allocator); - } - } - - return imageIsValid(_image) && imageIsCubemap(_image); - } - - bool imageOctantFromCubemap(Image& _dst, const Image& _src, bool _useBilinearInterpolation, AllocatorI* _allocator) - { - // Input check. - if(!imageIsCubemap(_src)) - { - return false; - } - - // Conversion is done in rgba32f format. - ImageSoftRef imageRgba32f; - imageRefOrConvert(imageRgba32f, TextureFormat::RGBA32F, _src, _allocator); - - // Alloc data. - const uint32_t bytesPerPixel = 4 /*numChannels*/ * 4 /*bytesPerChannel*/; - const uint32_t dstSize = imageRgba32f.m_height*2; - uint32_t dstDataSize = 0; - uint32_t dstMipOffsets[MAX_MIP_NUM]; - for (uint8_t mip = 0; mip < imageRgba32f.m_numMips; ++mip) - { - dstMipOffsets[mip] = dstDataSize; - const uint32_t dstMipSize = CMFT_MAX(UINT32_C(1), dstSize >> mip); - dstDataSize += dstMipSize * dstMipSize * bytesPerPixel; - } - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - // Get source image parameters. - uint32_t srcOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(srcOffsets, imageRgba32f); - - // Iterate over destination image (latlong). - for (uint8_t mip = 0; mip < imageRgba32f.m_numMips; ++mip) - { - const uint32_t dstMipSize = CMFT_MAX(UINT32_C(1), dstSize >> mip); - const uint32_t dstMipPitch = dstMipSize * bytesPerPixel; - const float invDstSizef = 1.0f/float(dstMipSize-1); - - const uint32_t srcMipSize = CMFT_MAX(UINT32_C(1), imageRgba32f.m_width >> mip); - const uint32_t srcPitch = srcMipSize * bytesPerPixel; - - const uint32_t srcMipSizeMinOne = srcMipSize-1; - const float srcMipSizeMinOnef = cmft::utof(srcMipSizeMinOne); - - uint8_t* dstMipData = (uint8_t*)dstData + dstMipOffsets[mip]; - for (uint32_t yy = 0; yy < dstMipSize; ++yy) - { - uint8_t* dstRowData = (uint8_t*)dstMipData + yy*dstMipPitch; - for (uint32_t xx = 0; xx < dstMipSize; ++xx) - { - float* dstColumnData = (float*)((uint8_t*)dstRowData + xx*bytesPerPixel); - - // Latlong (x,y). - const float xDst = cmft::utof(xx)*invDstSizef; - const float yDst = cmft::utof(yy)*invDstSizef; - - // Get cubemap vector (x,y,z) coresponding to latlong (x,y). - float vec[3]; - vecFromOctant(vec, xDst, yDst); - - // Get cubemap (u,v,faceIdx) from cubemap vector (x,y,z). - float xSrcf; - float ySrcf; - uint8_t faceIdx; - vecToTexelCoord(xSrcf, ySrcf, faceIdx, vec); - - // Convert from [0..1] to [0..(size-1)] range. - xSrcf *= srcMipSizeMinOnef; - ySrcf *= srcMipSizeMinOnef; - - // Sample from cubemap (u,v, faceIdx). - if (_useBilinearInterpolation) - { - const uint32_t x0 = cmft::ftou(xSrcf); - const uint32_t y0 = cmft::ftou(ySrcf); - const uint32_t x1 = CMFT_MIN(x0+1, srcMipSizeMinOne); - const uint32_t y1 = CMFT_MIN(y0+1, srcMipSizeMinOne); - - const uint8_t* srcFaceData = (const uint8_t*)imageRgba32f.m_data + srcOffsets[faceIdx][mip]; - const float *src0 = (const float*)((const uint8_t*)srcFaceData + y0*srcPitch + x0*bytesPerPixel); - const float *src1 = (const float*)((const uint8_t*)srcFaceData + y0*srcPitch + x1*bytesPerPixel); - const float *src2 = (const float*)((const uint8_t*)srcFaceData + y1*srcPitch + x0*bytesPerPixel); - const float *src3 = (const float*)((const uint8_t*)srcFaceData + y1*srcPitch + x1*bytesPerPixel); - - const float tx = xSrcf - float(int32_t(x0)); - const float ty = ySrcf - float(int32_t(y0)); - const float invTx = 1.0f - tx; - const float invTy = 1.0f - ty; - - float p0[3]; - float p1[3]; - float p2[3]; - float p3[3]; - vec3Mul(p0, src0, invTx*invTy); - vec3Mul(p1, src1, tx*invTy); - vec3Mul(p2, src2, invTx* ty); - vec3Mul(p3, src3, tx* ty); - - const float rr = p0[0] + p1[0] + p2[0] + p3[0]; - const float gg = p0[1] + p1[1] + p2[1] + p3[1]; - const float bb = p0[2] + p1[2] + p2[2] + p3[2]; - - dstColumnData[0] = rr; - dstColumnData[1] = gg; - dstColumnData[2] = bb; - dstColumnData[3] = 1.0f; - } - else - { - const uint32_t xSrc = cmft::ftou(xSrcf); - const uint32_t ySrc = cmft::ftou(ySrcf); - - const uint8_t* srcFaceData = (const uint8_t*)imageRgba32f.m_data + srcOffsets[faceIdx][mip]; - const float *src = (const float*)((const uint8_t*)srcFaceData + ySrc*srcPitch + xSrc*bytesPerPixel); - - dstColumnData[0] = src[0]; - dstColumnData[1] = src[1]; - dstColumnData[2] = src[2]; - dstColumnData[3] = 1.0f; - } - } - } - } - - // Fill image structure. - Image result; - result.m_width = dstSize; - result.m_height = dstSize; - result.m_dataSize = dstDataSize; - result.m_format = TextureFormat::RGBA32F; - result.m_numMips = imageRgba32f.m_numMips; - result.m_numFaces = 1; - result.m_data = dstData; - - // Convert back to source format. - if (TextureFormat::RGBA32F == _src.m_format) - { - imageMove(_dst, result, _allocator); - } - else - { - imageConvert(_dst, (TextureFormat::Enum)_src.m_format, result, _allocator); - imageUnload(result, _allocator); - } - - // Cleanup. - imageUnload(imageRgba32f, _allocator); - - return true; - - - } - - bool imageCubemapFromOctant(Image& _dst, const Image& _src, bool _useBilinearInterpolation, AllocatorI* _allocator) - { - if (!imageIsOctant(_src)) - { - return false; - } - - // Conversion is done in rgba32f format. - ImageSoftRef imageRgba32f; - imageRefOrConvert(imageRgba32f, TextureFormat::RGBA32F, _src, _allocator); - - // Alloc data. - const uint32_t bytesPerPixel = 4 /*numChannels*/ * 4 /*bytesPerChannel*/; - const uint32_t dstFaceSize = (imageRgba32f.m_height+1)/2; - const uint32_t dstPitch = dstFaceSize * bytesPerPixel; - const uint32_t dstFaceDataSize = dstPitch * dstFaceSize; - const uint32_t dstDataSize = dstFaceDataSize * CUBE_FACE_NUM; - void* dstData = CMFT_ALLOC(_allocator, dstDataSize); - MALLOC_CHECK(dstData); - - // Get source parameters. - const float srcWidthMinusOne = float(int32_t(imageRgba32f.m_width-1)); - const float srcHeightMinusOne = float(int32_t(imageRgba32f.m_height-1)); - const uint32_t srcPitch = imageRgba32f.m_width * bytesPerPixel; - const float invDstFaceSizef = 1.0f/float(dstFaceSize); - - // Iterate over destination image (cubemap). - for (uint8_t face = 0; face < 6; ++face) - { - uint8_t* dstFaceData = (uint8_t*)dstData + face*dstFaceDataSize; - for (uint32_t yy = 0; yy < dstFaceSize; ++yy) - { - uint8_t* dstRowData = (uint8_t*)dstFaceData + yy*dstPitch; - for (uint32_t xx = 0; xx < dstFaceSize; ++xx) - { - float* dstColumnData = (float*)((uint8_t*)dstRowData + xx*bytesPerPixel); - - // Cubemap (u,v) on current face. - const float uu = 2.0f*xx*invDstFaceSizef-1.0f; - const float vv = 2.0f*yy*invDstFaceSizef-1.0f; - - // Get cubemap vector (x,y,z) from (u,v,faceIdx). - float vec[3]; - texelCoordToVec(vec, uu, vv, face); - - // Convert cubemap vector (x,y,z) to latlong (u,v). - float xSrcf; - float ySrcf; - octantFromVec(xSrcf, ySrcf, vec); - - // Convert from [0..1] to [0..(size-1)] range. - xSrcf *= srcWidthMinusOne; - ySrcf *= srcHeightMinusOne; - - // Sample from latlong (u,v). - if (_useBilinearInterpolation) - { - const uint32_t x0 = cmft::ftou(xSrcf); - const uint32_t y0 = cmft::ftou(ySrcf); - const uint32_t x1 = CMFT_MIN(x0+1, imageRgba32f.m_width-1); - const uint32_t y1 = CMFT_MIN(y0+1, imageRgba32f.m_height-1); - - const float *src0 = (const float*)((const uint8_t*)imageRgba32f.m_data + y0*srcPitch + x0*bytesPerPixel); - const float *src1 = (const float*)((const uint8_t*)imageRgba32f.m_data + y0*srcPitch + x1*bytesPerPixel); - const float *src2 = (const float*)((const uint8_t*)imageRgba32f.m_data + y1*srcPitch + x0*bytesPerPixel); - const float *src3 = (const float*)((const uint8_t*)imageRgba32f.m_data + y1*srcPitch + x1*bytesPerPixel); - - const float tx = xSrcf - float(int32_t(x0)); - const float ty = ySrcf - float(int32_t(y0)); - const float invTx = 1.0f - tx; - const float invTy = 1.0f - ty; - - float p0[3]; - float p1[3]; - float p2[3]; - float p3[3]; - vec3Mul(p0, src0, invTx*invTy); - vec3Mul(p1, src1, tx*invTy); - vec3Mul(p2, src2, invTx* ty); - vec3Mul(p3, src3, tx* ty); - - const float rr = p0[0] + p1[0] + p2[0] + p3[0]; - const float gg = p0[1] + p1[1] + p2[1] + p3[1]; - const float bb = p0[2] + p1[2] + p2[2] + p3[2]; - - dstColumnData[0] = rr; - dstColumnData[1] = gg; - dstColumnData[2] = bb; - dstColumnData[3] = 1.0f; - } - else - { - const uint32_t xSrc = cmft::ftou(xSrcf); - const uint32_t ySrc = cmft::ftou(ySrcf); - const float *src = (const float*)((const uint8_t*)imageRgba32f.m_data + ySrc*srcPitch + xSrc*bytesPerPixel); - - dstColumnData[0] = src[0]; - dstColumnData[1] = src[1]; - dstColumnData[2] = src[2]; - dstColumnData[3] = 1.0f; - } - - } - } - } - - // Fill image structure. - Image result; - result.m_width = dstFaceSize; - result.m_height = dstFaceSize; - result.m_dataSize = dstDataSize; - result.m_format = TextureFormat::RGBA32F; - result.m_numMips = 1; - result.m_numFaces = 6; - result.m_data = dstData; - - // Convert result to source format. - if (TextureFormat::RGBA32F == _src.m_format) - { - imageMove(_dst, result, _allocator); - } - else - { - imageConvert(_dst, (TextureFormat::Enum)_src.m_format, result, _allocator); - imageUnload(result, _allocator); - } - - // Cleanup. - imageUnload(imageRgba32f, _allocator); - - return true; - } - - bool imageCubemapFromOctant(Image& _image, bool _useBilinearInterpolation, AllocatorI* _allocator) - { - Image tmp; - if(imageCubemapFromOctant(tmp, _image, _useBilinearInterpolation, _allocator)) - { - imageMove(_image, tmp, _allocator); - return true; - } - - return false; - } - - // Image loading. - //----- - - bool imageLoadDds(Image& _image, Rw* _rw, AllocatorI* _allocator) - { - size_t read; - CMFT_UNUSED(read); - - bool didOpen = rwFileOpen(_rw, "rb"); - RwScopeFileClose scopeClose(_rw, didOpen); - - RwSeekFn seekFn = rwSeekFnFor(_rw); - RwReadFn readFn = rwReadFnFor(_rw); - - // Read magic. - uint32_t magic; - readFn(_rw, &magic, sizeof(uint32_t)); - - // Check magic. - if (DDS_MAGIC != magic) - { - WARN("Dds magic invalid."); - return false; - } - - // Read header. - DdsHeader ddsHeader; - read = 0; - read += readFn(_rw, &ddsHeader.m_size, sizeof(ddsHeader.m_size)); - read += readFn(_rw, &ddsHeader.m_flags, sizeof(ddsHeader.m_flags)); - read += readFn(_rw, &ddsHeader.m_height, sizeof(ddsHeader.m_height)); - read += readFn(_rw, &ddsHeader.m_width, sizeof(ddsHeader.m_width)); - read += readFn(_rw, &ddsHeader.m_pitchOrLinearSize, sizeof(ddsHeader.m_pitchOrLinearSize)); - read += readFn(_rw, &ddsHeader.m_depth, sizeof(ddsHeader.m_depth)); - read += readFn(_rw, &ddsHeader.m_mipMapCount, sizeof(ddsHeader.m_mipMapCount)); - read += readFn(_rw, &ddsHeader.m_reserved1, sizeof(ddsHeader.m_reserved1)); - read += readFn(_rw, &ddsHeader.m_pixelFormat.m_size, sizeof(ddsHeader.m_pixelFormat.m_size)); - read += readFn(_rw, &ddsHeader.m_pixelFormat.m_flags, sizeof(ddsHeader.m_pixelFormat.m_flags)); - read += readFn(_rw, &ddsHeader.m_pixelFormat.m_fourcc, sizeof(ddsHeader.m_pixelFormat.m_fourcc)); - read += readFn(_rw, &ddsHeader.m_pixelFormat.m_rgbBitCount, sizeof(ddsHeader.m_pixelFormat.m_rgbBitCount)); - read += readFn(_rw, &ddsHeader.m_pixelFormat.m_rBitMask, sizeof(ddsHeader.m_pixelFormat.m_rBitMask)); - read += readFn(_rw, &ddsHeader.m_pixelFormat.m_gBitMask, sizeof(ddsHeader.m_pixelFormat.m_gBitMask)); - read += readFn(_rw, &ddsHeader.m_pixelFormat.m_bBitMask, sizeof(ddsHeader.m_pixelFormat.m_bBitMask)); - read += readFn(_rw, &ddsHeader.m_pixelFormat.m_aBitMask, sizeof(ddsHeader.m_pixelFormat.m_aBitMask)); - read += readFn(_rw, &ddsHeader.m_caps, sizeof(ddsHeader.m_caps)); - read += readFn(_rw, &ddsHeader.m_caps2, sizeof(ddsHeader.m_caps2)); - read += readFn(_rw, &ddsHeader.m_caps3, sizeof(ddsHeader.m_caps3)); - read += readFn(_rw, &ddsHeader.m_caps4, sizeof(ddsHeader.m_caps4)); - read += readFn(_rw, &ddsHeader.m_reserved2, sizeof(ddsHeader.m_reserved2)); - DEBUG_CHECK(read == DDS_HEADER_SIZE, "Error reading file header."); - - // Read DdsDxt10 header if present. - DdsHeaderDxt10 ddsHeaderDxt10; - memset(&ddsHeaderDxt10, 0, sizeof(DdsHeaderDxt10)); - const bool hasDdsDxt10 = (DDS_DX10 == ddsHeader.m_pixelFormat.m_fourcc && (ddsHeader.m_flags&DDPF_FOURCC)); - if (hasDdsDxt10) - { - read = 0; - read += readFn(_rw, &ddsHeaderDxt10.m_dxgiFormat, sizeof(ddsHeaderDxt10.m_dxgiFormat)); - read += readFn(_rw, &ddsHeaderDxt10.m_resourceDimension, sizeof(ddsHeaderDxt10.m_resourceDimension)); - read += readFn(_rw, &ddsHeaderDxt10.m_miscFlags, sizeof(ddsHeaderDxt10.m_miscFlags)); - read += readFn(_rw, &ddsHeaderDxt10.m_arraySize, sizeof(ddsHeaderDxt10.m_arraySize)); - read += readFn(_rw, &ddsHeaderDxt10.m_miscFlags2, sizeof(ddsHeaderDxt10.m_miscFlags2)); - DEBUG_CHECK(read == DDS_DX10_HEADER_SIZE, "Error reading Dds dx10 file header."); - } - - // Validate header. - if (DDS_HEADER_SIZE != ddsHeader.m_size) - { - WARN("Invalid Dds header size!"); - return false; - } - - if ((ddsHeader.m_flags & (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT)) != (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT)) - { - WARN("Invalid Dds header flags!"); - return false; - } - - if (0 == (ddsHeader.m_caps & DDSCAPS_TEXTURE)) - { - WARN("Invalid Dds header caps!"); - return false; - } - - if (0 == ddsHeader.m_mipMapCount) - { - WARN("Dds image mipmap count is 0. Setting to 1."); - ddsHeader.m_mipMapCount = 1; - } - - const bool isCubemap = (0 != (ddsHeader.m_caps2 & DDSCAPS2_CUBEMAP)); - if (isCubemap && (DDS_CUBEMAP_ALLFACES != (ddsHeader.m_caps2 & DDS_CUBEMAP_ALLFACES))) - { - WARN("Partial cubemap not supported!"); - return false; - } - - // Get format. - TextureFormat::Enum format = TextureFormat::Null; - if (hasDdsDxt10) - { - for (uint8_t ii = 0, end = CMFT_COUNTOF(s_translateDdsDxgiFormat); ii < end; ++ii) - { - if (s_translateDdsDxgiFormat[ii].m_dxgiFormat == ddsHeaderDxt10.m_dxgiFormat) - { - format = s_translateDdsDxgiFormat[ii].m_textureFormat; - break; - } - } - } - else - { - uint32_t ddsBcFlag = 0; - for (uint8_t ii = 0, end = CMFT_COUNTOF(s_translateDdsPfBitCount); ii < end; ++ii) - { - if (s_translateDdsPfBitCount[ii].m_bitCount == ddsHeader.m_pixelFormat.m_rgbBitCount) - { - ddsBcFlag = s_translateDdsPfBitCount[ii].m_flag; - break; - } - } - - const uint32_t ddsFormat = ddsHeader.m_pixelFormat.m_flags & DDPF_FOURCC - ? ddsHeader.m_pixelFormat.m_fourcc - : (ddsHeader.m_pixelFormat.m_flags | ddsBcFlag) - ; - - for (uint8_t ii = 0, end = CMFT_COUNTOF(s_translateDdsFormat); ii < end; ++ii) - { - if (s_translateDdsFormat[ii].m_format == ddsFormat) - { - format = s_translateDdsFormat[ii].m_textureFormat; - break; - } - } - } - - if (TextureFormat::Null == format) - { - const uint8_t bytesPerPixel = uint8_t(ddsHeader.m_pixelFormat.m_rgbBitCount/8); - for (uint8_t ii = 0, end = CMFT_COUNTOF(s_ddsValidFormats); ii < end; ++ii) - { - if (bytesPerPixel == getImageDataInfo(s_ddsValidFormats[ii]).m_bytesPerPixel) - { - format = TextureFormat::Enum(ii); - } - } - - WARN("DDS data format unknown. Guessing..."); - - if (TextureFormat::Null == format) - { - WARN("DDS data format not supported!"); - return false; - } - } - - // Calculate data size. - const uint8_t numFaces = isCubemap ? 6 : 1; - const uint32_t bytesPerPixel = getImageDataInfo(format).m_bytesPerPixel; - uint32_t dataSize = 0; - for (uint8_t face = 0; face < numFaces; ++face) - { - for (uint8_t mip = 0; mip < ddsHeader.m_mipMapCount; ++mip) - { - uint32_t width = CMFT_MAX(UINT32_C(1), ddsHeader.m_width >> mip); - uint32_t height = CMFT_MAX(UINT32_C(1), ddsHeader.m_height >> mip); - dataSize += width * height * bytesPerPixel; - } - } - - // Some software tools produce invalid dds file. - // Flags claim there should be a ddsdxt10 header after dds header but in fact image data starts there. - // Therefore, to handle those situations, image data size will be checked against remaining unread data size. - - // Seek to the end to get remaining data size. - const int64_t currentPos = seekFn(_rw, 0, Whence::Current); - const int64_t endPos = seekFn(_rw, 0, Whence::End); - const int64_t remaining = endPos - currentPos; - - // Seek back to currentPos or 20 before currentPos in case remaining unread data size does match image data size. - seekFn(_rw, currentPos - DDS_DX10_HEADER_SIZE*(remaining == dataSize-DDS_DX10_HEADER_SIZE), Whence::Begin); - - // Alloc and read data. - void* data = CMFT_ALLOC(_allocator, dataSize); - MALLOC_CHECK(data); - read = readFn(_rw, data, dataSize); - DEBUG_CHECK(read == dataSize, "Could not read dds image data."); - - // Fill image structure. - Image result; - result.m_width = ddsHeader.m_width; - result.m_height = ddsHeader.m_height; - result.m_dataSize = dataSize; - result.m_format = format; - result.m_numMips = uint8_t(ddsHeader.m_mipMapCount); - result.m_numFaces = numFaces; - result.m_data = data; - - // Output. - imageMove(_image, result, _allocator); - - return true; - } - - bool imageLoadKtx(Image& _image, Rw* _rw, AllocatorI* _allocator) - { - size_t read; - CMFT_UNUSED(read); - - bool didOpen = rwFileOpen(_rw, "rb"); - RwScopeFileClose scopeClose(_rw, didOpen); - - RwSeekFn seekFn = rwSeekFnFor(_rw); - RwReadFn readFn = rwReadFnFor(_rw); - - KtxHeader ktxHeader; - - // Read magic. - uint8_t magic[12]; - read = readFn(_rw, &magic, KTX_MAGIC_LEN); - DEBUG_CHECK(read == 12, "Could not read from file."); - - const uint8_t ktxMagic[12] = KTX_MAGIC; - if (0 != memcmp(magic, ktxMagic, KTX_MAGIC_LEN)) - { - WARN("Ktx magic invalid."); - return false; - } - - // Read header. - read = 0; - read += readFn(_rw, &ktxHeader.m_endianness, sizeof(ktxHeader.m_endianness)); - read += readFn(_rw, &ktxHeader.m_glType, sizeof(ktxHeader.m_glType)); - read += readFn(_rw, &ktxHeader.m_glTypeSize, sizeof(ktxHeader.m_glTypeSize)); - read += readFn(_rw, &ktxHeader.m_glFormat, sizeof(ktxHeader.m_glFormat)); - read += readFn(_rw, &ktxHeader.m_glInternalFormat, sizeof(ktxHeader.m_glInternalFormat)); - read += readFn(_rw, &ktxHeader.m_glBaseInternalFormat, sizeof(ktxHeader.m_glBaseInternalFormat)); - read += readFn(_rw, &ktxHeader.m_pixelWidth, sizeof(ktxHeader.m_pixelWidth)); - read += readFn(_rw, &ktxHeader.m_pixelHeight, sizeof(ktxHeader.m_pixelHeight)); - read += readFn(_rw, &ktxHeader.m_pixelDepth, sizeof(ktxHeader.m_pixelDepth)); - read += readFn(_rw, &ktxHeader.m_numArrayElements, sizeof(ktxHeader.m_numArrayElements)); - read += readFn(_rw, &ktxHeader.m_numFaces, sizeof(ktxHeader.m_numFaces)); - read += readFn(_rw, &ktxHeader.m_numMips, sizeof(ktxHeader.m_numMips)); - read += readFn(_rw, &ktxHeader.m_bytesKeyValue, sizeof(ktxHeader.m_bytesKeyValue)); - DEBUG_CHECK(read == KTX_HEADER_SIZE, "Error reading Ktx file header."); - - if (0 == ktxHeader.m_numMips) - { - WARN("Ktx image mipmap count is 0. Setting to 1."); - ktxHeader.m_numMips = 1; - } - - // Get format. - TextureFormat::Enum format = TextureFormat::Null; - for (uint8_t ii = 0, end = CMFT_COUNTOF(s_translateKtxFormat); ii < end; ++ii) - { - if (s_translateKtxFormat[ii].m_glInternalFormat == ktxHeader.m_glInternalFormat) - { - format = s_translateKtxFormat[ii].m_textureFormat; - break; - } - } - - if (TextureFormat::Null == format) - { - WARN("Ktx file internal format unknown."); - return false; - } - - const uint32_t bytesPerPixel = getImageDataInfo(format).m_bytesPerPixel; - - // Compute data offsets. - uint32_t offsets[MAX_MIP_NUM][CUBE_FACE_NUM]; - uint32_t dataSize = 0; - for (uint8_t face = 0; face < ktxHeader.m_numFaces; ++face) - { - for (uint8_t mip = 0; mip < ktxHeader.m_numMips; ++mip) - { - offsets[mip][face] = dataSize; - const uint32_t width = CMFT_MAX(UINT32_C(1), ktxHeader.m_pixelWidth >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), ktxHeader.m_pixelHeight >> mip); - dataSize += width * height * bytesPerPixel; - } - } - - // Alloc data. - void* data = (void*)CMFT_ALLOC(_allocator, dataSize); - MALLOC_CHECK(data); - - // Jump header key-value data. - seekFn(_rw, ktxHeader.m_bytesKeyValue, Whence::Current); - - // Read data. - for (uint8_t mip = 0; mip < ktxHeader.m_numMips; ++mip) - { - const uint32_t width = CMFT_MAX(UINT32_C(1), ktxHeader.m_pixelWidth >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), ktxHeader.m_pixelHeight >> mip); - const uint32_t pitch = width * bytesPerPixel; - - // Read face size. - uint32_t faceSize; - read = readFn(_rw, &faceSize, sizeof(faceSize)); - DEBUG_CHECK(read == 4, "Error reading Ktx data."); - - const uint32_t mipSize = faceSize * ktxHeader.m_numFaces; - const uint32_t pitchRounding = (KTX_UNPACK_ALIGNMENT-1)-((pitch + KTX_UNPACK_ALIGNMENT-1)&(KTX_UNPACK_ALIGNMENT-1)); - const uint32_t faceRounding = (KTX_UNPACK_ALIGNMENT-1)-((faceSize + KTX_UNPACK_ALIGNMENT-1)&(KTX_UNPACK_ALIGNMENT-1)); - const uint32_t mipRounding = (KTX_UNPACK_ALIGNMENT-1)-((mipSize + KTX_UNPACK_ALIGNMENT-1)&(KTX_UNPACK_ALIGNMENT-1)); - - if (faceSize != ((pitch + pitchRounding) * height)) - { - WARN("Ktx face size invalid."); - } - - for (uint8_t face = 0; face < ktxHeader.m_numFaces; ++face) - { - uint8_t* faceData = (uint8_t*)data + offsets[mip][face]; - - if (0 == pitchRounding) - { - // Read entire face at once. - read = readFn(_rw, &faceData, faceSize); - DEBUG_CHECK(read == faceSize, "Error reading Ktx face data."); - } - else - { - // Read row by row. - for (uint32_t yy = 0; yy < ktxHeader.m_pixelHeight; ++yy) - { - // Read row. - uint8_t* dst = (uint8_t*)faceData + yy*pitch; - read = readFn(_rw, dst, pitch); - DEBUG_CHECK(read == pitch, "Error reading Ktx row data."); - - // Jump row rounding. - seekFn(_rw, pitchRounding, Whence::Current); - } - } - - // Jump face rounding. - seekFn(_rw, faceRounding, Whence::Current); - } - - // Jump mip rounding. - seekFn(_rw, mipRounding, Whence::Current); - } - - // Fill image structure. - Image result; - result.m_width = ktxHeader.m_pixelWidth; - result.m_height = ktxHeader.m_pixelHeight; - result.m_dataSize = dataSize; - result.m_format = format; - result.m_numMips = uint8_t(ktxHeader.m_numMips); - result.m_numFaces = uint8_t(ktxHeader.m_numFaces); - result.m_data = data; - - // Output. - imageMove(_image, result, _allocator); - - return true; - } - - static inline const char* readLine(Rw* _rw, RwSeekFn _rwSeekFn, RwReadFn _rwReadFn, char* _out, uint32_t _max) - { - _rwReadFn(_rw, _out, _max); - - _out[_max-1] = '\0'; // Make sure the string is null terminated. - - const char* eol = cmft::streol(_out); - const char* nl = cmft::strnl(eol); - - // Seek back right after newline character. - if (NULL != nl) - { - const int64_t pos = nl - _out - int32_t(_max); - _rwSeekFn(_rw, pos, Whence::Current); - } - - return nl; - } - - bool imageLoadHdr(Image& _image, Rw* _rw, AllocatorI* _allocator) - { - size_t read; - CMFT_UNUSED(read); - - bool didOpen = rwFileOpen(_rw, "rb"); - RwScopeFileClose scopeClose(_rw, didOpen); - - RwSeekFn seekFn = rwSeekFnFor(_rw); - RwReadFn readFn = rwReadFnFor(_rw); - - // Read magic. - char magic[HDR_MAGIC_LEN]; - readFn(_rw, magic, HDR_MAGIC_LEN); - - // Skip nl char. - seekFn(_rw, 1, Whence::Current); - - // Check magic. - if (0 != strncmp(magic, HDR_MAGIC_FULL, HDR_MAGIC_LEN)) - { - WARN("HDR magic not valid."); - return false; - } - - HdrHeader hdrHeader; - hdrHeader.m_valid = 0; - hdrHeader.m_gamma = 1.0f; - hdrHeader.m_exposure = 1.0f; - - // Read header. - bool formatDefined = false; - for (uint8_t ii = 0, stop = 20; ii < stop; ++ii) - { - // Read next line. - char buf[256]; - const char* nl = readLine(_rw, seekFn, readFn, buf, sizeof(buf)); - - if ((0 == buf[0]) - || ('\n' == buf[0])) - { - // End of header. - break; - } - - const size_t len = (NULL != nl) ? nl-buf : sizeof(buf); - if (0 == strncmp(buf, "FORMAT=32-bit_rle_rgbe\n", len)) - { - formatDefined = true; - } - else if (1 == sscanf(buf, "GAMMA=%g", &hdrHeader.m_gamma)) - { - hdrHeader.m_valid |= HDR_VALID_GAMMA; - } - else if (1 == sscanf(buf, "EXPOSURE=%g", &hdrHeader.m_exposure)) - { - hdrHeader.m_valid |= HDR_VALID_EXPOSURE; - } - } - - if (!formatDefined) - { - WARN("Invalid Hdr header."); - } - - // Read image size. - int32_t width; - int32_t height; - char buf[256]; - readLine(_rw, seekFn, readFn, buf, sizeof(buf)); - sscanf(buf, "-Y %d +X %d", &height, &width); - - // Allocate data. - const uint32_t dataSize = width * height * 4 /* bytesPerPixel */; - uint8_t* data = (uint8_t*)CMFT_ALLOC(_allocator, dataSize); - MALLOC_CHECK(data); - - // Read first chunk. - unsigned char rgbe[4]; - readFn(_rw, rgbe, sizeof(rgbe)); - - uint8_t* dataPtr = (uint8_t*)data; - - if ((width < 8) - || (width > 0x7fff) - || (rgbe[0] != 2) - || (rgbe[1] != 2) - || (rgbe[2] & 0x80)) - { - // File not RLE. - - // Save already read pixel. - dataPtr[0] = rgbe[0]; - dataPtr[1] = rgbe[1]; - dataPtr[2] = rgbe[2]; - dataPtr[3] = rgbe[3]; - dataPtr += 4; - - // Read rest of the file. - const uint32_t remainingDataSize = dataSize - 4; - read = readFn(_rw, dataPtr, remainingDataSize); - DEBUG_CHECK(read == remainingDataSize, "Error reading Hdr image data."); - } - else - { - // File is RLE. - - uint8_t* scanlineBuffer = (uint8_t*)alloca(width*4); - MALLOC_CHECK(scanlineBuffer); - uint8_t* ptr; - const uint8_t* ptrEnd; - uint32_t numScanlines = height-1; - int32_t count; - for (;;) - { - DEBUG_CHECK(((uint16_t(rgbe[2])<<8)|(rgbe[3]&0xff)) == width, "Hdr file scanline width is invalid."); - - ptr = scanlineBuffer; - for (uint8_t ii = 0; ii < 4; ++ii) - { - ptrEnd = (const uint8_t*)scanlineBuffer + width*(ii+1); - while (ptr < ptrEnd) - { - unsigned char rle[2]; - readFn(_rw, rle, sizeof(rle)); - - if (rle[0] > 128) - { - // RLE chunk. - count = rle[0] - 128; - DEBUG_CHECK((count != 0) && (count <= (ptrEnd - ptr)), "Bad scanline data!"); - while (count-- > 0) - { - *ptr++ = rle[1]; - } - } - else - { - // Normal chunk. - count = rle[0]; - DEBUG_CHECK((count != 0) && (count <= (ptrEnd - ptr)), "Bad scanline data!"); - *ptr++ = rle[1]; - if (--count > 0) - { - read = readFn(_rw, ptr, count); - DEBUG_CHECK(int32_t(read) == count, "Error reading Hdr image data."); - ptr += count; - } - } - } - } - - // Copy scanline data. - for (int32_t ii = 0; ii < width; ++ii) - { - dataPtr[0] = scanlineBuffer[ii+(0*width)]; - dataPtr[1] = scanlineBuffer[ii+(1*width)]; - dataPtr[2] = scanlineBuffer[ii+(2*width)]; - dataPtr[3] = scanlineBuffer[ii+(3*width)]; - dataPtr += 4; - } - - // Break if reached the end. - if (0 == numScanlines--) - { - break; - } - - // Read next scanline. - readFn(_rw, rgbe, sizeof(rgbe)); - } - } - - // Fill image structure. - Image result; - result.m_width = uint32_t(width); - result.m_height = uint32_t(height); - result.m_dataSize = dataSize; - result.m_format = TextureFormat::RGBE; - result.m_numMips = 1; - result.m_numFaces = 1; - result.m_data = (void*)data; - - // Output. - imageMove(_image, result, _allocator); - - return true; - } - - bool imageLoadTga(Image& _image, Rw* _rw, AllocatorI* _allocator) - { - size_t read; - CMFT_UNUSED(read); - - bool didOpen = rwFileOpen(_rw, "rb"); - RwScopeFileClose scopeClose(_rw, didOpen); - - RwSeekFn seekFn = rwSeekFnFor(_rw); - RwReadFn readFn = rwReadFnFor(_rw); - - // Load header. - TgaHeader tgaHeader; - read = 0; - read += readFn(_rw, &tgaHeader.m_idLength, sizeof(tgaHeader.m_idLength)); - read += readFn(_rw, &tgaHeader.m_colorMapType, sizeof(tgaHeader.m_colorMapType)); - read += readFn(_rw, &tgaHeader.m_imageType, sizeof(tgaHeader.m_imageType)); - read += readFn(_rw, &tgaHeader.m_colorMapOrigin, sizeof(tgaHeader.m_colorMapOrigin)); - read += readFn(_rw, &tgaHeader.m_colorMapLength, sizeof(tgaHeader.m_colorMapLength)); - read += readFn(_rw, &tgaHeader.m_colorMapDepth, sizeof(tgaHeader.m_colorMapDepth)); - read += readFn(_rw, &tgaHeader.m_xOrigin, sizeof(tgaHeader.m_xOrigin)); - read += readFn(_rw, &tgaHeader.m_yOrigin, sizeof(tgaHeader.m_yOrigin)); - read += readFn(_rw, &tgaHeader.m_width, sizeof(tgaHeader.m_width)); - read += readFn(_rw, &tgaHeader.m_height, sizeof(tgaHeader.m_height)); - read += readFn(_rw, &tgaHeader.m_bitsPerPixel, sizeof(tgaHeader.m_bitsPerPixel)); - read += readFn(_rw, &tgaHeader.m_imageDescriptor, sizeof(tgaHeader.m_imageDescriptor)); - DEBUG_CHECK(read == TGA_HEADER_SIZE, "Error reading file header."); - - // Check header. - if(0 == (TGA_IT_RGB & tgaHeader.m_imageType)) - { - WARN("Tga file is not true-color image."); - return false; - } - - // Get format. - TextureFormat::Enum format; - if (24 == tgaHeader.m_bitsPerPixel) - { - format = TextureFormat::BGR8; - DEBUG_CHECK(0x0 == (tgaHeader.m_imageDescriptor&0xf), "Alpha channel not properly defined."); - } - else if (32 == tgaHeader.m_bitsPerPixel) - { - format = TextureFormat::BGRA8; - DEBUG_CHECK(0x8 == (tgaHeader.m_imageDescriptor&0xf), "Alpha channel not properly defined."); - } - else - { - WARN("Non-supported Tga pixel depth - %u.", tgaHeader.m_bitsPerPixel); - return false; - } - - // Alloc data. - const uint32_t numBytesPerPixel = tgaHeader.m_bitsPerPixel/8; - const uint32_t numPixels = tgaHeader.m_width * tgaHeader.m_height; - const uint32_t dataSize = numPixels * numBytesPerPixel; - uint8_t* data = (uint8_t*)CMFT_ALLOC(_allocator, dataSize); - MALLOC_CHECK(data); - - // Skip to data. - const uint32_t skip = tgaHeader.m_idLength + (tgaHeader.m_colorMapType&0x1)*tgaHeader.m_colorMapLength; - seekFn(_rw, skip, Whence::Current); - - // Load data. - const bool bCompressed = (0 != (tgaHeader.m_imageType&TGA_IT_RLE)); - if (bCompressed) - { - uint8_t buf[5]; - uint32_t n = 0; - uint8_t* dataPtr = data; - while (n < numPixels) - { - read = readFn(_rw, buf, 1+numBytesPerPixel); - DEBUG_CHECK(read == (1+numBytesPerPixel), "Could not read from file."); - - const uint8_t count = buf[0] & 0x7f; - - memcpy(dataPtr, &buf[1], numBytesPerPixel); - dataPtr += numBytesPerPixel; - n++; - - if (buf[0] & 0x80) - { - // RLE chunk. - for (uint8_t ii = 0; ii < count; ++ii) - { - memcpy(dataPtr, &buf[1], numBytesPerPixel); - dataPtr += numBytesPerPixel; - n++; - } - } - else - { - // Normal chunk. - for (uint8_t ii = 0; ii < count; ++ii) - { - read = readFn(_rw, buf, numBytesPerPixel); - DEBUG_CHECK(read == +numBytesPerPixel, "Could not read from file."); - - memcpy(dataPtr, buf, numBytesPerPixel); - dataPtr += numBytesPerPixel; - n++; - } - } - } - } - else - { - read = readFn(_rw, data, dataSize); - DEBUG_CHECK(read == dataSize, "Could not read from file."); - } - - // Fill image structure. - Image result; - result.m_width = tgaHeader.m_width; - result.m_height = tgaHeader.m_height; - result.m_dataSize = dataSize; - result.m_format = format; - result.m_numMips = 1; - result.m_numFaces = 1; - result.m_data = data; - - // Flip if necessary. - const uint32_t flip = 0 - | (tgaHeader.m_imageDescriptor & TGA_DESC_HORIZONTAL ? IMAGE_OP_FLIP_Y : 0) - | (tgaHeader.m_imageDescriptor & TGA_DESC_VERTICAL ? 0 : IMAGE_OP_FLIP_X) - ; - if (flip) - { - imageTransform(result, flip); - } - - // Output. - imageMove(_image, result, _allocator); - - return true; - } - - static bool isTga(uint32_t _magic) - { - //byte 2 is imageType and must be: 1, 2, 3, 9, 10 or 11 - //byte 1 is colorMapType and must be 1 if imageType is 1 or 9, 0 otherwise - const uint8_t colorMapType = uint8_t((_magic>> 8)&0xff); - const uint8_t imageType = uint8_t((_magic>>16)&0xff); - switch(imageType) - { - case 1: - case 9: - return (1 == colorMapType); - - case 2: - case 3: - case 10: - case 11: - return (0 == colorMapType); - }; - - return false; - } - - bool imageLoad(Image& _image, Rw* _rw, TextureFormat::Enum _convertTo, AllocatorI* _allocator) - { - bool didOpen = rwFileOpen(_rw, "rb"); - RwScopeFileClose scopeClose(_rw, didOpen); - - if (!rwFileOpened(_rw)) - { - return false; - } - - RwSeekFn seekFn = rwSeekFnFor(_rw); - RwReadFn readFn = rwReadFnFor(_rw); - - // Read magic. - uint32_t magic; - readFn(_rw, &magic, sizeof(magic)); - - // Seek to beginning. - seekFn(_rw, 0, Whence::Begin); - - // Load image. - bool loaded = false; - if (DDS_MAGIC == magic) - { - loaded = imageLoadDds(_image, _rw, _allocator); - } - else if (HDR_MAGIC == magic) - { - loaded = imageLoadHdr(_image, _rw, _allocator); - } - else if (KTX_MAGIC_SHORT == magic) - { - loaded = imageLoadKtx(_image, _rw, _allocator); - } - else if (isTga(magic)) - { - loaded = imageLoadTga(_image, _rw, _allocator); - } - - if (!loaded) - { - return false; - } - - // Convert if necessary. - if (TextureFormat::Null != _convertTo - && _image.m_format != _convertTo) - { - imageConvert(_image, _convertTo, _allocator); - } - - return true; - } - - bool imageLoad(Image& _image, const char* _filePath, TextureFormat::Enum _convertTo, AllocatorI* _allocator) - { - Rw rw; - rwInit(&rw, _filePath); - - return imageLoad(_image, &rw, _convertTo, _allocator); - } - - bool imageLoad(Image& _image, const void* _data, uint32_t _dataSize, TextureFormat::Enum _convertTo, AllocatorI* _allocator) - { - Rw rw; - rwInit(&rw, const_cast(_data), _dataSize); - - return imageLoad(_image, &rw, _convertTo, _allocator); - } - - /// - bool imageLoadStb(Image& _image, const char* _filePath, TextureFormat::Enum _convertTo, AllocatorI* _allocator) - { - // Try loading the image through stb_image. - int stbWidth, stbHeight, stbNumComponents; - // Passing reqNumComponents as 4 forces RGBA8 in data. - // After stbi_load, stbNumComponents will hold the actual # of components from the source image. - const int reqNumComponents = 4; - uint8_t* data = (uint8_t*)stbi_load(_filePath, &stbWidth, &stbHeight, &stbNumComponents, reqNumComponents); - - if (NULL == data) - { - return false; - } - - // Fill image structure. - Image result; - result.m_width = (uint16_t)stbWidth; - result.m_height = (uint16_t)stbHeight; - result.m_dataSize = stbWidth*stbHeight*reqNumComponents; - result.m_format = cmft::TextureFormat::RGBA8; - result.m_numMips = 1; - result.m_numFaces = 1; - result.m_data = data; - - // Convert if necessary. - if (TextureFormat::Null != _convertTo - && _image.m_format != _convertTo) - { - imageConvert(_image, _convertTo, result, _allocator); - } - else - { - imageCopy(_image, result, _allocator); //TODO: use imageMove instead of imageCopy if the same allocator was used from stbi_load(). - } - - stbi_image_free(data); - - return true; - } - - /// - bool imageLoadStb(Image& _image, const void* _data, uint32_t _dataSize, TextureFormat::Enum _convertTo, AllocatorI* _allocator) - { - // Try loading the image through stb_image. - int stbWidth, stbHeight, stbNumComponents; - // Passing reqNumComponents as 4 forces RGBA8 in data. - // After stbi_load, stbNumComponents will hold the actual # of components from the source image. - const int reqNumComponents = 4; - uint8_t* data = (uint8_t*)stbi_load_from_memory((const stbi_uc*)_data, (int)_dataSize, &stbWidth, &stbHeight, &stbNumComponents, reqNumComponents); - - if (NULL == data) - { - return false; - } - - // Fill image structure. - Image result; - result.m_width = (uint16_t)stbWidth; - result.m_height = (uint16_t)stbHeight; - result.m_dataSize = stbWidth*stbHeight*reqNumComponents; - result.m_format = cmft::TextureFormat::RGBA8; - result.m_numMips = 1; - result.m_numFaces = 1; - result.m_data = data; - - // Convert if necessary. - if (TextureFormat::Null != _convertTo - && _image.m_format != _convertTo) - { - imageConvert(_image, _convertTo, result, _allocator); - } - else - { - imageCopy(_image, result, _allocator); //TODO: use imageMove instead of imageCopy if the same allocator was used from stbi_load(). - } - - stbi_image_free(data); - - return true; - } - - bool imageIsValid(const Image& _image) - { - return (NULL != _image.m_data); - } - - // Image saving. - //----- - - bool imageSaveDds(const char* _fileName, const Image& _image) - { - size_t write; - CMFT_UNUSED(write); - - char fileName[CMFT_PATH_LEN]; - strcpy(fileName, _fileName); - cmft::strlcat(fileName, getFilenameExtensionStr(ImageFileType::DDS), CMFT_PATH_LEN); - - // Open file. - FILE* fp = fopen(fileName, "wb"); - if (NULL == fp) - { - WARN("Could not open file %s for writing.", fileName); - return false; - } - cmft::ScopeFclose cleanup(fp); - - DdsHeader ddsHeader; - DdsHeaderDxt10 ddsHeaderDxt10; - ddsHeaderFromImage(ddsHeader, &ddsHeaderDxt10, _image); - - // Write magic. - const uint32_t magic = DDS_MAGIC; - write = fwrite(&magic, 1, 4, fp); - DEBUG_CHECK(write == sizeof(magic), "Error writing Dds magic."); - FERROR_CHECK(fp); - - // Write header. - write = 0; - write += fwrite(&ddsHeader.m_size, 1, sizeof(ddsHeader.m_size), fp); - write += fwrite(&ddsHeader.m_flags, 1, sizeof(ddsHeader.m_flags), fp); - write += fwrite(&ddsHeader.m_height, 1, sizeof(ddsHeader.m_height), fp); - write += fwrite(&ddsHeader.m_width, 1, sizeof(ddsHeader.m_width), fp); - write += fwrite(&ddsHeader.m_pitchOrLinearSize, 1, sizeof(ddsHeader.m_pitchOrLinearSize), fp); - write += fwrite(&ddsHeader.m_depth, 1, sizeof(ddsHeader.m_depth), fp); - write += fwrite(&ddsHeader.m_mipMapCount, 1, sizeof(ddsHeader.m_mipMapCount), fp); - write += fwrite(&ddsHeader.m_reserved1, 1, sizeof(ddsHeader.m_reserved1), fp); - write += fwrite(&ddsHeader.m_pixelFormat.m_size, 1, sizeof(ddsHeader.m_pixelFormat.m_size), fp); - write += fwrite(&ddsHeader.m_pixelFormat.m_flags, 1, sizeof(ddsHeader.m_pixelFormat.m_flags), fp); - write += fwrite(&ddsHeader.m_pixelFormat.m_fourcc, 1, sizeof(ddsHeader.m_pixelFormat.m_fourcc), fp); - write += fwrite(&ddsHeader.m_pixelFormat.m_rgbBitCount, 1, sizeof(ddsHeader.m_pixelFormat.m_rgbBitCount), fp); - write += fwrite(&ddsHeader.m_pixelFormat.m_rBitMask, 1, sizeof(ddsHeader.m_pixelFormat.m_rBitMask), fp); - write += fwrite(&ddsHeader.m_pixelFormat.m_gBitMask, 1, sizeof(ddsHeader.m_pixelFormat.m_gBitMask), fp); - write += fwrite(&ddsHeader.m_pixelFormat.m_bBitMask, 1, sizeof(ddsHeader.m_pixelFormat.m_bBitMask), fp); - write += fwrite(&ddsHeader.m_pixelFormat.m_aBitMask, 1, sizeof(ddsHeader.m_pixelFormat.m_aBitMask), fp); - write += fwrite(&ddsHeader.m_caps, 1, sizeof(ddsHeader.m_caps), fp); - write += fwrite(&ddsHeader.m_caps2, 1, sizeof(ddsHeader.m_caps2), fp); - write += fwrite(&ddsHeader.m_caps3, 1, sizeof(ddsHeader.m_caps3), fp); - write += fwrite(&ddsHeader.m_caps4, 1, sizeof(ddsHeader.m_caps4), fp); - write += fwrite(&ddsHeader.m_reserved2, 1, sizeof(ddsHeader.m_reserved2), fp); - DEBUG_CHECK(write == DDS_HEADER_SIZE, "Error writing Dds file header."); - FERROR_CHECK(fp); - - if (DDS_DX10 == ddsHeader.m_pixelFormat.m_fourcc) - { - write = 0; - write += fwrite(&ddsHeaderDxt10.m_dxgiFormat, 1, sizeof(ddsHeaderDxt10.m_dxgiFormat), fp); - write += fwrite(&ddsHeaderDxt10.m_resourceDimension, 1, sizeof(ddsHeaderDxt10.m_resourceDimension), fp); - write += fwrite(&ddsHeaderDxt10.m_miscFlags, 1, sizeof(ddsHeaderDxt10.m_miscFlags), fp); - write += fwrite(&ddsHeaderDxt10.m_arraySize, 1, sizeof(ddsHeaderDxt10.m_arraySize), fp); - write += fwrite(&ddsHeaderDxt10.m_miscFlags2, 1, sizeof(ddsHeaderDxt10.m_miscFlags2), fp); - DEBUG_CHECK(write == DDS_DX10_HEADER_SIZE, "Error writing Dds dx10 file header."); - FERROR_CHECK(fp); - } - - // Write data. - DEBUG_CHECK(NULL != _image.m_data, "Image data is null."); - write = fwrite(_image.m_data, 1, _image.m_dataSize, fp); - DEBUG_CHECK(write == _image.m_dataSize, "Error writing Dds image data."); - FERROR_CHECK(fp); - - return true; - } - - bool imageSaveKtx(const char* _fileName, const Image& _image) - { - char fileName[CMFT_PATH_LEN]; - strcpy(fileName, _fileName); - cmft::strlcat(fileName, getFilenameExtensionStr(ImageFileType::KTX), CMFT_PATH_LEN); - - // Open file. - FILE* fp = fopen(fileName, "wb"); - if (NULL == fp) - { - WARN("Could not open file %s for writing.", fileName); - return false; - } - cmft::ScopeFclose cleanup(fp); - - KtxHeader ktxHeader; - ktxHeaderFromImage(ktxHeader, _image); - - size_t write; - CMFT_UNUSED(write); - - // Write magic. - const uint8_t magic[KTX_MAGIC_LEN+1] = KTX_MAGIC; - write = fwrite(&magic, 1, KTX_MAGIC_LEN, fp); - DEBUG_CHECK(write == KTX_MAGIC_LEN, "Error writing Ktx magic."); - FERROR_CHECK(fp); - - // Write header. - write = 0; - write += fwrite(&ktxHeader.m_endianness, 1, sizeof(ktxHeader.m_endianness), fp); - write += fwrite(&ktxHeader.m_glType, 1, sizeof(ktxHeader.m_glType), fp); - write += fwrite(&ktxHeader.m_glTypeSize, 1, sizeof(ktxHeader.m_glTypeSize), fp); - write += fwrite(&ktxHeader.m_glFormat, 1, sizeof(ktxHeader.m_glFormat), fp); - write += fwrite(&ktxHeader.m_glInternalFormat, 1, sizeof(ktxHeader.m_glInternalFormat), fp); - write += fwrite(&ktxHeader.m_glBaseInternalFormat, 1, sizeof(ktxHeader.m_glBaseInternalFormat), fp); - write += fwrite(&ktxHeader.m_pixelWidth, 1, sizeof(ktxHeader.m_pixelWidth), fp); - write += fwrite(&ktxHeader.m_pixelHeight, 1, sizeof(ktxHeader.m_pixelHeight), fp); - write += fwrite(&ktxHeader.m_pixelDepth, 1, sizeof(ktxHeader.m_pixelDepth), fp); - write += fwrite(&ktxHeader.m_numArrayElements, 1, sizeof(ktxHeader.m_numArrayElements), fp); - write += fwrite(&ktxHeader.m_numFaces, 1, sizeof(ktxHeader.m_numFaces), fp); - write += fwrite(&ktxHeader.m_numMips, 1, sizeof(ktxHeader.m_numMips), fp); - write += fwrite(&ktxHeader.m_bytesKeyValue, 1, sizeof(ktxHeader.m_bytesKeyValue), fp); - DEBUG_CHECK(write == KTX_HEADER_SIZE, "Error writing Ktx header."); - - // Get source offsets. - uint32_t offsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(offsets, _image); - - const uint32_t bytesPerPixel = getImageDataInfo(_image.m_format).m_bytesPerPixel; - const uint8_t pad[4] = { 0, 0, 0, 0 }; - - // Write data. - DEBUG_CHECK(NULL != _image.m_data, "Image data is null."); - for (uint8_t mip = 0; mip < _image.m_numMips; ++mip) - { - const uint32_t width = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t height = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - - const uint32_t pitch = width * bytesPerPixel; - const uint32_t faceSize = pitch * height; - const uint32_t mipSize = faceSize * _image.m_numFaces; - - const uint32_t pitchRounding = (KTX_UNPACK_ALIGNMENT-1)-((pitch + KTX_UNPACK_ALIGNMENT-1)&(KTX_UNPACK_ALIGNMENT-1)); - const uint32_t faceRounding = (KTX_UNPACK_ALIGNMENT-1)-((faceSize + KTX_UNPACK_ALIGNMENT-1)&(KTX_UNPACK_ALIGNMENT-1)); - const uint32_t mipRounding = (KTX_UNPACK_ALIGNMENT-1)-((mipSize + KTX_UNPACK_ALIGNMENT-1)&(KTX_UNPACK_ALIGNMENT-1)); - - // Write face size. - write = fwrite(&faceSize, sizeof(uint32_t), 1, fp); - DEBUG_CHECK(write == 1, "Error writing Ktx data."); - FERROR_CHECK(fp); - - for (uint8_t face = 0; face < _image.m_numFaces; ++face) - { - const uint8_t* faceData = (const uint8_t*)_image.m_data + offsets[face][mip]; - - if (0 == pitchRounding) - { - // Write entire face at once. - write = fwrite(faceData, 1, faceSize, fp); - DEBUG_CHECK(write == faceSize, "Error writing Ktx face data."); - FERROR_CHECK(fp); - } - else - { - // Write row by row. - for (uint32_t yy = 0; yy < height; ++yy) - { - // Write row. - const uint8_t* src = (const uint8_t*)faceData + yy*pitch; - write = fwrite(src, 1, pitch, fp); - DEBUG_CHECK(write == pitch, "Error writing Ktx row data."); - FERROR_CHECK(fp); - - // Write row rounding. - write = fwrite(&pad, 1, pitchRounding, fp); - DEBUG_CHECK(write == pitchRounding, "Error writing Ktx row rounding."); - FERROR_CHECK(fp); - } - } - - // Write face rounding. - if (faceRounding) - { - write = fwrite(&pad, 1, faceRounding, fp); - DEBUG_CHECK(write == faceRounding, "Error writing Ktx face rounding."); - FERROR_CHECK(fp); - } - } - - // Write mip rounding. - if (mipRounding) - { - write = fwrite(&pad, 1, mipRounding, fp); - DEBUG_CHECK(write == mipRounding, "Error writing Ktx mip rounding."); - FERROR_CHECK(fp); - } - } - - return true; - } - - bool imageSaveHdr(const char* _fileName, const Image& _image, AllocatorI* _allocator) - { - char fileName[CMFT_PATH_LEN]; - char mipName[CMFT_PATH_LEN]; - - strcpy(fileName, _fileName); - - const uint32_t bytesPerPixel = getImageDataInfo(_image.m_format).m_bytesPerPixel; - - for (uint8_t mip = 0, endMip = _image.m_numMips; mip < endMip; ++mip) - { - cmft::stracpy(mipName, fileName); - - const uint32_t mipWidth = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t mipHeight = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - - if (_image.m_numMips != 1) - { - char mipStr[8]; - cmft::snprintf(mipStr, sizeof(mipStr), "%d", mip); - - char mipWidthStr[8]; - cmft::snprintf(mipWidthStr, sizeof(mipWidthStr), "%d", mipWidth); - - char mipHeightStr[8]; - cmft::snprintf(mipHeightStr, sizeof(mipHeightStr), "%d", mipHeight); - - cmft::strlcat(mipName, "_", CMFT_PATH_LEN); - cmft::strlcat(mipName, mipStr, CMFT_PATH_LEN); - cmft::strlcat(mipName, "_", CMFT_PATH_LEN); - cmft::strlcat(mipName, mipWidthStr, CMFT_PATH_LEN); - cmft::strlcat(mipName, "x", CMFT_PATH_LEN); - cmft::strlcat(mipName, mipHeightStr, CMFT_PATH_LEN); - } - - cmft::strlcat(mipName, getFilenameExtensionStr(ImageFileType::HDR), CMFT_PATH_LEN); - - // Open file. - FILE* fp = fopen(mipName, "wb"); - if (NULL == fp) - { - WARN("Could not open file %s for writing.", mipName); - return false; - } - cmft::ScopeFclose cleanup(fp); - - // Hdr file type assumes rgbe image format. - ImageSoftRef imageRgbe; - imageRefOrConvert(imageRgbe, TextureFormat::RGBE, _image, _allocator); - - // Get image offsets. - uint32_t imageOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(imageOffsets, _image); - const uint8_t* mipData = (const uint8_t*)imageRgbe.m_data + imageOffsets[0][mip]; - - if (1 != imageRgbe.m_numFaces) - { - WARN("Image seems to be containing more than one face. " - "Only the first one will be saved due to the limits of HDR format." - ); - } - - HdrHeader hdrHeader; - hdrHeaderFromImage(hdrHeader, imageRgbe); - - size_t write = 0; - CMFT_UNUSED(write); - - // Write magic. - char magic[HDR_MAGIC_LEN+1] = HDR_MAGIC_FULL; - magic[HDR_MAGIC_LEN] = '\n'; - write = fwrite(&magic, HDR_MAGIC_LEN+1, 1, fp); - DEBUG_CHECK(write == 1, "Error writing Hdr magic."); - FERROR_CHECK(fp); - - // Write comment. - char comment[21] = "# Output from cmft.\n"; - write = fwrite(&comment, 20, 1, fp); - DEBUG_CHECK(write == 1, "Error writing Hdr comment."); - FERROR_CHECK(fp); - - // Write format. - const char format[24] = "FORMAT=32-bit_rle_rgbe\n"; - write = fwrite(&format, 23, 1, fp); - DEBUG_CHECK(write == 1, "Error writing Hdr format."); - FERROR_CHECK(fp); - - // Don't write gamma for now... - //char gamma[32]; - //sprintf(gamma, "GAMMA=%g\n", hdrHeader.m_gamma); - //const size_t gammaLen = strlen(gamma); - //write = fwrite(&gamma, gammaLen, 1, fp); - //DEBUG_CHECK(write == 1, "Error writing Hdr gamma."); - //FERROR_CHECK(fp); - - // Write exposure. - char exposure[32]; - sprintf(exposure, "EXPOSURE=%g\n", hdrHeader.m_exposure); - const size_t exposureLen = strlen(exposure); - write = fwrite(&exposure, exposureLen, 1, fp); - DEBUG_CHECK(write == 1, "Error writing Hdr exposure."); - FERROR_CHECK(fp); - - // Write header terminator. - char headerTerminator = '\n'; - write = fwrite(&headerTerminator, 1, 1, fp); - DEBUG_CHECK(write == 1, "Error writing Hdr header terminator."); - FERROR_CHECK(fp); - - // Write image size. - char imageSize[32]; - sprintf(imageSize, "-Y %d +X %d\n", mipHeight, mipWidth); - const size_t imageSizeLen = strlen(imageSize); - write = fwrite(&imageSize, imageSizeLen, 1, fp); - DEBUG_CHECK(write == 1, "Error writing Hdr image size."); - FERROR_CHECK(fp); - - // Write data. - DEBUG_CHECK(NULL != imageRgbe.m_data, "Image data is null."); - write = fwrite(mipData, bytesPerPixel * mipWidth * mipHeight, 1, fp); - DEBUG_CHECK(write == 1, "Error writing Hdr data."); - FERROR_CHECK(fp); - - // Cleanup. - imageUnload(imageRgbe, _allocator); - } - - return true; - } - - bool imageSaveTga(const char* _fileName, const Image& _image, bool _yflip = true) - { - char fileName[CMFT_PATH_LEN]; - char mipName[CMFT_PATH_LEN]; - - bool result = true; - const uint8_t bytesPerPixel = getImageDataInfo(_image.m_format).m_bytesPerPixel; - - for (uint8_t face = 0, endFace = _image.m_numFaces; face < endFace; ++face) - { - cmft::stracpy(fileName, _fileName); - - if (_image.m_numFaces != 1) - { - cmft::strlcat(fileName, "_", CMFT_PATH_LEN); - cmft::strlcat(fileName, getCubemapFaceIdStr(face), CMFT_PATH_LEN); - } - - for (uint8_t mip = 0, endMip = _image.m_numMips; mip < endMip; ++mip) - { - cmft::stracpy(mipName, fileName); - - const uint32_t mipWidth = CMFT_MAX(UINT32_C(1), _image.m_width >> mip); - const uint32_t mipHeight = CMFT_MAX(UINT32_C(1), _image.m_height >> mip); - const uint32_t mipPitch = mipWidth * bytesPerPixel; - - if (_image.m_numMips != 1) - { - char mipStr[8]; - cmft::snprintf(mipStr, sizeof(mipStr), "%d", mip); - - char mipWidthStr[8]; - cmft::snprintf(mipWidthStr, sizeof(mipWidthStr), "%d", mipWidth); - - char mipHeightStr[8]; - cmft::snprintf(mipHeightStr, sizeof(mipHeightStr), "%d", mipHeight); - - cmft::strlcat(mipName, "_", CMFT_PATH_LEN); - cmft::strlcat(mipName, mipStr, CMFT_PATH_LEN); - cmft::strlcat(mipName, "_", CMFT_PATH_LEN); - cmft::strlcat(mipName, mipWidthStr, CMFT_PATH_LEN); - cmft::strlcat(mipName, "x", CMFT_PATH_LEN); - cmft::strlcat(mipName, mipHeightStr, CMFT_PATH_LEN); - } - - cmft::strlcat(mipName, getFilenameExtensionStr(ImageFileType::TGA), CMFT_PATH_LEN); - - // Open file. - FILE* fp = fopen(mipName, "wb"); - if (NULL == fp) - { - WARN("Could not open file %s for writing.", mipName); - result = false; - } - - TgaHeader tgaHeader; - tgaHeaderFromImage(tgaHeader, _image, mip); - - // Write header. - size_t write = 0; - CMFT_UNUSED(write); - write += fwrite(&tgaHeader.m_idLength, 1, sizeof(tgaHeader.m_idLength), fp); - write += fwrite(&tgaHeader.m_colorMapType, 1, sizeof(tgaHeader.m_colorMapType), fp); - write += fwrite(&tgaHeader.m_imageType, 1, sizeof(tgaHeader.m_imageType), fp); - write += fwrite(&tgaHeader.m_colorMapOrigin, 1, sizeof(tgaHeader.m_colorMapOrigin), fp); - write += fwrite(&tgaHeader.m_colorMapLength, 1, sizeof(tgaHeader.m_colorMapLength), fp); - write += fwrite(&tgaHeader.m_colorMapDepth, 1, sizeof(tgaHeader.m_colorMapDepth), fp); - write += fwrite(&tgaHeader.m_xOrigin, 1, sizeof(tgaHeader.m_xOrigin), fp); - write += fwrite(&tgaHeader.m_yOrigin, 1, sizeof(tgaHeader.m_yOrigin), fp); - write += fwrite(&tgaHeader.m_width, 1, sizeof(tgaHeader.m_width), fp); - write += fwrite(&tgaHeader.m_height, 1, sizeof(tgaHeader.m_height), fp); - write += fwrite(&tgaHeader.m_bitsPerPixel, 1, sizeof(tgaHeader.m_bitsPerPixel), fp); - write += fwrite(&tgaHeader.m_imageDescriptor, 1, sizeof(tgaHeader.m_imageDescriptor), fp); - DEBUG_CHECK(write == TGA_HEADER_SIZE, "Error writing Tga header."); - FERROR_CHECK(fp); - - // Get image offsets. - uint32_t imageOffsets[CUBE_FACE_NUM][MAX_MIP_NUM]; - imageGetMipOffsets(imageOffsets, _image); - - // Write data. //TODO: implement RLE option. - DEBUG_CHECK(NULL != _image.m_data, "Image data is null."); - const uint8_t* mipData = (const uint8_t*)_image.m_data + imageOffsets[face][mip]; - if (_yflip) - { - const uint8_t* src = (const uint8_t*)mipData + mipHeight * mipPitch; - for (uint32_t yy = 0; yy < mipHeight; ++yy) - { - src-=mipPitch; - write = fwrite(src, 1, mipPitch, fp); - DEBUG_CHECK(write == mipPitch, "Error writing Tga data."); - FERROR_CHECK(fp); - } - } - else - { - const uint8_t* src = (const uint8_t*)mipData; - for (uint32_t yy = 0; yy < mipHeight; ++yy) - { - write = fwrite(src, 1, mipPitch, fp); - DEBUG_CHECK(write == mipPitch, "Error writing Tga data."); - FERROR_CHECK(fp); - src+=mipPitch; - } - } - - // Write footer. - TgaFooter tgaFooter = { 0, 0, TGA_ID }; - write = fwrite(&tgaFooter.m_extensionOffset, 1, sizeof(tgaFooter.m_extensionOffset), fp); - write += fwrite(&tgaFooter.m_developerOffset, 1, sizeof(tgaFooter.m_developerOffset), fp); - write += fwrite(&tgaFooter.m_signature, 1, sizeof(tgaFooter.m_signature), fp); - DEBUG_CHECK(TGA_FOOTER_SIZE == write, "Error writing Tga footer."); - FERROR_CHECK(fp); - - // Cleanup. - fclose(fp); - } - - } - - return result; - } - - bool imageSave(const Image& _image, const char* _fileName, ImageFileType::Enum _ft, TextureFormat::Enum _convertTo, AllocatorI* _allocator) - { - // Get image in desired format. - ImageSoftRef image; - if (TextureFormat::Null != _convertTo) - { - imageRefOrConvert(image, _convertTo, _image, _allocator); - } - else - { - imageRef(image, _image); - } - - // Check for valid texture format and save. - bool result = false; - if (checkValidTextureFormat(_ft, image.m_format)) - { - if (ImageFileType::DDS == _ft) - { - result = imageSaveDds(_fileName, image); - } - else if (ImageFileType::KTX == _ft) - { - result = imageSaveKtx(_fileName, image); - } - else if (ImageFileType::TGA == _ft) - { - result = imageSaveTga(_fileName, image); - } - else if (ImageFileType::HDR == _ft) - { - result = imageSaveHdr(_fileName, image, _allocator); - } - } - else - { - char buf[1024]; - getValidTextureFormatsStr(buf, _ft); - - WARN("Could not save %s as *.%s image." - " Valid internal formats are: %s." - " Choose one of the valid internal formats or a different file type.\n" - , getTextureFormatStr(image.m_format) - , getFilenameExtensionStr(_ft) - , buf - ); - } - - // Cleanup. - imageUnload(image, _allocator); - - return result; - } - - bool imageSave(const Image& _image, const char* _fileName, ImageFileType::Enum _ft, OutputType::Enum _ot, TextureFormat::Enum _tf, bool _printOutput, AllocatorI* _allocator) - { - // Input check. - const bool validOutputType = checkValidOutputType(_ft, _ot); - if (!validOutputType) - { - char validOutputTypes[128]; - getValidOutputTypesStr(validOutputTypes, _ft); - WARN("Invalid output type for requested file type. File type: %s. Output type: %s." - " Valid output types for requested file type are: %s." - , getFileTypeStr(_ft), getOutputTypeStr(_ot) - , validOutputTypes - ); - return false; - } - - const bool validTextureFormat = checkValidTextureFormat(_ft, _tf); - if (!validTextureFormat) - { - char validTextureFormats[128]; - getValidTextureFormatsStr(validTextureFormats, _ft); - WARN("Invalid texture format for requested file type. File type: %s. Output type: %s." - " Valid texture formats for requested file type are: %s." - , getFileTypeStr(_ft), getTextureFormatStr(_tf) - , validTextureFormats - ); - return false; - } - - bool result = false; - - // Face list is a special case because it is saving 6 images. - if (OutputType::FaceList == _ot) - { - Image outputFaceList[6]; - imageFaceListFromCubemap(outputFaceList, _image, _allocator); - - result = true; - - for (uint8_t face = 0; face < 6; ++face) - { - char faceFileName[2048]; - sprintf(faceFileName, "%s_%s", _fileName, getCubemapFaceIdStr(face)); - - if (_printOutput) - { - INFO("Saving %s%s [%s %ux%u %s %s %u-faces %d-mips]." - , faceFileName - , getFilenameExtensionStr(_ft) - , getFileTypeStr(_ft) - , outputFaceList[face].m_width - , outputFaceList[face].m_height - , getTextureFormatStr(outputFaceList[face].m_format) - , getOutputTypeStr(_ot) - , outputFaceList[face].m_numFaces - , outputFaceList[face].m_numMips - ); - } - - const bool saved = imageSave(outputFaceList[face], faceFileName, _ft, _tf, _allocator); - if (!saved) - { - WARN("Saving failed!"); - } - - result &= saved; - } - - for (uint8_t face = 0; face < 6; ++face) - { - imageUnload(outputFaceList[face], _allocator); - } - - } - // Cubemap is a special case becase no transformation is required. - else if (OutputType::Cubemap == _ot) - { - if (_printOutput) - { - INFO("Saving %s%s [%s %ux%u %s %s %u-faces %d-mips]." - , _fileName - , getFilenameExtensionStr(_ft) - , getFileTypeStr(_ft) - , _image.m_width - , _image.m_height - , getTextureFormatStr(_tf) - , getOutputTypeStr(_ot) - , _image.m_numFaces - , _image.m_numMips - ); - } - - result = imageSave(_image, _fileName, _ft, _tf, _allocator); - if (!result) - { - WARN("Saving failed!"); - } - } - else - { - Image outputImage; - - if (OutputType::LatLong == _ot) - { - imageLatLongFromCubemap(outputImage, _image, true, _allocator); - } - else if (OutputType::HCross == _ot) - { - imageCrossFromCubemap(outputImage, _image, false, _allocator); - } - else if (OutputType::VCross == _ot) - { - imageCrossFromCubemap(outputImage, _image, true, _allocator); - } - else if (OutputType::HStrip == _ot) - { - imageStripFromCubemap(outputImage, _image, false, _allocator); - } - else if (OutputType::VStrip == _ot) - { - imageStripFromCubemap(outputImage, _image, true, _allocator); - } - else if (OutputType::Octant == _ot) - { - imageOctantFromCubemap(outputImage, _image, true, _allocator); - } - else - { - WARN("Invalid output type."); - return false; - } - - if (_printOutput) - { - INFO("Saving %s%s [%s %ux%u %s %s %u-faces %d-mips]." - , _fileName - , getFilenameExtensionStr(_ft) - , getFileTypeStr(_ft) - , outputImage.m_width - , outputImage.m_height - , getTextureFormatStr(_tf) - , getOutputTypeStr(_ot) - , outputImage.m_numFaces - , outputImage.m_numMips - ); - } - - result = imageSave(outputImage, _fileName, _ft, _tf, _allocator); - if (!result) - { - WARN("Saving failed!"); - } - - imageUnload(outputImage, _allocator); - } - - return result; - } - - // ImageRef - //----- - - bool imageAsCubemap(ImageSoftRef& _dst, const Image& _src, AllocatorI* _allocator) - { - if (imageIsCubemap(_src)) - { - imageRef(_dst, _src); - return true; - } - else if (imageCubemapFromCross(_dst, _src, _allocator) - || imageCubemapFromLatLong(_dst, _src, true, _allocator) - || imageCubemapFromStrip(_dst, _src, _allocator)) - { - return true; - } - - return false; - } - - void imageRefOrConvert(ImageHardRef& _dst, TextureFormat::Enum _format, Image& _src, AllocatorI* _allocator) - { - if (_format == _src.m_format) - { - imageRef(_dst, _src); - } - else - { - imageUnload(_dst, _allocator); - imageConvert(_dst, _format, _src, _allocator); - } - } - - void imageRefOrConvert(ImageSoftRef& _dst, TextureFormat::Enum _format, const Image& _src, AllocatorI* _allocator) - { - if (_format == _src.m_format) - { - imageRef(_dst, _src); - } - else - { - imageUnload(_dst, _allocator); - imageConvert(_dst, _format, _src, _allocator); - } - } - - void imageRef(ImageSoftRef& _dst, const Image& _src) - { - _dst.m_data = _src.m_data; - _dst.m_width = _src.m_width; - _dst.m_height = _src.m_height; - _dst.m_dataSize = _src.m_dataSize; - _dst.m_format = _src.m_format; - _dst.m_numMips = _src.m_numMips; - _dst.m_numFaces = _src.m_numFaces; - _dst.m_isRef = true; - } - - void imageRef(ImageHardRef& _dst, Image& _src) - { - _dst.m_data = _src.m_data; - _dst.m_width = _src.m_width; - _dst.m_height = _src.m_height; - _dst.m_dataSize = _src.m_dataSize; - _dst.m_format = _src.m_format; - _dst.m_numMips = _src.m_numMips; - _dst.m_numFaces = _src.m_numFaces; - _dst.m_origDataPtr = &_src.m_data; - } - - void imageMove(Image& _dst, ImageSoftRef& _src, AllocatorI* _allocator) - { - if (_src.isRef()) - { - DEBUG_CHECK(false, "Soft reference cannot be moved!"); - abort(); - } - - imageUnload(_dst, _allocator); - _dst.m_data = _src.m_data; - _dst.m_width = _src.m_width; - _dst.m_height = _src.m_height; - _dst.m_dataSize = _src.m_dataSize; - _dst.m_format = _src.m_format; - _dst.m_numMips = _src.m_numMips; - _dst.m_numFaces = _src.m_numFaces; - - _src.m_data = NULL; - } - - void imageMove(Image& _dst, ImageHardRef& _src, AllocatorI* _allocator) - { - imageUnload(_dst, _allocator); - _dst.m_data = _src.m_data; - _dst.m_width = _src.m_width; - _dst.m_height = _src.m_height; - _dst.m_dataSize = _src.m_dataSize; - _dst.m_format = _src.m_format; - _dst.m_numMips = _src.m_numMips; - _dst.m_numFaces = _src.m_numFaces; - - _src.m_data = NULL; - if (_src.isRef()) - { - *_src.m_origDataPtr = NULL; - } - } - - void imageUnload(ImageSoftRef& _image, AllocatorI* _allocator) - { - if (_image.isCopy() && _image.m_data) - { - CMFT_FREE(_allocator, _image.m_data); - _image.m_data = NULL; - } - } - - void imageUnload(ImageHardRef& _image, AllocatorI* _allocator) - { - if (_image.isCopy() && _image.m_data) - { - CMFT_FREE(_allocator, _image.m_data); - _image.m_data = NULL; - } - } - -} // namespace cmft - -/* vim: set sw=4 ts=4 expandtab: */ diff --git a/ext/cmft/image.h b/ext/cmft/image.h deleted file mode 100644 index 3ddbe477..00000000 --- a/ext/cmft/image.h +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright 2014 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#ifndef CMFT_IMAGE_H_HEADER_GUARD -#define CMFT_IMAGE_H_HEADER_GUARD - -#include -#include -#include - -#include "allocator.h" - -#ifndef UINT8_MAX // Fixing mingw bug. - #define UINT8_MAX (255) -#endif //UINT8_MAX - -namespace cmft -{ - #define CUBE_FACE_NUM 6 - #define MAX_MIP_NUM 16 - - enum ImageTransformArgs - { - IMAGE_FACE_POSITIVEX = 0x0000, - IMAGE_FACE_NEGATIVEX = 0x0001, - IMAGE_FACE_POSITIVEY = 0x0002, - IMAGE_FACE_NEGATIVEY = 0x0003, - IMAGE_FACE_POSITIVEZ = 0x0004, - IMAGE_FACE_NEGATIVEZ = 0x0005, - IMAGE_FACE_SHIFT = 0, - IMAGE_FACE_MASK = 0x0007, - - IMAGE_OP_ROT_90 = 0x0100, - IMAGE_OP_ROT_180 = 0x0200, - IMAGE_OP_ROT_270 = 0x0400, - IMAGE_OP_FLIP_X = 0x1000, - IMAGE_OP_FLIP_Y = 0x2000, - IMAGE_OP_SHIFT = 8, - IMAGE_OP_MASK = 0xff00, - }; - - struct ImageFileType - { - enum Enum - { - DDS, - KTX, - TGA, - HDR, - - Count - }; - }; - - struct OutputType - { - enum Enum - { - LatLong, - Cubemap, - HCross, - VCross, - HStrip, - VStrip, - FaceList, - Octant, - - Count, - Null = -1, - }; - }; - - struct TextureFormat - { - enum Enum - { - BGR8, - RGB8, - RGB16, - RGB16F, - RGB32F, - RGBE, - - BGRA8, - RGBA8, - RGBA16, - RGBA16F, - RGBA32F, - - RGBM, - - Count, - Null = -1, - }; - }; - - struct ImageDataInfo - { - uint8_t m_bytesPerPixel; - uint8_t m_numChanels; - uint8_t m_hasAlpha; - uint8_t m_pixelType; - }; - - struct Image - { - Image() - { - m_width = 0; - m_height = 0; - m_dataSize = 0; - m_format = TextureFormat::Null; - m_numMips = 0; - m_numFaces = 0; - m_data = NULL; - } - - uint32_t m_width; - uint32_t m_height; - uint32_t m_dataSize; - TextureFormat::Enum m_format; - uint8_t m_numMips; - uint8_t m_numFaces; - void* m_data; - }; - - extern AllocatorI* g_allocator; - - /// - const char* getFileTypeStr(ImageFileType::Enum _ft); - - /// - const char* getOutputTypeStr(OutputType::Enum _ot); - - /// - const char* getCubemapFaceIdStr(uint8_t _face); - - /// - const char* getFilenameExtensionStr(ImageFileType::Enum _ft); - - /// - const char* getTextureFormatStr(TextureFormat::Enum _format); - - /// Returns a OutputType::Null terminating array of valid output types for requested file type. - const OutputType::Enum* getValidOutputTypes(ImageFileType::Enum _fileType); - - /// - void getValidOutputTypesStr(char* _str, ImageFileType::Enum _fileType); - - /// - bool checkValidOutputType(ImageFileType::Enum _fileType, OutputType::Enum _outputType); - - /// Returns a TextureFormat::Null terminating array of valid texture formats for requested file type. - const TextureFormat::Enum* getValidTextureFormats(ImageFileType::Enum _fileType); - - /// - void getValidTextureFormatsStr(char* _str, ImageFileType::Enum _fileType); - - /// - bool checkValidTextureFormat(ImageFileType::Enum _fileType, TextureFormat::Enum _textureFormat); - - /// - const ImageDataInfo& getImageDataInfo(TextureFormat::Enum _format); - - /// - uint8_t getNaturalAlignment(TextureFormat::Enum _format); - - /// - void imageCreate(Image& _image, uint32_t _width, uint32_t _height, uint32_t _rgba = 0x303030ff, uint8_t _numMips = 1, uint8_t _numFaces = 1, TextureFormat::Enum _format = TextureFormat::RGBA32F, AllocatorI* _allocator = g_allocator); - - /// - void imageUnload(Image& _image, AllocatorI* _allocator = g_allocator); - - /// - void imageMove(Image& _dst, Image& _src, AllocatorI* _allocator = g_allocator); - - /// - void imageCopy(Image& _dst, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// - uint32_t imageGetNumPixels(const Image& _image); - - /// - void imageGetMipOffsets(uint32_t _offsets[CUBE_FACE_NUM][MAX_MIP_NUM], const Image& _image); - - /// - void imageGetFaceOffsets(uint32_t _faceOffsets[CUBE_FACE_NUM], const Image& _image); - - /// - void toRgba32f(float _rgba32f[4], TextureFormat::Enum _srcFormat, const void* _src); - - /// - void imageToRgba32f(Image& _dst, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// - void imageToRgba32f(Image& _image, AllocatorI* _allocator = g_allocator); - - /// - void fromRgba32f(void* _out, TextureFormat::Enum _format, const float _rgba32f[4]); - - /// - void imageFromRgba32f(Image& _dst, TextureFormat::Enum _dstFormat, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// - void imageFromRgba32f(Image& _image, TextureFormat::Enum _textureFormat, AllocatorI* _allocator = g_allocator); - - /// - void imageConvert(Image& _dst, TextureFormat::Enum _dstFormat, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// - void imageConvert(Image& _image, TextureFormat::Enum _format, AllocatorI* _allocator = g_allocator); - - /// - void imageGetPixel(void* _out, TextureFormat::Enum _format, uint32_t _x, uint32_t _y, uint8_t _face, uint8_t _mip, const Image& _image); - - /// - void imageCubemapGetPixel(void* _out, TextureFormat::Enum _format, float _dir[3], uint8_t _mip, const Image& _image); - - /// - void imageResize(Image& _dst, uint32_t _width, uint32_t _height, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// - void imageResize(Image& _image, uint32_t _width, uint32_t _height, AllocatorI* _allocator = g_allocator); - - /// - void imageResize(Image& _dst, uint32_t _faceSize, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// - void imageResize(Image& _image, uint32_t _faceSize, AllocatorI* _allocator = g_allocator); - - /// - uint32_t imageGetCubemapFaceSize(const Image& _image); - - /// Notice: because all transformations are done on data in place, - /// rotations work properly only when image width == image height (which is true for cubemap images). - /// Flip operations work properly regardless of aspect ratio. -#define imageTransform(_image, ...) imageTransformUseMacroInstead(&(_image), __VA_ARGS__, UINT32_MAX) - void imageTransformUseMacroInstead(Image* _image, ...); - - /// Notice: _argList should end with UINT32_MAX. - void imageTransformArg(Image& _image, va_list _argList); - - /// - void imageGenerateMipMapChain(Image& _image, uint8_t _numMips=UINT8_MAX, AllocatorI* _allocator = g_allocator); - - /// - void imageEncodeRGBM(Image& _image, AllocatorI* _allocator = g_allocator); - - /// - void imageApplyGamma(Image& _image, float _gammaPow, AllocatorI* _allocator = g_allocator); - - /// - void imageClamp(Image& _dst, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// - void imageClamp(Image& _image, AllocatorI* _allocator = g_allocator); - - /// .....___.... - /// +------+ ....__....... . | | . _________________ ___ ___ _______________ - /// /| /| . | | . .___|___|___. | | |___| | |_ | . | - /// +-+----+ | .__|__|__ __. | | | | | | __ __ __ __ __ __ |___| |___| |_ | . . . | - /// | | | | | | | | | |___|___|___| | | | | | | | | | |___| |___| |_ | . . . | - /// | +----+-+ |__|__|__|__| . | | . | | |__|__|__|__|__|__| |___| |___| |_ |...............| - /// |/ |/ . | | . . |___| . |_________________| |___| |___| |_ | . . . | - /// +------+ ...|__|...... . | | . |___| |___| | | . . . | - /// ....|___|.... |___| |_______._______| - /// - /// Cubemap HCross VCross Lat Long HStrip VStrip Face list Octant - /// - /// Octant: - /// Octahedron environment maps: http://www.vis.uni-stuttgart.de/~dachsbcn/download/vmvOctaMaps.pdf - /// A survey of efficient representations for independent unit vectors: http://jcgt.org/published/0003/02/01/paper.pdf (page 8. and 9.) - /// - - /// - bool imageIsCubemap(const Image& _image); - - /// - /// Checks if image is a latlong image. Not an actual test, just checks the image ratio. - /// - bool imageIsLatLong(const Image& _image); - - /// - bool imageIsHStrip(const Image& _image); - - /// - bool imageIsVStrip(const Image& _image); - - /// - bool imageIsOctant(const Image& _image); - - /// - bool imageValidCubemapFaceList(const Image _faceList[6]); - - /// - bool imageIsCubeCross(const Image& _image, bool _fastCheck = false); - - /// - bool imageIsEnvironmentMap(const Image& _image, bool _fastCheck = false); - - /// - bool imageCubemapFromCross(Image& _dst, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// - bool imageCubemapFromCross(Image& _image, AllocatorI* _allocator = g_allocator); - - /// - bool imageCubemapFromLatLong(Image& _dst, const Image& _src, bool _useBilinearInterpolation = true, AllocatorI* _allocator = g_allocator); - - /// - bool imageCubemapFromLatLong(Image& _image, bool _useBilinearInterpolation = true, AllocatorI* _allocator = g_allocator); - - /// - bool imageLatLongFromCubemap(Image& _dst, const Image& _src, bool _useBilinearInterpolation = true, AllocatorI* _allocator = g_allocator); - - /// - bool imageLatLongFromCubemap(Image& _cubemap, bool _useBilinearInterpolation = true, AllocatorI* _allocator = g_allocator); - - /// - bool imageStripFromCubemap(Image& _dst, const Image& _src, bool _vertical = false, AllocatorI* _allocator = g_allocator); - - /// - bool imageStripFromCubemap(Image& _image, bool _vertical = false, AllocatorI* _allocator = g_allocator); - - /// - bool imageCubemapFromStrip(Image& _dst, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// - bool imageCubemapFromStrip(Image& _image, AllocatorI* _allocator = g_allocator); - - /// - bool imageFaceListFromCubemap(Image _faceList[6], const Image& _cubemap, AllocatorI* _allocator = g_allocator); - - /// - bool imageCubemapFromFaceList(Image& _cubemap, const Image _faceList[6], AllocatorI* _allocator = g_allocator); - - /// - bool imageCrossFromCubemap(Image& _dst, const Image& _src, bool _vertical = true, AllocatorI* _allocator = g_allocator); - - /// - bool imageCrossFromCubemap(Image& _image, bool _vertical = true, AllocatorI* _allocator = g_allocator); - - /// - bool imageToCubemap(Image& _dst, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// - bool imageToCubemap(Image& _image, AllocatorI* _allocator = g_allocator); - - /// - bool imageOctantFromCubemap(Image& _dst, const Image& _src, bool _useBilinearInterpolation, AllocatorI* _allocator); - - /// - bool imageCubemapFromOctant(Image& _dst, const Image& _src, bool _useBilinearInterpolation = true, AllocatorI* _allocator = g_allocator); - - /// - bool imageCubemapFromOctant(Image& _image, bool _useBilinearInterpolation = true, AllocatorI* _allocator = g_allocator); - - /// - bool imageLoad(Image& _image, const char* _filePath, TextureFormat::Enum _convertTo = TextureFormat::Null, AllocatorI* _allocator = g_allocator); - - /// - bool imageLoad(Image& _image, const void* _data, uint32_t _dataSize, TextureFormat::Enum _convertTo = TextureFormat::Null, AllocatorI* _allocator = g_allocator); - - /// - bool imageLoadStb(Image& _image, const char* _filePath, TextureFormat::Enum _convertTo = TextureFormat::Null, AllocatorI* _allocator = g_allocator); - - /// - bool imageLoadStb(Image& _image, const void* _data, uint32_t _dataSize, TextureFormat::Enum _convertTo = TextureFormat::Null, AllocatorI* _allocator = g_allocator); - - /// - bool imageIsValid(const Image& _image); - - /// - bool imageSave(const Image& _image, const char* _fileName, ImageFileType::Enum _ft, TextureFormat::Enum _convertTo = TextureFormat::Null, AllocatorI* _allocator = g_allocator); - - /// - bool imageSave(const Image& _image, const char* _fileName, ImageFileType::Enum _ft, OutputType::Enum _ot, TextureFormat::Enum _tf = TextureFormat::Null, bool _printOutput = false, AllocatorI* _allocator = g_allocator); - - // ImageRef - //----- - - struct ImageSoftRef : public Image - { - ImageSoftRef() - { - m_isRef = false; - } - - inline bool isRef() const { return m_isRef; } - inline bool isCopy() const { return !m_isRef; } - - bool m_isRef; - }; - - struct ImageHardRef : public Image - { - ImageHardRef() - { - m_origDataPtr = NULL; - } - - inline bool isRef() const { return (NULL != m_origDataPtr); } - inline bool isCopy() const { return (NULL == m_origDataPtr); } - - void** m_origDataPtr; - }; - - /// - bool imageAsCubemap(ImageSoftRef& _dst, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// If requested format is the same as source, _dst becomes a reference to _src. - /// Otherwise, _dst is filled with a converted copy of the image. - /// Either way, imageUnload() should be called on _dst and it will free the data in case a copy was made. - void imageRefOrConvert(ImageHardRef& _dst, TextureFormat::Enum _format, Image& _src, AllocatorI* _allocator = g_allocator); - - /// - void imageRefOrConvert(ImageSoftRef& _dst, TextureFormat::Enum _format, const Image& _src, AllocatorI* _allocator = g_allocator); - - /// - void imageRef(ImageSoftRef& _dst, const Image& _src); - - /// - void imageRef(ImageHardRef& _dst, Image& _src); - - /// - void imageMove(Image& _dst, ImageSoftRef& _src, AllocatorI* _allocator = g_allocator); - - /// - void imageMove(Image& _dst, ImageHardRef& _src, AllocatorI* _allocator = g_allocator); - - /// - void imageUnload(ImageSoftRef& _image, AllocatorI* _allocator = g_allocator); - - /// - void imageUnload(ImageHardRef& _image, AllocatorI* _allocator = g_allocator); - -} // namespace cmft - -#endif //CMFT_IMAGE_H_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ diff --git a/ext/cmft/print.h b/ext/cmft/print.h deleted file mode 100644 index 0001cd01..00000000 --- a/ext/cmft/print.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014 Dario Manesku. All rights reserved. - * License: http://www.opensource.org/licenses/BSD-2-Clause - */ - -#ifndef CMFT_PRINT_H_HEADER_GUARD -#define CMFT_PRINT_H_HEADER_GUARD - -namespace cmft -{ - typedef int (*PrintFunc)(const char* _format, ...); - - void setWarningPrintf(PrintFunc _printf); - void setInfoPrintf(PrintFunc _printf); - -} // namespace cmft - -#endif //CMFT_PRINT_H_HEADER_GUARD - -/* vim: set sw=4 ts=4 expandtab: */ diff --git a/ext/ffmpegCodec.cpp b/ext/ffmpegCodec/ffmpegCodec.cpp similarity index 98% rename from ext/ffmpegCodec.cpp rename to ext/ffmpegCodec/ffmpegCodec.cpp index ceb18d8b..6e96fc8a 100644 --- a/ext/ffmpegCodec.cpp +++ b/ext/ffmpegCodec/ffmpegCodec.cpp @@ -346,13 +346,13 @@ namespace FFMPEGCodec finished = receive_frame(m_codec_context, m_frame, &pkt); //int64_t pts = m_frame->pts; - + double pts = 0; //if (static_cast(m_frame->pkt_pts) != int64_t(AV_NOPTS_VALUE)) { pts = av_q2d(m_format_context->streams[m_video_stream]->time_base) * (m_frame->pts - m_start_time); } - + int current_frame = int((pts) * Fps() + 0.5f); //Log("Current frame %d\n", current_frame2); @@ -428,7 +428,7 @@ namespace FFMPEGCodec #define VIDEO_TMP_FILE "tmp.h264" using namespace std; - void Debug(const std::string& str, int err) + void Debug(const std::string& str, int err) { Log(str.c_str()); } @@ -512,7 +512,7 @@ namespace FFMPEGCodec av_dump_format(ofctx, 0, VIDEO_TMP_FILE, 1); } - void Encoder::AddFrame(uint8_t *data, int width, int height) + void Encoder::AddFrame(uint8_t *data, int width, int height) { int err; if (!videoFrame) { @@ -620,10 +620,14 @@ namespace FFMPEGCodec } } - void Encoder::Remux() + void Encoder::Remux() { AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL; + int64_t ts = 0; int err; + AVStream *inVideoStream; + AVStream *outVideoStream; + AVPacket videoPkt; if ((err = avformat_open_input(&ifmt_ctx, VIDEO_TMP_FILE, 0, 0)) < 0) { Debug("Failed to open input file for remuxing", err); @@ -638,8 +642,8 @@ namespace FFMPEGCodec goto end; } - AVStream *inVideoStream = ifmt_ctx->streams[0]; - AVStream *outVideoStream = avformat_new_stream(ofmt_ctx, NULL); + inVideoStream = ifmt_ctx->streams[0]; + outVideoStream = avformat_new_stream(ofmt_ctx, NULL); if (!outVideoStream) { Debug("Failed to allocate output video stream", 0); goto end; @@ -660,8 +664,6 @@ namespace FFMPEGCodec goto end; } - AVPacket videoPkt; - int64_t ts = 0; while (true) { if ((err = av_read_frame(ifmt_ctx, &videoPkt)) < 0) { break; @@ -694,4 +696,4 @@ namespace FFMPEGCodec avformat_free_context(ofmt_ctx); } } -} \ No newline at end of file +} diff --git a/ext/ffmpegCodec.h b/ext/ffmpegCodec/ffmpegCodec.h similarity index 100% rename from ext/ffmpegCodec.h rename to ext/ffmpegCodec/ffmpegCodec.h diff --git a/ext/imHotKey.h b/ext/imHotKey.h index d1d57f77..4de00fec 100644 --- a/ext/imHotKey.h +++ b/ext/imHotKey.h @@ -97,7 +97,7 @@ namespace ImHotKey int x = 0; while (Keys[y][x].lib) { -#ifdef SDL_h_ +#ifdef USE_SDL if (Keys[y][x].scanCodePage7 == scancode) #elif WIN32 if (Keys[y][x].scanCodePage1 == scancode) @@ -207,7 +207,7 @@ namespace ImHotKey if (ImGui::IsKeyPressed(i, false)) { int imKey; -#ifdef SDL_h_ +#ifdef USE_SDL imKey = i; #elif WIN32 imKey = MapVirtualKeyA(i, MAPVK_VK_TO_VSC); @@ -238,7 +238,7 @@ namespace ImHotKey ImGui::Indent(ofs); } } -#ifdef SDL_h_ +#ifdef USE_SDL bool& butSwtch = keyDown[key.scanCodePage7]; #elif WIN32 bool& butSwtch = keyDown[key.scanCodePage1]; @@ -315,7 +315,7 @@ namespace ImHotKey if (ImGui::IsKeyDown(i)) { int imKey; -#ifdef SDL_h_ +#ifdef USE_SDL imKey = i; #elif WIN32 imKey = MapVirtualKeyA(i, MAPVK_VK_TO_VSC); diff --git a/ext/imgInspect.h b/ext/imgInspect.h index 17744006..5b27c35f 100644 --- a/ext/imgInspect.h +++ b/ext/imgInspect.h @@ -125,7 +125,8 @@ namespace ImageInspect const int height, const unsigned char* const bits, ImVec2 mouseUVCoord, - ImVec2 displayedTextureSize) + ImVec2 displayedTextureSize, + bool invertY) { ImGui::BeginTooltip(); ImGui::BeginGroup(); @@ -139,13 +140,13 @@ namespace ImageInspect static int zoomSize = 4; const float quadWidth = zoomRectangleWidth / float(zoomSize * 2 + 1); const ImVec2 quadSize(quadWidth, quadWidth); - const int basex = ImClamp(int(mouseUVCoord.x * width), zoomSize, width - zoomSize); - const int basey = ImClamp(int(mouseUVCoord.y * height), zoomSize, height - zoomSize); + const int basex = ImClamp(int(mouseUVCoord.x * width), zoomSize, width - zoomSize - 1); + const int basey = ImClamp(int(mouseUVCoord.y * height), zoomSize, height - zoomSize - 1); for (int y = -zoomSize; y <= zoomSize; y++) { for (int x = -zoomSize; x <= zoomSize; x++) { - uint32_t texel = ((uint32_t*)bits)[(basey - y) * width + x + basex]; + uint32_t texel = invertY ? ((uint32_t*)bits)[(height - 1 - basey + y) * width + x + basex] : ((uint32_t*)bits)[(basey - y) * width + x + basex]; ImVec2 pos = pickRc.Min + ImVec2(float(x + zoomSize), float(y + zoomSize)) * quadSize; draw_list->AddRectFilled(pos, pos + quadSize, texel); } @@ -163,7 +164,7 @@ namespace ImageInspect { for (int x = -zoomSize; x <= zoomSize; x++) { - uint32_t texel = ((uint32_t*)bits)[(basey - y) * width + x + basex]; + uint32_t texel = invertY ? ((uint32_t*)bits)[(height - 1 - basey + y) * width + x + basex] : ((uint32_t*)bits)[(basey - y) * width + x + basex]; const ImVec2 posQuad = normRc.Min + ImVec2(float(x + zoomSize), float(y + zoomSize)) * quadSize; //draw_list->AddRectFilled(pos, pos + quadSize, texel); const float nx = float(texel & 0xFF) / 128.f - 1.f; @@ -173,12 +174,10 @@ namespace ImageInspect } } - - ImGui::EndGroup(); ImGui::SameLine(); ImGui::BeginGroup(); - uint32_t texel = ((uint32_t*)bits)[(basey - zoomSize * 2 - 1) * width + basex]; + uint32_t texel = invertY ? ((uint32_t*)bits)[(height - 1 - basey) * width + basex] : ((uint32_t*)bits)[basey * width + basex]; ImVec4 color = ImColor(texel); ImVec4 colHSV; ImGui::ColorConvertRGBtoHSV(color.x, color.y, color.z, colHSV.x, colHSV.y, colHSV.z); diff --git a/ext/imgui_color_gradient.cpp b/ext/imgui_color_gradient.cpp new file mode 100644 index 00000000..41e38420 --- /dev/null +++ b/ext/imgui_color_gradient.cpp @@ -0,0 +1,391 @@ +// +// imgui_color_gradient.cpp +// imgui extension +// +// Created by David Gallardo on 11/06/16. + + +#include "imgui_color_gradient.h" +#include "imgui_internal.h" + +static const float GRADIENT_BAR_WIDGET_HEIGHT = 25; +static const float GRADIENT_BAR_EDITOR_HEIGHT = 40; +static const float GRADIENT_MARK_DELETE_DIFFY = 40; + +ImGradient::ImGradient() +{ + //addMark(0.0f, ImColor(0.0f,0.0f,0.0f)); + //addMark(1.0f, ImColor(1.0f,1.0f,1.0f)); +} + +ImGradient::~ImGradient() +{ + for (ImGradientMark* mark : m_marks) + { + delete mark; + } +} + +void ImGradient::addMark(float position, ImColor const color) +{ + position = ImClamp(position, 0.0f, 1.0f); + ImGradientMark* newMark = new ImGradientMark(); + newMark->position = position; + newMark->color[0] = color.Value.x; + newMark->color[1] = color.Value.y; + newMark->color[2] = color.Value.z; + + m_marks.push_back(newMark); + + refreshCache(); +} + +void ImGradient::removeMark(ImGradientMark* mark) +{ + m_marks.remove(mark); + refreshCache(); +} + +void ImGradient::getColorAt(float position, float* color) const +{ + position = ImClamp(position, 0.0f, 1.0f); + int cachePos = (position * 255); + cachePos *= 3; + color[0] = m_cachedValues[cachePos+0]; + color[1] = m_cachedValues[cachePos+1]; + color[2] = m_cachedValues[cachePos+2]; +} + +void ImGradient::computeColorAt(float position, float* color) const +{ + position = ImClamp(position, 0.0f, 1.0f); + + ImGradientMark* lower = nullptr; + ImGradientMark* upper = nullptr; + + for(ImGradientMark* mark : m_marks) + { + if(mark->position < position) + { + if(!lower || lower->position < mark->position) + { + lower = mark; + } + } + + if(mark->position >= position) + { + if(!upper || upper->position > mark->position) + { + upper = mark; + } + } + } + + if(upper && !lower) + { + lower = upper; + } + else if(!upper && lower) + { + upper = lower; + } + else if(!lower && !upper) + { + color[0] = color[1] = color[2] = 0; + return; + } + + if(upper == lower) + { + color[0] = upper->color[0]; + color[1] = upper->color[1]; + color[2] = upper->color[2]; + } + else + { + float distance = upper->position - lower->position; + float delta = (position - lower->position) / distance; + + //lerp + color[0] = ((1.0f - delta) * lower->color[0]) + ((delta) * upper->color[0]); + color[1] = ((1.0f - delta) * lower->color[1]) + ((delta) * upper->color[1]); + color[2] = ((1.0f - delta) * lower->color[2]) + ((delta) * upper->color[2]); + } +} + +void ImGradient::refreshCache() +{ + m_marks.sort([](const ImGradientMark * a, const ImGradientMark * b) { return a->position < b->position; }); + + for(int i = 0; i < 256; ++i) + { + computeColorAt(i/255.0f, &m_cachedValues[i*3]); + } +} + + + +namespace ImGui +{ + static void DrawGradientBar(ImGradient* gradient, + struct ImVec2 const & bar_pos, + float maxWidth, + float height) + { + ImVec4 colorA = {1,1,1,1}; + ImVec4 colorB = {1,1,1,1}; + float prevX = bar_pos.x; + float barBottom = bar_pos.y + height; + ImGradientMark* prevMark = nullptr; + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + draw_list->AddRectFilled(ImVec2(bar_pos.x - 2, bar_pos.y - 2), + ImVec2(bar_pos.x + maxWidth + 2, barBottom + 2), + IM_COL32(100, 100, 100, 255)); + + if(gradient->getMarks().size() == 0) + { + draw_list->AddRectFilled(ImVec2(bar_pos.x, bar_pos.y), + ImVec2(bar_pos.x + maxWidth, barBottom), + IM_COL32(255, 255, 255, 255)); + + } + + ImU32 colorAU32 = 0; + ImU32 colorBU32 = 0; + + for(auto markIt = gradient->getMarks().begin(); markIt != gradient->getMarks().end(); ++markIt ) + { + ImGradientMark* mark = *markIt; + + float from = prevX; + float to = prevX = bar_pos.x + mark->position * maxWidth; + + if(prevMark == nullptr) + { + colorA.x = mark->color[0]; + colorA.y = mark->color[1]; + colorA.z = mark->color[2]; + } + else + { + colorA.x = prevMark->color[0]; + colorA.y = prevMark->color[1]; + colorA.z = prevMark->color[2]; + } + + colorB.x = mark->color[0]; + colorB.y = mark->color[1]; + colorB.z = mark->color[2]; + + colorAU32 = ImGui::ColorConvertFloat4ToU32(colorA); + colorBU32 = ImGui::ColorConvertFloat4ToU32(colorB); + + if(mark->position > 0.0) + { + + draw_list->AddRectFilledMultiColor(ImVec2(from, bar_pos.y), + ImVec2(to, barBottom), + colorAU32, colorBU32, colorBU32, colorAU32); + } + + prevMark = mark; + } + + if(prevMark && prevMark->position < 1.0) + { + + draw_list->AddRectFilledMultiColor(ImVec2(prevX, bar_pos.y), + ImVec2(bar_pos.x + maxWidth, barBottom), + colorBU32, colorBU32, colorBU32, colorBU32); + } + + ImGui::SetCursorScreenPos(ImVec2(bar_pos.x, bar_pos.y + height + 10.0f)); + } + + static void DrawGradientMarks(ImGradient* gradient, + ImGradientMark* & draggingMark, + ImGradientMark* & selectedMark, + struct ImVec2 const & bar_pos, + float maxWidth, + float height) + { + ImVec4 colorA = {1,1,1,1}; + ImVec4 colorB = {1,1,1,1}; + float barBottom = bar_pos.y + height; + ImGradientMark* prevMark = nullptr; + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImU32 colorAU32 = 0; + ImU32 colorBU32 = 0; + + for(auto markIt = gradient->getMarks().begin(); markIt != gradient->getMarks().end(); ++markIt ) + { + ImGradientMark* mark = *markIt; + + if(!selectedMark) + { + selectedMark = mark; + } + + float to = bar_pos.x + mark->position * maxWidth; + + if(prevMark == nullptr) + { + colorA.x = mark->color[0]; + colorA.y = mark->color[1]; + colorA.z = mark->color[2]; + } + else + { + colorA.x = prevMark->color[0]; + colorA.y = prevMark->color[1]; + colorA.z = prevMark->color[2]; + } + + colorB.x = mark->color[0]; + colorB.y = mark->color[1]; + colorB.z = mark->color[2]; + + colorAU32 = ImGui::ColorConvertFloat4ToU32(colorA); + colorBU32 = ImGui::ColorConvertFloat4ToU32(colorB); + + draw_list->AddTriangleFilled(ImVec2(to, bar_pos.y + (height - 6)), + ImVec2(to - 6, barBottom), + ImVec2(to + 6, barBottom), IM_COL32(100, 100, 100, 255)); + + draw_list->AddRectFilled(ImVec2(to - 6, barBottom), + ImVec2(to + 6, bar_pos.y + (height + 12)), + IM_COL32(100, 100, 100, 255), 1.0f, 1.0f); + + draw_list->AddRectFilled(ImVec2(to - 5, bar_pos.y + (height + 1)), + ImVec2(to + 5, bar_pos.y + (height + 11)), + IM_COL32(0, 0, 0, 255), 1.0f, 1.0f); + + if(selectedMark == mark) + { + draw_list->AddTriangleFilled(ImVec2(to, bar_pos.y + (height - 3)), + ImVec2(to - 4, barBottom + 1), + ImVec2(to + 4, barBottom + 1), IM_COL32(0, 255, 0, 255)); + + draw_list->AddRect(ImVec2(to - 5, bar_pos.y + (height + 1)), + ImVec2(to + 5, bar_pos.y + (height + 11)), + IM_COL32(0, 255, 0, 255), 1.0f, 1.0f); + } + + draw_list->AddRectFilledMultiColor(ImVec2(to - 3, bar_pos.y + (height + 3)), + ImVec2(to + 3, bar_pos.y + (height + 9)), + colorBU32, colorBU32, colorBU32, colorBU32); + + ImGui::SetCursorScreenPos(ImVec2(to - 6, barBottom)); + ImGui::InvisibleButton("mark", ImVec2(12, 12)); + + if(ImGui::IsItemHovered()) + { + if(ImGui::IsMouseClicked(0)) + { + selectedMark = mark; + draggingMark = mark; + } + } + + + prevMark = mark; + } + + ImGui::SetCursorScreenPos(ImVec2(bar_pos.x, bar_pos.y + height + 20.0f)); + } + + bool GradientButton(ImGradient* gradient) + { + if(!gradient) return false; + + ImVec2 widget_pos = ImGui::GetCursorScreenPos(); + // ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + float maxWidth = ImMax(250.0f, ImGui::GetContentRegionAvail().x - 100.0f); + bool clicked = ImGui::InvisibleButton("gradient_bar", ImVec2(maxWidth, GRADIENT_BAR_WIDGET_HEIGHT)); + + DrawGradientBar(gradient, widget_pos, maxWidth, GRADIENT_BAR_WIDGET_HEIGHT); + + return clicked; + } + + bool GradientEditor(ImGradient* gradient, + ImGradientMark* & draggingMark, + ImGradientMark* & selectedMark) + { + if(!gradient) return false; + + bool modified = false; + + ImVec2 bar_pos = ImGui::GetCursorScreenPos(); + bar_pos.x += 10; + float maxWidth = ImGui::GetContentRegionAvail().x - 20; + float barBottom = bar_pos.y + GRADIENT_BAR_EDITOR_HEIGHT; + + ImGui::InvisibleButton("gradient_editor_bar", ImVec2(maxWidth, GRADIENT_BAR_EDITOR_HEIGHT)); + + if(ImGui::IsItemHovered() && ImGui::IsMouseClicked(0)) + { + float pos = (ImGui::GetIO().MousePos.x - bar_pos.x) / maxWidth; + + float newMarkCol[4]; + gradient->getColorAt(pos, newMarkCol); + + + gradient->addMark(pos, ImColor(newMarkCol[0], newMarkCol[1], newMarkCol[2])); + } + + DrawGradientBar(gradient, bar_pos, maxWidth, GRADIENT_BAR_EDITOR_HEIGHT); + DrawGradientMarks(gradient, draggingMark, selectedMark, bar_pos, maxWidth, GRADIENT_BAR_EDITOR_HEIGHT); + + if(!ImGui::IsMouseDown(0) && draggingMark) + { + draggingMark = nullptr; + } + + if(ImGui::IsMouseDragging(0) && draggingMark) + { + float increment = ImGui::GetIO().MouseDelta.x / maxWidth; + bool insideZone = (ImGui::GetIO().MousePos.x > bar_pos.x) && + (ImGui::GetIO().MousePos.x < bar_pos.x + maxWidth); + + if(increment != 0.0f && insideZone) + { + draggingMark->position += increment; + draggingMark->position = ImClamp(draggingMark->position, 0.0f, 1.0f); + gradient->refreshCache(); + modified = true; + } + + float diffY = ImGui::GetIO().MousePos.y - barBottom; + + if(diffY >= GRADIENT_MARK_DELETE_DIFFY) + { + gradient->removeMark(draggingMark); + draggingMark = nullptr; + selectedMark = nullptr; + modified = true; + } + } + + if(!selectedMark && gradient->getMarks().size() > 0) + { + selectedMark = gradient->getMarks().front(); + } + + if(selectedMark) + { + bool colorModified = ImGui::ColorPicker3("", selectedMark->color); + + if(selectedMark && colorModified) + { + modified = true; + gradient->refreshCache(); + } + } + + return modified; + } +}; diff --git a/ext/imgui_color_gradient.h b/ext/imgui_color_gradient.h new file mode 100644 index 00000000..86e046b4 --- /dev/null +++ b/ext/imgui_color_gradient.h @@ -0,0 +1,86 @@ +// +// imgui_color_gradient.h +// imgui extension +// +// Created by David Gallardo on 11/06/16. + +/* + + Usage: + + ::GRADIENT DATA:: + ImGradient gradient; + + ::BUTTON:: + if(ImGui::GradientButton(&gradient)) + { + //set show editor flag to true/false + } + + ::EDITOR:: + static ImGradientMark* draggingMark = nullptr; + static ImGradientMark* selectedMark = nullptr; + + bool updated = ImGui::GradientEditor(&gradient, draggingMark, selectedMark); + + ::GET A COLOR:: + float color[3]; + gradient.getColorAt(0.3f, color); //position from 0 to 1 + + ::MODIFY GRADIENT WITH CODE:: + gradient.getMarks().clear(); + gradient.addMark(0.0f, ImColor(0.2f, 0.1f, 0.0f)); + gradient.addMark(0.7f, ImColor(120, 200, 255)); + + ::WOOD BROWNS PRESET:: + gradient.getMarks().clear(); + gradient.addMark(0.0f, ImColor(0xA0, 0x79, 0x3D)); + gradient.addMark(0.2f, ImColor(0xAA, 0x83, 0x47)); + gradient.addMark(0.3f, ImColor(0xB4, 0x8D, 0x51)); + gradient.addMark(0.4f, ImColor(0xBE, 0x97, 0x5B)); + gradient.addMark(0.6f, ImColor(0xC8, 0xA1, 0x65)); + gradient.addMark(0.7f, ImColor(0xD2, 0xAB, 0x6F)); + gradient.addMark(0.8f, ImColor(0xDC, 0xB5, 0x79)); + gradient.addMark(1.0f, ImColor(0xE6, 0xBF, 0x83)); + + */ + +#pragma once + +#include "imgui.h" + +#include + +struct ImGradientMark +{ + float color[4]; + float position; //0 to 1 +}; + +class ImGradient +{ +public: + ImGradient(); + ~ImGradient(); + + void getColorAt(float position, float* color) const; + void addMark(float position, ImColor const color); + void removeMark(ImGradientMark* mark); + void refreshCache(); + std::list & getMarks(){ return m_marks; } +private: + void computeColorAt(float position, float* color) const; + std::list m_marks; + float m_cachedValues[256 * 3]; +}; + +namespace ImGui +{ + bool GradientButton(ImGradient* gradient); + + bool GradientEditor(ImGradient* gradient, + ImGradientMark* & draggingMark, + ImGradientMark* & selectedMark); + + +} diff --git a/ext/imgui_impl_bgfx.cpp b/ext/imgui_impl_bgfx.cpp new file mode 100644 index 00000000..1250ec9e --- /dev/null +++ b/ext/imgui_impl_bgfx.cpp @@ -0,0 +1,1063 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include +#include + +#include +#include +#include "imgui_impl_bgfx.h" + +inline bool checkAvailTransientBuffers(uint32_t _numVertices, const bgfx::VertexDecl& _decl, uint32_t _numIndices) +{ + return _numVertices == bgfx::getAvailTransientVertexBuffer(_numVertices, _decl) + && (0 == _numIndices || _numIndices == bgfx::getAvailTransientIndexBuffer(_numIndices)) + ; +} + +static const uint8_t vs_ocornut_imgui_glsl[527] = +{ + 0x56, 0x53, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0xf2, 0xe1, 0x01, 0x00, 0x0b, 0x75, // VSH............u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, // _viewTexel...... + 0xea, 0x01, 0x00, 0x00, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x68, 0x69, // ....attribute hi + 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x61, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, // ghp vec4 a_color + 0x30, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x68, 0x69, 0x67, // 0;.attribute hig + 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, // hp vec3 a_positi + 0x6f, 0x6e, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x68, 0x69, // on;.attribute hi + 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, // ghp vec2 a_texco + 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x68, 0x69, // ord0;.varying hi + 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, // ghp vec4 v_color + 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, // 0;.varying highp + 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // vec2 v_texcoord + 0x30, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, // 0;.uniform highp + 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x54, 0x65, 0x78, 0x65, // vec4 u_viewTexe + 0x6c, 0x3b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, // l;.void main (). + 0x7b, 0x0a, 0x20, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, // {. highp vec2 t + 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // mpvar_1;. tmpva + 0x72, 0x5f, 0x31, 0x20, 0x3d, 0x20, 0x28, 0x28, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x61, 0x5f, // r_1 = ((2.0 * a_ + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x78, 0x79, 0x29, 0x20, 0x2a, 0x20, 0x75, // position.xy) * u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x2e, 0x78, 0x79, 0x29, 0x3b, 0x0a, // _viewTexel.xy);. + 0x20, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x74, 0x6d, 0x70, // highp vec4 tmp + 0x76, 0x61, 0x72, 0x5f, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, // var_2;. tmpvar_ + 0x32, 0x2e, 0x7a, 0x77, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x30, 0x2e, 0x30, 0x2c, // 2.zw = vec2(0.0, + 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, // 1.0);. tmpvar_ + 0x32, 0x2e, 0x78, 0x20, 0x3d, 0x20, 0x28, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, // 2.x = (tmpvar_1. + 0x78, 0x20, 0x2d, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, // x - 1.0);. tmpv + 0x61, 0x72, 0x5f, 0x32, 0x2e, 0x79, 0x20, 0x3d, 0x20, 0x28, 0x31, 0x2e, 0x30, 0x20, 0x2d, 0x20, // ar_2.y = (1.0 - + 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x79, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x67, // tmpvar_1.y);. g + 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x74, 0x6d, 0x70, // l_Position = tmp + 0x76, 0x61, 0x72, 0x5f, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, // var_2;. v_texco + 0x6f, 0x72, 0x64, 0x30, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, // ord0 = a_texcoor + 0x64, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x20, 0x3d, // d0;. v_color0 = + 0x20, 0x61, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, // a_color0;.}... +}; +static const uint8_t vs_ocornut_imgui_spv[1362] = +{ + 0x56, 0x53, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0xf2, 0xe1, 0x01, 0x00, 0x0b, 0x75, // VSH............u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, // _viewTexel...... + 0x24, 0x05, 0x00, 0x00, 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, // $.....#......... + 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, // ................ + 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, // ........GLSL.std + 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // .450............ + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, // ................ + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, // main....F...J... + 0x4e, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, // N...Y.......`... + 0x03, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, // ................ + 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, // ....main........ + 0x24, 0x00, 0x00, 0x00, 0x24, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x00, 0x06, 0x00, 0x06, 0x00, // $...$Global..... + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x54, 0x65, // $.......u_viewTe + 0x78, 0x65, 0x6c, 0x00, 0x05, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xel.....&....... + 0x05, 0x00, 0x05, 0x00, 0x46, 0x00, 0x00, 0x00, 0x61, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, // ....F...a_color0 + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x61, 0x5f, 0x70, 0x6f, // ........J...a_po + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x4e, 0x00, 0x00, 0x00, // sition......N... + 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x00, 0x05, 0x00, 0x0a, 0x00, // a_texcoord0..... + 0x59, 0x00, 0x00, 0x00, 0x40, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x4f, // Y...@entryPointO + 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, // utput.gl_Positio + 0x6e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x40, 0x65, 0x6e, 0x74, // n...........@ent + 0x72, 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x76, 0x5f, // ryPointOutput.v_ + 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x60, 0x00, 0x00, 0x00, // color0......`... + 0x40, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, // @entryPointOutpu + 0x74, 0x2e, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x00, 0x00, 0x00, // t.v_texcoord0... + 0x48, 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, // H...$.......#... + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // ....G...$....... + 0x47, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // G...&..."....... + 0x47, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // G...&...!....... + 0x47, 0x00, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // G...F........... + 0x47, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // G...J........... + 0x47, 0x00, 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // G...N........... + 0x47, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // G...Y........... + 0x47, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // G............... + 0x47, 0x00, 0x04, 0x00, 0x60, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // G...`........... + 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, // ........!....... + 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // ............ ... + 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, // ................ + 0x17, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // ................ + 0x17, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // ................ + 0x15, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // ........ ....... + 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, // +..............? + 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +............... + 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // +....... ......@ + 0x1e, 0x00, 0x03, 0x00, 0x24, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, // ....$....... ... + 0x25, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, // %.......$...;... + 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, // %...&.......+... + 0x16, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, // ....'....... ... + 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, // (........... ... + 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, // E...........;... + 0x45, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, // E...F....... ... + 0x49, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, // I...........;... + 0x49, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, // I...J....... ... + 0x4d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, // M...........;... + 0x4d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, // M...N....... ... + 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, // X...........;... + 0x58, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, // X...Y.......;... + 0x58, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, // X........... ... + 0x5f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, // _...........;... + 0x5f, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, // _...`........... + 0x06, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, // ........6....... + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, // ................ + 0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, // ....=.......G... + 0x46, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, // F...=.......K... + 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, // J...=.......O... + 0x4e, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, // N...O.......z... + 0x4b, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // K...K........... + 0x8e, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, // ........{...z... + 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, // ...A...(...|... + 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, // &...'...=....... + 0x7d, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x00, 0x00, // }...|...O....... + 0x7e, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ~...}...}....... + 0x01, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, // ................ + 0x7b, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, // {...~...Q....... + 0x81, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, // ................ + 0x06, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, // ................ + 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, // Q............... + 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, // ....P........... + 0x82, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, // ................ + 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, // ................ + 0x18, 0x00, 0x00, 0x00, 0x52, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, // ....R........... + 0x8e, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, // ............>... + 0x59, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x5c, 0x00, 0x00, 0x00, // Y.......>....... + 0x47, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, // G...>...`...O... + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x03, 0x05, 0x00, 0x01, 0x00, 0x10, 0x00, // ....8........... + 0x10, 0x00, // .. +}; +static const uint8_t vs_ocornut_imgui_dx9[365] = +{ + 0x56, 0x53, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0xf2, 0xe1, 0x01, 0x00, 0x0b, 0x75, // VSH............u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, // _viewTexel...... + 0x48, 0x01, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0xfe, 0xff, 0x20, 0x00, 0x43, 0x54, 0x41, 0x42, // H......... .CTAB + 0x1c, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, // ....S........... + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, // ........L...0... + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........<....... + 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x00, 0x01, 0x00, 0x03, 0x00, // u_viewTexel..... + 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x73, 0x5f, 0x33, // ............vs_3 + 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, // _0.Microsoft (R) + 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, // HLSL Shader Com + 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x00, 0xab, 0x51, 0x00, 0x00, 0x05, // piler 10.1..Q... + 0x01, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0x80, 0x3f, // .......@.......? + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, // ................ + 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, // ................ + 0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, // ................ + 0x00, 0x00, 0x0f, 0xe0, 0x1f, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0f, 0xe0, // ................ + 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x03, 0xe0, 0x05, 0x00, 0x00, 0x03, // ................ + 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0xe4, 0x90, 0x04, 0x00, 0x00, 0x04, // ................ + 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x55, 0xa0, // ..............U. + 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0x55, 0x80, 0x01, 0x00, 0x00, 0xa1, // ..........U..... + 0x01, 0x00, 0xaa, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0c, 0xe0, 0x01, 0x00, 0xb4, 0xa0, // ................ + 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0xe4, 0x90, 0x01, 0x00, 0x00, 0x02, // ................ + 0x02, 0x00, 0x03, 0xe0, 0x02, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00, 0x00, // ............. +}; +static const uint8_t vs_ocornut_imgui_dx11[618] = +{ + 0x56, 0x53, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0xf2, 0xe1, 0x01, 0x00, 0x0b, 0x75, // VSH............u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, // _viewTexel...... + 0x3c, 0x02, 0x00, 0x00, 0x44, 0x58, 0x42, 0x43, 0x22, 0x5c, 0xcc, 0x36, 0x58, 0xb2, 0x23, 0x45, // <...DXBC"..6X.#E + 0x8a, 0x2b, 0xbd, 0x13, 0xac, 0xf2, 0xa4, 0x09, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x00, // .+..........<... + 0x03, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, // ....,........... + 0x49, 0x53, 0x47, 0x4e, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // ISGNh........... + 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // P............... + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........V....... + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, // ................ + 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // _............... + 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x50, 0x4f, // ........COLOR.PO + 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, // SITION.TEXCOORD. + 0x4f, 0x53, 0x47, 0x4e, 0x6c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // OSGNl........... + 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // P............... + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, // ................ + 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // b............... + 0x02, 0x00, 0x00, 0x00, 0x03, 0x0c, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, // ........SV_POSIT + 0x49, 0x4f, 0x4e, 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, // ION.COLOR.TEXCOO + 0x52, 0x44, 0x00, 0xab, 0x53, 0x48, 0x44, 0x52, 0x24, 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, // RD..SHDR$...@... + 0x49, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x04, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, // I...Y...F. ..... + 0x01, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // ...._........... + 0x5f, 0x00, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, // _...2......._... + 0x32, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0xf2, 0x20, 0x10, 0x00, // 2.......g.... .. + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, // ........e.... .. + 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0x32, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, // ....e...2 ...... + 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x08, 0xc2, 0x20, 0x10, 0x00, // h.......6.... .. + 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .....@.......... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x38, 0x00, 0x00, 0x08, 0x32, 0x00, 0x10, 0x00, // .......?8...2... + 0x00, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x80, 0x20, 0x00, // ....F.......F. . + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x09, 0x12, 0x20, 0x10, 0x00, // ........2.... .. + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, // .............@.. + 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbf, 0x32, 0x00, 0x00, 0x0a, // ...@.@......2... + 0x22, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x10, 0x80, 0x41, 0x00, 0x00, 0x00, // " ..........A... + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x00, 0x00, // .....@.....@.@.. + 0x00, 0x00, 0x80, 0x3f, 0x36, 0x00, 0x00, 0x05, 0xf2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, // ...?6.... ...... + 0x46, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0x32, 0x20, 0x10, 0x00, // F.......6...2 .. + 0x02, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, // ....F.......>... + 0x00, 0x03, 0x05, 0x00, 0x01, 0x00, 0x10, 0x00, 0x10, 0x00, // .......... +}; +static const uint8_t vs_ocornut_imgui_mtl[889] = +{ + 0x56, 0x53, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0xf2, 0xe1, 0x01, 0x00, 0x0b, 0x75, // VSH............u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, // _viewTexel...... + 0x4b, 0x03, 0x00, 0x00, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x6d, 0x65, // K...#include .#inc + 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x73, 0x69, 0x6d, 0x64, 0x2f, 0x73, 0x69, 0x6d, 0x64, 0x2e, // lude ..using namesp + 0x61, 0x63, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, // ace metal;..stru + 0x63, 0x74, 0x20, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, // ct _Global.{. + 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x54, 0x65, // float4 u_viewTe + 0x78, 0x65, 0x6c, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, // xel;.};..struct + 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x0a, // xlatMtlMain_out. + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x5f, 0x65, 0x6e, // {. float4 _en + 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x76, // tryPointOutput_v + 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x20, 0x5b, 0x5b, 0x75, 0x73, 0x65, 0x72, 0x28, 0x6c, // _color0 [[user(l + 0x6f, 0x63, 0x6e, 0x30, 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, // ocn0)]];. flo + 0x61, 0x74, 0x32, 0x20, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x4f, // at2 _entryPointO + 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // utput_v_texcoord + 0x30, 0x20, 0x5b, 0x5b, 0x75, 0x73, 0x65, 0x72, 0x28, 0x6c, 0x6f, 0x63, 0x6e, 0x31, 0x29, 0x5d, // 0 [[user(locn1)] + 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x67, 0x6c, // ];. float4 gl + 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5b, 0x5b, 0x70, 0x6f, 0x73, 0x69, // _Position [[posi + 0x74, 0x69, 0x6f, 0x6e, 0x5d, 0x5d, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, // tion]];.};..stru + 0x63, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x69, // ct xlatMtlMain_i + 0x6e, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x61, // n.{. float4 a + 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x20, 0x5b, 0x5b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, // _color0 [[attrib + 0x75, 0x74, 0x65, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, // ute(0)]];. fl + 0x6f, 0x61, 0x74, 0x33, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, // oat3 a_position + 0x5b, 0x5b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x31, 0x29, 0x5d, 0x5d, // [[attribute(1)]] + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x61, 0x5f, 0x74, // ;. float2 a_t + 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x20, 0x5b, 0x5b, 0x61, 0x74, 0x74, 0x72, 0x69, // excoord0 [[attri + 0x62, 0x75, 0x74, 0x65, 0x28, 0x32, 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x76, // bute(2)]];.};..v + 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, // ertex xlatMtlMai + 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, // n_out xlatMtlMai + 0x6e, 0x28, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x6e, // n(xlatMtlMain_in + 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x5b, 0x73, 0x74, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x6e, 0x5d, 0x5d, // in [[stage_in]] + 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x20, 0x5f, 0x47, 0x6c, 0x6f, 0x62, // , constant _Glob + 0x61, 0x6c, 0x26, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x75, 0x20, 0x5b, 0x5b, 0x62, 0x75, 0x66, // al& _mtl_u [[buf + 0x66, 0x65, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, // fer(0)]]).{. + 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x20, // xlatMtlMain_out + 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, // out = {};. fl + 0x6f, 0x61, 0x74, 0x32, 0x20, 0x5f, 0x31, 0x32, 0x33, 0x20, 0x3d, 0x20, 0x28, 0x69, 0x6e, 0x2e, // oat2 _123 = (in. + 0x61, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x78, 0x79, 0x20, 0x2a, 0x20, // a_position.xy * + 0x32, 0x2e, 0x30, 0x29, 0x20, 0x2a, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x75, 0x2e, 0x75, 0x5f, // 2.0) * _mtl_u.u_ + 0x76, 0x69, 0x65, 0x77, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x2e, 0x78, 0x79, 0x3b, 0x0a, 0x20, 0x20, // viewTexel.xy;. + 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, // out.gl_Positio + 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x28, 0x5f, 0x31, 0x32, 0x33, 0x2e, // n = float4(_123. + 0x78, 0x20, 0x2d, 0x20, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x2d, 0x20, 0x5f, // x - 1.0, 1.0 - _ + 0x31, 0x32, 0x33, 0x2e, 0x79, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, // 123.y, 0.0, 1.0) + 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, // ;. out._entry + 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x76, 0x5f, 0x63, 0x6f, // PointOutput_v_co + 0x6c, 0x6f, 0x72, 0x30, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x2e, 0x61, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, // lor0 = in.a_colo + 0x72, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x5f, 0x65, 0x6e, 0x74, // r0;. out._ent + 0x72, 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x76, 0x5f, // ryPointOutput_v_ + 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x2e, 0x61, // texcoord0 = in.a + 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, // _texcoord0;. + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, // return out;.}... + 0x03, 0x05, 0x00, 0x01, 0x00, 0x10, 0x00, 0x10, 0x00, // ......... +}; +extern const uint8_t* vs_ocornut_imgui_pssl; +extern const uint32_t vs_ocornut_imgui_pssl_size; + +static const uint8_t fs_ocornut_imgui_glsl[242] = +{ + 0x46, 0x53, 0x48, 0x06, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x73, // FSH............s + 0x5f, 0x74, 0x65, 0x78, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x76, 0x61, // _tex..........va + 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, // rying highp vec4 + 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, // v_color0;.varyi + 0x6e, 0x67, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x76, 0x5f, // ng highp vec2 v_ + 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, // texcoord0;.unifo + 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, 0x73, 0x5f, 0x74, // rm sampler2D s_t + 0x65, 0x78, 0x3b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, // ex;.void main () + 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x77, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x74, // .{. lowp vec4 t + 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // mpvar_1;. tmpva + 0x72, 0x5f, 0x31, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x20, // r_1 = texture2D + 0x28, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x2c, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, // (s_tex, v_texcoo + 0x72, 0x64, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, // rd0);. gl_FragC + 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x28, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, // olor = (tmpvar_1 + 0x20, 0x2a, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x29, 0x3b, 0x0a, 0x7d, 0x0a, // * v_color0);.}. + 0x0a, 0x00, // .. +}; +static const uint8_t fs_ocornut_imgui_spv[834] = +{ + 0x46, 0x53, 0x48, 0x06, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x03, // FSH...........,. + 0x00, 0x00, 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x8b, 0x00, // ....#........... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, // ................ + 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, // ......GLSL.std.4 + 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, // 50.............. + 0x00, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, // ..............ma + 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x5c, 0x00, // in....M...Q..... + 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, // ................ + 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, // ................ + 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x22, 0x00, // ..main........". + 0x00, 0x00, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x00, 0x00, // ..s_texSampler.. + 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x54, // ......%...s_texT + 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x4d, 0x00, // exture........M. + 0x00, 0x00, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, // ..v_color0...... + 0x05, 0x00, 0x51, 0x00, 0x00, 0x00, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // ..Q...v_texcoord + 0x30, 0x00, 0x05, 0x00, 0x06, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62, 0x67, 0x66, 0x78, 0x5f, 0x46, // 0.........bgfx_F + 0x72, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x30, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x22, 0x00, // ragData0..G...". + 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x22, 0x00, // ..".......G...". + 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x25, 0x00, // ..!.......G...%. + 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x25, 0x00, // ..".......G...%. + 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x4d, 0x00, // ..!.......G...M. + 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x51, 0x00, // ..........G...Q. + 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x5c, 0x00, // ..........G..... + 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, // ................ + 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1a, 0x00, // ..!............. + 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, // .............. . + 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x07, 0x00, // ................ + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x07, 0x00, // ................ + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, // ...... ...!..... + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, // ......;...!...". + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, // ...... ...$..... + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, // ......;...$...%. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, 0x08, 0x00, // ..........1..... + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, // .. ...L......... + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x01, 0x00, // ..;...L...M..... + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, // .. ...P......... + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x01, 0x00, // ..;...P...Q..... + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, // .. ...[......... + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x03, 0x00, // ..;...[......... + 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ..6............. + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, // ..............=. + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, // ......#..."...=. + 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x3d, 0x00, // ......&...%...=. + 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x3d, 0x00, // ......N...M...=. + 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x56, 0x00, // ......R...Q...V. + 0x05, 0x00, 0x31, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x23, 0x00, // ..1.......&...#. + 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x88, 0x00, // ..W............. + 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x7c, 0x00, // ..R...........|. + 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x5c, 0x00, // ......N...>..... + 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00, // ..|.......8..... + 0x00, 0x00, // .. +}; +static const uint8_t fs_ocornut_imgui_dx9[235] = +{ + 0x46, 0x53, 0x48, 0x06, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x73, // FSH............s + 0x5f, 0x74, 0x65, 0x78, 0x30, 0x01, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x03, // _tex0........... + 0xff, 0xff, 0xfe, 0xff, 0x1f, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x4f, 0x00, // ......CTAB....O. + 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x91, // ................ + 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, // ..H...0......... + 0x02, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x00, // ..8.......s_tex. + 0xab, 0xab, 0x04, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x70, 0x73, 0x5f, 0x33, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, // ..ps_3_0.Microso + 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, // ft (R) HLSL Shad + 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2e, 0x31, // er Compiler 10.1 + 0x00, 0xab, 0x1f, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, // ................ + 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x03, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, // ................ + 0x00, 0x90, 0x00, 0x08, 0x0f, 0xa0, 0x42, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x01, 0x00, // ......B......... + 0xe4, 0x90, 0x00, 0x08, 0xe4, 0xa0, 0x05, 0x00, 0x00, 0x03, 0x00, 0x08, 0x0f, 0x80, 0x00, 0x00, // ................ + 0xe4, 0x80, 0x00, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00, 0x00, // ........... +}; +static const uint8_t fs_ocornut_imgui_dx11[402] = +{ + 0x46, 0x53, 0x48, 0x06, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x73, // FSH............s + 0x5f, 0x74, 0x65, 0x78, 0x30, 0x01, 0x00, 0x00, 0x01, 0x00, 0x70, 0x01, 0x00, 0x00, 0x44, 0x58, // _tex0.....p...DX + 0x42, 0x43, 0xbe, 0x78, 0xe7, 0xa5, 0x19, 0x0c, 0x70, 0xeb, 0x4c, 0xb1, 0xac, 0x1f, 0x16, 0x84, // BC.x....p.L..... + 0xe9, 0x97, 0x01, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2c, 0x00, // ......p.......,. + 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x4e, 0x6c, 0x00, // ..........ISGNl. + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // ..........P..... + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, // ................ + 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, // ................ + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, // ..........b..... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, // ................ + 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x43, 0x4f, // ..SV_POSITION.CO + 0x4c, 0x4f, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab, 0x4f, 0x53, // LOR.TEXCOORD..OS + 0x47, 0x4e, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, // GN,........... . + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x00, // ......SV_TARGET. + 0xab, 0xab, 0x53, 0x48, 0x44, 0x52, 0x94, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x25, 0x00, // ..SHDR....@...%. + 0x00, 0x00, 0x5a, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x18, // ..Z....`......X. + 0x00, 0x04, 0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, // ...p......UU..b. + 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, // ..........b...2. + 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, // ......e.... .... + 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xf2, 0x00, // ..h.......E..... + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7e, // ......F.......F~ + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, // .......`......8. + 0x00, 0x07, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, // ... ......F..... + 0x00, 0x00, 0x46, 0x1e, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, 0x00, 0x00, // ..F.......>..... + 0x00, 0x00, // .. +}; +static const uint8_t fs_ocornut_imgui_mtl[547] = +{ + 0x46, 0x53, 0x48, 0x06, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x02, // FSH............. + 0x00, 0x00, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x6d, 0x65, 0x74, 0x61, // ..#include .#inclu + 0x64, 0x65, 0x20, 0x3c, 0x73, 0x69, 0x6d, 0x64, 0x2f, 0x73, 0x69, 0x6d, 0x64, 0x2e, 0x68, 0x3e, // de + 0x0a, 0x0a, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, // ..using namespac + 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, // e metal;..struct + 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, // xlatMtlMain_out + 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x62, 0x67, // .{. float4 bg + 0x66, 0x78, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x30, 0x20, 0x5b, 0x5b, 0x63, // fx_FragData0 [[c + 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, // olor(0)]];.};..s + 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, // truct xlatMtlMai + 0x6e, 0x5f, 0x69, 0x6e, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, // n_in.{. float + 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x20, 0x5b, 0x5b, 0x75, 0x73, 0x65, // 4 v_color0 [[use + 0x72, 0x28, 0x6c, 0x6f, 0x63, 0x6e, 0x30, 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, // r(locn0)]];. + 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, // float2 v_texcoor + 0x64, 0x30, 0x20, 0x5b, 0x5b, 0x75, 0x73, 0x65, 0x72, 0x28, 0x6c, 0x6f, 0x63, 0x6e, 0x31, 0x29, // d0 [[user(locn1) + 0x5d, 0x5d, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, // ]];.};..fragment + 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, // xlatMtlMain_out + 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x28, 0x78, 0x6c, 0x61, // xlatMtlMain(xla + 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x5b, // tMtlMain_in in [ + 0x5b, 0x73, 0x74, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x6e, 0x5d, 0x5d, 0x2c, 0x20, 0x74, 0x65, 0x78, // [stage_in]], tex + 0x74, 0x75, 0x72, 0x65, 0x32, 0x64, 0x3c, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3e, 0x20, 0x73, 0x5f, // ture2d s_ + 0x74, 0x65, 0x78, 0x20, 0x5b, 0x5b, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x30, 0x29, // tex [[texture(0) + 0x5d, 0x5d, 0x2c, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x20, 0x73, 0x5f, 0x74, 0x65, // ]], sampler s_te + 0x78, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x20, 0x5b, 0x5b, 0x73, 0x61, 0x6d, 0x70, 0x6c, // xSampler [[sampl + 0x65, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x78, // er(0)]]).{. x + 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x20, 0x6f, // latMtlMain_out o + 0x75, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, // ut = {};. out + 0x2e, 0x62, 0x67, 0x66, 0x78, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x30, 0x20, // .bgfx_FragData0 + 0x3d, 0x20, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x28, 0x73, // = s_tex.sample(s + 0x5f, 0x74, 0x65, 0x78, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x6e, 0x2e, // _texSampler, in. + 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x29, 0x20, 0x2a, 0x20, 0x69, // v_texcoord0) * i + 0x6e, 0x2e, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, // n.v_color0;. + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, // return out;.}... + 0x00, 0x00, 0x00, // ... +}; +extern const uint8_t* fs_ocornut_imgui_pssl; +extern const uint32_t fs_ocornut_imgui_pssl_size; + +static const uint8_t vs_imgui_image_glsl[340] = +{ + 0x56, 0x53, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x1e, 0x3e, 0x3c, 0x01, 0x00, 0x0a, 0x75, // VSH.....o.><...u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x04, 0x01, 0x00, 0x00, 0x01, 0x00, 0x30, // _viewProj......0 + 0x01, 0x00, 0x00, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x68, 0x69, 0x67, // ...attribute hig + 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, // hp vec3 a_positi + 0x6f, 0x6e, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x68, 0x69, // on;.attribute hi + 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, // ghp vec2 a_texco + 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x68, 0x69, // ord0;.varying hi + 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, // ghp vec2 v_texco + 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x68, 0x69, // ord0;.uniform hi + 0x67, 0x68, 0x70, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, // ghp mat4 u_viewP + 0x72, 0x6f, 0x6a, 0x3b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, // roj;.void main ( + 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, // ).{. highp vec4 + 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, // tmpvar_1;. tmp + 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x7a, 0x77, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, // var_1.zw = vec2( + 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, // 0.0, 1.0);. tmp + 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x78, 0x79, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, // var_1.xy = a_pos + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x78, 0x79, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x50, // ition.xy;. gl_P + 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x28, 0x75, 0x5f, 0x76, 0x69, 0x65, // osition = (u_vie + 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x20, 0x2a, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, // wProj * tmpvar_1 + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, // );. v_texcoord0 + 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, // = a_texcoord0;. + 0x7d, 0x0a, 0x0a, 0x00, // }... +}; +static const uint8_t vs_imgui_image_spv[1131] = +{ + 0x56, 0x53, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x1e, 0x3e, 0x3c, 0x01, 0x00, 0x0a, 0x75, // VSH.....o.><...u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x04, 0x01, 0x00, 0x00, 0x04, 0x00, 0x40, // _viewProj......@ + 0x04, 0x00, 0x00, 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x84, // .....#.......... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, // ................ + 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, // .......GLSL.std. + 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // 450............. + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, // ...............m + 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x45, // ain....8...<...E + 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0xf4, // ...I............ + 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, // ...........main. + 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x24, 0x47, 0x6c, 0x6f, 0x62, // .......!...$Glob + 0x61, 0x6c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, // al.....!.......u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x23, // _viewProj......# + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00, 0x61, // ...........8...a + 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x3c, // _position......< + 0x00, 0x00, 0x00, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x00, 0x05, // ...a_texcoord0.. + 0x00, 0x0a, 0x00, 0x45, 0x00, 0x00, 0x00, 0x40, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, // ...E...@entryPoi + 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, // ntOutput.gl_Posi + 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x49, 0x00, 0x00, 0x00, 0x40, // tion.......I...@ + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, // entryPointOutput + 0x2e, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x00, 0x00, 0x00, 0x48, // .v_texcoord0...H + 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x48, // ...!...........H + 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, // ...!.......#.... + 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, // ...H...!........ + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x21, 0x00, 0x00, 0x00, 0x02, // .......G...!.... + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, // ...G...#...".... + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, // ...G...#...!.... + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, // ...G...8........ + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, // ...G...<........ + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x45, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, // ...G...E........ + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x49, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, // ...G...I........ + 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, // ...........!.... + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, // ............... + 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, // ................ + 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, // ................ + 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, // ................ + 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, // ........... .... + 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, // ...+............ + 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, // ...+............ + 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, // ...+............ + 0x00, 0x80, 0x3f, 0x18, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, // ..?.... ........ + 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, // .......!... ... + 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x3b, // ...".......!...; + 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, // ..."...#....... + 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, // ...$....... ... + 0x00, 0x04, 0x00, 0x37, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, // ...7...........; + 0x00, 0x04, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, // ...7...8....... + 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3b, // ...;...........; + 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, // ...;...<....... + 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, // ...D...........; + 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, // ...D...E....... + 0x00, 0x04, 0x00, 0x48, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3b, // ...H...........; + 0x00, 0x04, 0x00, 0x48, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x36, // ...H...I.......6 + 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // ................ + 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, // ...........=.... + 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, // ...9...8...=.... + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, // ...=...<...Q.... + 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, // ...a...9.......Q + 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x01, // .......b...9.... + 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x61, // ...P.......c...a + 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x41, // ...b...........A + 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x19, // ...$...d...#.... + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x64, // ...=... ...e...d + 0x00, 0x00, 0x00, 0x90, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x63, // ...........f...c + 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6b, // ...e...Q.......k + 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, // ...f............ + 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x52, 0x00, 0x06, 0x00, 0x0b, // ...l...k...R.... + 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x01, // .......l...f.... + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x45, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x3e, // ...>...E.......> + 0x00, 0x03, 0x00, 0x49, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, // ...I...=.......8 + 0x00, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x10, 0x00, 0x40, 0x00, // .........@. +}; +static const uint8_t vs_imgui_image_dx9[288] = +{ + 0x56, 0x53, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x1e, 0x3e, 0x3c, 0x01, 0x00, 0x0a, 0x75, // VSH.....o.><...u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x04, 0x01, 0x00, 0x00, 0x04, 0x00, 0xfc, // _viewProj....... + 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0xfe, 0xff, 0x20, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, // ......... .CTAB. + 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, // ...S............ + 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, // .......L...0.... + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, // .......<.......u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x00, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, // _viewProj....... + 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x73, 0x5f, 0x33, 0x5f, // ...........vs_3_ + 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, // 0.Microsoft (R) + 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, // HLSL Shader Comp + 0x69, 0x6c, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x00, 0xab, 0x1f, 0x00, 0x00, 0x02, 0x00, // iler 10.1....... + 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, // ................ + 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0xe0, 0x1f, // ................ + 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x03, 0xe0, 0x05, 0x00, 0x00, 0x03, 0x00, // ................ + 0x00, 0x0f, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x00, 0x00, 0x55, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, // .........U...... + 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0xa0, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0xe4, 0x80, 0x02, // ................ + 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, 0xe4, 0xa0, 0x01, // ................ + 0x00, 0x00, 0x02, 0x01, 0x00, 0x03, 0xe0, 0x01, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00, 0x00, // ................ +}; +static const uint8_t vs_imgui_image_dx11[479] = +{ + 0x56, 0x53, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x1e, 0x3e, 0x3c, 0x01, 0x00, 0x0a, 0x75, // VSH.....o.><...u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xb4, // _viewProj....... + 0x01, 0x00, 0x00, 0x44, 0x58, 0x42, 0x43, 0x62, 0x0c, 0x7d, 0x32, 0x98, 0x4b, 0xbb, 0x29, 0xce, // ...DXBCb.}2.K.). + 0xaa, 0xb2, 0xca, 0x5d, 0xc9, 0x55, 0xf0, 0x01, 0x00, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00, 0x03, // ...].U.......... + 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x49, // ...,...........I + 0x53, 0x47, 0x4e, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x38, // SGNL...........8 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .......A........ + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x50, // ...............P + 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, // OSITION.TEXCOORD + 0x00, 0xab, 0xab, 0x4f, 0x53, 0x47, 0x4e, 0x50, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, // ...OSGNP........ + 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, // ...8............ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, // ...........D.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, // ................ + 0x0c, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x54, // ...SV_POSITION.T + 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab, 0xab, 0xab, 0x53, 0x48, 0x44, 0x52, 0xd4, // EXCOORD....SHDR. + 0x00, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x35, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x04, 0x46, // ...@...5...Y...F + 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0x32, // . ........._...2 + 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x01, // ......._...2.... + 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ...g.... ....... + 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0x32, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, // ...e...2 ......h + 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, 0xf2, 0x00, 0x10, 0x00, 0x00, // .......8........ + 0x00, 0x00, 0x00, 0x56, 0x15, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, 0x00, // ...V.......F. .. + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, 0xf2, 0x00, 0x10, 0x00, 0x00, // .......2........ + 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, // ...F. .......... + 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .......F........ + 0x00, 0x00, 0x08, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, // .... ......F.... + 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x36, // ...F. .........6 + 0x00, 0x00, 0x05, 0x32, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, 0x01, // ...2 ......F.... + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, 0x00, 0x02, 0x01, 0x00, 0x10, 0x00, 0x40, 0x00, // ...>.........@. +}; +static const uint8_t vs_imgui_image_mtl[686] = +{ + 0x56, 0x53, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x1e, 0x3e, 0x3c, 0x01, 0x00, 0x0a, 0x75, // VSH.....o.><...u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x04, 0x01, 0x00, 0x00, 0x04, 0x00, 0x83, // _viewProj....... + 0x02, 0x00, 0x00, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x6d, 0x65, 0x74, // ...#include .#incl + 0x75, 0x64, 0x65, 0x20, 0x3c, 0x73, 0x69, 0x6d, 0x64, 0x2f, 0x73, 0x69, 0x6d, 0x64, 0x2e, 0x68, // ude ..using namespa + 0x63, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, // ce metal;..struc + 0x74, 0x20, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, // t _Global.{. + 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x78, 0x34, 0x20, 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, // float4x4 u_viewP + 0x72, 0x6f, 0x6a, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, // roj;.};..struct + 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x0a, // xlatMtlMain_out. + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x5f, 0x65, 0x6e, // {. float2 _en + 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x76, // tryPointOutput_v + 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x20, 0x5b, 0x5b, 0x75, 0x73, 0x65, // _texcoord0 [[use + 0x72, 0x28, 0x6c, 0x6f, 0x63, 0x6e, 0x30, 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, // r(locn0)]];. + 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, // float4 gl_Positi + 0x6f, 0x6e, 0x20, 0x5b, 0x5b, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5d, 0x5d, 0x3b, // on [[position]]; + 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, // .};..struct xlat + 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x6e, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, // MtlMain_in.{. + 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, // float3 a_positi + 0x6f, 0x6e, 0x20, 0x5b, 0x5b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x30, // on [[attribute(0 + 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, // )]];. float2 + 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x20, 0x5b, 0x5b, 0x61, 0x74, // a_texcoord0 [[at + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x28, 0x31, 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x7d, 0x3b, // tribute(1)]];.}; + 0x0a, 0x0a, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, // ..vertex xlatMtl + 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, // Main_out xlatMtl + 0x4d, 0x61, 0x69, 0x6e, 0x28, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, // Main(xlatMtlMain + 0x5f, 0x69, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x5b, 0x73, 0x74, 0x61, 0x67, 0x65, 0x5f, 0x69, // _in in [[stage_i + 0x6e, 0x5d, 0x5d, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x20, 0x5f, 0x47, // n]], constant _G + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x26, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x75, 0x20, 0x5b, 0x5b, // lobal& _mtl_u [[ + 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x29, 0x0a, 0x7b, 0x0a, 0x20, // buffer(0)]]).{. + 0x20, 0x20, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, // xlatMtlMain_o + 0x75, 0x74, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, // ut out = {};. + 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, // out.gl_Position + 0x20, 0x3d, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x75, 0x2e, 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, // = _mtl_u.u_view + 0x50, 0x72, 0x6f, 0x6a, 0x20, 0x2a, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x28, 0x69, 0x6e, // Proj * float4(in + 0x2e, 0x61, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x78, 0x79, 0x2c, 0x20, // .a_position.xy, + 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, // 0.0, 1.0);. o + 0x75, 0x74, 0x2e, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x4f, 0x75, // ut._entryPointOu + 0x74, 0x70, 0x75, 0x74, 0x5f, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, // tput_v_texcoord0 + 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x2e, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // = in.a_texcoord + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, // 0;. return ou + 0x74, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, 0x02, 0x01, 0x00, 0x10, 0x00, 0x40, 0x00, // t;.}........@. +}; +extern const uint8_t* vs_imgui_image_pssl; +extern const uint32_t vs_imgui_image_pssl_size; + +static const uint8_t fs_imgui_image_glsl[364] = +{ + 0x46, 0x53, 0x48, 0x06, 0x6f, 0x1e, 0x3e, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x11, 0x75, // FSH.o.><.......u + 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, // _imageLodEnabled + 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, // .......s_texColo + 0x72, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x30, 0x01, 0x00, 0x00, 0x76, 0x61, 0x72, 0x79, 0x69, // r......0...varyi + 0x6e, 0x67, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x76, 0x5f, // ng highp vec2 v_ + 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, // texcoord0;.unifo + 0x72, 0x6d, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x75, 0x5f, // rm highp vec4 u_ + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x3b, // imageLodEnabled; + 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, // .uniform sampler + 0x32, 0x44, 0x20, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, 0x76, // 2D s_texColor;.v + 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, // oid main ().{. + 0x6c, 0x6f, 0x77, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, // lowp vec4 tmpvar + 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x78, // _1;. tmpvar_1.x + 0x79, 0x7a, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x4c, 0x6f, // yz = texture2DLo + 0x64, 0x20, 0x20, 0x20, 0x20, 0x28, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, // d (s_texColor + 0x2c, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2c, 0x20, 0x75, // , v_texcoord0, u + 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, // _imageLodEnabled + 0x2e, 0x78, 0x29, 0x2e, 0x78, 0x79, 0x7a, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // .x).xyz;. tmpva + 0x72, 0x5f, 0x31, 0x2e, 0x77, 0x20, 0x3d, 0x20, 0x28, 0x30, 0x2e, 0x32, 0x20, 0x2b, 0x20, 0x28, // r_1.w = (0.2 + ( + 0x30, 0x2e, 0x38, 0x20, 0x2a, 0x20, 0x75, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, // 0.8 * u_imageLod + 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x79, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x67, // Enabled.y));. g + 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x6d, // l_FragColor = tm + 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, // pvar_1;.}... +}; +static const uint8_t fs_imgui_image_spv[1270] = +{ + 0x46, 0x53, 0x48, 0x06, 0x6f, 0x1e, 0x3e, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x75, // FSH.o.><.......u + 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, // _imageLodEnabled + 0x12, 0x01, 0x00, 0x00, 0x01, 0x00, 0xc8, 0x04, 0x00, 0x00, 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, // ............#... + 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, // ................ + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, // ..............GL + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, // SL.std.450...... + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, // ................ + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, // ......main....e. + 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, // ..n............. + 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x05, 0x00, // ................ + 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, // ......main...... + 0x07, 0x00, 0x22, 0x00, 0x00, 0x00, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, // .."...s_texColor + 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x25, 0x00, // Sampler.......%. + 0x00, 0x00, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x65, 0x78, 0x74, // ..s_texColorText + 0x75, 0x72, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00, 0x24, 0x47, // ure.......F...$G + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x00, 0x06, 0x00, 0x08, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, // lobal.....F..... + 0x00, 0x00, 0x75, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, 0x45, 0x6e, 0x61, 0x62, // ..u_imageLodEnab + 0x6c, 0x65, 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, // led.......H..... + 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x65, 0x00, 0x00, 0x00, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, // ......e...v_texc + 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x00, 0x05, 0x00, 0x06, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x62, 0x67, // oord0.....n...bg + 0x66, 0x78, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x30, 0x00, 0x00, 0x47, 0x00, // fx_FragData0..G. + 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, // .."...".......G. + 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, // .."...!.......G. + 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, // ..%...".......G. + 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, // ..%...!.......H. + 0x05, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, // ..F.......#..... + 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x46, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, // ..G...F.......G. + 0x04, 0x00, 0x48, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, // ..H...".......G. + 0x04, 0x00, 0x48, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, // ..H...!.......G. + 0x04, 0x00, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, // ..e...........G. + 0x04, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, // ..n............. + 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, // ......!......... + 0x00, 0x00, 0x1a, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x07, 0x00, // ................ + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, // .. ............. + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0b, 0x00, // ................ + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0e, 0x00, // ................ + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x21, 0x00, // .......... ...!. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x21, 0x00, // ..........;...!. + 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x24, 0x00, // .."....... ...$. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x24, 0x00, // ..........;...$. + 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x28, 0x00, // ..%...........(. + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, // .. .......+...(. + 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x31, 0x00, // ..-...........1. + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x46, 0x00, 0x00, 0x00, 0x0e, 0x00, // ..........F..... + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x47, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x00, // .. ...G.......F. + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x47, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, // ..;...G...H..... + 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, // ......N... ..... + 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, // ..+...N...O..... + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, // .. ...P......... + 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0xcd, 0xcc, // ..+.......V..... + 0x4c, 0x3e, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0xcd, 0xcc, // L>+.......W..... + 0x4c, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x01, 0x00, // L?+...N...X..... + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, // .. ...d......... + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, // ..;...d...e..... + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0e, 0x00, // .. ...m......... + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x03, 0x00, // ..;...m...n..... + 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ..6............. + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, // ..............=. + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, // ......#..."...=. + 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x3d, 0x00, // ......&...%...=. + 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x41, 0x00, // ......f...e...A. + 0x06, 0x00, 0x50, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x2d, 0x00, // ..P.......H...-. + 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8d, 0x00, // ..O...=......... + 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x56, 0x00, 0x05, 0x00, 0x31, 0x00, 0x00, 0x00, 0xa5, 0x00, // ......V...1..... + 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x58, 0x00, 0x07, 0x00, 0x0e, 0x00, // ..&...#...X..... + 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x02, 0x00, // ..........f..... + 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x50, 0x00, 0x00, 0x00, 0x90, 0x00, // ......A...P..... + 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3d, 0x00, // ..H...-...X...=. + 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x85, 0x00, // ................ + 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x91, 0x00, // ..........W..... + 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x56, 0x00, // ..............V. + 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x96, 0x00, // ......Q......... + 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x07, 0x00, // ..........Q..... + 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, // ..............Q. + 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x02, 0x00, // ................ + 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x96, 0x00, // ..P............. + 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x3e, 0x00, // ..............>. + 0x03, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, // ..n...........8. + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, // ...... +}; +static const uint8_t fs_imgui_image_dx9[392] = +{ + 0x46, 0x53, 0x48, 0x06, 0x6f, 0x1e, 0x3e, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0a, 0x73, // FSH.o.><.......s + 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x01, 0x00, 0x00, 0x01, 0x00, 0x11, // _texColor0...... + 0x75, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, // u_imageLodEnable + 0x64, 0x12, 0x01, 0x00, 0x00, 0x01, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xfe, // d......L........ + 0xff, 0x2e, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, // ...CTAB......... + 0x03, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x84, // ................ + 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x50, // ...D...........P + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, // .......`........ + 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x5f, 0x74, 0x65, 0x78, // ...t.......s_tex + 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0xab, 0x04, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, // Color........... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, // .......u_imageLo + 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x00, 0xab, 0xab, 0x01, 0x00, 0x03, 0x00, 0x01, // dEnabled........ + 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x73, 0x5f, 0x33, 0x5f, // ...........ps_3_ + 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, // 0.Microsoft (R) + 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, // HLSL Shader Comp + 0x69, 0x6c, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x00, 0xab, 0x51, 0x00, 0x00, 0x05, 0x01, // iler 10.1..Q.... + 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0x4c, 0x3f, 0xcd, // ......?......L?. + 0xcc, 0x4c, 0x3e, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x03, 0x90, 0x1f, // .L>............. + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x00, 0x08, 0x0f, 0xa0, 0x05, 0x00, 0x00, 0x03, 0x00, // ................ + 0x00, 0x07, 0x80, 0x01, 0x00, 0xd0, 0xa0, 0x00, 0x00, 0xc4, 0x90, 0x01, 0x00, 0x00, 0x02, 0x00, // ................ + 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0xa0, 0x5f, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x00, // ......._........ + 0x00, 0xe4, 0x80, 0x00, 0x08, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x07, 0x80, 0x00, // ................ + 0x00, 0xe4, 0x80, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x04, // ................ + 0x00, 0x00, 0x04, 0x00, 0x08, 0x08, 0x80, 0x00, 0x00, 0x55, 0xa0, 0x00, 0x00, 0xaa, 0x80, 0x00, // .........U...... + 0x00, 0xff, 0x80, 0xff, 0xff, 0x00, 0x00, 0x00, // ........ +}; +static const uint8_t fs_imgui_image_dx11[451] = +{ + 0x46, 0x53, 0x48, 0x06, 0x6f, 0x1e, 0x3e, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x11, 0x75, // FSH.o.><.......u + 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, // _imageLodEnabled + 0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, // .......s_texColo + 0x72, 0x30, 0x01, 0x00, 0x00, 0x01, 0x00, 0x84, 0x01, 0x00, 0x00, 0x44, 0x58, 0x42, 0x43, 0x60, // r0.........DXBC` + 0x83, 0xa2, 0x5c, 0x77, 0x3d, 0xcc, 0x9b, 0xb9, 0x73, 0xdf, 0x41, 0x6b, 0x18, 0x8f, 0x0e, 0x01, // ...w=...s.Ak.... + 0x00, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x84, // ...........,.... + 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x4e, 0x50, 0x00, 0x00, 0x00, 0x02, // .......ISGNP.... + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // .......8........ + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x44, // ...............D + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, // ................ + 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, // .......SV_POSITI + 0x4f, 0x4e, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab, 0xab, 0xab, 0x4f, // ON.TEXCOORD....O + 0x53, 0x47, 0x4e, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, // SGN,........... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, // .......SV_TARGET + 0x00, 0xab, 0xab, 0x53, 0x48, 0x44, 0x52, 0xc4, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x31, // ...SHDR....@...1 + 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x04, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ...Y...F. ...... + 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, // ...Z....`......X + 0x18, 0x00, 0x04, 0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, // ....p......UU..b + 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, // ...2.......e.... + 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x48, // ......h.......H + 0x00, 0x00, 0x0c, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, 0x01, // ...........F.... + 0x00, 0x00, 0x00, 0x46, 0x7e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, // ...F~.......`... + 0x00, 0x00, 0x00, 0x0a, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, // ..... .........6 + 0x00, 0x00, 0x05, 0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, // ...r ......F.... + 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, 0x82, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, // ...2.... ....... + 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0xcd, // . ..........@... + 0xcc, 0x4c, 0x3f, 0x01, 0x40, 0x00, 0x00, 0xcd, 0xcc, 0x4c, 0x3e, 0x3e, 0x00, 0x00, 0x01, 0x00, // .L?.@....L>>.... + 0x00, 0x10, 0x00, // ... +}; +static const uint8_t fs_imgui_image_mtl[768] = +{ + 0x46, 0x53, 0x48, 0x06, 0x6f, 0x1e, 0x3e, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x75, // FSH.o.><.......u + 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, // _imageLodEnabled + 0x12, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd2, 0x02, 0x00, 0x00, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, // ..........#inclu + 0x64, 0x65, 0x20, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x64, 0x6c, 0x69, 0x62, // de .#include ..using + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x3b, // namespace metal; + 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, // ..struct _Global + 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x75, 0x5f, // .{. float4 u_ + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x3b, // imageLodEnabled; + 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, // .};..struct xlat + 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x0a, 0x7b, 0x0a, 0x20, 0x20, // MtlMain_out.{. + 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x62, 0x67, 0x66, 0x78, 0x5f, 0x46, 0x72, // float4 bgfx_Fr + 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x30, 0x20, 0x5b, 0x5b, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x28, // agData0 [[color( + 0x30, 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, // 0)]];.};..struct + 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x6e, 0x0a, // xlatMtlMain_in. + 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x76, 0x5f, 0x74, // {. float2 v_t + 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x20, 0x5b, 0x5b, 0x75, 0x73, 0x65, 0x72, 0x28, // excoord0 [[user( + 0x6c, 0x6f, 0x63, 0x6e, 0x30, 0x29, 0x5d, 0x5d, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x66, 0x72, // locn0)]];.};..fr + 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, // agment xlatMtlMa + 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, // in_out xlatMtlMa + 0x69, 0x6e, 0x28, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x5f, 0x69, // in(xlatMtlMain_i + 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x5b, 0x73, 0x74, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x6e, 0x5d, // n in [[stage_in] + 0x5d, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x20, 0x5f, 0x47, 0x6c, 0x6f, // ], constant _Glo + 0x62, 0x61, 0x6c, 0x26, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x75, 0x20, 0x5b, 0x5b, 0x62, 0x75, // bal& _mtl_u [[bu + 0x66, 0x66, 0x65, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, // ffer(0)]], textu + 0x72, 0x65, 0x32, 0x64, 0x3c, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3e, 0x20, 0x73, 0x5f, 0x74, 0x65, // re2d s_te + 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x5b, 0x5b, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, // xColor [[texture + 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x2c, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x20, 0x73, // (0)]], sampler s + 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, // _texColorSampler + 0x20, 0x5b, 0x5b, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x29, // [[sampler(0)]]) + 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, // .{. xlatMtlMa + 0x69, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x3b, // in_out out = {}; + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x62, 0x67, 0x66, 0x78, 0x5f, 0x46, 0x72, // . out.bgfx_Fr + 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x30, 0x20, 0x3d, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, // agData0 = float4 + 0x28, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2e, 0x73, 0x61, 0x6d, 0x70, // (s_texColor.samp + 0x6c, 0x65, 0x28, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x53, 0x61, 0x6d, // le(s_texColorSam + 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x6e, 0x2e, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, // pler, in.v_texco + 0x6f, 0x72, 0x64, 0x30, 0x2c, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x28, 0x5f, 0x6d, 0x74, 0x6c, // ord0, level(_mtl + 0x5f, 0x75, 0x2e, 0x75, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, 0x45, 0x6e, 0x61, // _u.u_imageLodEna + 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x78, 0x29, 0x29, 0x2e, 0x78, 0x79, 0x7a, 0x2c, 0x20, 0x30, 0x2e, // bled.x)).xyz, 0. + 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x32, 0x39, 0x38, 0x30, 0x32, 0x33, 0x32, 0x32, // 2000000029802322 + 0x33, 0x38, 0x37, 0x36, 0x39, 0x35, 0x33, 0x31, 0x32, 0x35, 0x20, 0x2b, 0x20, 0x28, 0x30, 0x2e, // 3876953125 + (0. + 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x39, 0x32, 0x30, 0x39, 0x32, 0x38, 0x39, // 8000000119209289 + 0x35, 0x35, 0x30, 0x37, 0x38, 0x31, 0x32, 0x35, 0x20, 0x2a, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, // 55078125 * _mtl_ + 0x75, 0x2e, 0x75, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x6f, 0x64, 0x45, 0x6e, 0x61, 0x62, // u.u_imageLodEnab + 0x6c, 0x65, 0x64, 0x2e, 0x79, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, // led.y));. ret + 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, 0x00, 0x10, 0x00, // urn out;.}...... +}; +extern const uint8_t* fs_imgui_image_pssl; +extern const uint32_t fs_imgui_image_pssl_size; + + +static const bgfx::EmbeddedShader s_embeddedShaders[] = +{ + BGFX_EMBEDDED_SHADER(vs_ocornut_imgui), + BGFX_EMBEDDED_SHADER(fs_ocornut_imgui), + BGFX_EMBEDDED_SHADER(vs_imgui_image), + BGFX_EMBEDDED_SHADER(fs_imgui_image), + + BGFX_EMBEDDED_SHADER_END() +}; + +bgfx::VertexDecl m_decl; +bgfx::ProgramHandle m_program; +bgfx::ProgramHandle m_imageProgram; +bgfx::TextureHandle m_texture; +bgfx::UniformHandle s_tex; +bgfx::UniformHandle u_imageLodEnabled; + +void ImGui_Implbgfx_Init() +{ + bgfx::RendererType::Enum type = bgfx::getRendererType(); + m_program = bgfx::createProgram( + bgfx::createEmbeddedShader(s_embeddedShaders, type, "vs_ocornut_imgui") + , bgfx::createEmbeddedShader(s_embeddedShaders, type, "fs_ocornut_imgui") + , true + ); + + u_imageLodEnabled = bgfx::createUniform("u_imageLodEnabled", bgfx::UniformType::Vec4); + m_imageProgram = bgfx::createProgram( + bgfx::createEmbeddedShader(s_embeddedShaders, type, "vs_imgui_image") + , bgfx::createEmbeddedShader(s_embeddedShaders, type, "fs_imgui_image") + , true + ); + + m_decl + .begin() + .add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float) + .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) + .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) + .end(); + + s_tex = bgfx::createUniform("s_tex", bgfx::UniformType::Sampler); +} + +void ImGui_Implbgfx_Shutdown() +{ + bgfx::destroy(s_tex); + bgfx::destroy(m_texture); + + bgfx::destroy(u_imageLodEnabled); + bgfx::destroy(m_imageProgram); + bgfx::destroy(m_program); +} + +void ImGui_Implbgfx_CreateDeviceObjects() +{ + uint8_t* data; + int32_t width; + int32_t height; + const ImGuiIO& io = ImGui::GetIO(); + + io.Fonts->GetTexDataAsRGBA32(&data, &width, &height); + + m_texture = bgfx::createTexture2D( + (uint16_t)width + , (uint16_t)height + , false + , 1 + , bgfx::TextureFormat::BGRA8 + , 0 + , bgfx::copy(data, width * height * 4) + ); +} + +bool font_built = false; +void ImGui_Implbgfx_NewFrame() +{ + if (!font_built) + { + ImGui_Implbgfx_CreateDeviceObjects(); + font_built = true; + } +} + +void ImGui_Implbgfx_RenderDrawData(bgfx::ViewId viewId, ImDrawData* _drawData) +{ + const ImGuiIO& io = ImGui::GetIO(); + const float width = io.DisplaySize.x; + const float height = io.DisplaySize.y; + + + bgfx::setViewName(viewId, "ImGui"); + bgfx::setViewMode(viewId, bgfx::ViewMode::Sequential); + + const bgfx::Caps* caps = bgfx::getCaps(); + { + float ortho[16]; + bx::mtxOrtho(ortho, 0.0f, width, height, 0.0f, 0.0f, 1000.0f, 0.0f, caps->homogeneousDepth); + bgfx::setViewTransform(viewId, NULL, ortho); + bgfx::setViewRect(viewId, 0, 0, uint16_t(width), uint16_t(height) ); + } + + // Render command lists + for (int32_t ii = 0, num = _drawData->CmdListsCount; ii < num; ++ii) + { + bgfx::TransientVertexBuffer tvb; + bgfx::TransientIndexBuffer tib; + + const ImDrawList* drawList = _drawData->CmdLists[ii]; + uint32_t numVertices = (uint32_t)drawList->VtxBuffer.size(); + uint32_t numIndices = (uint32_t)drawList->IdxBuffer.size(); + + if (!checkAvailTransientBuffers(numVertices, m_decl, numIndices) ) + { + // not enough space in transient buffer just quit drawing the rest... + break; + } + + bgfx::allocTransientVertexBuffer(&tvb, numVertices, m_decl); + bgfx::allocTransientIndexBuffer(&tib, numIndices); + + ImDrawVert* verts = (ImDrawVert*)tvb.data; + bx::memCopy(verts, drawList->VtxBuffer.begin(), numVertices * sizeof(ImDrawVert) ); + + ImDrawIdx* indices = (ImDrawIdx*)tib.data; + bx::memCopy(indices, drawList->IdxBuffer.begin(), numIndices * sizeof(ImDrawIdx) ); + + uint32_t offset = 0; + for (const ImDrawCmd* cmd = drawList->CmdBuffer.begin(), *cmdEnd = drawList->CmdBuffer.end(); cmd != cmdEnd; ++cmd) + { + if (cmd->UserCallback) + { + cmd->UserCallback(drawList, cmd); + } + else if (0 != cmd->ElemCount) + { + uint64_t state = 0 + | BGFX_STATE_WRITE_RGB + | BGFX_STATE_WRITE_A + | BGFX_STATE_MSAA + ; + + bgfx::TextureHandle th = m_texture; + bgfx::ProgramHandle program = m_program; + + if (NULL != cmd->TextureId) + { + union { ImTextureID ptr; struct { bgfx::TextureHandle handle; uint8_t flags; uint8_t mip; } s; } texture = { cmd->TextureId }; + /*state |= 0 != (IMGUI_FLAGS_ALPHA_BLEND & texture.s.flags) + ? BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) + : BGFX_STATE_NONE + ;*/ + th = texture.s.handle; + if (0 != texture.s.mip) + { + const float lodEnabled[4] = { float(texture.s.mip), 1.0f, 0.0f, 0.0f }; + bgfx::setUniform(u_imageLodEnabled, lodEnabled); + program = m_imageProgram; + } + } + state |= BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA); + + const uint16_t xx = uint16_t(bx::max(cmd->ClipRect.x, 0.0f) ); + const uint16_t yy = uint16_t(bx::max(cmd->ClipRect.y, 0.0f) ); + bgfx::setScissor(xx, yy + , uint16_t(bx::min(cmd->ClipRect.z, 65535.0f)-xx) + , uint16_t(bx::min(cmd->ClipRect.w, 65535.0f)-yy) + ); + + bgfx::setState(state); + bgfx::setTexture(0, s_tex, th); + bgfx::setVertexBuffer(0, &tvb, 0, numVertices); + bgfx::setIndexBuffer(&tib, offset, cmd->ElemCount); + assert(program.idx); + bgfx::submit(viewId, program); + } + + offset += cmd->ElemCount; + } + } +} diff --git a/ext/imgui_impl_bgfx.h b/ext/imgui_impl_bgfx.h new file mode 100644 index 00000000..76e9380c --- /dev/null +++ b/ext/imgui_impl_bgfx.h @@ -0,0 +1,36 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once + +struct ImDrawData; + +#define IMGUI_FLAGS_NONE UINT8_C(0x00) +#define IMGUI_FLAGS_ALPHA_BLEND UINT8_C(0x01) + +void ImGui_Implbgfx_Init(); +void ImGui_Implbgfx_Shutdown(); +void ImGui_Implbgfx_RenderDrawData(bgfx::ViewId viewId, ImDrawData* _drawData); +void ImGui_Implbgfx_NewFrame(); diff --git a/ext/imgui_impl_opengl3.cpp b/ext/imgui_impl_opengl3.cpp deleted file mode 100644 index 21fd2573..00000000 --- a/ext/imgui_impl_opengl3.cpp +++ /dev/null @@ -1,653 +0,0 @@ -// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline -// - Desktop GL: 3.x 4.x -// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) -// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) - -// Implemented features: -// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. -// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. - -// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. -// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. -// https://github.com/ocornut/imgui - -// CHANGELOG -// (minor and older changes stripped away, please see git history for details) -// 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. -// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop. -// 2019-03-15: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early. -// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0). -// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader. -// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display. -// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450). -// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. -// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN. -// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used. -// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES". -// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation. -// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link. -// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples. -// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. -// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state. -// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer. -// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150". -// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context. -// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself. -// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150. -// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode. -// 2017-05-01: OpenGL: Fixed save and restore of current blend func state. -// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE. -// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle. -// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752) - -//---------------------------------------- -// OpenGL GLSL GLSL -// version version string -//---------------------------------------- -// 2.0 110 "#version 110" -// 2.1 120 "#version 120" -// 3.0 130 "#version 130" -// 3.1 140 "#version 140" -// 3.2 150 "#version 150" -// 3.3 330 "#version 330 core" -// 4.0 400 "#version 400 core" -// 4.1 410 "#version 410 core" -// 4.2 420 "#version 410 core" -// 4.3 430 "#version 430 core" -// ES 2.0 100 "#version 100" = WebGL 1.0 -// ES 3.0 300 "#version 300 es" = WebGL 2.0 -//---------------------------------------- - -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif - -#include "imgui.h" -#include "imgui_impl_opengl3.h" -#include -#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier -#include // intptr_t -#else -#include // intptr_t -#endif -#if defined(__APPLE__) -#include "TargetConditionals.h" -#endif - -// Auto-detect GL version -#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) -#if (defined(__APPLE__) && TARGET_OS_IOS) || (defined(__ANDROID__)) -#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es" -#elif defined(__EMSCRIPTEN__) -#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100" -#endif -#endif - -#if defined(IMGUI_IMPL_OPENGL_ES2) -#include -#elif defined(IMGUI_IMPL_OPENGL_ES3) -#include // Use GL ES 3 -#else -// About Desktop OpenGL function loaders: -// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. -// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). -// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. -#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) -#include // Needs to be initialized with gl3wInit() in user's code -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) -#include // Needs to be initialized with glewInit() in user's code -#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) -#include // Needs to be initialized with gladLoadGL() in user's code -#else -#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM -#endif -#endif - -// OpenGL Data -static char g_GlslVersionString[32] = ""; -static GLuint g_FontTexture = 0; -static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; -static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location -static int g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location -static unsigned int g_VboHandle = 0, g_ElementsHandle = 0; - -// Forward Declarations -static void ImGui_ImplOpenGL3_InitPlatformInterface(); -static void ImGui_ImplOpenGL3_ShutdownPlatformInterface(); - -// Functions -bool ImGui_ImplOpenGL3_Init(const char* glsl_version) -{ - // Setup back-end capabilities flags - ImGuiIO& io = ImGui::GetIO(); - io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) - io.BackendRendererName = "imgui_impl_opengl3"; - - // Store GLSL version string so we can refer to it later in case we recreate shaders. Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure. -#if defined(IMGUI_IMPL_OPENGL_ES2) - if (glsl_version == NULL) - glsl_version = "#version 100"; -#elif defined(IMGUI_IMPL_OPENGL_ES3) - if (glsl_version == NULL) - glsl_version = "#version 300 es"; -#else - if (glsl_version == NULL) - glsl_version = "#version 130"; -#endif - IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString)); - strcpy(g_GlslVersionString, glsl_version); - strcat(g_GlslVersionString, "\n"); - - // Make a dummy GL call (we don't actually need the result) - // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code. - // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above. - GLint current_texture; - glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); - - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - ImGui_ImplOpenGL3_InitPlatformInterface(); - - return true; -} - -void ImGui_ImplOpenGL3_Shutdown() -{ - ImGui_ImplOpenGL3_ShutdownPlatformInterface(); - ImGui_ImplOpenGL3_DestroyDeviceObjects(); -} - -void ImGui_ImplOpenGL3_NewFrame() -{ - if (!g_FontTexture) - ImGui_ImplOpenGL3_CreateDeviceObjects(); -} - -static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) -{ - // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); -#ifdef GL_POLYGON_MODE - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -#endif - - // Setup viewport, orthographic projection matrix - // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is (0,0) for single viewport apps. - glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); - float L = draw_data->DisplayPos.x; - float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; - float T = draw_data->DisplayPos.y; - float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; - const float ortho_projection[4][4] = - { - { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, - { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, - { 0.0f, 0.0f, -1.0f, 0.0f }, - { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, - }; - glUseProgram(g_ShaderHandle); - glUniform1i(g_AttribLocationTex, 0); - glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); -#ifdef GL_SAMPLER_BINDING - glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. -#endif - - (void)vertex_array_object; -#ifndef IMGUI_IMPL_OPENGL_ES2 - glBindVertexArray(vertex_array_object); -#endif - - // Bind vertex/index buffers and setup attributes for ImDrawVert - glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); - glEnableVertexAttribArray(g_AttribLocationVtxPos); - glEnableVertexAttribArray(g_AttribLocationVtxUV); - glEnableVertexAttribArray(g_AttribLocationVtxColor); - glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); - glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); - glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); -} - -// OpenGL3 Render function. -// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) -// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. -void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) -{ - // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if (fb_width <= 0 || fb_height <= 0) - return; - - // Backup GL state - GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture); - glActiveTexture(GL_TEXTURE0); - GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); - GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); -#ifdef GL_SAMPLER_BINDING - GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler); -#endif - GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); -#ifndef IMGUI_IMPL_OPENGL_ES2 - GLint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object); -#endif -#ifdef GL_POLYGON_MODE - GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); -#endif - GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); - GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); - GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb); - GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb); - GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha); - GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha); - GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb); - GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha); - GLboolean last_enable_blend = glIsEnabled(GL_BLEND); - GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); - GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); - GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - bool clip_origin_lower_left = true; -#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) - GLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT) - if (last_clip_origin == GL_UPPER_LEFT) - clip_origin_lower_left = false; -#endif - - // Setup desired GL state - // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts) - // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound. - GLuint vertex_array_object = 0; -#ifndef IMGUI_IMPL_OPENGL_ES2 - glGenVertexArrays(1, &vertex_array_object); -#endif - ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); - - // Will project scissor/clipping rectangles into framebuffer space - ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) - - // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - size_t idx_buffer_offset = 0; - - // Upload vertex/index buffers - glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); - - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != NULL) - { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); - else - pcmd->UserCallback(cmd_list, pcmd); - } - else - { - // Project scissor/clipping rectangles into framebuffer space - ImVec4 clip_rect; - clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; - clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; - clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; - clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; - - if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) - { - // Apply scissor/clipping rectangle - if (clip_origin_lower_left) - glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); - else - glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) - - // Bind texture, Draw - glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); - glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)idx_buffer_offset); - } - } - idx_buffer_offset += pcmd->ElemCount * sizeof(ImDrawIdx); - } - } - - // Destroy the temporary VAO -#ifndef IMGUI_IMPL_OPENGL_ES2 - glDeleteVertexArrays(1, &vertex_array_object); -#endif - - // Restore modified GL state - glUseProgram(last_program); - glBindTexture(GL_TEXTURE_2D, last_texture); -#ifdef GL_SAMPLER_BINDING - glBindSampler(0, last_sampler); -#endif - glActiveTexture(last_active_texture); -#ifndef IMGUI_IMPL_OPENGL_ES2 - glBindVertexArray(last_vertex_array_object); -#endif - glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); - glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); - glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); - if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); - if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); - if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); - if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); -#ifdef GL_POLYGON_MODE - glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); -#endif - glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); - glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); -} - -bool ImGui_ImplOpenGL3_CreateFontsTexture() -{ - // Build texture atlas - ImGuiIO& io = ImGui::GetIO(); - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. - - // Upload texture to graphics system - GLint last_texture; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); - glGenTextures(1, &g_FontTexture); - glBindTexture(GL_TEXTURE_2D, g_FontTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -#ifdef GL_UNPACK_ROW_LENGTH - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); -#endif - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - // Store our identifier - io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture; - - // Restore state - glBindTexture(GL_TEXTURE_2D, last_texture); - - return true; -} - -void ImGui_ImplOpenGL3_DestroyFontsTexture() -{ - if (g_FontTexture) - { - ImGuiIO& io = ImGui::GetIO(); - glDeleteTextures(1, &g_FontTexture); - io.Fonts->TexID = 0; - g_FontTexture = 0; - } -} - -// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file. -static bool CheckShader(GLuint handle, const char* desc) -{ - GLint status = 0, log_length = 0; - glGetShaderiv(handle, GL_COMPILE_STATUS, &status); - glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length); - if ((GLboolean)status == GL_FALSE) - fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc); - if (log_length > 0) - { - ImVector buf; - buf.resize((int)(log_length + 1)); - glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); - fprintf(stderr, "%s\n", buf.begin()); - } - return (GLboolean)status == GL_TRUE; -} - -// If you get an error please report on GitHub. You may try different GL context version or GLSL version. -static bool CheckProgram(GLuint handle, const char* desc) -{ - GLint status = 0, log_length = 0; - glGetProgramiv(handle, GL_LINK_STATUS, &status); - glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length); - if ((GLboolean)status == GL_FALSE) - fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString); - if (log_length > 0) - { - ImVector buf; - buf.resize((int)(log_length + 1)); - glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); - fprintf(stderr, "%s\n", buf.begin()); - } - return (GLboolean)status == GL_TRUE; -} - -bool ImGui_ImplOpenGL3_CreateDeviceObjects() -{ - // Backup GL state - GLint last_texture, last_array_buffer; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); - glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); -#ifndef IMGUI_IMPL_OPENGL_ES2 - GLint last_vertex_array; - glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); -#endif - - // Parse GLSL version string - int glsl_version = 130; - sscanf(g_GlslVersionString, "#version %d", &glsl_version); - - const GLchar* vertex_shader_glsl_120 = - "uniform mat4 ProjMtx;\n" - "attribute vec2 Position;\n" - "attribute vec2 UV;\n" - "attribute vec4 Color;\n" - "varying vec2 Frag_UV;\n" - "varying vec4 Frag_Color;\n" - "void main()\n" - "{\n" - " Frag_UV = UV;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" - "}\n"; - - const GLchar* vertex_shader_glsl_130 = - "uniform mat4 ProjMtx;\n" - "in vec2 Position;\n" - "in vec2 UV;\n" - "in vec4 Color;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main()\n" - "{\n" - " Frag_UV = UV;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" - "}\n"; - - const GLchar* vertex_shader_glsl_300_es = - "precision mediump float;\n" - "layout (location = 0) in vec2 Position;\n" - "layout (location = 1) in vec2 UV;\n" - "layout (location = 2) in vec4 Color;\n" - "uniform mat4 ProjMtx;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main()\n" - "{\n" - " Frag_UV = UV;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" - "}\n"; - - const GLchar* vertex_shader_glsl_410_core = - "layout (location = 0) in vec2 Position;\n" - "layout (location = 1) in vec2 UV;\n" - "layout (location = 2) in vec4 Color;\n" - "uniform mat4 ProjMtx;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main()\n" - "{\n" - " Frag_UV = UV;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" - "}\n"; - - const GLchar* fragment_shader_glsl_120 = - "#ifdef GL_ES\n" - " precision mediump float;\n" - "#endif\n" - "uniform sampler2D Texture;\n" - "varying vec2 Frag_UV;\n" - "varying vec4 Frag_Color;\n" - "void main()\n" - "{\n" - " gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n" - "}\n"; - - const GLchar* fragment_shader_glsl_130 = - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "out vec4 Out_Color;\n" - "void main()\n" - "{\n" - " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" - "}\n"; - - const GLchar* fragment_shader_glsl_300_es = - "precision mediump float;\n" - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "layout (location = 0) out vec4 Out_Color;\n" - "void main()\n" - "{\n" - " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" - "}\n"; - - const GLchar* fragment_shader_glsl_410_core = - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "uniform sampler2D Texture;\n" - "layout (location = 0) out vec4 Out_Color;\n" - "void main()\n" - "{\n" - " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" - "}\n"; - - // Select shaders matching our GLSL versions - const GLchar* vertex_shader = NULL; - const GLchar* fragment_shader = NULL; - if (glsl_version < 130) - { - vertex_shader = vertex_shader_glsl_120; - fragment_shader = fragment_shader_glsl_120; - } - else if (glsl_version >= 410) - { - vertex_shader = vertex_shader_glsl_410_core; - fragment_shader = fragment_shader_glsl_410_core; - } - else if (glsl_version == 300) - { - vertex_shader = vertex_shader_glsl_300_es; - fragment_shader = fragment_shader_glsl_300_es; - } - else - { - vertex_shader = vertex_shader_glsl_130; - fragment_shader = fragment_shader_glsl_130; - } - - // Create shaders - const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader }; - g_VertHandle = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL); - glCompileShader(g_VertHandle); - CheckShader(g_VertHandle, "vertex shader"); - - const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader }; - g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL); - glCompileShader(g_FragHandle); - CheckShader(g_FragHandle, "fragment shader"); - - g_ShaderHandle = glCreateProgram(); - glAttachShader(g_ShaderHandle, g_VertHandle); - glAttachShader(g_ShaderHandle, g_FragHandle); - glLinkProgram(g_ShaderHandle); - CheckProgram(g_ShaderHandle, "shader program"); - - g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); - g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); - g_AttribLocationVtxPos = glGetAttribLocation(g_ShaderHandle, "Position"); - g_AttribLocationVtxUV = glGetAttribLocation(g_ShaderHandle, "UV"); - g_AttribLocationVtxColor = glGetAttribLocation(g_ShaderHandle, "Color"); - - // Create buffers - glGenBuffers(1, &g_VboHandle); - glGenBuffers(1, &g_ElementsHandle); - - ImGui_ImplOpenGL3_CreateFontsTexture(); - - // Restore modified GL state - glBindTexture(GL_TEXTURE_2D, last_texture); - glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); -#ifndef IMGUI_IMPL_OPENGL_ES2 - glBindVertexArray(last_vertex_array); -#endif - - return true; -} - -void ImGui_ImplOpenGL3_DestroyDeviceObjects() -{ - if (g_VboHandle) glDeleteBuffers(1, &g_VboHandle); - if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle); - g_VboHandle = g_ElementsHandle = 0; - - if (g_ShaderHandle && g_VertHandle) glDetachShader(g_ShaderHandle, g_VertHandle); - if (g_VertHandle) glDeleteShader(g_VertHandle); - g_VertHandle = 0; - - if (g_ShaderHandle && g_FragHandle) glDetachShader(g_ShaderHandle, g_FragHandle); - if (g_FragHandle) glDeleteShader(g_FragHandle); - g_FragHandle = 0; - - if (g_ShaderHandle) glDeleteProgram(g_ShaderHandle); - g_ShaderHandle = 0; - - ImGui_ImplOpenGL3_DestroyFontsTexture(); -} - -//-------------------------------------------------------------------------------------------------------- -// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT -// This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously. -// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. -//-------------------------------------------------------------------------------------------------------- - -static void ImGui_ImplOpenGL3_RenderWindow(ImGuiViewport* viewport, void*) -{ - if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) - { - ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); - glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); - glClear(GL_COLOR_BUFFER_BIT); - } - ImGui_ImplOpenGL3_RenderDrawData(viewport->DrawData); -} - -static void ImGui_ImplOpenGL3_InitPlatformInterface() -{ - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL3_RenderWindow; -} - -static void ImGui_ImplOpenGL3_ShutdownPlatformInterface() -{ - ImGui::DestroyPlatformWindows(); -} diff --git a/ext/imgui_impl_opengl3.h b/ext/imgui_impl_opengl3.h deleted file mode 100644 index e4484301..00000000 --- a/ext/imgui_impl_opengl3.h +++ /dev/null @@ -1,47 +0,0 @@ -// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline -// - Desktop GL: 3.x 4.x -// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) -// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) - -// Implemented features: -// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. -// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. - -// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. -// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. -// https://github.com/ocornut/imgui - -// About Desktop OpenGL function loaders: -// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. -// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). -// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. - -// About GLSL version: -// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string. -// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es" -// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. - -#pragma once - -// Specific OpenGL versions -//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten -//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android - -// Set default OpenGL3 loader to be gl3w -#if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \ - && !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \ - && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \ - && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) -#define IMGUI_IMPL_OPENGL_LOADER_GL3W -#endif - -IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL); -IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); -IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); -IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); - -// Called by Init/NewFrame/Shutdown -IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); -IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); -IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); diff --git a/ext/imgui_impl_sdl.cpp b/ext/imgui_impl_sdl.cpp index 7df4ad10..d921a09b 100644 --- a/ext/imgui_impl_sdl.cpp +++ b/ext/imgui_impl_sdl.cpp @@ -47,8 +47,8 @@ // SDL // (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended) -#include -#include +#include +#include #if defined(__APPLE__) #include "TargetConditionals.h" #endif @@ -577,7 +577,7 @@ static void ImGui_ImplSDL2_SwapBuffers(ImGuiViewport* viewport, void*) // Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface) // SDL is graceful enough to _not_ need so we can safely include this. #if SDL_HAS_VULKAN -#include +#include static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface) { ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData; diff --git a/ext/stb_image.h b/ext/stb_image.h deleted file mode 100644 index a056138d..00000000 --- a/ext/stb_image.h +++ /dev/null @@ -1,7187 +0,0 @@ -/* stb_image - v2.16 - public domain image loader - http://nothings.org/stb_image.h - no warranty implied; use at your own risk - - Do this: - #define STB_IMAGE_IMPLEMENTATION - before you include this file in *one* C or C++ file to create the implementation. - - // i.e. it should look like this: - #include ... - #include ... - #include ... - #define STB_IMAGE_IMPLEMENTATION - #include "stb_image.h" - - You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. - And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free - - - QUICK NOTES: - Primarily of interest to game developers and other people who can - avoid problematic images and only need the trivial interface - - JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) - PNG 1/2/4/8/16-bit-per-channel - - TGA (not sure what subset, if a subset) - BMP non-1bpp, non-RLE - PSD (composited view only, no extra channels, 8/16 bit-per-channel) - - GIF (*comp always reports as 4-channel) - HDR (radiance rgbE format) - PIC (Softimage PIC) - PNM (PPM and PGM binary only) - - Animated GIF still needs a proper API, but here's one way to do it: - http://gist.github.com/urraka/685d9a6340b26b830d49 - - - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - - decode from arbitrary I/O callbacks - - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) - - Full documentation under "DOCUMENTATION" below. - - -LICENSE - - See end of file for license information. - -RECENT REVISION HISTORY: - - 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes - 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 - RGB-format JPEG; remove white matting in PSD; - allocate large structures on the stack; - correct channel count for PNG & BMP - 2.10 (2016-01-22) avoid warning introduced in 2.09 - 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED - - See end of file for full revision history. - - - ============================ Contributors ========================= - - Image formats Extensions, features - Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) - Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) - Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) - Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) - Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) - Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) - Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) - github:urraka (animated gif) Junggon Kim (PNM comments) - Daniel Gibson (16-bit TGA) - socks-the-fox (16-bit PNG) - Jeremy Sawicki (handle all ImageNet JPGs) - Optimizations & bugfixes - Fabian "ryg" Giesen - Arseny Kapoulkine - John-Mark Allen - - Bug & warning fixes - Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan - Dave Moore Roy Eltham Hayaki Saito Nathan Reed - Won Chun Luke Graham Johan Duparc Nick Verigakis - the Horde3D community Thomas Ruf Ronny Chevalier Baldur Karlsson - Janez Zemva John Bartholomew Michal Cichon github:rlyeh - Jonathan Blow Ken Hamada Tero Hanninen github:romigrou - Laurent Gomila Cort Stratton Sergio Gonzalez github:svdijk - Aruelien Pocheville Thibault Reuille Cass Everitt github:snagar - Ryamond Barbiero Paul Du Bois Engin Manap github:Zelex - Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210 - Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw - Blazej Dariusz Roszkowski Gregory Mullen github:phprus - Christian Floisand Kevin Schmidt github:poppolopoppo -*/ - -#ifndef STBI_INCLUDE_STB_IMAGE_H -#define STBI_INCLUDE_STB_IMAGE_H - -// DOCUMENTATION -// -// Limitations: -// - no 16-bit-per-channel PNG -// - no 12-bit-per-channel JPEG -// - no JPEGs with arithmetic coding -// - no 1-bit BMP -// - GIF always returns *comp=4 -// -// Basic usage (see HDR discussion below for HDR usage): -// int x,y,n; -// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); -// // ... process data if not NULL ... -// // ... x = width, y = height, n = # 8-bit components per pixel ... -// // ... replace '0' with '1'..'4' to force that many components per pixel -// // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) -// -// Standard parameters: -// int *x -- outputs image width in pixels -// int *y -- outputs image height in pixels -// int *channels_in_file -- outputs # of image components in image file -// int desired_channels -- if non-zero, # of image components requested in result -// -// The return value from an image loader is an 'unsigned char *' which points -// to the pixel data, or NULL on an allocation failure or if the image is -// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, -// with each pixel consisting of N interleaved 8-bit components; the first -// pixel pointed to is top-left-most in the image. There is no padding between -// image scanlines or between pixels, regardless of format. The number of -// components N is 'desired_channels' if desired_channels is non-zero, or -// *channels_in_file otherwise. If desired_channels is non-zero, -// *channels_in_file has the number of components that _would_ have been -// output otherwise. E.g. if you set desired_channels to 4, you will always -// get RGBA output, but you can check *channels_in_file to see if it's trivially -// opaque because e.g. there were only 3 channels in the source image. -// -// An output image with N components has the following components interleaved -// in this order in each pixel: -// -// N=#comp components -// 1 grey -// 2 grey, alpha -// 3 red, green, blue -// 4 red, green, blue, alpha -// -// If image loading fails for any reason, the return value will be NULL, -// and *x, *y, *channels_in_file will be unchanged. The function -// stbi_failure_reason() can be queried for an extremely brief, end-user -// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS -// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly -// more user-friendly ones. -// -// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. -// -// =========================================================================== -// -// Philosophy -// -// stb libraries are designed with the following priorities: -// -// 1. easy to use -// 2. easy to maintain -// 3. good performance -// -// Sometimes I let "good performance" creep up in priority over "easy to maintain", -// and for best performance I may provide less-easy-to-use APIs that give higher -// performance, in addition to the easy to use ones. Nevertheless, it's important -// to keep in mind that from the standpoint of you, a client of this library, -// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. -// -// Some secondary priorities arise directly from the first two, some of which -// make more explicit reasons why performance can't be emphasized. -// -// - Portable ("ease of use") -// - Small source code footprint ("easy to maintain") -// - No dependencies ("ease of use") -// -// =========================================================================== -// -// I/O callbacks -// -// I/O callbacks allow you to read from arbitrary sources, like packaged -// files or some other source. Data read from callbacks are processed -// through a small internal buffer (currently 128 bytes) to try to reduce -// overhead. -// -// The three functions you must define are "read" (reads some bytes of data), -// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). -// -// =========================================================================== -// -// SIMD support -// -// The JPEG decoder will try to automatically use SIMD kernels on x86 when -// supported by the compiler. For ARM Neon support, you must explicitly -// request it. -// -// (The old do-it-yourself SIMD API is no longer supported in the current -// code.) -// -// On x86, SSE2 will automatically be used when available based on a run-time -// test; if not, the generic C versions are used as a fall-back. On ARM targets, -// the typical path is to have separate builds for NEON and non-NEON devices -// (at least this is true for iOS and Android). Therefore, the NEON support is -// toggled by a build flag: define STBI_NEON to get NEON loops. -// -// If for some reason you do not want to use any of SIMD code, or if -// you have issues compiling it, you can disable it entirely by -// defining STBI_NO_SIMD. -// -// =========================================================================== -// -// HDR image support (disable by defining STBI_NO_HDR) -// -// stb_image now supports loading HDR images in general, and currently -// the Radiance .HDR file format, although the support is provided -// generically. You can still load any file through the existing interface; -// if you attempt to load an HDR file, it will be automatically remapped to -// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; -// both of these constants can be reconfigured through this interface: -// -// stbi_hdr_to_ldr_gamma(2.2f); -// stbi_hdr_to_ldr_scale(1.0f); -// -// (note, do not use _inverse_ constants; stbi_image will invert them -// appropriately). -// -// Additionally, there is a new, parallel interface for loading files as -// (linear) floats to preserve the full dynamic range: -// -// float *data = stbi_loadf(filename, &x, &y, &n, 0); -// -// If you load LDR images through this interface, those images will -// be promoted to floating point values, run through the inverse of -// constants corresponding to the above: -// -// stbi_ldr_to_hdr_scale(1.0f); -// stbi_ldr_to_hdr_gamma(2.2f); -// -// Finally, given a filename (or an open file or memory block--see header -// file for details) containing image data, you can query for the "most -// appropriate" interface to use (that is, whether the image is HDR or -// not), using: -// -// stbi_is_hdr(char *filename); -// -// =========================================================================== -// -// iPhone PNG support: -// -// By default we convert iphone-formatted PNGs back to RGB, even though -// they are internally encoded differently. You can disable this conversion -// by by calling stbi_convert_iphone_png_to_rgb(0), in which case -// you will always just get the native iphone "format" through (which -// is BGR stored in RGB). -// -// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per -// pixel to remove any premultiplied alpha *only* if the image file explicitly -// says there's premultiplied data (currently only happens in iPhone images, -// and only if iPhone convert-to-rgb processing is on). -// -// =========================================================================== -// -// ADDITIONAL CONFIGURATION -// -// - You can suppress implementation of any of the decoders to reduce -// your code footprint by #defining one or more of the following -// symbols before creating the implementation. -// -// STBI_NO_JPEG -// STBI_NO_PNG -// STBI_NO_BMP -// STBI_NO_PSD -// STBI_NO_TGA -// STBI_NO_GIF -// STBI_NO_HDR -// STBI_NO_PIC -// STBI_NO_PNM (.ppm and .pgm) -// -// - You can request *only* certain decoders and suppress all other ones -// (this will be more forward-compatible, as addition of new decoders -// doesn't require you to disable them explicitly): -// -// STBI_ONLY_JPEG -// STBI_ONLY_PNG -// STBI_ONLY_BMP -// STBI_ONLY_PSD -// STBI_ONLY_TGA -// STBI_ONLY_GIF -// STBI_ONLY_HDR -// STBI_ONLY_PIC -// STBI_ONLY_PNM (.ppm and .pgm) -// -// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still -// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB -// - - -#ifndef STBI_NO_STDIO -#include -#endif // STBI_NO_STDIO - -#define STBI_VERSION 1 - -enum -{ - STBI_default = 0, // only used for desired_channels - - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4 -}; - -typedef unsigned char stbi_uc; -typedef unsigned short stbi_us; - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef STB_IMAGE_STATIC -#define STBIDEF static -#else -#define STBIDEF extern -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// PRIMARY API - works on images of any type -// - -// -// load image by filename, open file, or memory buffer -// - -typedef struct -{ - int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read - void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative - int (*eof) (void *user); // returns nonzero if we are at end of file/data -} stbi_io_callbacks; - -//////////////////////////////////// -// -// 8-bits-per-channel interface -// - -STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); - -#ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); -// for stbi_load_from_file, file pointer is left pointing immediately after image -#endif - -//////////////////////////////////// -// -// 16-bits-per-channel interface -// - -STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); - -#ifndef STBI_NO_STDIO -STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); -#endif - -//////////////////////////////////// -// -// float-per-channel interface -// -#ifndef STBI_NO_LINEAR - STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); - - #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); - #endif -#endif - -#ifndef STBI_NO_HDR - STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); - STBIDEF void stbi_hdr_to_ldr_scale(float scale); -#endif // STBI_NO_HDR - -#ifndef STBI_NO_LINEAR - STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); - STBIDEF void stbi_ldr_to_hdr_scale(float scale); -#endif // STBI_NO_LINEAR - -// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); -#ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename); -STBIDEF int stbi_is_hdr_from_file(FILE *f); -#endif // STBI_NO_STDIO - - -// get a VERY brief reason for failure -// NOT THREADSAFE -STBIDEF const char *stbi_failure_reason (void); - -// free the loaded image -- this is just free() -STBIDEF void stbi_image_free (void *retval_from_stbi_load); - -// get image dimensions & components without fully decoding -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); - -#endif - - - -// for image formats that explicitly notate that they have premultiplied alpha, -// we just return the colors as stored in the file. set this flag to force -// unpremultiplication. results are undefined if the unpremultiply overflow. -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); - -// indicate whether we should process iphone images back to canonical format, -// or just pass them through "as-is" -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); - -// flip the image vertically, so the first pixel in the output array is the bottom left -STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); - -// ZLIB client - used by PNG, available for other purposes - -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); -STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - -STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - - -#ifdef __cplusplus -} -#endif - -// -// -//// end header file ///////////////////////////////////////////////////// -#endif // STBI_INCLUDE_STB_IMAGE_H - -#ifdef STB_IMAGE_IMPLEMENTATION - -#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ - || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ - || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ - || defined(STBI_ONLY_ZLIB) - #ifndef STBI_ONLY_JPEG - #define STBI_NO_JPEG - #endif - #ifndef STBI_ONLY_PNG - #define STBI_NO_PNG - #endif - #ifndef STBI_ONLY_BMP - #define STBI_NO_BMP - #endif - #ifndef STBI_ONLY_PSD - #define STBI_NO_PSD - #endif - #ifndef STBI_ONLY_TGA - #define STBI_NO_TGA - #endif - #ifndef STBI_ONLY_GIF - #define STBI_NO_GIF - #endif - #ifndef STBI_ONLY_HDR - #define STBI_NO_HDR - #endif - #ifndef STBI_ONLY_PIC - #define STBI_NO_PIC - #endif - #ifndef STBI_ONLY_PNM - #define STBI_NO_PNM - #endif -#endif - -#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) -#define STBI_NO_ZLIB -#endif - - -#include -#include // ptrdiff_t on osx -#include -#include -#include - -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -#include // ldexp -#endif - -#ifndef STBI_NO_STDIO -#include -#endif - -#ifndef STBI_ASSERT -#include -#define STBI_ASSERT(x) assert(x) -#endif - - -#ifndef _MSC_VER - #ifdef __cplusplus - #define stbi_inline inline - #else - #define stbi_inline - #endif -#else - #define stbi_inline __forceinline -#endif - - -#ifdef _MSC_VER -typedef unsigned short stbi__uint16; -typedef signed short stbi__int16; -typedef unsigned int stbi__uint32; -typedef signed int stbi__int32; -#else -#include -typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; -typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; -#endif - -// should produce compiler error if size is wrong -typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; - -#ifdef _MSC_VER -#define STBI_NOTUSED(v) (void)(v) -#else -#define STBI_NOTUSED(v) (void)sizeof(v) -#endif - -#ifdef _MSC_VER -#define STBI_HAS_LROTL -#endif - -#ifdef STBI_HAS_LROTL - #define stbi_lrot(x,y) _lrotl(x,y) -#else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) -#endif - -#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) -// ok -#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) -// ok -#else -#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." -#endif - -#ifndef STBI_MALLOC -#define STBI_MALLOC(sz) malloc(sz) -#define STBI_REALLOC(p,newsz) realloc(p,newsz) -#define STBI_FREE(p) free(p) -#endif - -#ifndef STBI_REALLOC_SIZED -#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) -#endif - -// x86/x64 detection -#if defined(__x86_64__) || defined(_M_X64) -#define STBI__X64_TARGET -#elif defined(__i386) || defined(_M_IX86) -#define STBI__X86_TARGET -#endif - -#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) -// gcc doesn't support sse2 intrinsics unless you compile with -msse2, -// which in turn means it gets to use SSE2 everywhere. This is unfortunate, -// but previous attempts to provide the SSE2 functions with runtime -// detection caused numerous issues. The way architecture extensions are -// exposed in GCC/Clang is, sadly, not really suited for one-file libs. -// New behavior: if compiled with -msse2, we use SSE2 without any -// detection; if not, we don't use it at all. -#define STBI_NO_SIMD -#endif - -#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) -// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET -// -// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the -// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. -// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not -// simultaneously enabling "-mstackrealign". -// -// See https://github.com/nothings/stb/issues/81 for more information. -// -// So default to no SSE2 on 32-bit MinGW. If you've read this far and added -// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. -#define STBI_NO_SIMD -#endif - -#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) -#define STBI_SSE2 -#include - -#ifdef _MSC_VER - -#if _MSC_VER >= 1400 // not VC6 -#include // __cpuid -static int stbi__cpuid3(void) -{ - int info[4]; - __cpuid(info,1); - return info[3]; -} -#else -static int stbi__cpuid3(void) -{ - int res; - __asm { - mov eax,1 - cpuid - mov res,edx - } - return res; -} -#endif - -#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name - -static int stbi__sse2_available(void) -{ - int info3 = stbi__cpuid3(); - return ((info3 >> 26) & 1) != 0; -} -#else // assume GCC-style if not VC++ -#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) - -static int stbi__sse2_available(void) -{ - // If we're even attempting to compile this on GCC/Clang, that means - // -msse2 is on, which means the compiler is allowed to use SSE2 - // instructions at will, and so are we. - return 1; -} -#endif -#endif - -// ARM NEON -#if defined(STBI_NO_SIMD) && defined(STBI_NEON) -#undef STBI_NEON -#endif - -#ifdef STBI_NEON -#include -// assume GCC or Clang on ARM targets -#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) -#endif - -#ifndef STBI_SIMD_ALIGN -#define STBI_SIMD_ALIGN(type, name) type name -#endif - -/////////////////////////////////////////////// -// -// stbi__context struct and start_xxx functions - -// stbi__context structure is our basic context used by all images, so it -// contains all the IO context, plus some basic image information -typedef struct -{ - stbi__uint32 img_x, img_y; - int img_n, img_out_n; - - stbi_io_callbacks io; - void *io_user_data; - - int read_from_callbacks; - int buflen; - stbi_uc buffer_start[128]; - - stbi_uc *img_buffer, *img_buffer_end; - stbi_uc *img_buffer_original, *img_buffer_original_end; -} stbi__context; - - -static void stbi__refill_buffer(stbi__context *s); - -// initialize a memory-decode context -static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) -{ - s->io.read = NULL; - s->read_from_callbacks = 0; - s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; - s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; -} - -// initialize a callback-based context -static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) -{ - s->io = *c; - s->io_user_data = user; - s->buflen = sizeof(s->buffer_start); - s->read_from_callbacks = 1; - s->img_buffer_original = s->buffer_start; - stbi__refill_buffer(s); - s->img_buffer_original_end = s->img_buffer_end; -} - -#ifndef STBI_NO_STDIO - -static int stbi__stdio_read(void *user, char *data, int size) -{ - return (int) fread(data,1,size,(FILE*) user); -} - -static void stbi__stdio_skip(void *user, int n) -{ - fseek((FILE*) user, n, SEEK_CUR); -} - -static int stbi__stdio_eof(void *user) -{ - return feof((FILE*) user); -} - -static stbi_io_callbacks stbi__stdio_callbacks = -{ - stbi__stdio_read, - stbi__stdio_skip, - stbi__stdio_eof, -}; - -static void stbi__start_file(stbi__context *s, FILE *f) -{ - stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); -} - -//static void stop_file(stbi__context *s) { } - -#endif // !STBI_NO_STDIO - -static void stbi__rewind(stbi__context *s) -{ - // conceptually rewind SHOULD rewind to the beginning of the stream, - // but we just rewind to the beginning of the initial buffer, because - // we only use it after doing 'test', which only ever looks at at most 92 bytes - s->img_buffer = s->img_buffer_original; - s->img_buffer_end = s->img_buffer_original_end; -} - -enum -{ - STBI_ORDER_RGB, - STBI_ORDER_BGR -}; - -typedef struct -{ - int bits_per_channel; - int num_channels; - int channel_order; -} stbi__result_info; - -#ifndef STBI_NO_JPEG -static int stbi__jpeg_test(stbi__context *s); -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PNG -static int stbi__png_test(stbi__context *s); -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_BMP -static int stbi__bmp_test(stbi__context *s); -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_TGA -static int stbi__tga_test(stbi__context *s); -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s); -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_HDR -static int stbi__hdr_test(stbi__context *s); -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PIC -static int stbi__pic_test(stbi__context *s); -static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_GIF -static int stbi__gif_test(stbi__context *s); -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s); -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -// this is not threadsafe -static const char *stbi__g_failure_reason; - -STBIDEF const char *stbi_failure_reason(void) -{ - return stbi__g_failure_reason; -} - -static int stbi__err(const char *str) -{ - stbi__g_failure_reason = str; - return 0; -} - -static void *stbi__malloc(size_t size) -{ - return STBI_MALLOC(size); -} - -// stb_image uses ints pervasively, including for offset calculations. -// therefore the largest decoded image size we can support with the -// current code, even on 64-bit targets, is INT_MAX. this is not a -// significant limitation for the intended use case. -// -// we do, however, need to make sure our size calculations don't -// overflow. hence a few helper functions for size calculations that -// multiply integers together, making sure that they're non-negative -// and no overflow occurs. - -// return 1 if the sum is valid, 0 on overflow. -// negative terms are considered invalid. -static int stbi__addsizes_valid(int a, int b) -{ - if (b < 0) return 0; - // now 0 <= b <= INT_MAX, hence also - // 0 <= INT_MAX - b <= INTMAX. - // And "a + b <= INT_MAX" (which might overflow) is the - // same as a <= INT_MAX - b (no overflow) - return a <= INT_MAX - b; -} - -// returns 1 if the product is valid, 0 on overflow. -// negative factors are considered invalid. -static int stbi__mul2sizes_valid(int a, int b) -{ - if (a < 0 || b < 0) return 0; - if (b == 0) return 1; // mul-by-0 is always safe - // portable way to check for no overflows in a*b - return a <= INT_MAX/b; -} - -// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow -static int stbi__mad2sizes_valid(int a, int b, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); -} - -// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow -static int stbi__mad3sizes_valid(int a, int b, int c, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__addsizes_valid(a*b*c, add); -} - -// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow -static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); -} - -// mallocs with size overflow checking -static void *stbi__malloc_mad2(int a, int b, int add) -{ - if (!stbi__mad2sizes_valid(a, b, add)) return NULL; - return stbi__malloc(a*b + add); -} - -static void *stbi__malloc_mad3(int a, int b, int c, int add) -{ - if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; - return stbi__malloc(a*b*c + add); -} - -static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) -{ - if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; - return stbi__malloc(a*b*c*d + add); -} - -// stbi__err - error -// stbi__errpf - error returning pointer to float -// stbi__errpuc - error returning pointer to unsigned char - -#ifdef STBI_NO_FAILURE_STRINGS - #define stbi__err(x,y) 0 -#elif defined(STBI_FAILURE_USERMSG) - #define stbi__err(x,y) stbi__err(y) -#else - #define stbi__err(x,y) stbi__err(x) -#endif - -#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) -#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) - -STBIDEF void stbi_image_free(void *retval_from_stbi_load) -{ - STBI_FREE(retval_from_stbi_load); -} - -#ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); -#endif - -#ifndef STBI_NO_HDR -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); -#endif - -static int stbi__vertically_flip_on_load = 0; - -STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) -{ - stbi__vertically_flip_on_load = flag_true_if_should_flip; -} - -static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields - ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed - ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order - ri->num_channels = 0; - - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); - #endif - #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); - #endif - - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); - return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif - - #ifndef STBI_NO_TGA - // test tga last because it's a crappy test! - if (stbi__tga_test(s)) - return stbi__tga_load(s,x,y,comp,req_comp, ri); - #endif - - return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); -} - -static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi_uc *reduced; - - reduced = (stbi_uc *) stbi__malloc(img_len); - if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); - - for (i = 0; i < img_len; ++i) - reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling - - STBI_FREE(orig); - return reduced; -} - -static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi__uint16 *enlarged; - - enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); - if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); - - for (i = 0; i < img_len; ++i) - enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff - - STBI_FREE(orig); - return enlarged; -} - -static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) -{ - int row; - size_t bytes_per_row = (size_t)w * bytes_per_pixel; - stbi_uc temp[2048]; - stbi_uc *bytes = (stbi_uc *)image; - - for (row = 0; row < (h>>1); row++) { - stbi_uc *row0 = bytes + row*bytes_per_row; - stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; - // swap row0 with row1 - size_t bytes_left = bytes_per_row; - while (bytes_left) { - size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); - memcpy(temp, row0, bytes_copy); - memcpy(row0, row1, bytes_copy); - memcpy(row1, temp, bytes_copy); - row0 += bytes_copy; - row1 += bytes_copy; - bytes_left -= bytes_copy; - } - } -} - -static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); - - if (result == NULL) - return NULL; - - if (ri.bits_per_channel != 8) { - STBI_ASSERT(ri.bits_per_channel == 16); - result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 8; - } - - // @TODO: move stbi__convert_format to here - - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); - } - - return (unsigned char *) result; -} - -static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); - - if (result == NULL) - return NULL; - - if (ri.bits_per_channel != 16) { - STBI_ASSERT(ri.bits_per_channel == 8); - result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 16; - } - - // @TODO: move stbi__convert_format16 to here - // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision - - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); - } - - return (stbi__uint16 *) result; -} - -#ifndef STBI_NO_HDR -static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) -{ - if (stbi__vertically_flip_on_load && result != NULL) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); - } -} -#endif - -#ifndef STBI_NO_STDIO - -static FILE *stbi__fopen(char const *filename, char const *mode) -{ - FILE *f; -#if defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; -#else - f = fopen(filename, mode); -#endif - return f; -} - - -STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - unsigned char *result; - if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; -} - -STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__uint16 *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; -} - -STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - stbi__uint16 *result; - if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file_16(f,x,y,comp,req_comp); - fclose(f); - return result; -} - - -#endif //!STBI_NO_STDIO - -STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); -} - -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); -} - -STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); -} - -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_LINEAR -static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - stbi__result_info ri; - float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); - if (hdr_data) - stbi__float_postprocess(hdr_data,x,y,comp,req_comp); - return hdr_data; - } - #endif - data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); - if (data) - return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); -} - -STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__loadf_main(&s,x,y,comp,req_comp); -} - -STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__loadf_main(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_STDIO -STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - float *result; - FILE *f = stbi__fopen(filename, "rb"); - if (!f) return stbi__errpf("can't fopen", "Unable to open file"); - result = stbi_loadf_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_file(&s,f); - return stbi__loadf_main(&s,x,y,comp,req_comp); -} -#endif // !STBI_NO_STDIO - -#endif // !STBI_NO_LINEAR - -// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is -// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always -// reports false! - -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(buffer); - STBI_NOTUSED(len); - return 0; - #endif -} - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result=0; - if (f) { - result = stbi_is_hdr_from_file(f); - fclose(f); - } - return result; -} - -STBIDEF int stbi_is_hdr_from_file(FILE *f) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_file(&s,f); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(f); - return 0; - #endif -} -#endif // !STBI_NO_STDIO - -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(clbk); - STBI_NOTUSED(user); - return 0; - #endif -} - -#ifndef STBI_NO_LINEAR -static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; - -STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } -STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } -#endif - -static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; - -STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } -STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } - - -////////////////////////////////////////////////////////////////////////////// -// -// Common code used by all image loaders -// - -enum -{ - STBI__SCAN_load=0, - STBI__SCAN_type, - STBI__SCAN_header -}; - -static void stbi__refill_buffer(stbi__context *s) -{ - int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); - if (n == 0) { - // at end of file, treat same as if from memory, but need to handle case - // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file - s->read_from_callbacks = 0; - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start+1; - *s->img_buffer = 0; - } else { - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start + n; - } -} - -stbi_inline static stbi_uc stbi__get8(stbi__context *s) -{ - if (s->img_buffer < s->img_buffer_end) - return *s->img_buffer++; - if (s->read_from_callbacks) { - stbi__refill_buffer(s); - return *s->img_buffer++; - } - return 0; -} - -stbi_inline static int stbi__at_eof(stbi__context *s) -{ - if (s->io.read) { - if (!(s->io.eof)(s->io_user_data)) return 0; - // if feof() is true, check if buffer = end - // special case: we've only got the special 0 character at the end - if (s->read_from_callbacks == 0) return 1; - } - - return s->img_buffer >= s->img_buffer_end; -} - -static void stbi__skip(stbi__context *s, int n) -{ - if (n < 0) { - s->img_buffer = s->img_buffer_end; - return; - } - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - s->img_buffer = s->img_buffer_end; - (s->io.skip)(s->io_user_data, n - blen); - return; - } - } - s->img_buffer += n; -} - -static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - int res, count; - - memcpy(buffer, s->img_buffer, blen); - - count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); - res = (count == (n-blen)); - s->img_buffer = s->img_buffer_end; - return res; - } - } - - if (s->img_buffer+n <= s->img_buffer_end) { - memcpy(buffer, s->img_buffer, n); - s->img_buffer += n; - return 1; - } else - return 0; -} - -static int stbi__get16be(stbi__context *s) -{ - int z = stbi__get8(s); - return (z << 8) + stbi__get8(s); -} - -static stbi__uint32 stbi__get32be(stbi__context *s) -{ - stbi__uint32 z = stbi__get16be(s); - return (z << 16) + stbi__get16be(s); -} - -#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) -// nothing -#else -static int stbi__get16le(stbi__context *s) -{ - int z = stbi__get8(s); - return z + (stbi__get8(s) << 8); -} -#endif - -#ifndef STBI_NO_BMP -static stbi__uint32 stbi__get32le(stbi__context *s) -{ - stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); -} -#endif - -#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings - - -////////////////////////////////////////////////////////////////////////////// -// -// generic converter from built-in img_n to req_comp -// individual types do this automatically as much as possible (e.g. jpeg -// does all cases internally since it needs to colorspace convert anyway, -// and it never has alpha, so very few cases ). png can automatically -// interleave an alpha=255 channel, but falls back to this for other cases -// -// assume data buffer is malloced, so malloc a new one and free that one -// only failure mode is malloc failing - -static stbi_uc stbi__compute_y(int r, int g, int b) -{ - return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); -} - -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - unsigned char *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); - if (good == NULL) { - STBI_FREE(data); - return stbi__errpuc("outofmem", "Out of memory"); - } - - for (j=0; j < (int) y; ++j) { - unsigned char *src = data + j * x * img_n ; - unsigned char *dest = good + j * x * req_comp; - - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; - default: STBI_ASSERT(0); - } - #undef STBI__CASE - } - - STBI_FREE(data); - return good; -} - -static stbi__uint16 stbi__compute_y_16(int r, int g, int b) -{ - return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); -} - -static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - stbi__uint16 *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); - if (good == NULL) { - STBI_FREE(data); - return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); - } - - for (j=0; j < (int) y; ++j) { - stbi__uint16 *src = data + j * x * img_n ; - stbi__uint16 *dest = good + j * x * req_comp; - - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; - default: STBI_ASSERT(0); - } - #undef STBI__CASE - } - - STBI_FREE(data); - return good; -} - -#ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) -{ - int i,k,n; - float *output; - if (!data) return NULL; - output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); - } - if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; - } - STBI_FREE(data); - return output; -} -#endif - -#ifndef STBI_NO_HDR -#define stbi__float2int(x) ((int) (x)) -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) -{ - int i,k,n; - stbi_uc *output; - if (!data) return NULL; - output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - if (k < comp) { - float z = data[i*comp+k] * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - } - STBI_FREE(data); - return output; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// "baseline" JPEG/JFIF decoder -// -// simple implementation -// - doesn't support delayed output of y-dimension -// - simple interface (only one output format: 8-bit interleaved RGB) -// - doesn't try to recover corrupt jpegs -// - doesn't allow partial loading, loading multiple at once -// - still fast on x86 (copying globals into locals doesn't help x86) -// - allocates lots of intermediate memory (full size of all components) -// - non-interleaved case requires this anyway -// - allows good upsampling (see next) -// high-quality -// - upsampled channels are bilinearly interpolated, even across blocks -// - quality integer IDCT derived from IJG's 'slow' -// performance -// - fast huffman; reasonable integer IDCT -// - some SIMD kernels for common paths on targets with SSE2/NEON -// - uses a lot of intermediate memory, could cache poorly - -#ifndef STBI_NO_JPEG - -// huffman decoding acceleration -#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache - -typedef struct -{ - stbi_uc fast[1 << FAST_BITS]; - // weirdly, repacking this into AoS is a 10% speed loss, instead of a win - stbi__uint16 code[256]; - stbi_uc values[256]; - stbi_uc size[257]; - unsigned int maxcode[18]; - int delta[17]; // old 'firstsymbol' - old 'firstcode' -} stbi__huffman; - -typedef struct -{ - stbi__context *s; - stbi__huffman huff_dc[4]; - stbi__huffman huff_ac[4]; - stbi__uint16 dequant[4][64]; - stbi__int16 fast_ac[4][1 << FAST_BITS]; - -// sizes for components, interleaved MCUs - int img_h_max, img_v_max; - int img_mcu_x, img_mcu_y; - int img_mcu_w, img_mcu_h; - -// definition of jpeg image component - struct - { - int id; - int h,v; - int tq; - int hd,ha; - int dc_pred; - - int x,y,w2,h2; - stbi_uc *data; - void *raw_data, *raw_coeff; - stbi_uc *linebuf; - short *coeff; // progressive only - int coeff_w, coeff_h; // number of 8x8 coefficient blocks - } img_comp[4]; - - stbi__uint32 code_buffer; // jpeg entropy-coded buffer - int code_bits; // number of valid bits - unsigned char marker; // marker seen while filling entropy buffer - int nomore; // flag if we saw a marker so must stop - - int progressive; - int spec_start; - int spec_end; - int succ_high; - int succ_low; - int eob_run; - int jfif; - int app14_color_transform; // Adobe APP14 tag - int rgb; - - int scan_n, order[4]; - int restart_interval, todo; - -// kernels - void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); - void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); - stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); -} stbi__jpeg; - -static int stbi__build_huffman(stbi__huffman *h, int *count) -{ - int i,j,k=0,code; - // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) - h->size[k++] = (stbi_uc) (i+1); - h->size[k] = 0; - - // compute actual symbols (from jpeg spec) - code = 0; - k = 0; - for(j=1; j <= 16; ++j) { - // compute delta to add to code to compute symbol id - h->delta[j] = k - code; - if (h->size[k] == j) { - while (h->size[k] == j) - h->code[k++] = (stbi__uint16) (code++); - if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); - } - // compute largest code + 1 for this size, preshifted as needed later - h->maxcode[j] = code << (16-j); - code <<= 1; - } - h->maxcode[j] = 0xffffffff; - - // build non-spec acceleration table; 255 is flag for not-accelerated - memset(h->fast, 255, 1 << FAST_BITS); - for (i=0; i < k; ++i) { - int s = h->size[i]; - if (s <= FAST_BITS) { - int c = h->code[i] << (FAST_BITS-s); - int m = 1 << (FAST_BITS-s); - for (j=0; j < m; ++j) { - h->fast[c+j] = (stbi_uc) i; - } - } - } - return 1; -} - -// build a table that decodes both magnitude and value of small ACs in -// one go. -static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) -{ - int i; - for (i=0; i < (1 << FAST_BITS); ++i) { - stbi_uc fast = h->fast[i]; - fast_ac[i] = 0; - if (fast < 255) { - int rs = h->values[fast]; - int run = (rs >> 4) & 15; - int magbits = rs & 15; - int len = h->size[fast]; - - if (magbits && len + magbits <= FAST_BITS) { - // magnitude code followed by receive_extend code - int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); - int m = 1 << (magbits - 1); - if (k < m) k += (~0U << magbits) + 1; - // if the result is small enough, we can fit it in fast_ac table - if (k >= -128 && k <= 127) - fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); - } - } - } -} - -static void stbi__grow_buffer_unsafe(stbi__jpeg *j) -{ - do { - int b = j->nomore ? 0 : stbi__get8(j->s); - if (b == 0xff) { - int c = stbi__get8(j->s); - while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes - if (c != 0) { - j->marker = (unsigned char) c; - j->nomore = 1; - return; - } - } - j->code_buffer |= b << (24 - j->code_bits); - j->code_bits += 8; - } while (j->code_bits <= 24); -} - -// (1 << n) - 1 -static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; - -// decode a jpeg huffman value from the bitstream -stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) -{ - unsigned int temp; - int c,k; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - // look at the top FAST_BITS and determine what symbol ID it is, - // if the code is <= FAST_BITS - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - k = h->fast[c]; - if (k < 255) { - int s = h->size[k]; - if (s > j->code_bits) - return -1; - j->code_buffer <<= s; - j->code_bits -= s; - return h->values[k]; - } - - // naive test is to shift the code_buffer down so k bits are - // valid, then test against maxcode. To speed this up, we've - // preshifted maxcode left so that it has (16-k) 0s at the - // end; in other words, regardless of the number of bits, it - // wants to be compared against something shifted to have 16; - // that way we don't need to shift inside the loop. - temp = j->code_buffer >> 16; - for (k=FAST_BITS+1 ; ; ++k) - if (temp < h->maxcode[k]) - break; - if (k == 17) { - // error! code not found - j->code_bits -= 16; - return -1; - } - - if (k > j->code_bits) - return -1; - - // convert the huffman code to the symbol id - c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; - STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); - - // convert the id to a symbol - j->code_bits -= k; - j->code_buffer <<= k; - return h->values[c]; -} - -// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); - - sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB - k = stbi_lrot(j->code_buffer, n); - STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); -} - -// get some unsigned bits -stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) -{ - unsigned int k; - if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k; -} - -stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) -{ - unsigned int k; - if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); - k = j->code_buffer; - j->code_buffer <<= 1; - --j->code_bits; - return k & 0x80000000; -} - -// given a value that's at position X in the zigzag stream, -// where does it appear in the 8x8 matrix coded as row-major? -static stbi_uc stbi__jpeg_dezigzag[64+15] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - // let corrupt input sample past end - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63 -}; - -// decode one 64-entry block-- -static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) -{ - int diff,dc,k; - int t; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - - // 0 all the ac values now so we can do it 32-bits at a time - memset(data,0,64*sizeof(data[0])); - - diff = t ? stbi__extend_receive(j, t) : 0; - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc * dequant[0]); - - // decode AC components, see JPEG spec - k = 1; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * dequant[zig]); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (rs != 0xf0) break; // end block - k += 16; - } else { - k += r; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); - } - } - } while (k < 64); - return 1; -} - -static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) -{ - int diff,dc; - int t; - if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - if (j->succ_high == 0) { - // first scan for DC coefficient, must be first - memset(data,0,64*sizeof(data[0])); // 0 all the ac values now - t = stbi__jpeg_huff_decode(j, hdc); - diff = t ? stbi__extend_receive(j, t) : 0; - - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc << j->succ_low); - } else { - // refinement scan for DC coefficient - if (stbi__jpeg_get_bit(j)) - data[0] += (short) (1 << j->succ_low); - } - return 1; -} - -// @OPTIMIZE: store non-zigzagged during the decode passes, -// and only de-zigzag when dequantizing -static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) -{ - int k; - if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->succ_high == 0) { - int shift = j->succ_low; - - if (j->eob_run) { - --j->eob_run; - return 1; - } - - k = j->spec_start; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) << shift); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r); - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - --j->eob_run; - break; - } - k += 16; - } else { - k += r; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) << shift); - } - } - } while (k <= j->spec_end); - } else { - // refinement scan for these AC coefficients - - short bit = (short) (1 << j->succ_low); - - if (j->eob_run) { - --j->eob_run; - for (k = j->spec_start; k <= j->spec_end; ++k) { - short *p = &data[stbi__jpeg_dezigzag[k]]; - if (*p != 0) - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } - } else { - k = j->spec_start; - do { - int r,s; - int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r) - 1; - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - r = 64; // force end of block - } else { - // r=15 s=0 should write 16 0s, so we just do - // a run of 15 0s and then write s (which is 0), - // so we don't have to do anything special here - } - } else { - if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); - // sign bit - if (stbi__jpeg_get_bit(j)) - s = bit; - else - s = -bit; - } - - // advance by r - while (k <= j->spec_end) { - short *p = &data[stbi__jpeg_dezigzag[k++]]; - if (*p != 0) { - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } else { - if (r == 0) { - *p = (short) s; - break; - } - --r; - } - } - } while (k <= j->spec_end); - } - } - return 1; -} - -// take a -128..127 value and stbi__clamp it and convert to 0..255 -stbi_inline static stbi_uc stbi__clamp(int x) -{ - // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { - if (x < 0) return 0; - if (x > 255) return 255; - } - return (stbi_uc) x; -} - -#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) -#define stbi__fsh(x) ((x) << 12) - -// derived from jidctint -- DCT_ISLOW -#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ - int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ - p2 = s2; \ - p3 = s6; \ - p1 = (p2+p3) * stbi__f2f(0.5411961f); \ - t2 = p1 + p3*stbi__f2f(-1.847759065f); \ - t3 = p1 + p2*stbi__f2f( 0.765366865f); \ - p2 = s0; \ - p3 = s4; \ - t0 = stbi__fsh(p2+p3); \ - t1 = stbi__fsh(p2-p3); \ - x0 = t0+t3; \ - x3 = t0-t3; \ - x1 = t1+t2; \ - x2 = t1-t2; \ - t0 = s7; \ - t1 = s5; \ - t2 = s3; \ - t3 = s1; \ - p3 = t0+t2; \ - p4 = t1+t3; \ - p1 = t0+t3; \ - p2 = t1+t2; \ - p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ - t0 = t0*stbi__f2f( 0.298631336f); \ - t1 = t1*stbi__f2f( 2.053119869f); \ - t2 = t2*stbi__f2f( 3.072711026f); \ - t3 = t3*stbi__f2f( 1.501321110f); \ - p1 = p5 + p1*stbi__f2f(-0.899976223f); \ - p2 = p5 + p2*stbi__f2f(-2.562915447f); \ - p3 = p3*stbi__f2f(-1.961570560f); \ - p4 = p4*stbi__f2f(-0.390180644f); \ - t3 += p1+p4; \ - t2 += p2+p3; \ - t1 += p2+p4; \ - t0 += p1+p3; - -static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) -{ - int i,val[64],*v=val; - stbi_uc *o; - short *d = data; - - // columns - for (i=0; i < 8; ++i,++d, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0] << 2; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } - - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - // so we want to round that, which means adding 0.5 * 1<<17, - // aka 65536. Also, we'll end up with -128 to 127 that we want - // to encode as 0..255 by adding 128, so we'll add that before the shift - x0 += 65536 + (128<<17); - x1 += 65536 + (128<<17); - x2 += 65536 + (128<<17); - x3 += 65536 + (128<<17); - // tried computing the shifts into temps, or'ing the temps to see - // if any were out of range, but that was slower - o[0] = stbi__clamp((x0+t3) >> 17); - o[7] = stbi__clamp((x0-t3) >> 17); - o[1] = stbi__clamp((x1+t2) >> 17); - o[6] = stbi__clamp((x1-t2) >> 17); - o[2] = stbi__clamp((x2+t1) >> 17); - o[5] = stbi__clamp((x2-t1) >> 17); - o[3] = stbi__clamp((x3+t0) >> 17); - o[4] = stbi__clamp((x3-t0) >> 17); - } -} - -#ifdef STBI_SSE2 -// sse2 integer IDCT. not the fastest possible implementation but it -// produces bit-identical results to the generic C version so it's -// fully "transparent". -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - // This is constructed to match our regular (generic) integer IDCT exactly. - __m128i row0, row1, row2, row3, row4, row5, row6, row7; - __m128i tmp; - - // dot product constant: even elems=x, odd elems=y - #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) - - // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) - // out(1) = c1[even]*x + c1[odd]*y - #define dct_rot(out0,out1, x,y,c0,c1) \ - __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ - __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ - __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ - __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ - __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ - __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) - - // out = in << 12 (in 16-bit, out 32-bit) - #define dct_widen(out, in) \ - __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ - __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) - - // wide add - #define dct_wadd(out, a, b) \ - __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_add_epi32(a##_h, b##_h) - - // wide sub - #define dct_wsub(out, a, b) \ - __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) - - // butterfly a/b, add bias, then shift by "s" and pack - #define dct_bfly32o(out0, out1, a,b,bias,s) \ - { \ - __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ - __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ - dct_wadd(sum, abiased, b); \ - dct_wsub(dif, abiased, b); \ - out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ - out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ - } - - // 8-bit interleave step (for transposes) - #define dct_interleave8(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi8(a, b); \ - b = _mm_unpackhi_epi8(tmp, b) - - // 16-bit interleave step (for transposes) - #define dct_interleave16(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi16(a, b); \ - b = _mm_unpackhi_epi16(tmp, b) - - #define dct_pass(bias,shift) \ - { \ - /* even part */ \ - dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ - __m128i sum04 = _mm_add_epi16(row0, row4); \ - __m128i dif04 = _mm_sub_epi16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ - dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ - __m128i sum17 = _mm_add_epi16(row1, row7); \ - __m128i sum35 = _mm_add_epi16(row3, row5); \ - dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ - dct_wadd(x4, y0o, y4o); \ - dct_wadd(x5, y1o, y5o); \ - dct_wadd(x6, y2o, y5o); \ - dct_wadd(x7, y3o, y4o); \ - dct_bfly32o(row0,row7, x0,x7,bias,shift); \ - dct_bfly32o(row1,row6, x1,x6,bias,shift); \ - dct_bfly32o(row2,row5, x2,x5,bias,shift); \ - dct_bfly32o(row3,row4, x3,x4,bias,shift); \ - } - - __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); - __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); - __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); - __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); - __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); - __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); - __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); - __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); - - // rounding biases in column/row passes, see stbi__idct_block for explanation. - __m128i bias_0 = _mm_set1_epi32(512); - __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); - - // load - row0 = _mm_load_si128((const __m128i *) (data + 0*8)); - row1 = _mm_load_si128((const __m128i *) (data + 1*8)); - row2 = _mm_load_si128((const __m128i *) (data + 2*8)); - row3 = _mm_load_si128((const __m128i *) (data + 3*8)); - row4 = _mm_load_si128((const __m128i *) (data + 4*8)); - row5 = _mm_load_si128((const __m128i *) (data + 5*8)); - row6 = _mm_load_si128((const __m128i *) (data + 6*8)); - row7 = _mm_load_si128((const __m128i *) (data + 7*8)); - - // column pass - dct_pass(bias_0, 10); - - { - // 16bit 8x8 transpose pass 1 - dct_interleave16(row0, row4); - dct_interleave16(row1, row5); - dct_interleave16(row2, row6); - dct_interleave16(row3, row7); - - // transpose pass 2 - dct_interleave16(row0, row2); - dct_interleave16(row1, row3); - dct_interleave16(row4, row6); - dct_interleave16(row5, row7); - - // transpose pass 3 - dct_interleave16(row0, row1); - dct_interleave16(row2, row3); - dct_interleave16(row4, row5); - dct_interleave16(row6, row7); - } - - // row pass - dct_pass(bias_1, 17); - - { - // pack - __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 - __m128i p1 = _mm_packus_epi16(row2, row3); - __m128i p2 = _mm_packus_epi16(row4, row5); - __m128i p3 = _mm_packus_epi16(row6, row7); - - // 8bit 8x8 transpose pass 1 - dct_interleave8(p0, p2); // a0e0a1e1... - dct_interleave8(p1, p3); // c0g0c1g1... - - // transpose pass 2 - dct_interleave8(p0, p1); // a0c0e0g0... - dct_interleave8(p2, p3); // b0d0f0h0... - - // transpose pass 3 - dct_interleave8(p0, p2); // a0b0c0d0... - dct_interleave8(p1, p3); // a4b4c4d4... - - // store - _mm_storel_epi64((__m128i *) out, p0); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p2); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p1); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p3); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); - } - -#undef dct_const -#undef dct_rot -#undef dct_widen -#undef dct_wadd -#undef dct_wsub -#undef dct_bfly32o -#undef dct_interleave8 -#undef dct_interleave16 -#undef dct_pass -} - -#endif // STBI_SSE2 - -#ifdef STBI_NEON - -// NEON integer IDCT. should produce bit-identical -// results to the generic C version. -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; - - int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); - int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); - int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); - int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); - int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); - int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); - int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); - int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); - int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); - int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); - int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); - int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); - -#define dct_long_mul(out, inq, coeff) \ - int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) - -#define dct_long_mac(out, acc, inq, coeff) \ - int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) - -#define dct_widen(out, inq) \ - int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ - int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) - -// wide add -#define dct_wadd(out, a, b) \ - int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vaddq_s32(a##_h, b##_h) - -// wide sub -#define dct_wsub(out, a, b) \ - int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vsubq_s32(a##_h, b##_h) - -// butterfly a/b, then shift using "shiftop" by "s" and pack -#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ - { \ - dct_wadd(sum, a, b); \ - dct_wsub(dif, a, b); \ - out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ - out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ - } - -#define dct_pass(shiftop, shift) \ - { \ - /* even part */ \ - int16x8_t sum26 = vaddq_s16(row2, row6); \ - dct_long_mul(p1e, sum26, rot0_0); \ - dct_long_mac(t2e, p1e, row6, rot0_1); \ - dct_long_mac(t3e, p1e, row2, rot0_2); \ - int16x8_t sum04 = vaddq_s16(row0, row4); \ - int16x8_t dif04 = vsubq_s16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - int16x8_t sum15 = vaddq_s16(row1, row5); \ - int16x8_t sum17 = vaddq_s16(row1, row7); \ - int16x8_t sum35 = vaddq_s16(row3, row5); \ - int16x8_t sum37 = vaddq_s16(row3, row7); \ - int16x8_t sumodd = vaddq_s16(sum17, sum35); \ - dct_long_mul(p5o, sumodd, rot1_0); \ - dct_long_mac(p1o, p5o, sum17, rot1_1); \ - dct_long_mac(p2o, p5o, sum35, rot1_2); \ - dct_long_mul(p3o, sum37, rot2_0); \ - dct_long_mul(p4o, sum15, rot2_1); \ - dct_wadd(sump13o, p1o, p3o); \ - dct_wadd(sump24o, p2o, p4o); \ - dct_wadd(sump23o, p2o, p3o); \ - dct_wadd(sump14o, p1o, p4o); \ - dct_long_mac(x4, sump13o, row7, rot3_0); \ - dct_long_mac(x5, sump24o, row5, rot3_1); \ - dct_long_mac(x6, sump23o, row3, rot3_2); \ - dct_long_mac(x7, sump14o, row1, rot3_3); \ - dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ - dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ - dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ - dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ - } - - // load - row0 = vld1q_s16(data + 0*8); - row1 = vld1q_s16(data + 1*8); - row2 = vld1q_s16(data + 2*8); - row3 = vld1q_s16(data + 3*8); - row4 = vld1q_s16(data + 4*8); - row5 = vld1q_s16(data + 5*8); - row6 = vld1q_s16(data + 6*8); - row7 = vld1q_s16(data + 7*8); - - // add DC bias - row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); - - // column pass - dct_pass(vrshrn_n_s32, 10); - - // 16bit 8x8 transpose - { -// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. -// whether compilers actually get this is another story, sadly. -#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } -#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } - - // pass 1 - dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 - dct_trn16(row2, row3); - dct_trn16(row4, row5); - dct_trn16(row6, row7); - - // pass 2 - dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 - dct_trn32(row1, row3); - dct_trn32(row4, row6); - dct_trn32(row5, row7); - - // pass 3 - dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 - dct_trn64(row1, row5); - dct_trn64(row2, row6); - dct_trn64(row3, row7); - -#undef dct_trn16 -#undef dct_trn32 -#undef dct_trn64 - } - - // row pass - // vrshrn_n_s32 only supports shifts up to 16, we need - // 17. so do a non-rounding shift of 16 first then follow - // up with a rounding shift by 1. - dct_pass(vshrn_n_s32, 16); - - { - // pack and round - uint8x8_t p0 = vqrshrun_n_s16(row0, 1); - uint8x8_t p1 = vqrshrun_n_s16(row1, 1); - uint8x8_t p2 = vqrshrun_n_s16(row2, 1); - uint8x8_t p3 = vqrshrun_n_s16(row3, 1); - uint8x8_t p4 = vqrshrun_n_s16(row4, 1); - uint8x8_t p5 = vqrshrun_n_s16(row5, 1); - uint8x8_t p6 = vqrshrun_n_s16(row6, 1); - uint8x8_t p7 = vqrshrun_n_s16(row7, 1); - - // again, these can translate into one instruction, but often don't. -#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } -#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } - - // sadly can't use interleaved stores here since we only write - // 8 bytes to each scan line! - - // 8x8 8-bit transpose pass 1 - dct_trn8_8(p0, p1); - dct_trn8_8(p2, p3); - dct_trn8_8(p4, p5); - dct_trn8_8(p6, p7); - - // pass 2 - dct_trn8_16(p0, p2); - dct_trn8_16(p1, p3); - dct_trn8_16(p4, p6); - dct_trn8_16(p5, p7); - - // pass 3 - dct_trn8_32(p0, p4); - dct_trn8_32(p1, p5); - dct_trn8_32(p2, p6); - dct_trn8_32(p3, p7); - - // store - vst1_u8(out, p0); out += out_stride; - vst1_u8(out, p1); out += out_stride; - vst1_u8(out, p2); out += out_stride; - vst1_u8(out, p3); out += out_stride; - vst1_u8(out, p4); out += out_stride; - vst1_u8(out, p5); out += out_stride; - vst1_u8(out, p6); out += out_stride; - vst1_u8(out, p7); - -#undef dct_trn8_8 -#undef dct_trn8_16 -#undef dct_trn8_32 - } - -#undef dct_long_mul -#undef dct_long_mac -#undef dct_widen -#undef dct_wadd -#undef dct_wsub -#undef dct_bfly32o -#undef dct_pass -} - -#endif // STBI_NEON - -#define STBI__MARKER_none 0xff -// if there's a pending marker from the entropy stream, return that -// otherwise, fetch from the stream and get a marker. if there's no -// marker, return 0xff, which is never a valid marker value -static stbi_uc stbi__get_marker(stbi__jpeg *j) -{ - stbi_uc x; - if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } - x = stbi__get8(j->s); - if (x != 0xff) return STBI__MARKER_none; - while (x == 0xff) - x = stbi__get8(j->s); // consume repeated 0xff fill bytes - return x; -} - -// in each scan, we'll have scan_n components, and the order -// of the components is specified by order[] -#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) - -// after a restart interval, stbi__jpeg_reset the entropy decoder and -// the dc prediction -static void stbi__jpeg_reset(stbi__jpeg *j) -{ - j->code_bits = 0; - j->code_buffer = 0; - j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; - j->marker = STBI__MARKER_none; - j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; - j->eob_run = 0; - // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, - // since we don't even allow 1<<30 pixels -} - -static int stbi__parse_entropy_coded_data(stbi__jpeg *z) -{ - stbi__jpeg_reset(z); - if (!z->progressive) { - if (z->scan_n == 1) { - int i,j; - STBI_SIMD_ALIGN(short, data[64]); - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - STBI_SIMD_ALIGN(short, data[64]); - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x)*8; - int y2 = (j*z->img_comp[n].v + y)*8; - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } else { - if (z->scan_n == 1) { - int i,j; - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - if (z->spec_start == 0) { - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } else { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) - return 0; - } - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x); - int y2 = (j*z->img_comp[n].v + y); - short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } -} - -static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) -{ - int i; - for (i=0; i < 64; ++i) - data[i] *= dequant[i]; -} - -static void stbi__jpeg_finish(stbi__jpeg *z) -{ - if (z->progressive) { - // dequantize and idct the data - int i,j,n; - for (n=0; n < z->s->img_n; ++n) { - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - } - } - } - } -} - -static int stbi__process_marker(stbi__jpeg *z, int m) -{ - int L; - switch (m) { - case STBI__MARKER_none: // no marker found - return stbi__err("expected marker","Corrupt JPEG"); - - case 0xDD: // DRI - specify restart interval - if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); - z->restart_interval = stbi__get16be(z->s); - return 1; - - case 0xDB: // DQT - define quantization table - L = stbi__get16be(z->s)-2; - while (L > 0) { - int q = stbi__get8(z->s); - int p = q >> 4, sixteen = (p != 0); - int t = q & 15,i; - if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); - if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); - - for (i=0; i < 64; ++i) - z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); - L -= (sixteen ? 129 : 65); - } - return L==0; - - case 0xC4: // DHT - define huffman table - L = stbi__get16be(z->s)-2; - while (L > 0) { - stbi_uc *v; - int sizes[16],i,n=0; - int q = stbi__get8(z->s); - int tc = q >> 4; - int th = q & 15; - if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); - for (i=0; i < 16; ++i) { - sizes[i] = stbi__get8(z->s); - n += sizes[i]; - } - L -= 17; - if (tc == 0) { - if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; - v = z->huff_dc[th].values; - } else { - if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; - v = z->huff_ac[th].values; - } - for (i=0; i < n; ++i) - v[i] = stbi__get8(z->s); - if (tc != 0) - stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); - L -= n; - } - return L==0; - } - - // check for comment block or APP blocks - if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - L = stbi__get16be(z->s); - if (L < 2) { - if (m == 0xFE) - return stbi__err("bad COM len","Corrupt JPEG"); - else - return stbi__err("bad APP len","Corrupt JPEG"); - } - L -= 2; - - if (m == 0xE0 && L >= 5) { // JFIF APP0 segment - static const unsigned char tag[5] = {'J','F','I','F','\0'}; - int ok = 1; - int i; - for (i=0; i < 5; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 5; - if (ok) - z->jfif = 1; - } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment - static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; - int ok = 1; - int i; - for (i=0; i < 6; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 6; - if (ok) { - stbi__get8(z->s); // version - stbi__get16be(z->s); // flags0 - stbi__get16be(z->s); // flags1 - z->app14_color_transform = stbi__get8(z->s); // color transform - L -= 6; - } - } - - stbi__skip(z->s, L); - return 1; - } - - return stbi__err("unknown marker","Corrupt JPEG"); -} - -// after we see SOS -static int stbi__process_scan_header(stbi__jpeg *z) -{ - int i; - int Ls = stbi__get16be(z->s); - z->scan_n = stbi__get8(z->s); - if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); - if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); - for (i=0; i < z->scan_n; ++i) { - int id = stbi__get8(z->s), which; - int q = stbi__get8(z->s); - for (which = 0; which < z->s->img_n; ++which) - if (z->img_comp[which].id == id) - break; - if (which == z->s->img_n) return 0; // no match - z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); - z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); - z->order[i] = which; - } - - { - int aa; - z->spec_start = stbi__get8(z->s); - z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 - aa = stbi__get8(z->s); - z->succ_high = (aa >> 4); - z->succ_low = (aa & 15); - if (z->progressive) { - if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) - return stbi__err("bad SOS", "Corrupt JPEG"); - } else { - if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); - if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); - z->spec_end = 63; - } - } - - return 1; -} - -static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) -{ - int i; - for (i=0; i < ncomp; ++i) { - if (z->img_comp[i].raw_data) { - STBI_FREE(z->img_comp[i].raw_data); - z->img_comp[i].raw_data = NULL; - z->img_comp[i].data = NULL; - } - if (z->img_comp[i].raw_coeff) { - STBI_FREE(z->img_comp[i].raw_coeff); - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].coeff = 0; - } - if (z->img_comp[i].linebuf) { - STBI_FREE(z->img_comp[i].linebuf); - z->img_comp[i].linebuf = NULL; - } - } - return why; -} - -static int stbi__process_frame_header(stbi__jpeg *z, int scan) -{ - stbi__context *s = z->s; - int Lf,p,i,q, h_max=1,v_max=1,c; - Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG - p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline - s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG - s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires - c = stbi__get8(s); - if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); - s->img_n = c; - for (i=0; i < c; ++i) { - z->img_comp[i].data = NULL; - z->img_comp[i].linebuf = NULL; - } - - if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); - - z->rgb = 0; - for (i=0; i < s->img_n; ++i) { - static unsigned char rgb[3] = { 'R', 'G', 'B' }; - z->img_comp[i].id = stbi__get8(s); - if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) - ++z->rgb; - q = stbi__get8(s); - z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); - z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); - z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); - } - - if (scan != STBI__SCAN_load) return 1; - - if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); - - for (i=0; i < s->img_n; ++i) { - if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; - if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; - } - - // compute interleaved mcu info - z->img_h_max = h_max; - z->img_v_max = v_max; - z->img_mcu_w = h_max * 8; - z->img_mcu_h = v_max * 8; - // these sizes can't be more than 17 bits - z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; - z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; - - for (i=0; i < s->img_n; ++i) { - // number of effective pixels (e.g. for non-interleaved MCU) - z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; - z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; - // to simplify generation, we'll allocate enough memory to decode - // the bogus oversized data from using interleaved MCUs and their - // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't - // discard the extra data until colorspace conversion - // - // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) - // so these muls can't overflow with 32-bit ints (which we require) - z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; - z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].coeff = 0; - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].linebuf = NULL; - z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); - if (z->img_comp[i].raw_data == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - // align blocks for idct using mmx/sse - z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); - if (z->progressive) { - // w2, h2 are multiples of 8 (see above) - z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; - z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; - z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); - if (z->img_comp[i].raw_coeff == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); - } - } - - return 1; -} - -// use comparisons since in some cases we handle more than one case (e.g. SOF) -#define stbi__DNL(x) ((x) == 0xdc) -#define stbi__SOI(x) ((x) == 0xd8) -#define stbi__EOI(x) ((x) == 0xd9) -#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) -#define stbi__SOS(x) ((x) == 0xda) - -#define stbi__SOF_progressive(x) ((x) == 0xc2) - -static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) -{ - int m; - z->jfif = 0; - z->app14_color_transform = -1; // valid values are 0,1,2 - z->marker = STBI__MARKER_none; // initialize cached marker to empty - m = stbi__get_marker(z); - if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); - if (scan == STBI__SCAN_type) return 1; - m = stbi__get_marker(z); - while (!stbi__SOF(m)) { - if (!stbi__process_marker(z,m)) return 0; - m = stbi__get_marker(z); - while (m == STBI__MARKER_none) { - // some files have extra padding after their blocks, so ok, we'll scan - if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); - m = stbi__get_marker(z); - } - } - z->progressive = stbi__SOF_progressive(m); - if (!stbi__process_frame_header(z, scan)) return 0; - return 1; -} - -// decode image to YCbCr format -static int stbi__decode_jpeg_image(stbi__jpeg *j) -{ - int m; - for (m = 0; m < 4; m++) { - j->img_comp[m].raw_data = NULL; - j->img_comp[m].raw_coeff = NULL; - } - j->restart_interval = 0; - if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; - m = stbi__get_marker(j); - while (!stbi__EOI(m)) { - if (stbi__SOS(m)) { - if (!stbi__process_scan_header(j)) return 0; - if (!stbi__parse_entropy_coded_data(j)) return 0; - if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } - } - // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 - } - } else if (stbi__DNL(m)) { - int Ld = stbi__get16be(j->s); - stbi__uint32 NL = stbi__get16be(j->s); - if (Ld != 4) stbi__err("bad DNL len", "Corrupt JPEG"); - if (NL != j->s->img_y) stbi__err("bad DNL height", "Corrupt JPEG"); - } else { - if (!stbi__process_marker(j, m)) return 0; - } - m = stbi__get_marker(j); - } - if (j->progressive) - stbi__jpeg_finish(j); - return 1; -} - -// static jfif-centered resampling (across block boundaries) - -typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, - int w, int hs); - -#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) - -static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - STBI_NOTUSED(out); - STBI_NOTUSED(in_far); - STBI_NOTUSED(w); - STBI_NOTUSED(hs); - return in_near; -} - -static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples vertically for every one in input - int i; - STBI_NOTUSED(hs); - for (i=0; i < w; ++i) - out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); - return out; -} - -static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples horizontally for every one in input - int i; - stbi_uc *input = in_near; - - if (w == 1) { - // if only one sample, can't do any interpolation - out[0] = out[1] = input[0]; - return out; - } - - out[0] = input[0]; - out[1] = stbi__div4(input[0]*3 + input[1] + 2); - for (i=1; i < w-1; ++i) { - int n = 3*input[i]+2; - out[i*2+0] = stbi__div4(n+input[i-1]); - out[i*2+1] = stbi__div4(n+input[i+1]); - } - out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); - out[i*2+1] = input[w-1]; - - STBI_NOTUSED(in_far); - STBI_NOTUSED(hs); - - return out; -} - -#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) - -static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i,t0,t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - out[0] = stbi__div4(t1+2); - for (i=1; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); - - STBI_NOTUSED(hs); - - return out; -} - -#if defined(STBI_SSE2) || defined(STBI_NEON) -static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i=0,t0,t1; - - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - // process groups of 8 pixels for as long as we can. - // note we can't handle the last pixel in a row in this loop - // because we need to handle the filter boundary conditions. - for (; i < ((w-1) & ~7); i += 8) { -#if defined(STBI_SSE2) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - __m128i zero = _mm_setzero_si128(); - __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); - __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); - __m128i farw = _mm_unpacklo_epi8(farb, zero); - __m128i nearw = _mm_unpacklo_epi8(nearb, zero); - __m128i diff = _mm_sub_epi16(farw, nearw); - __m128i nears = _mm_slli_epi16(nearw, 2); - __m128i curr = _mm_add_epi16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - __m128i prv0 = _mm_slli_si128(curr, 2); - __m128i nxt0 = _mm_srli_si128(curr, 2); - __m128i prev = _mm_insert_epi16(prv0, t1, 0); - __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - __m128i bias = _mm_set1_epi16(8); - __m128i curs = _mm_slli_epi16(curr, 2); - __m128i prvd = _mm_sub_epi16(prev, curr); - __m128i nxtd = _mm_sub_epi16(next, curr); - __m128i curb = _mm_add_epi16(curs, bias); - __m128i even = _mm_add_epi16(prvd, curb); - __m128i odd = _mm_add_epi16(nxtd, curb); - - // interleave even and odd pixels, then undo scaling. - __m128i int0 = _mm_unpacklo_epi16(even, odd); - __m128i int1 = _mm_unpackhi_epi16(even, odd); - __m128i de0 = _mm_srli_epi16(int0, 4); - __m128i de1 = _mm_srli_epi16(int1, 4); - - // pack and write output - __m128i outv = _mm_packus_epi16(de0, de1); - _mm_storeu_si128((__m128i *) (out + i*2), outv); -#elif defined(STBI_NEON) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - uint8x8_t farb = vld1_u8(in_far + i); - uint8x8_t nearb = vld1_u8(in_near + i); - int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); - int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); - int16x8_t curr = vaddq_s16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - int16x8_t prv0 = vextq_s16(curr, curr, 7); - int16x8_t nxt0 = vextq_s16(curr, curr, 1); - int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); - int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - int16x8_t curs = vshlq_n_s16(curr, 2); - int16x8_t prvd = vsubq_s16(prev, curr); - int16x8_t nxtd = vsubq_s16(next, curr); - int16x8_t even = vaddq_s16(curs, prvd); - int16x8_t odd = vaddq_s16(curs, nxtd); - - // undo scaling and round, then store with even/odd phases interleaved - uint8x8x2_t o; - o.val[0] = vqrshrun_n_s16(even, 4); - o.val[1] = vqrshrun_n_s16(odd, 4); - vst2_u8(out + i*2, o); -#endif - - // "previous" value for next iter - t1 = 3*in_near[i+7] + in_far[i+7]; - } - - t0 = t1; - t1 = 3*in_near[i] + in_far[i]; - out[i*2] = stbi__div16(3*t1 + t0 + 8); - - for (++i; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); - - STBI_NOTUSED(hs); - - return out; -} -#endif - -static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // resample with nearest-neighbor - int i,j; - STBI_NOTUSED(in_far); - for (i=0; i < w; ++i) - for (j=0; j < hs; ++j) - out[i*hs+j] = in_near[i]; - return out; -} - -// this is a reduced-precision calculation of YCbCr-to-RGB introduced -// to make sure the code produces the same results in both SIMD and scalar -#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} - -#if defined(STBI_SSE2) || defined(STBI_NEON) -static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) -{ - int i = 0; - -#ifdef STBI_SSE2 - // step == 3 is pretty ugly on the final interleave, and i'm not convinced - // it's useful in practice (you wouldn't use it for textures, for example). - // so just accelerate step == 4 case. - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - __m128i signflip = _mm_set1_epi8(-0x80); - __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); - __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); - __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); - __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); - __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); - __m128i xw = _mm_set1_epi16(255); // alpha channel - - for (; i+7 < count; i += 8) { - // load - __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); - __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); - __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); - __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 - __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 - - // unpack to short (and left-shift cr, cb by 8) - __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); - __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); - __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); - - // color transform - __m128i yws = _mm_srli_epi16(yw, 4); - __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); - __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); - __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); - __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); - __m128i rws = _mm_add_epi16(cr0, yws); - __m128i gwt = _mm_add_epi16(cb0, yws); - __m128i bws = _mm_add_epi16(yws, cb1); - __m128i gws = _mm_add_epi16(gwt, cr1); - - // descale - __m128i rw = _mm_srai_epi16(rws, 4); - __m128i bw = _mm_srai_epi16(bws, 4); - __m128i gw = _mm_srai_epi16(gws, 4); - - // back to byte, set up for transpose - __m128i brb = _mm_packus_epi16(rw, bw); - __m128i gxb = _mm_packus_epi16(gw, xw); - - // transpose to interleave channels - __m128i t0 = _mm_unpacklo_epi8(brb, gxb); - __m128i t1 = _mm_unpackhi_epi8(brb, gxb); - __m128i o0 = _mm_unpacklo_epi16(t0, t1); - __m128i o1 = _mm_unpackhi_epi16(t0, t1); - - // store - _mm_storeu_si128((__m128i *) (out + 0), o0); - _mm_storeu_si128((__m128i *) (out + 16), o1); - out += 32; - } - } -#endif - -#ifdef STBI_NEON - // in this version, step=3 support would be easy to add. but is there demand? - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - uint8x8_t signflip = vdup_n_u8(0x80); - int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); - int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); - int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); - int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); - - for (; i+7 < count; i += 8) { - // load - uint8x8_t y_bytes = vld1_u8(y + i); - uint8x8_t cr_bytes = vld1_u8(pcr + i); - uint8x8_t cb_bytes = vld1_u8(pcb + i); - int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); - int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); - - // expand to s16 - int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); - int16x8_t crw = vshll_n_s8(cr_biased, 7); - int16x8_t cbw = vshll_n_s8(cb_biased, 7); - - // color transform - int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); - int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); - int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); - int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); - int16x8_t rws = vaddq_s16(yws, cr0); - int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); - int16x8_t bws = vaddq_s16(yws, cb1); - - // undo scaling, round, convert to byte - uint8x8x4_t o; - o.val[0] = vqrshrun_n_s16(rws, 4); - o.val[1] = vqrshrun_n_s16(gws, 4); - o.val[2] = vqrshrun_n_s16(bws, 4); - o.val[3] = vdup_n_u8(255); - - // store, interleaving r/g/b/a - vst4_u8(out, o); - out += 8*4; - } - } -#endif - - for (; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#endif - -// set up the kernels -static void stbi__setup_jpeg(stbi__jpeg *j) -{ - j->idct_block_kernel = stbi__idct_block; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; - -#ifdef STBI_SSE2 - if (stbi__sse2_available()) { - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; - } -#endif - -#ifdef STBI_NEON - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; -#endif -} - -// clean up the temporary component buffers -static void stbi__cleanup_jpeg(stbi__jpeg *j) -{ - stbi__free_jpeg_components(j, j->s->img_n, 0); -} - -typedef struct -{ - resample_row_func resample; - stbi_uc *line0,*line1; - int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion - int ystep; // how far through vertical expansion we are - int ypos; // which pre-expansion row we're on -} stbi__resample; - -// fast 0..255 * 0..255 => 0..255 rounded multiplication -static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) -{ - unsigned int t = x*y + 128; - return (stbi_uc) ((t + (t >>8)) >> 8); -} - -static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) -{ - int n, decode_n, is_rgb; - z->s->img_n = 0; // make stbi__cleanup_jpeg safe - - // validate req_comp - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - - // load a jpeg image from whichever source, but leave in YCbCr format - if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } - - // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; - - is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); - - if (z->s->img_n == 3 && n < 3 && !is_rgb) - decode_n = 1; - else - decode_n = z->s->img_n; - - // resample and color-convert - { - int k; - unsigned int i,j; - stbi_uc *output; - stbi_uc *coutput[4]; - - stbi__resample res_comp[4]; - - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - - // allocate line buffer big enough for upsampling off the edges - // with upsample factor of 4 - z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); - if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - r->hs = z->img_h_max / z->img_comp[k].h; - r->vs = z->img_v_max / z->img_comp[k].v; - r->ystep = r->vs >> 1; - r->w_lores = (z->s->img_x + r->hs-1) / r->hs; - r->ypos = 0; - r->line0 = r->line1 = z->img_comp[k].data; - - if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; - else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; - else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; - else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; - else r->resample = stbi__resample_row_generic; - } - - // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); - if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - // now go ahead and resample - for (j=0; j < z->s->img_y; ++j) { - stbi_uc *out = output + n * z->s->img_x * j; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - int y_bot = r->ystep >= (r->vs >> 1); - coutput[k] = r->resample(z->img_comp[k].linebuf, - y_bot ? r->line1 : r->line0, - y_bot ? r->line0 : r->line1, - r->w_lores, r->hs); - if (++r->ystep >= r->vs) { - r->ystep = 0; - r->line0 = r->line1; - if (++r->ypos < z->img_comp[k].y) - r->line1 += z->img_comp[k].w2; - } - } - if (n >= 3) { - stbi_uc *y = coutput[0]; - if (z->s->img_n == 3) { - if (is_rgb) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = y[i]; - out[1] = coutput[1][i]; - out[2] = coutput[2][i]; - out[3] = 255; - out += n; - } - } else { - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else if (z->s->img_n == 4) { - if (z->app14_color_transform == 0) { // CMYK - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(coutput[0][i], m); - out[1] = stbi__blinn_8x8(coutput[1][i], m); - out[2] = stbi__blinn_8x8(coutput[2][i], m); - out[3] = 255; - out += n; - } - } else if (z->app14_color_transform == 2) { // YCCK - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(255 - out[0], m); - out[1] = stbi__blinn_8x8(255 - out[1], m); - out[2] = stbi__blinn_8x8(255 - out[2], m); - out += n; - } - } else { // YCbCr + alpha? Ignore the fourth channel for now - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else - for (i=0; i < z->s->img_x; ++i) { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; // not used if n==3 - out += n; - } - } else { - if (is_rgb) { - if (n == 1) - for (i=0; i < z->s->img_x; ++i) - *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - else { - for (i=0; i < z->s->img_x; ++i, out += 2) { - out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - out[1] = 255; - } - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); - stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); - stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); - out[0] = stbi__compute_y(r, g, b); - out[1] = 255; - out += n; - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); - out[1] = 255; - out += n; - } - } else { - stbi_uc *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; - } - } - } - stbi__cleanup_jpeg(z); - *out_x = z->s->img_x; - *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output - return output; - } -} - -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - unsigned char* result; - stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); - STBI_NOTUSED(ri); - j->s = s; - stbi__setup_jpeg(j); - result = load_jpeg_image(j, x,y,comp,req_comp); - STBI_FREE(j); - return result; -} - -static int stbi__jpeg_test(stbi__context *s) -{ - int r; - stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); - j->s = s; - stbi__setup_jpeg(j); - r = stbi__decode_jpeg_header(j, STBI__SCAN_type); - stbi__rewind(s); - STBI_FREE(j); - return r; -} - -static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) -{ - if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { - stbi__rewind( j->s ); - return 0; - } - if (x) *x = j->s->img_x; - if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; - return 1; -} - -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) -{ - int result; - stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); - j->s = s; - result = stbi__jpeg_info_raw(j, x, y, comp); - STBI_FREE(j); - return result; -} -#endif - -// public domain zlib decode v0.2 Sean Barrett 2006-11-18 -// simple implementation -// - all input must be provided in an upfront buffer -// - all output is written to a single output buffer (can malloc/realloc) -// performance -// - fast huffman - -#ifndef STBI_NO_ZLIB - -// fast-way is faster to check than jpeg huffman, but slow way is slower -#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables -#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) - -// zlib-style huffman encoding -// (jpegs packs from left, zlib from right, so can't share code) -typedef struct -{ - stbi__uint16 fast[1 << STBI__ZFAST_BITS]; - stbi__uint16 firstcode[16]; - int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; -} stbi__zhuffman; - -stbi_inline static int stbi__bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); - return n; -} - -stbi_inline static int stbi__bit_reverse(int v, int bits) -{ - STBI_ASSERT(bits <= 16); - // to bit reverse n bits, reverse 16 and shift - // e.g. 11 bits, bit reverse and shift away 5 - return stbi__bitreverse16(v) >> (16-bits); -} - -static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; - - // DEFLATE spec for generating codes - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 0, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - if (sizes[i] > (1 << i)) - return stbi__err("bad sizes", "Corrupt PNG"); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); - z->maxcode[i] = code << (16-i); // preshift for inner loop - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; // sentinel - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); - z->size [c] = (stbi_uc ) s; - z->value[c] = (stbi__uint16) i; - if (s <= STBI__ZFAST_BITS) { - int j = stbi__bit_reverse(next_code[s],s); - while (j < (1 << STBI__ZFAST_BITS)) { - z->fast[j] = fastv; - j += (1 << s); - } - } - ++next_code[s]; - } - } - return 1; -} - -// zlib-from-memory implementation for PNG reading -// because PNG allows splitting the zlib stream arbitrarily, -// and it's annoying structurally to have PNG call ZLIB call PNG, -// we require PNG read all the IDATs and combine them into a single -// memory buffer - -typedef struct -{ - stbi_uc *zbuffer, *zbuffer_end; - int num_bits; - stbi__uint32 code_buffer; - - char *zout; - char *zout_start; - char *zout_end; - int z_expandable; - - stbi__zhuffman z_length, z_distance; -} stbi__zbuf; - -stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) -{ - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; -} - -static void stbi__fill_bits(stbi__zbuf *z) -{ - do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); - z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; - z->num_bits += 8; - } while (z->num_bits <= 24); -} - -stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) -{ - unsigned int k; - if (z->num_bits < n) stbi__fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; -} - -static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s,k; - // not resolved by fast table, so compute it the slow way - // use jpeg approach, which requires MSbits at top - k = stbi__bit_reverse(a->code_buffer, 16); - for (s=STBI__ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s == 16) return -1; // invalid code! - // code size is s, so: - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - STBI_ASSERT(z->size[b] == s); - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; -} - -stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b) { - s = b >> 9; - a->code_buffer >>= s; - a->num_bits -= s; - return b & 511; - } - return stbi__zhuffman_decode_slowpath(a, z); -} - -static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes -{ - char *q; - int cur, limit, old_limit; - z->zout = zout; - if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (int) (z->zout - z->zout_start); - limit = old_limit = (int) (z->zout_end - z->zout_start); - while (cur + n > limit) - limit *= 2; - q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); - STBI_NOTUSED(old_limit); - if (q == NULL) return stbi__err("outofmem", "Out of memory"); - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; -} - -static int stbi__zlength_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; - -static int stbi__zlength_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - -static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - -static int stbi__zdist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -static int stbi__parse_huffman_block(stbi__zbuf *a) -{ - char *zout = a->zout; - for(;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); - if (z < 256) { - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes - if (zout >= a->zout_end) { - if (!stbi__zexpand(a, zout, 1)) return 0; - zout = a->zout; - } - *zout++ = (char) z; - } else { - stbi_uc *p; - int len,dist; - if (z == 256) { - a->zout = zout; - return 1; - } - z -= 257; - len = stbi__zlength_base[z]; - if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); - dist = stbi__zdist_base[z]; - if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { - if (!stbi__zexpand(a, zout, len)) return 0; - zout = a->zout; - } - p = (stbi_uc *) (zout - dist); - if (dist == 1) { // run of one byte; common in images. - stbi_uc v = *p; - if (len) { do *zout++ = v; while (--len); } - } else { - if (len) { do *zout++ = *p++; while (--len); } - } - } - } -} - -static int stbi__compute_huffman_codes(stbi__zbuf *a) -{ - static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - stbi__zhuffman z_codelength; - stbi_uc lencodes[286+32+137];//padding for maximum single op - stbi_uc codelength_sizes[19]; - int i,n; - - int hlit = stbi__zreceive(a,5) + 257; - int hdist = stbi__zreceive(a,5) + 1; - int hclen = stbi__zreceive(a,4) + 4; - int ntot = hlit + hdist; - - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = stbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; - } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; - - n = 0; - while (n < ntot) { - int c = stbi__zhuffman_decode(a, &z_codelength); - if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); - if (c < 16) - lencodes[n++] = (stbi_uc) c; - else { - stbi_uc fill = 0; - if (c == 16) { - c = stbi__zreceive(a,2)+3; - if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); - fill = lencodes[n-1]; - } else if (c == 17) - c = stbi__zreceive(a,3)+3; - else { - STBI_ASSERT(c == 18); - c = stbi__zreceive(a,7)+11; - } - if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); - memset(lencodes+n, fill, c); - n += c; - } - } - if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; - return 1; -} - -static int stbi__parse_uncompressed_block(stbi__zbuf *a) -{ - stbi_uc header[4]; - int len,nlen,k; - if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); // discard - // drain the bit-packed data into header - k = 0; - while (a->num_bits > 0) { - header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check - a->code_buffer >>= 8; - a->num_bits -= 8; - } - STBI_ASSERT(a->num_bits == 0); - // now fill header the normal way - while (k < 4) - header[k++] = stbi__zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); - if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, a->zout, len)) return 0; - memcpy(a->zout, a->zbuffer, len); - a->zbuffer += len; - a->zout += len; - return 1; -} - -static int stbi__parse_zlib_header(stbi__zbuf *a) -{ - int cmf = stbi__zget8(a); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = stbi__zget8(a); - if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png - if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; -} - -static const stbi_uc stbi__zdefault_length[288] = -{ - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 -}; -static const stbi_uc stbi__zdefault_distance[32] = -{ - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 -}; -/* -Init algorithm: -{ - int i; // use <= to match clearly with spec - for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; - for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; - for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; - for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; - - for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; -} -*/ - -static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) -{ - int final, type; - if (parse_header) - if (!stbi__parse_zlib_header(a)) return 0; - a->num_bits = 0; - a->code_buffer = 0; - do { - final = stbi__zreceive(a,1); - type = stbi__zreceive(a,2); - if (type == 0) { - if (!stbi__parse_uncompressed_block(a)) return 0; - } else if (type == 3) { - return 0; - } else { - if (type == 1) { - // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; - } else { - if (!stbi__compute_huffman_codes(a)) return 0; - } - if (!stbi__parse_huffman_block(a)) return 0; - } - } while (!final); - return 1; -} - -static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) -{ - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; - - return stbi__parse_zlib(a, parse_header); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) -{ - return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) - return (int) (a.zout - a.zout_start); - else - return -1; -} - -STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(16384); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer+len; - if (stbi__do_zlib(&a, p, 16384, 1, 0)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) - return (int) (a.zout - a.zout_start); - else - return -1; -} -#endif - -// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 -// simple implementation -// - only 8-bit samples -// - no CRC checking -// - allocates lots of intermediate memory -// - avoids problem of streaming data between subsystems -// - avoids explicit window management -// performance -// - uses stb_zlib, a PD zlib implementation with fast huffman decoding - -#ifndef STBI_NO_PNG -typedef struct -{ - stbi__uint32 length; - stbi__uint32 type; -} stbi__pngchunk; - -static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) -{ - stbi__pngchunk c; - c.length = stbi__get32be(s); - c.type = stbi__get32be(s); - return c; -} - -static int stbi__check_png_header(stbi__context *s) -{ - static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); - return 1; -} - -typedef struct -{ - stbi__context *s; - stbi_uc *idata, *expanded, *out; - int depth; -} stbi__png; - - -enum { - STBI__F_none=0, - STBI__F_sub=1, - STBI__F_up=2, - STBI__F_avg=3, - STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static stbi_uc first_row_filter[5] = -{ - STBI__F_none, - STBI__F_sub, - STBI__F_none, - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static int stbi__paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; -} - -static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; - -// create the png data from post-deflated data -static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) -{ - int bytes = (depth == 16? 2 : 1); - stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n*bytes; - stbi__uint32 img_len, img_width_bytes; - int k; - int img_n = s->img_n; // copy it into a local for later - - int output_bytes = out_n*bytes; - int filter_bytes = img_n*bytes; - int width = x; - - STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into - if (!a->out) return stbi__err("outofmem", "Out of memory"); - - img_width_bytes = (((img_n * x * depth) + 7) >> 3); - img_len = (img_width_bytes + 1) * y; - // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, - // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), - // so just check for raw_len < img_len always. - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); - - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior; - int filter = *raw++; - - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); - - if (depth < 8) { - STBI_ASSERT(img_width_bytes <= x); - cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place - filter_bytes = 1; - width = img_width_bytes; - } - prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above - - // if first row, use special filter that doesn't sample previous row - if (j == 0) filter = first_row_filter[filter]; - - // handle first byte explicitly - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } - } - - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else if (depth == 16) { - if (img_n != out_n) { - cur[filter_bytes] = 255; // first pixel top byte - cur[filter_bytes+1] = 255; // first pixel bottom byte - } - raw += filter_bytes; - cur += output_bytes; - prior += output_bytes; - } else { - raw += 1; - cur += 1; - prior += 1; - } - - // this is a little gross, so that we don't switch per-pixel or per-component - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*filter_bytes; - #define STBI__CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - // "none" filter turns into a memcpy here; make that explicit. - case STBI__F_none: memcpy(cur, raw, nk); break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; - } - #undef STBI__CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define STBI__CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ - for (k=0; k < filter_bytes; ++k) - switch (filter) { - STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; - } - #undef STBI__CASE - - // the loop above sets the high byte of the pixels' alpha, but for - // 16 bit png files we also need the low byte set. we'll do that here. - if (depth == 16) { - cur = a->out + stride*j; // start at the beginning of the row again - for (i=0; i < x; ++i,cur+=output_bytes) { - cur[filter_bytes+1] = 255; - } - } - } - } - - // we make a separate pass to expand bits to pixels; for performance, - // this could run two scanlines behind the above code, so it won't - // intefere with filtering but will still be in the cache. - if (depth < 8) { - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit - // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range - - // note that the final byte might overshoot and write more data than desired. - // we can allocate enough data that this never writes out of memory, but it - // could also overwrite the next scanline. can it overwrite non-empty data - // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. - // so we need to explicitly clamp the final ones - - if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); - } - if (k > 0) *cur++ = scale * ((*in >> 4) ); - } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); - } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); - } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); - } - if (img_n != out_n) { - int q; - // insert alpha = 255 - cur = a->out + stride*j; - if (img_n == 1) { - for (q=x-1; q >= 0; --q) { - cur[q*2+1] = 255; - cur[q*2+0] = cur[q]; - } - } else { - STBI_ASSERT(img_n == 3); - for (q=x-1; q >= 0; --q) { - cur[q*4+3] = 255; - cur[q*4+2] = cur[q*3+2]; - cur[q*4+1] = cur[q*3+1]; - cur[q*4+0] = cur[q*3+0]; - } - } - } - } - } else if (depth == 16) { - // force the image data from big-endian to platform-native. - // this is done in a separate pass due to the decoding relying - // on the data being untouched, but could probably be done - // per-line during decode if care is taken. - stbi_uc *cur = a->out; - stbi__uint16 *cur16 = (stbi__uint16*)cur; - - for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { - *cur16 = (cur[0] << 8) | cur[1]; - } - } - - return 1; -} - -static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) -{ - int bytes = (depth == 16 ? 2 : 1); - int out_bytes = out_n * bytes; - stbi_uc *final; - int p; - if (!interlaced) - return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); - - // de-interlacing - final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); - for (p=0; p < 7; ++p) { - int xorig[] = { 0,4,0,2,0,1,0 }; - int yorig[] = { 0,0,4,0,2,0,1 }; - int xspc[] = { 8,8,4,4,2,2,1 }; - int yspc[] = { 8,8,8,4,4,2,2 }; - int i,j,x,y; - // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 - x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; - y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; - if (x && y) { - stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { - STBI_FREE(final); - return 0; - } - for (j=0; j < y; ++j) { - for (i=0; i < x; ++i) { - int out_y = j*yspc[p]+yorig[p]; - int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, - a->out + (j*x+i)*out_bytes, out_bytes); - } - } - STBI_FREE(a->out); - image_data += img_len; - image_data_len -= img_len; - } - } - a->out = final; - - return 1; -} - -static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - // compute color-based transparency, assuming we've - // already got 255 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi__uint16 *p = (stbi__uint16*) z->out; - - // compute color-based transparency, assuming we've - // already got 65535 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i = 0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 65535); - p += 2; - } - } else { - for (i = 0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) -{ - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi_uc *p, *temp_out, *orig = a->out; - - p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); - - // between here and free(out) below, exitting would leak - temp_out = p; - - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - STBI_FREE(a->out); - a->out = temp_out; - - STBI_NOTUSED(len); - - return 1; -} - -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; - -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; -} - -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag = flag_true_if_should_convert; -} - -static void stbi__de_iphone(stbi__png *z) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - if (s->img_out_n == 3) { // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; - } - } else { - STBI_ASSERT(s->img_out_n == 4); - if (stbi__unpremultiply_on_load) { - // convert bgr to rgb and unpremultiply - for (i=0; i < pixel_count; ++i) { - stbi_uc a = p[3]; - stbi_uc t = p[0]; - if (a) { - stbi_uc half = a / 2; - p[0] = (p[2] * 255 + half) / a; - p[1] = (p[1] * 255 + half) / a; - p[2] = ( t * 255 + half) / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } - } - } -} - -#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) -{ - stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]; - stbi__uint16 tc16[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, is_iphone=0; - stbi__context *s = z->s; - - z->expanded = NULL; - z->idata = NULL; - z->out = NULL; - - if (!stbi__check_png_header(s)) return 0; - - if (scan == STBI__SCAN_type) return 1; - - for (;;) { - stbi__pngchunk c = stbi__get_chunk_header(s); - switch (c.type) { - case STBI__PNG_TYPE('C','g','B','I'): - is_iphone = 1; - stbi__skip(s, c.length); - break; - case STBI__PNG_TYPE('I','H','D','R'): { - int comp,filter; - if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); - first = 0; - if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); - color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); - comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); - filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); - interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; - } else { - // if paletted, then pal_n is our final components, and - // img_n is # components to decompress/filter. - s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS - } - break; - } - - case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = stbi__get8(s); - palette[i*4+1] = stbi__get8(s); - palette[i*4+2] = stbi__get8(s); - palette[i*4+3] = 255; - } - break; - } - - case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = stbi__get8(s); - } else { - if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); - has_trans = 1; - if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is - } else { - for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger - } - } - break; - } - - case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } - if ((int)(ioff + c.length) < (int)ioff) return 0; - if (ioff + c.length > idata_limit) { - stbi__uint32 idata_limit_old = idata_limit; - stbi_uc *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - STBI_NOTUSED(idata_limit_old); - p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); - z->idata = p; - } - if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); - ioff += c.length; - break; - } - - case STBI__PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len, bpl; - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); - // initial guess for decoded data size to avoid unnecessary reallocs - bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component - raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); - if (z->expanded == NULL) return 0; // zlib should set error - STBI_FREE(z->idata); z->idata = NULL; - if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - s->img_out_n = s->img_n+1; - else - s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; - if (has_trans) { - if (z->depth == 16) { - if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; - } else { - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; - } - } - if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) - stbi__de_iphone(z); - if (pal_img_n) { - // pal_img_n == 3 or 4 - s->img_n = pal_img_n; // record the actual colors we had - s->img_out_n = pal_img_n; - if (req_comp >= 3) s->img_out_n = req_comp; - if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) - return 0; - } else if (has_trans) { - // non-paletted image with tRNS -> source image has (constant) alpha - ++s->img_n; - } - STBI_FREE(z->expanded); z->expanded = NULL; - return 1; - } - - default: - // if critical, fail - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if ((c.type & (1 << 29)) == 0) { - #ifndef STBI_NO_FAILURE_STRINGS - // not threadsafe - static char invalid_chunk[] = "XXXX PNG chunk not known"; - invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); - invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); - invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); - invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); - #endif - return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); - } - stbi__skip(s, c.length); - break; - } - // end of PNG chunk, read and skip CRC - stbi__get32be(s); - } -} - -static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) -{ - void *result=NULL; - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth < 8) - ri->bits_per_channel = 8; - else - ri->bits_per_channel = p->depth; - result = p->out; - p->out = NULL; - if (req_comp && req_comp != p->s->img_out_n) { - if (ri->bits_per_channel == 8) - result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - else - result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - p->s->img_out_n = req_comp; - if (result == NULL) return result; - } - *x = p->s->img_x; - *y = p->s->img_y; - if (n) *n = p->s->img_n; - } - STBI_FREE(p->out); p->out = NULL; - STBI_FREE(p->expanded); p->expanded = NULL; - STBI_FREE(p->idata); p->idata = NULL; - - return result; -} - -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi__png p; - p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp, ri); -} - -static int stbi__png_test(stbi__context *s) -{ - int r; - r = stbi__check_png_header(s); - stbi__rewind(s); - return r; -} - -static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) -{ - if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { - stbi__rewind( p->s ); - return 0; - } - if (x) *x = p->s->img_x; - if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n; - return 1; -} - -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__png p; - p.s = s; - return stbi__png_info_raw(&p, x, y, comp); -} -#endif - -// Microsoft/Windows BMP image - -#ifndef STBI_NO_BMP -static int stbi__bmp_test_raw(stbi__context *s) -{ - int r; - int sz; - if (stbi__get8(s) != 'B') return 0; - if (stbi__get8(s) != 'M') return 0; - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - stbi__get32le(s); // discard data offset - sz = stbi__get32le(s); - r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); - return r; -} - -static int stbi__bmp_test(stbi__context *s) -{ - int r = stbi__bmp_test_raw(s); - stbi__rewind(s); - return r; -} - - -// returns 0..31 for the highest set bit -static int stbi__high_bit(unsigned int z) -{ - int n=0; - if (z == 0) return -1; - if (z >= 0x10000) n += 16, z >>= 16; - if (z >= 0x00100) n += 8, z >>= 8; - if (z >= 0x00010) n += 4, z >>= 4; - if (z >= 0x00004) n += 2, z >>= 2; - if (z >= 0x00002) n += 1, z >>= 1; - return n; -} - -static int stbi__bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; -} - -static int stbi__shiftsigned(int v, int shift, int bits) -{ - int result; - int z=0; - - if (shift < 0) v <<= -shift; - else v >>= shift; - result = v; - - z = bits; - while (z < 8) { - result += v >> z; - z += bits; - } - return result; -} - -typedef struct -{ - int bpp, offset, hsz; - unsigned int mr,mg,mb,ma, all_a; -} stbi__bmp_data; - -static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) -{ - int hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - info->offset = stbi__get32le(s); - info->hsz = hsz = stbi__get32le(s); - info->mr = info->mg = info->mb = info->ma = 0; - - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); - if (hsz == 12) { - s->img_x = stbi__get16le(s); - s->img_y = stbi__get16le(s); - } else { - s->img_x = stbi__get32le(s); - s->img_y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); - info->bpp = stbi__get16le(s); - if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); - if (hsz != 12) { - int compress = stbi__get32le(s); - if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); - stbi__get32le(s); // discard sizeof - stbi__get32le(s); // discard hres - stbi__get32le(s); // discard vres - stbi__get32le(s); // discard colorsused - stbi__get32le(s); // discard max important - if (hsz == 40 || hsz == 56) { - if (hsz == 56) { - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - } - if (info->bpp == 16 || info->bpp == 32) { - if (compress == 0) { - if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } - } else if (compress == 3) { - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - // not documented, but generated by photoshop and handled by mspaint - if (info->mr == info->mg && info->mg == info->mb) { - // ?!?!? - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else { - int i; - if (hsz != 108 && hsz != 124) - return stbi__errpuc("bad BMP", "bad BMP"); - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - info->ma = stbi__get32le(s); - stbi__get32le(s); // discard color space - for (i=0; i < 12; ++i) - stbi__get32le(s); // discard color space parameters - if (hsz == 124) { - stbi__get32le(s); // discard rendering intent - stbi__get32le(s); // discard offset of profile data - stbi__get32le(s); // discard size of profile data - stbi__get32le(s); // discard reserved - } - } - } - return (void *) 1; -} - - -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - unsigned int mr=0,mg=0,mb=0,ma=0, all_a; - stbi_uc pal[256][4]; - int psize=0,i,j,width; - int flip_vertically, pad, target; - stbi__bmp_data info; - STBI_NOTUSED(ri); - - info.all_a = 255; - if (stbi__bmp_parse_header(s, &info) == NULL) - return NULL; // error code already set - - flip_vertically = ((int) s->img_y) > 0; - s->img_y = abs((int) s->img_y); - - mr = info.mr; - mg = info.mg; - mb = info.mb; - ma = info.ma; - all_a = info.all_a; - - if (info.hsz == 12) { - if (info.bpp < 24) - psize = (info.offset - 14 - 24) / 3; - } else { - if (info.bpp < 16) - psize = (info.offset - 14 - info.hsz) >> 2; - } - - s->img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 - target = req_comp; - else - target = s->img_n; // if they want monochrome, we'll post-convert - - // sanity-check size - if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) - return stbi__errpuc("too large", "Corrupt BMP"); - - out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - if (info.bpp < 16) { - int z=0; - if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } - for (i=0; i < psize; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - if (info.hsz != 12) stbi__get8(s); - pal[i][3] = 255; - } - stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); - if (info.bpp == 4) width = (s->img_x + 1) >> 1; - else if (info.bpp == 8) width = s->img_x; - else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } - pad = (-width)&3; - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=stbi__get8(s),v2=0; - if (info.bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (info.bpp == 8) ? stbi__get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - } - stbi__skip(s, pad); - } - } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; - int z = 0; - int easy=0; - stbi__skip(s, info.offset - 14 - info.hsz); - if (info.bpp == 24) width = 3 * s->img_x; - else if (info.bpp == 16) width = 2*s->img_x; - else /* bpp = 32 and pad = 0 */ width=0; - pad = (-width) & 3; - if (info.bpp == 24) { - easy = 1; - } else if (info.bpp == 32) { - if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) - easy = 2; - } - if (!easy) { - if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - // right shift amt to put high bit in position #7 - rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); - gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); - bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); - ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); - } - for (j=0; j < (int) s->img_y; ++j) { - if (easy) { - for (i=0; i < (int) s->img_x; ++i) { - unsigned char a; - out[z+2] = stbi__get8(s); - out[z+1] = stbi__get8(s); - out[z+0] = stbi__get8(s); - z += 3; - a = (easy == 2 ? stbi__get8(s) : 255); - all_a |= a; - if (target == 4) out[z++] = a; - } - } else { - int bpp = info.bpp; - for (i=0; i < (int) s->img_x; ++i) { - stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); - int a; - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); - a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); - all_a |= a; - if (target == 4) out[z++] = STBI__BYTECAST(a); - } - } - stbi__skip(s, pad); - } - } - - // if alpha channel is all 0s, replace with all 255s - if (target == 4 && all_a == 0) - for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) - out[i] = 255; - - if (flip_vertically) { - stbi_uc t; - for (j=0; j < (int) s->img_y>>1; ++j) { - stbi_uc *p1 = out + j *s->img_x*target; - stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; - for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i], p1[i] = p2[i], p2[i] = t; - } - } - } - - if (req_comp && req_comp != target) { - out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - return out; -} -#endif - -// Targa Truevision - TGA -// by Jonathan Dummer -#ifndef STBI_NO_TGA -// returns STBI_rgb or whatever, 0 on error -static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) -{ - // only RGB or RGBA (incl. 16bit) or grey allowed - if(is_rgb16) *is_rgb16 = 0; - switch(bits_per_pixel) { - case 8: return STBI_grey; - case 16: if(is_grey) return STBI_grey_alpha; - // else: fall-through - case 15: if(is_rgb16) *is_rgb16 = 1; - return STBI_rgb; - case 24: // fall-through - case 32: return bits_per_pixel/8; - default: return 0; - } -} - -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) -{ - int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; - int sz, tga_colormap_type; - stbi__get8(s); // discard Offset - tga_colormap_type = stbi__get8(s); // colormap type - if( tga_colormap_type > 1 ) { - stbi__rewind(s); - return 0; // only RGB or indexed allowed - } - tga_image_type = stbi__get8(s); // image type - if ( tga_colormap_type == 1 ) { // colormapped (paletted) image - if (tga_image_type != 1 && tga_image_type != 9) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip image x and y origin - tga_colormap_bpp = sz; - } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE - if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { - stbi__rewind(s); - return 0; // only RGB or grey allowed, +/- RLE - } - stbi__skip(s,9); // skip colormap specification and image x/y origin - tga_colormap_bpp = 0; - } - tga_w = stbi__get16le(s); - if( tga_w < 1 ) { - stbi__rewind(s); - return 0; // test width - } - tga_h = stbi__get16le(s); - if( tga_h < 1 ) { - stbi__rewind(s); - return 0; // test height - } - tga_bits_per_pixel = stbi__get8(s); // bits per pixel - stbi__get8(s); // ignore alpha bits - if (tga_colormap_bpp != 0) { - if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { - // when using a colormap, tga_bits_per_pixel is the size of the indexes - // I don't think anything but 8 or 16bit indexes makes sense - stbi__rewind(s); - return 0; - } - tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); - } else { - tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); - } - if(!tga_comp) { - stbi__rewind(s); - return 0; - } - if (x) *x = tga_w; - if (y) *y = tga_h; - if (comp) *comp = tga_comp; - return 1; // seems to have passed everything -} - -static int stbi__tga_test(stbi__context *s) -{ - int res = 0; - int sz, tga_color_type; - stbi__get8(s); // discard Offset - tga_color_type = stbi__get8(s); // color type - if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed - sz = stbi__get8(s); // image type - if ( tga_color_type == 1 ) { // colormapped (paletted) image - if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; - stbi__skip(s,4); // skip image x and y origin - } else { // "normal" image w/o colormap - if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE - stbi__skip(s,9); // skip colormap specification and image x/y origin - } - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height - sz = stbi__get8(s); // bits per pixel - if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; - - res = 1; // if we got this far, everything's good and we can return 1 instead of 0 - -errorEnd: - stbi__rewind(s); - return res; -} - -// read 16bit value and convert to 24bit RGB -static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) -{ - stbi__uint16 px = (stbi__uint16)stbi__get16le(s); - stbi__uint16 fiveBitMask = 31; - // we have 3 channels with 5bits each - int r = (px >> 10) & fiveBitMask; - int g = (px >> 5) & fiveBitMask; - int b = px & fiveBitMask; - // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later - out[0] = (stbi_uc)((r * 255)/31); - out[1] = (stbi_uc)((g * 255)/31); - out[2] = (stbi_uc)((b * 255)/31); - - // some people claim that the most significant bit might be used for alpha - // (possibly if an alpha-bit is set in the "image descriptor byte") - // but that only made 16bit test images completely translucent.. - // so let's treat all 15 and 16bit TGAs as RGB with no alpha. -} - -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - // read in the TGA header stuff - int tga_offset = stbi__get8(s); - int tga_indexed = stbi__get8(s); - int tga_image_type = stbi__get8(s); - int tga_is_RLE = 0; - int tga_palette_start = stbi__get16le(s); - int tga_palette_len = stbi__get16le(s); - int tga_palette_bits = stbi__get8(s); - int tga_x_origin = stbi__get16le(s); - int tga_y_origin = stbi__get16le(s); - int tga_width = stbi__get16le(s); - int tga_height = stbi__get16le(s); - int tga_bits_per_pixel = stbi__get8(s); - int tga_comp, tga_rgb16=0; - int tga_inverted = stbi__get8(s); - // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) - // image data - unsigned char *tga_data; - unsigned char *tga_palette = NULL; - int i, j; - unsigned char raw_data[4] = {0}; - int RLE_count = 0; - int RLE_repeating = 0; - int read_next_pixel = 1; - STBI_NOTUSED(ri); - - // do a tiny bit of precessing - if ( tga_image_type >= 8 ) - { - tga_image_type -= 8; - tga_is_RLE = 1; - } - tga_inverted = 1 - ((tga_inverted >> 5) & 1); - - // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); - else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); - - if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency - return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); - - // tga info - *x = tga_width; - *y = tga_height; - if (comp) *comp = tga_comp; - - if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) - return stbi__errpuc("too large", "Corrupt TGA"); - - tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); - if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); - - // skip to the data's starting position (offset usually = 0) - stbi__skip(s, tga_offset ); - - if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { - for (i=0; i < tga_height; ++i) { - int row = tga_inverted ? tga_height -i - 1 : i; - stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; - stbi__getn(s, tga_row, tga_width * tga_comp); - } - } else { - // do I need to load a palette? - if ( tga_indexed) - { - // any data to skip? (offset usually = 0) - stbi__skip(s, tga_palette_start ); - // load the palette - tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); - if (!tga_palette) { - STBI_FREE(tga_data); - return stbi__errpuc("outofmem", "Out of memory"); - } - if (tga_rgb16) { - stbi_uc *pal_entry = tga_palette; - STBI_ASSERT(tga_comp == STBI_rgb); - for (i=0; i < tga_palette_len; ++i) { - stbi__tga_read_rgb16(s, pal_entry); - pal_entry += tga_comp; - } - } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { - STBI_FREE(tga_data); - STBI_FREE(tga_palette); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } - } - // load the data - for (i=0; i < tga_width * tga_height; ++i) - { - // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? - if ( tga_is_RLE ) - { - if ( RLE_count == 0 ) - { - // yep, get the next byte as a RLE command - int RLE_cmd = stbi__get8(s); - RLE_count = 1 + (RLE_cmd & 127); - RLE_repeating = RLE_cmd >> 7; - read_next_pixel = 1; - } else if ( !RLE_repeating ) - { - read_next_pixel = 1; - } - } else - { - read_next_pixel = 1; - } - // OK, if I need to read a pixel, do it now - if ( read_next_pixel ) - { - // load however much data we did have - if ( tga_indexed ) - { - // read in index, then perform the lookup - int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); - if ( pal_idx >= tga_palette_len ) { - // invalid index - pal_idx = 0; - } - pal_idx *= tga_comp; - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = tga_palette[pal_idx+j]; - } - } else if(tga_rgb16) { - STBI_ASSERT(tga_comp == STBI_rgb); - stbi__tga_read_rgb16(s, raw_data); - } else { - // read in the data raw - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = stbi__get8(s); - } - } - // clear the reading flag for the next pixel - read_next_pixel = 0; - } // end of reading a pixel - - // copy data - for (j = 0; j < tga_comp; ++j) - tga_data[i*tga_comp+j] = raw_data[j]; - - // in case we're in RLE mode, keep counting down - --RLE_count; - } - // do I need to invert the image? - if ( tga_inverted ) - { - for (j = 0; j*2 < tga_height; ++j) - { - int index1 = j * tga_width * tga_comp; - int index2 = (tga_height - 1 - j) * tga_width * tga_comp; - for (i = tga_width * tga_comp; i > 0; --i) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; - } - } - } - // clear my palette, if I had one - if ( tga_palette != NULL ) - { - STBI_FREE( tga_palette ); - } - } - - // swap RGB - if the source data was RGB16, it already is in the right order - if (tga_comp >= 3 && !tga_rgb16) - { - unsigned char* tga_pixel = tga_data; - for (i=0; i < tga_width * tga_height; ++i) - { - unsigned char temp = tga_pixel[0]; - tga_pixel[0] = tga_pixel[2]; - tga_pixel[2] = temp; - tga_pixel += tga_comp; - } - } - - // convert to target component count - if (req_comp && req_comp != tga_comp) - tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); - - // the things I do to get rid of an error message, and yet keep - // Microsoft's C compilers happy... [8^( - tga_palette_start = tga_palette_len = tga_palette_bits = - tga_x_origin = tga_y_origin = 0; - // OK, done - return tga_data; -} -#endif - -// ************************************************************************************************* -// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB - -#ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s) -{ - int r = (stbi__get32be(s) == 0x38425053); - stbi__rewind(s); - return r; -} - -static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) -{ - int count, nleft, len; - - count = 0; - while ((nleft = pixelCount - count) > 0) { - len = stbi__get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - if (len > nleft) return 0; // corrupt data - count += len; - while (len) { - *p = stbi__get8(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi_uc val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len = 257 - len; - if (len > nleft) return 0; // corrupt data - val = stbi__get8(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } - } - - return 1; -} - -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - int pixelCount; - int channelCount, compression; - int channel, i; - int bitdepth; - int w,h; - stbi_uc *out; - STBI_NOTUSED(ri); - - // Check identifier - if (stbi__get32be(s) != 0x38425053) // "8BPS" - return stbi__errpuc("not PSD", "Corrupt PSD image"); - - // Check file type version. - if (stbi__get16be(s) != 1) - return stbi__errpuc("wrong version", "Unsupported version of PSD image"); - - // Skip 6 reserved bytes. - stbi__skip(s, 6 ); - - // Read the number of channels (R, G, B, A, etc). - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) - return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); - - // Read the rows and columns of the image. - h = stbi__get32be(s); - w = stbi__get32be(s); - - // Make sure the depth is 8 bits. - bitdepth = stbi__get16be(s); - if (bitdepth != 8 && bitdepth != 16) - return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); - - // Make sure the color mode is RGB. - // Valid options are: - // 0: Bitmap - // 1: Grayscale - // 2: Indexed color - // 3: RGB color - // 4: CMYK color - // 7: Multichannel - // 8: Duotone - // 9: Lab color - if (stbi__get16be(s) != 3) - return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); - - // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) - stbi__skip(s,stbi__get32be(s) ); - - // Skip the image resources. (resolution, pen tool paths, etc) - stbi__skip(s, stbi__get32be(s) ); - - // Skip the reserved data. - stbi__skip(s, stbi__get32be(s) ); - - // Find out if the data is compressed. - // Known values: - // 0: no compression - // 1: RLE compressed - compression = stbi__get16be(s); - if (compression > 1) - return stbi__errpuc("bad compression", "PSD has an unknown compression format"); - - // Check size - if (!stbi__mad3sizes_valid(4, w, h, 0)) - return stbi__errpuc("too large", "Corrupt PSD"); - - // Create the destination image. - - if (!compression && bitdepth == 16 && bpc == 16) { - out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); - ri->bits_per_channel = 16; - } else - out = (stbi_uc *) stbi__malloc(4 * w*h); - - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - pixelCount = w*h; - - // Initialize the data to zero. - //memset( out, 0, pixelCount * 4 ); - - // Finally, the image data. - if (compression) { - // RLE as used by .PSD and .TIFF - // Loop until you get the number of unpacked bytes you are expecting: - // Read the next source byte into n. - // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. - // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. - // Else if n is 128, noop. - // Endloop - - // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, - // which we're going to just skip. - stbi__skip(s, h * channelCount * 2 ); - - // Read the RLE data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; - - p = out+channel; - if (channel >= channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++, p += 4) - *p = (channel == 3 ? 255 : 0); - } else { - // Read the RLE data. - if (!stbi__psd_decode_rle(s, p, pixelCount)) { - STBI_FREE(out); - return stbi__errpuc("corrupt", "bad RLE data"); - } - } - } - - } else { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. - - // Read the data by channel. - for (channel = 0; channel < 4; channel++) { - if (channel >= channelCount) { - // Fill this channel with default data. - if (bitdepth == 16 && bpc == 16) { - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - stbi__uint16 val = channel == 3 ? 65535 : 0; - for (i = 0; i < pixelCount; i++, q += 4) - *q = val; - } else { - stbi_uc *p = out+channel; - stbi_uc val = channel == 3 ? 255 : 0; - for (i = 0; i < pixelCount; i++, p += 4) - *p = val; - } - } else { - if (ri->bits_per_channel == 16) { // output bpc - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - for (i = 0; i < pixelCount; i++, q += 4) - *q = (stbi__uint16) stbi__get16be(s); - } else { - stbi_uc *p = out+channel; - if (bitdepth == 16) { // input bpc - for (i = 0; i < pixelCount; i++, p += 4) - *p = (stbi_uc) (stbi__get16be(s) >> 8); - } else { - for (i = 0; i < pixelCount; i++, p += 4) - *p = stbi__get8(s); - } - } - } - } - } - - // remove weird white matte from PSD - if (channelCount >= 4) { - if (ri->bits_per_channel == 16) { - for (i=0; i < w*h; ++i) { - stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; - if (pixel[3] != 0 && pixel[3] != 65535) { - float a = pixel[3] / 65535.0f; - float ra = 1.0f / a; - float inv_a = 65535.0f * (1 - ra); - pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); - pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); - pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); - } - } - } else { - for (i=0; i < w*h; ++i) { - unsigned char *pixel = out + 4*i; - if (pixel[3] != 0 && pixel[3] != 255) { - float a = pixel[3] / 255.0f; - float ra = 1.0f / a; - float inv_a = 255.0f * (1 - ra); - pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); - pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); - pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); - } - } - } - } - - // convert to desired output format - if (req_comp && req_comp != 4) { - if (ri->bits_per_channel == 16) - out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); - else - out = stbi__convert_format(out, 4, req_comp, w, h); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - if (comp) *comp = 4; - *y = h; - *x = w; - - return out; -} -#endif - -// ************************************************************************************************* -// Softimage PIC loader -// by Tom Seddon -// -// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format -// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ - -#ifndef STBI_NO_PIC -static int stbi__pic_is4(stbi__context *s,const char *str) -{ - int i; - for (i=0; i<4; ++i) - if (stbi__get8(s) != (stbi_uc)str[i]) - return 0; - - return 1; -} - -static int stbi__pic_test_core(stbi__context *s) -{ - int i; - - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) - return 0; - - for(i=0;i<84;++i) - stbi__get8(s); - - if (!stbi__pic_is4(s,"PICT")) - return 0; - - return 1; -} - -typedef struct -{ - stbi_uc size,type,channel; -} stbi__pic_packet; - -static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) -{ - int mask=0x80, i; - - for (i=0; i<4; ++i, mask>>=1) { - if (channel & mask) { - if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); - dest[i]=stbi__get8(s); - } - } - - return dest; -} - -static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) -{ - int mask=0x80,i; - - for (i=0;i<4; ++i, mask>>=1) - if (channel&mask) - dest[i]=src[i]; -} - -static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) -{ - int act_comp=0,num_packets=0,y,chained; - stbi__pic_packet packets[10]; - - // this will (should...) cater for even some bizarre stuff like having data - // for the same channel in multiple packets. - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return stbi__errpuc("bad format","too many packets"); - - packet = &packets[num_packets++]; - - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - - act_comp |= packet->channel; - - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); - if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? - - for(y=0; ytype) { - default: - return stbi__errpuc("bad format","packet has bad compression type"); - - case 0: {//uncompressed - int x; - - for(x=0;xchannel,dest)) - return 0; - break; - } - - case 1://Pure RLE - { - int left=width, i; - - while (left>0) { - stbi_uc count,value[4]; - - count=stbi__get8(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); - - if (count > left) - count = (stbi_uc) left; - - if (!stbi__readval(s,packet->channel,value)) return 0; - - for(i=0; ichannel,dest,value); - left -= count; - } - } - break; - - case 2: {//Mixed RLE - int left=width; - while (left>0) { - int count = stbi__get8(s), i; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); - - if (count >= 128) { // Repeated - stbi_uc value[4]; - - if (count==128) - count = stbi__get16be(s); - else - count -= 127; - if (count > left) - return stbi__errpuc("bad file","scanline overrun"); - - if (!stbi__readval(s,packet->channel,value)) - return 0; - - for(i=0;ichannel,dest,value); - } else { // Raw - ++count; - if (count>left) return stbi__errpuc("bad file","scanline overrun"); - - for(i=0;ichannel,dest)) - return 0; - } - left-=count; - } - break; - } - } - } - } - - return result; -} - -static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) -{ - stbi_uc *result; - int i, x,y, internal_comp; - STBI_NOTUSED(ri); - - if (!comp) comp = &internal_comp; - - for (i=0; i<92; ++i) - stbi__get8(s); - - x = stbi__get16be(s); - y = stbi__get16be(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); - if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); - - stbi__get32be(s); //skip `ratio' - stbi__get16be(s); //skip `fields' - stbi__get16be(s); //skip `pad' - - // intermediate buffer is RGBA - result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); - memset(result, 0xff, x*y*4); - - if (!stbi__pic_load_core(s,x,y,comp, result)) { - STBI_FREE(result); - result=0; - } - *px = x; - *py = y; - if (req_comp == 0) req_comp = *comp; - result=stbi__convert_format(result,4,req_comp,x,y); - - return result; -} - -static int stbi__pic_test(stbi__context *s) -{ - int r = stbi__pic_test_core(s); - stbi__rewind(s); - return r; -} -#endif - -// ************************************************************************************************* -// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb - -#ifndef STBI_NO_GIF -typedef struct -{ - stbi__int16 prefix; - stbi_uc first; - stbi_uc suffix; -} stbi__gif_lzw; - -typedef struct -{ - int w,h; - stbi_uc *out, *old_out; // output buffer (always 4 components) - int flags, bgindex, ratio, transparent, eflags, delay; - stbi_uc pal[256][4]; - stbi_uc lpal[256][4]; - stbi__gif_lzw codes[4096]; - stbi_uc *color_table; - int parse, step; - int lflags; - int start_x, start_y; - int max_x, max_y; - int cur_x, cur_y; - int line_size; -} stbi__gif; - -static int stbi__gif_test_raw(stbi__context *s) -{ - int sz; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; - sz = stbi__get8(s); - if (sz != '9' && sz != '7') return 0; - if (stbi__get8(s) != 'a') return 0; - return 1; -} - -static int stbi__gif_test(stbi__context *s) -{ - int r = stbi__gif_test_raw(s); - stbi__rewind(s); - return r; -} - -static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) -{ - int i; - for (i=0; i < num_entries; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - pal[i][3] = transp == i ? 0 : 255; - } -} - -static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) -{ - stbi_uc version; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') - return stbi__err("not GIF", "Corrupt GIF"); - - version = stbi__get8(s); - if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); - if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); - - stbi__g_failure_reason = ""; - g->w = stbi__get16le(s); - g->h = stbi__get16le(s); - g->flags = stbi__get8(s); - g->bgindex = stbi__get8(s); - g->ratio = stbi__get8(s); - g->transparent = -1; - - if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments - - if (is_info) return 1; - - if (g->flags & 0x80) - stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); - - return 1; -} - -static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); - if (!stbi__gif_header(s, g, comp, 1)) { - STBI_FREE(g); - stbi__rewind( s ); - return 0; - } - if (x) *x = g->w; - if (y) *y = g->h; - STBI_FREE(g); - return 1; -} - -static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) -{ - stbi_uc *p, *c; - - // recurse to decode the prefixes, since the linked-list is backwards, - // and working backwards through an interleaved image would be nasty - if (g->codes[code].prefix >= 0) - stbi__out_gif_code(g, g->codes[code].prefix); - - if (g->cur_y >= g->max_y) return; - - p = &g->out[g->cur_x + g->cur_y]; - c = &g->color_table[g->codes[code].suffix * 4]; - - if (c[3] >= 128) { - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } - g->cur_x += 4; - - if (g->cur_x >= g->max_x) { - g->cur_x = g->start_x; - g->cur_y += g->step; - - while (g->cur_y >= g->max_y && g->parse > 0) { - g->step = (1 << g->parse) * g->line_size; - g->cur_y = g->start_y + (g->step >> 1); - --g->parse; - } - } -} - -static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) -{ - stbi_uc lzw_cs; - stbi__int32 len, init_code; - stbi__uint32 first; - stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; - stbi__gif_lzw *p; - - lzw_cs = stbi__get8(s); - if (lzw_cs > 12) return NULL; - clear = 1 << lzw_cs; - first = 1; - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - bits = 0; - valid_bits = 0; - for (init_code = 0; init_code < clear; init_code++) { - g->codes[init_code].prefix = -1; - g->codes[init_code].first = (stbi_uc) init_code; - g->codes[init_code].suffix = (stbi_uc) init_code; - } - - // support no starting clear code - avail = clear+2; - oldcode = -1; - - len = 0; - for(;;) { - if (valid_bits < codesize) { - if (len == 0) { - len = stbi__get8(s); // start new block - if (len == 0) - return g->out; - } - --len; - bits |= (stbi__int32) stbi__get8(s) << valid_bits; - valid_bits += 8; - } else { - stbi__int32 code = bits & codemask; - bits >>= codesize; - valid_bits -= codesize; - // @OPTIMIZE: is there some way we can accelerate the non-clear path? - if (code == clear) { // clear code - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - avail = clear + 2; - oldcode = -1; - first = 0; - } else if (code == clear + 1) { // end of stream code - stbi__skip(s, len); - while ((len = stbi__get8(s)) > 0) - stbi__skip(s,len); - return g->out; - } else if (code <= avail) { - if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); - - if (oldcode >= 0) { - p = &g->codes[avail++]; - if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); - p->prefix = (stbi__int16) oldcode; - p->first = g->codes[oldcode].first; - p->suffix = (code == avail) ? p->first : g->codes[code].first; - } else if (code == avail) - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - - stbi__out_gif_code(g, (stbi__uint16) code); - - if ((avail & codemask) == 0 && avail <= 0x0FFF) { - codesize++; - codemask = (1 << codesize) - 1; - } - - oldcode = code; - } else { - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - } - } - } -} - -static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1) -{ - int x, y; - stbi_uc *c = g->pal[g->bgindex]; - for (y = y0; y < y1; y += 4 * g->w) { - for (x = x0; x < x1; x += 4) { - stbi_uc *p = &g->out[y + x]; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = 0; - } - } -} - -// this function is designed to support animated gifs, although stb_image doesn't support it -static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) -{ - int i; - stbi_uc *prev_out = 0; - - if (g->out == 0 && !stbi__gif_header(s, g, comp,0)) - return 0; // stbi__g_failure_reason set by stbi__gif_header - - if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0)) - return stbi__errpuc("too large", "GIF too large"); - - prev_out = g->out; - g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0); - if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); - - switch ((g->eflags & 0x1C) >> 2) { - case 0: // unspecified (also always used on 1st frame) - stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h); - break; - case 1: // do not dispose - if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); - g->old_out = prev_out; - break; - case 2: // dispose to background - if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); - stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y); - break; - case 3: // dispose to previous - if (g->old_out) { - for (i = g->start_y; i < g->max_y; i += 4 * g->w) - memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x); - } - break; - } - - for (;;) { - switch (stbi__get8(s)) { - case 0x2C: /* Image Descriptor */ - { - int prev_trans = -1; - stbi__int32 x, y, w, h; - stbi_uc *o; - - x = stbi__get16le(s); - y = stbi__get16le(s); - w = stbi__get16le(s); - h = stbi__get16le(s); - if (((x + w) > (g->w)) || ((y + h) > (g->h))) - return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); - - g->line_size = g->w * 4; - g->start_x = x * 4; - g->start_y = y * g->line_size; - g->max_x = g->start_x + w * 4; - g->max_y = g->start_y + h * g->line_size; - g->cur_x = g->start_x; - g->cur_y = g->start_y; - - g->lflags = stbi__get8(s); - - if (g->lflags & 0x40) { - g->step = 8 * g->line_size; // first interlaced spacing - g->parse = 3; - } else { - g->step = g->line_size; - g->parse = 0; - } - - if (g->lflags & 0x80) { - stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); - g->color_table = (stbi_uc *) g->lpal; - } else if (g->flags & 0x80) { - if (g->transparent >= 0 && (g->eflags & 0x01)) { - prev_trans = g->pal[g->transparent][3]; - g->pal[g->transparent][3] = 0; - } - g->color_table = (stbi_uc *) g->pal; - } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - - o = stbi__process_gif_raster(s, g); - if (o == NULL) return NULL; - - if (prev_trans != -1) - g->pal[g->transparent][3] = (stbi_uc) prev_trans; - - return o; - } - - case 0x21: // Comment Extension. - { - int len; - if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. - len = stbi__get8(s); - if (len == 4) { - g->eflags = stbi__get8(s); - g->delay = stbi__get16le(s); - g->transparent = stbi__get8(s); - } else { - stbi__skip(s, len); - break; - } - } - while ((len = stbi__get8(s)) != 0) - stbi__skip(s, len); - break; - } - - case 0x3B: // gif stream termination code - return (stbi_uc *) s; // using '1' causes warning on some compilers - - default: - return stbi__errpuc("unknown code", "Corrupt GIF"); - } - } - - STBI_NOTUSED(req_comp); -} - -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *u = 0; - stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); - memset(g, 0, sizeof(*g)); - STBI_NOTUSED(ri); - - u = stbi__gif_load_next(s, g, comp, req_comp); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - if (u) { - *x = g->w; - *y = g->h; - if (req_comp && req_comp != 4) - u = stbi__convert_format(u, 4, req_comp, g->w, g->h); - } - else if (g->out) - STBI_FREE(g->out); - STBI_FREE(g); - return u; -} - -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) -{ - return stbi__gif_info_raw(s,x,y,comp); -} -#endif - -// ************************************************************************************************* -// Radiance RGBE HDR loader -// originally by Nicolas Schulz -#ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s, const char *signature) -{ - int i; - for (i=0; signature[i]; ++i) - if (stbi__get8(s) != signature[i]) - return 0; - stbi__rewind(s); - return 1; -} - -static int stbi__hdr_test(stbi__context* s) -{ - int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); - stbi__rewind(s); - if(!r) { - r = stbi__hdr_test_core(s, "#?RGBE\n"); - stbi__rewind(s); - } - return r; -} - -#define STBI__HDR_BUFLEN 1024 -static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) -{ - int len=0; - char c = '\0'; - - c = (char) stbi__get8(z); - - while (!stbi__at_eof(z) && c != '\n') { - buffer[len++] = c; - if (len == STBI__HDR_BUFLEN-1) { - // flush to end of line - while (!stbi__at_eof(z) && stbi__get8(z) != '\n') - ; - break; - } - c = (char) stbi__get8(z); - } - - buffer[len] = 0; - return buffer; -} - -static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) -{ - if ( input[3] != 0 ) { - float f1; - // Exponent - f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); - if (req_comp <= 2) - output[0] = (input[0] + input[1] + input[2]) * f1 / 3; - else { - output[0] = input[0] * f1; - output[1] = input[1] * f1; - output[2] = input[2] * f1; - } - if (req_comp == 2) output[1] = 1; - if (req_comp == 4) output[3] = 1; - } else { - switch (req_comp) { - case 4: output[3] = 1; /* fallthrough */ - case 3: output[0] = output[1] = output[2] = 0; - break; - case 2: output[1] = 1; /* fallthrough */ - case 1: output[0] = 0; - break; - } - } -} - -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int width, height; - stbi_uc *scanline; - float *hdr_data; - int len; - unsigned char count, value; - int i, j, k, c1,c2, z; - const char *headerToken; - STBI_NOTUSED(ri); - - // Check identifier - headerToken = stbi__hdr_gettoken(s,buffer); - if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) - return stbi__errpf("not HDR", "Corrupt HDR image"); - - // Parse header - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); - - // Parse width and height - // can't use sscanf() if we're not using stdio! - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - height = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - width = (int) strtol(token, NULL, 10); - - *x = width; - *y = height; - - if (comp) *comp = 3; - if (req_comp == 0) req_comp = 3; - - if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) - return stbi__errpf("too large", "HDR image is too large"); - - // Read data - hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); - if (!hdr_data) - return stbi__errpf("outofmem", "Out of memory"); - - // Load image data - // image data is stored as some number of sca - if ( width < 8 || width >= 32768) { - // Read flat data - for (j=0; j < height; ++j) { - for (i=0; i < width; ++i) { - stbi_uc rgbe[4]; - main_decode_loop: - stbi__getn(s, rgbe, 4); - stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); - } - } - } else { - // Read RLE-encoded data - scanline = NULL; - - for (j = 0; j < height; ++j) { - c1 = stbi__get8(s); - c2 = stbi__get8(s); - len = stbi__get8(s); - if (c1 != 2 || c2 != 2 || (len & 0x80)) { - // not run-length encoded, so we have to actually use THIS data as a decoded - // pixel (note this can't be a valid pixel--one of RGB must be >= 128) - stbi_uc rgbe[4]; - rgbe[0] = (stbi_uc) c1; - rgbe[1] = (stbi_uc) c2; - rgbe[2] = (stbi_uc) len; - rgbe[3] = (stbi_uc) stbi__get8(s); - stbi__hdr_convert(hdr_data, rgbe, req_comp); - i = 1; - j = 0; - STBI_FREE(scanline); - goto main_decode_loop; // yes, this makes no sense - } - len <<= 8; - len |= stbi__get8(s); - if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) { - scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); - if (!scanline) { - STBI_FREE(hdr_data); - return stbi__errpf("outofmem", "Out of memory"); - } - } - - for (k = 0; k < 4; ++k) { - int nleft; - i = 0; - while ((nleft = width - i) > 0) { - count = stbi__get8(s); - if (count > 128) { - // Run - value = stbi__get8(s); - count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = value; - } else { - // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = stbi__get8(s); - } - } - } - for (i=0; i < width; ++i) - stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); - } - if (scanline) - STBI_FREE(scanline); - } - - return hdr_data; -} - -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int dummy; - - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - - if (stbi__hdr_test(s) == 0) { - stbi__rewind( s ); - return 0; - } - - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) { - stbi__rewind( s ); - return 0; - } - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *y = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *x = (int) strtol(token, NULL, 10); - *comp = 3; - return 1; -} -#endif // STBI_NO_HDR - -#ifndef STBI_NO_BMP -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) -{ - void *p; - stbi__bmp_data info; - - info.all_a = 255; - p = stbi__bmp_parse_header(s, &info); - stbi__rewind( s ); - if (p == NULL) - return 0; - if (x) *x = s->img_x; - if (y) *y = s->img_y; - if (comp) *comp = info.ma ? 4 : 3; - return 1; -} -#endif - -#ifndef STBI_NO_PSD -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) -{ - int channelCount, dummy; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - *y = stbi__get32be(s); - *x = stbi__get32be(s); - if (stbi__get16be(s) != 8) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 3) { - stbi__rewind( s ); - return 0; - } - *comp = 4; - return 1; -} -#endif - -#ifndef STBI_NO_PIC -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) -{ - int act_comp=0,num_packets=0,chained,dummy; - stbi__pic_packet packets[10]; - - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { - stbi__rewind(s); - return 0; - } - - stbi__skip(s, 88); - - *x = stbi__get16be(s); - *y = stbi__get16be(s); - if (stbi__at_eof(s)) { - stbi__rewind( s); - return 0; - } - if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { - stbi__rewind( s ); - return 0; - } - - stbi__skip(s, 8); - - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return 0; - - packet = &packets[num_packets++]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - act_comp |= packet->channel; - - if (stbi__at_eof(s)) { - stbi__rewind( s ); - return 0; - } - if (packet->size != 8) { - stbi__rewind( s ); - return 0; - } - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); - - return 1; -} -#endif - -// ************************************************************************************************* -// Portable Gray Map and Portable Pixel Map loader -// by Ken Miller -// -// PGM: http://netpbm.sourceforge.net/doc/pgm.html -// PPM: http://netpbm.sourceforge.net/doc/ppm.html -// -// Known limitations: -// Does not support comments in the header section -// Does not support ASCII image data (formats P2 and P3) -// Does not support 16-bit-per-channel - -#ifndef STBI_NO_PNM - -static int stbi__pnm_test(stbi__context *s) -{ - char p, t; - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - return 1; -} - -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - STBI_NOTUSED(ri); - - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) - return 0; - - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - - if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) - return stbi__errpuc("too large", "PNM too large"); - - out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); - - if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - return out; -} - -static int stbi__pnm_isspace(char c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; -} - -static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) -{ - for (;;) { - while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) - *c = (char) stbi__get8(s); - - if (stbi__at_eof(s) || *c != '#') - break; - - while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) - *c = (char) stbi__get8(s); - } -} - -static int stbi__pnm_isdigit(char c) -{ - return c >= '0' && c <= '9'; -} - -static int stbi__pnm_getinteger(stbi__context *s, char *c) -{ - int value = 0; - - while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { - value = value*10 + (*c - '0'); - *c = (char) stbi__get8(s); - } - - return value; -} - -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) -{ - int maxv, dummy; - char c, p, t; - - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - - stbi__rewind(s); - - // Get identifier - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind(s); - return 0; - } - - *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm - - c = (char) stbi__get8(s); - stbi__pnm_skip_whitespace(s, &c); - - *x = stbi__pnm_getinteger(s, &c); // read width - stbi__pnm_skip_whitespace(s, &c); - - *y = stbi__pnm_getinteger(s, &c); // read height - stbi__pnm_skip_whitespace(s, &c); - - maxv = stbi__pnm_getinteger(s, &c); // read max value - - if (maxv > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); - else - return 1; -} -#endif - -static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PNG - if (stbi__png_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_GIF - if (stbi__gif_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_BMP - if (stbi__bmp_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PSD - if (stbi__psd_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PIC - if (stbi__pic_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PNM - if (stbi__pnm_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_HDR - if (stbi__hdr_info(s, x, y, comp)) return 1; - #endif - - // test tga last because it's a crappy test! - #ifndef STBI_NO_TGA - if (stbi__tga_info(s, x, y, comp)) - return 1; - #endif - return stbi__err("unknown image type", "Image not of any known type, or corrupt"); -} - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_info_from_file(f, x, y, comp); - fclose(f); - return result; -} - -STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__info_main(&s,x,y,comp); - fseek(f,pos,SEEK_SET); - return r; -} -#endif // !STBI_NO_STDIO - -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__info_main(&s,x,y,comp); -} - -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__info_main(&s,x,y,comp); -} - -#endif // STB_IMAGE_IMPLEMENTATION - -/* - revision history: - 2.16 (2017-07-23) all functions have 16-bit variants; - STBI_NO_STDIO works again; - compilation fixes; - fix rounding in unpremultiply; - optimize vertical flip; - disable raw_len validation; - documentation fixes - 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; - warning fixes; disable run-time SSE detection on gcc; - uniform handling of optional "return" values; - thread-safe initialization of zlib tables - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) allocate large structures on the stack - remove white matting for transparent PSD - fix reported channel count for PNG & BMP - re-enable SSE2 in non-gcc 64-bit - support RGB-formatted JPEG - read 16-bit PNGs (only as 8-bit) - 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED - 2.09 (2016-01-16) allow comments in PNM files - 16-bit-per-pixel TGA (not bit-per-component) - info() for TGA could break due to .hdr handling - info() for BMP to shares code instead of sloppy parse - can use STBI_REALLOC_SIZED if allocator doesn't support realloc - code cleanup - 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA - 2.07 (2015-09-13) fix compiler warnings - partial animated GIF support - limited 16-bpc PSD support - #ifdef unused functions - bug with < 92 byte PIC,PNM,HDR,TGA - 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value - 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning - 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit - 2.03 (2015-04-12) extra corruption checking (mmozeiko) - stbi_set_flip_vertically_on_load (nguillemot) - fix NEON support; fix mingw support - 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) - progressive JPEG (stb) - PGM/PPM support (Ken Miller) - STBI_MALLOC,STBI_REALLOC,STBI_FREE - GIF bugfix -- seemingly never worked - STBI_NO_*, STBI_ONLY_* - 1.48 (2014-12-14) fix incorrectly-named assert() - 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) - optimize PNG (ryg) - fix bug in interlaced PNG with user-specified channel count (stb) - 1.46 (2014-08-26) - fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG - 1.45 (2014-08-16) - fix MSVC-ARM internal compiler error by wrapping malloc - 1.44 (2014-08-07) - various warning fixes from Ronny Chevalier - 1.43 (2014-07-15) - fix MSVC-only compiler problem in code changed in 1.42 - 1.42 (2014-07-09) - don't define _CRT_SECURE_NO_WARNINGS (affects user code) - fixes to stbi__cleanup_jpeg path - added STBI_ASSERT to avoid requiring assert.h - 1.41 (2014-06-25) - fix search&replace from 1.36 that messed up comments/error messages - 1.40 (2014-06-22) - fix gcc struct-initialization warning - 1.39 (2014-06-15) - fix to TGA optimization when req_comp != number of components in TGA; - fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) - add support for BMP version 5 (more ignored fields) - 1.38 (2014-06-06) - suppress MSVC warnings on integer casts truncating values - fix accidental rename of 'skip' field of I/O - 1.37 (2014-06-04) - remove duplicate typedef - 1.36 (2014-06-03) - convert to header file single-file library - if de-iphone isn't set, load iphone images color-swapped instead of returning NULL - 1.35 (2014-05-27) - various warnings - fix broken STBI_SIMD path - fix bug where stbi_load_from_file no longer left file pointer in correct place - fix broken non-easy path for 32-bit BMP (possibly never used) - TGA optimization by Arseny Kapoulkine - 1.34 (unknown) - use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case - 1.33 (2011-07-14) - make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements - 1.32 (2011-07-13) - support for "info" function for all supported filetypes (SpartanJ) - 1.31 (2011-06-20) - a few more leak fixes, bug in PNG handling (SpartanJ) - 1.30 (2011-06-11) - added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) - removed deprecated format-specific test/load functions - removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway - error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) - fix inefficiency in decoding 32-bit BMP (David Woo) - 1.29 (2010-08-16) - various warning fixes from Aurelien Pocheville - 1.28 (2010-08-01) - fix bug in GIF palette transparency (SpartanJ) - 1.27 (2010-08-01) - cast-to-stbi_uc to fix warnings - 1.26 (2010-07-24) - fix bug in file buffering for PNG reported by SpartanJ - 1.25 (2010-07-17) - refix trans_data warning (Won Chun) - 1.24 (2010-07-12) - perf improvements reading from files on platforms with lock-heavy fgetc() - minor perf improvements for jpeg - deprecated type-specific functions so we'll get feedback if they're needed - attempt to fix trans_data warning (Won Chun) - 1.23 fixed bug in iPhone support - 1.22 (2010-07-10) - removed image *writing* support - stbi_info support from Jetro Lauha - GIF support from Jean-Marc Lienher - iPhone PNG-extensions from James Brown - warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) - 1.21 fix use of 'stbi_uc' in header (reported by jon blow) - 1.20 added support for Softimage PIC, by Tom Seddon - 1.19 bug in interlaced PNG corruption check (found by ryg) - 1.18 (2008-08-02) - fix a threading bug (local mutable static) - 1.17 support interlaced PNG - 1.16 major bugfix - stbi__convert_format converted one too many pixels - 1.15 initialize some fields for thread safety - 1.14 fix threadsafe conversion bug - header-file-only version (#define STBI_HEADER_FILE_ONLY before including) - 1.13 threadsafe - 1.12 const qualifiers in the API - 1.11 Support installable IDCT, colorspace conversion routines - 1.10 Fixes for 64-bit (don't use "unsigned long") - optimized upsampling by Fabian "ryg" Giesen - 1.09 Fix format-conversion for PSD code (bad global variables!) - 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz - 1.07 attempt to fix C++ warning/errors again - 1.06 attempt to fix C++ warning/errors again - 1.05 fix TGA loading to return correct *comp and use good luminance calc - 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free - 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR - 1.02 support for (subset of) HDR files, float interface for preferred access to them - 1.01 fix bug: possible bug in handling right-side up bmps... not sure - fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all - 1.00 interface to zlib that skips zlib header - 0.99 correct handling of alpha in palette - 0.98 TGA loader by lonesock; dynamically add loaders (untested) - 0.97 jpeg errors on too large a file; also catch another malloc failure - 0.96 fix detection of invalid v value - particleman@mollyrocket forum - 0.95 during header scan, seek to markers in case of padding - 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same - 0.93 handle jpegtran output; verbose errors - 0.92 read 4,8,16,24,32-bit BMP files of several formats - 0.91 output 24-bit Windows 3.0 BMP files - 0.90 fix a few more warnings; bump version number to approach 1.0 - 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd - 0.60 fix compiling as c++ - 0.59 fix warnings: merge Dave Moore's -Wall fixes - 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian - 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available - 0.56 fix bug: zlib uncompressed mode len vs. nlen - 0.55 fix bug: restart_interval not initialized to 0 - 0.54 allow NULL for 'int *comp' - 0.53 fix bug in png 3->4; speedup png decoding - 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments - 0.51 obey req_comp requests, 1-component jpegs return as 1-component, - on 'test' only check type, not whether we support this variant - 0.50 (2006-11-19) - first released version -*/ - - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ diff --git a/ext/stb_image_resize.h b/ext/stb_image_resize.h new file mode 100644 index 00000000..4f6ad35e --- /dev/null +++ b/ext/stb_image_resize.h @@ -0,0 +1,2630 @@ +/* stb_image_resize - v0.96 - public domain image resizing + by Jorge L Rodriguez (@VinoBS) - 2014 + http://github.com/nothings/stb + + Written with emphasis on usability, portability, and efficiency. (No + SIMD or threads, so it be easily outperformed by libs that use those.) + Only scaling and translation is supported, no rotations or shears. + Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation. + + COMPILING & LINKING + In one C/C++ file that #includes this file, do this: + #define STB_IMAGE_RESIZE_IMPLEMENTATION + before the #include. That will create the implementation in that file. + + QUICKSTART + stbir_resize_uint8( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, num_channels) + stbir_resize_float(...) + stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_chan , 0) + stbir_resize_uint8_srgb_edgemode( + input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP) + // WRAP/REFLECT/ZERO + + FULL API + See the "header file" section of the source for API documentation. + + ADDITIONAL DOCUMENTATION + + SRGB & FLOATING POINT REPRESENTATION + The sRGB functions presume IEEE floating point. If you do not have + IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use + a slower implementation. + + MEMORY ALLOCATION + The resize functions here perform a single memory allocation using + malloc. To control the memory allocation, before the #include that + triggers the implementation, do: + + #define STBIR_MALLOC(size,context) ... + #define STBIR_FREE(ptr,context) ... + + Each resize function makes exactly one call to malloc/free, so to use + temp memory, store the temp memory in the context and return that. + + ASSERT + Define STBIR_ASSERT(boolval) to override assert() and not use assert.h + + OPTIMIZATION + Define STBIR_SATURATE_INT to compute clamp values in-range using + integer operations instead of float operations. This may be faster + on some platforms. + + DEFAULT FILTERS + For functions which don't provide explicit control over what filters + to use, you can change the compile-time defaults with + + #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something + #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something + + See stbir_filter in the header-file section for the list of filters. + + NEW FILTERS + A number of 1D filter kernels are used. For a list of + supported filters see the stbir_filter enum. To add a new filter, + write a filter function and add it to stbir__filter_info_table. + + PROGRESS + For interactive use with slow resize operations, you can install + a progress-report callback: + + #define STBIR_PROGRESS_REPORT(val) some_func(val) + + The parameter val is a float which goes from 0 to 1 as progress is made. + + For example: + + static void my_progress_report(float progress); + #define STBIR_PROGRESS_REPORT(val) my_progress_report(val) + + #define STB_IMAGE_RESIZE_IMPLEMENTATION + #include "stb_image_resize.h" + + static void my_progress_report(float progress) + { + printf("Progress: %f%%\n", progress*100); + } + + MAX CHANNELS + If your image has more than 64 channels, define STBIR_MAX_CHANNELS + to the max you'll have. + + ALPHA CHANNEL + Most of the resizing functions provide the ability to control how + the alpha channel of an image is processed. The important things + to know about this: + + 1. The best mathematically-behaved version of alpha to use is + called "premultiplied alpha", in which the other color channels + have had the alpha value multiplied in. If you use premultiplied + alpha, linear filtering (such as image resampling done by this + library, or performed in texture units on GPUs) does the "right + thing". While premultiplied alpha is standard in the movie CGI + industry, it is still uncommon in the videogame/real-time world. + + If you linearly filter non-premultiplied alpha, strange effects + occur. (For example, the 50/50 average of 99% transparent bright green + and 1% transparent black produces 50% transparent dark green when + non-premultiplied, whereas premultiplied it produces 50% + transparent near-black. The former introduces green energy + that doesn't exist in the source image.) + + 2. Artists should not edit premultiplied-alpha images; artists + want non-premultiplied alpha images. Thus, art tools generally output + non-premultiplied alpha images. + + 3. You will get best results in most cases by converting images + to premultiplied alpha before processing them mathematically. + + 4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the + resizer does not do anything special for the alpha channel; + it is resampled identically to other channels. This produces + the correct results for premultiplied-alpha images, but produces + less-than-ideal results for non-premultiplied-alpha images. + + 5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, + then the resizer weights the contribution of input pixels + based on their alpha values, or, equivalently, it multiplies + the alpha value into the color channels, resamples, then divides + by the resultant alpha value. Input pixels which have alpha=0 do + not contribute at all to output pixels unless _all_ of the input + pixels affecting that output pixel have alpha=0, in which case + the result for that pixel is the same as it would be without + STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for + input images in integer formats. For input images in float format, + input pixels with alpha=0 have no effect, and output pixels + which have alpha=0 will be 0 in all channels. (For float images, + you can manually achieve the same result by adding a tiny epsilon + value to the alpha channel of every image, and then subtracting + or clamping it at the end.) + + 6. You can suppress the behavior described in #5 and make + all-0-alpha pixels have 0 in all channels by #defining + STBIR_NO_ALPHA_EPSILON. + + 7. You can separately control whether the alpha channel is + interpreted as linear or affected by the colorspace. By default + it is linear; you almost never want to apply the colorspace. + (For example, graphics hardware does not apply sRGB conversion + to the alpha channel.) + + CONTRIBUTORS + Jorge L Rodriguez: Implementation + Sean Barrett: API design, optimizations + Aras Pranckevicius: bugfix + Nathan Reed: warning fixes + + REVISIONS + 0.96 (2019-03-04) fixed warnings + 0.95 (2017-07-23) fixed warnings + 0.94 (2017-03-18) fixed warnings + 0.93 (2017-03-03) fixed bug with certain combinations of heights + 0.92 (2017-01-02) fix integer overflow on large (>2GB) images + 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions + 0.90 (2014-09-17) first released version + + LICENSE + See end of file for license information. + + TODO + Don't decode all of the image data when only processing a partial tile + Don't use full-width decode buffers when only processing a partial tile + When processing wide images, break processing into tiles so data fits in L1 cache + Installable filters? + Resize that respects alpha test coverage + (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage: + https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp ) +*/ + +#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H +#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H + +#ifdef _MSC_VER +typedef unsigned char stbir_uint8; +typedef unsigned short stbir_uint16; +typedef unsigned int stbir_uint32; +#else +#include +typedef uint8_t stbir_uint8; +typedef uint16_t stbir_uint16; +typedef uint32_t stbir_uint32; +#endif + +#ifndef STBIRDEF +#ifdef STB_IMAGE_RESIZE_STATIC +#define STBIRDEF static +#else +#ifdef __cplusplus +#define STBIRDEF extern "C" +#else +#define STBIRDEF extern +#endif +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// Easy-to-use API: +// +// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4) +// * input_w is input image width (x-axis), input_h is input image height (y-axis) +// * stride is the offset between successive rows of image data in memory, in bytes. you can +// specify 0 to mean packed continuously in memory +// * alpha channel is treated identically to other channels. +// * colorspace is linear or sRGB as specified by function name +// * returned result is 1 for success or 0 in case of an error. +// #define STBIR_ASSERT() to trigger an assert on parameter validation errors. +// * Memory required grows approximately linearly with input and output size, but with +// discontinuities at input_w == output_w and input_h == output_h. +// * These functions use a "default" resampling filter defined at compile time. To change the filter, +// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE +// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API. + +STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels); + +STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels); + + +// The following functions interpret image data as gamma-corrected sRGB. +// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel, +// or otherwise provide the index of the alpha channel. Flags value +// of 0 will probably do the right thing if you're not sure what +// the flags mean. + +#define STBIR_ALPHA_CHANNEL_NONE -1 + +// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will +// use alpha-weighted resampling (effectively premultiplying, resampling, +// then unpremultiplying). +#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0) +// The specified alpha channel should be handled as gamma-corrected value even +// when doing sRGB operations. +#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1) + +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags); + + +typedef enum +{ + STBIR_EDGE_CLAMP = 1, + STBIR_EDGE_REFLECT = 2, + STBIR_EDGE_WRAP = 3, + STBIR_EDGE_ZERO = 4, +} stbir_edge; + +// This function adds the ability to specify how requests to sample off the edge of the image are handled. +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode); + +////////////////////////////////////////////////////////////////////////////// +// +// Medium-complexity API +// +// This extends the easy-to-use API as follows: +// +// * Alpha-channel can be processed separately +// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE +// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT) +// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED) +// * Filter can be selected explicitly +// * uint16 image type +// * sRGB colorspace available for all types +// * context parameter for passing to STBIR_MALLOC + +typedef enum +{ + STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses + STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios + STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering + STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque + STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline + STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3 +} stbir_filter; + +typedef enum +{ + STBIR_COLORSPACE_LINEAR, + STBIR_COLORSPACE_SRGB, + + STBIR_MAX_COLORSPACES, +} stbir_colorspace; + +// The following functions are all identical except for the type of the image data + +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + +STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + + + +////////////////////////////////////////////////////////////////////////////// +// +// Full-complexity API +// +// This extends the medium API as follows: +// +// * uint32 image type +// * not typesafe +// * separate filter types for each axis +// * separate edge modes for each axis +// * can specify scale explicitly for subpixel correctness +// * can specify image source tile using texture coordinates + +typedef enum +{ + STBIR_TYPE_UINT8 , + STBIR_TYPE_UINT16, + STBIR_TYPE_UINT32, + STBIR_TYPE_FLOAT , + + STBIR_MAX_TYPES +} stbir_datatype; + +STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context); + +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float x_scale, float y_scale, + float x_offset, float y_offset); + +STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float s0, float t0, float s1, float t1); +// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use. + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H + + + + + +#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION + +#ifndef STBIR_ASSERT +#include +#define STBIR_ASSERT(x) assert(x) +#endif + +// For memset +#include + +#include + +#ifndef STBIR_MALLOC +#include +// use comma operator to evaluate c, to avoid "unused parameter" warnings +#define STBIR_MALLOC(size,c) ((void)(c), malloc(size)) +#define STBIR_FREE(ptr,c) ((void)(c), free(ptr)) +#endif + +#ifndef _MSC_VER +#ifdef __cplusplus +#define stbir__inline inline +#else +#define stbir__inline +#endif +#else +#define stbir__inline __forceinline +#endif + + +// should produce compiler error if size is wrong +typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBIR__NOTUSED(v) (void)(v) +#else +#define STBIR__NOTUSED(v) (void)sizeof(v) +#endif + +#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0])) + +#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE +#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM +#endif + +#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE +#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL +#endif + +#ifndef STBIR_PROGRESS_REPORT +#define STBIR_PROGRESS_REPORT(float_0_to_1) +#endif + +#ifndef STBIR_MAX_CHANNELS +#define STBIR_MAX_CHANNELS 64 +#endif + +#if STBIR_MAX_CHANNELS > 65536 +#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536." +// because we store the indices in 16-bit variables +#endif + +// This value is added to alpha just before premultiplication to avoid +// zeroing out color values. It is equivalent to 2^-80. If you don't want +// that behavior (it may interfere if you have floating point images with +// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to +// disable it. +#ifndef STBIR_ALPHA_EPSILON +#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20)) +#endif + + + +#ifdef _MSC_VER +#define STBIR__UNUSED_PARAM(v) (void)(v) +#else +#define STBIR__UNUSED_PARAM(v) (void)sizeof(v) +#endif + +// must match stbir_datatype +static unsigned char stbir__type_size[] = { + 1, // STBIR_TYPE_UINT8 + 2, // STBIR_TYPE_UINT16 + 4, // STBIR_TYPE_UINT32 + 4, // STBIR_TYPE_FLOAT +}; + +// Kernel function centered at 0 +typedef float (stbir__kernel_fn)(float x, float scale); +typedef float (stbir__support_fn)(float scale); + +typedef struct +{ + stbir__kernel_fn* kernel; + stbir__support_fn* support; +} stbir__filter_info; + +// When upsampling, the contributors are which source pixels contribute. +// When downsampling, the contributors are which destination pixels are contributed to. +typedef struct +{ + int n0; // First contributing pixel + int n1; // Last contributing pixel +} stbir__contributors; + +typedef struct +{ + const void* input_data; + int input_w; + int input_h; + int input_stride_bytes; + + void* output_data; + int output_w; + int output_h; + int output_stride_bytes; + + float s0, t0, s1, t1; + + float horizontal_shift; // Units: output pixels + float vertical_shift; // Units: output pixels + float horizontal_scale; + float vertical_scale; + + int channels; + int alpha_channel; + stbir_uint32 flags; + stbir_datatype type; + stbir_filter horizontal_filter; + stbir_filter vertical_filter; + stbir_edge edge_horizontal; + stbir_edge edge_vertical; + stbir_colorspace colorspace; + + stbir__contributors* horizontal_contributors; + float* horizontal_coefficients; + + stbir__contributors* vertical_contributors; + float* vertical_coefficients; + + int decode_buffer_pixels; + float* decode_buffer; + + float* horizontal_buffer; + + // cache these because ceil/floor are inexplicably showing up in profile + int horizontal_coefficient_width; + int vertical_coefficient_width; + int horizontal_filter_pixel_width; + int vertical_filter_pixel_width; + int horizontal_filter_pixel_margin; + int vertical_filter_pixel_margin; + int horizontal_num_contributors; + int vertical_num_contributors; + + int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter) + int ring_buffer_num_entries; // Total number of entries in the ring buffer. + int ring_buffer_first_scanline; + int ring_buffer_last_scanline; + int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer + float* ring_buffer; + + float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds. + + int horizontal_contributors_size; + int horizontal_coefficients_size; + int vertical_contributors_size; + int vertical_coefficients_size; + int decode_buffer_size; + int horizontal_buffer_size; + int ring_buffer_size; + int encode_buffer_size; +} stbir__info; + + +static const float stbir__max_uint8_as_float = 255.0f; +static const float stbir__max_uint16_as_float = 65535.0f; +static const double stbir__max_uint32_as_float = 4294967295.0; + + +static stbir__inline int stbir__min(int a, int b) +{ + return a < b ? a : b; +} + +static stbir__inline float stbir__saturate(float x) +{ + if (x < 0) + return 0; + + if (x > 1) + return 1; + + return x; +} + +#ifdef STBIR_SATURATE_INT +static stbir__inline stbir_uint8 stbir__saturate8(int x) +{ + if ((unsigned int) x <= 255) + return x; + + if (x < 0) + return 0; + + return 255; +} + +static stbir__inline stbir_uint16 stbir__saturate16(int x) +{ + if ((unsigned int) x <= 65535) + return x; + + if (x < 0) + return 0; + + return 65535; +} +#endif + +static float stbir__srgb_uchar_to_linear_float[256] = { + 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f, + 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f, + 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f, + 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, + 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f, + 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, + 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f, + 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f, + 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f, + 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f, + 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, + 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f, + 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, + 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f, + 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f, + 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f, + 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f, + 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f, + 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f, + 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, + 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f, + 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f, + 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f, + 0.982251f, 0.991102f, 1.0f +}; + +static float stbir__srgb_to_linear(float f) +{ + if (f <= 0.04045f) + return f / 12.92f; + else + return (float)pow((f + 0.055f) / 1.055f, 2.4f); +} + +static float stbir__linear_to_srgb(float f) +{ + if (f <= 0.0031308f) + return f * 12.92f; + else + return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f; +} + +#ifndef STBIR_NON_IEEE_FLOAT +// From https://gist.github.com/rygorous/2203834 + +typedef union +{ + stbir_uint32 u; + float f; +} stbir__FP32; + +static const stbir_uint32 fp32_to_srgb8_tab4[104] = { + 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d, + 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a, + 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033, + 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067, + 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5, + 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2, + 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143, + 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af, + 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240, + 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300, + 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401, + 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, + 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, +}; + +static stbir_uint8 stbir__linear_to_srgb_uchar(float in) +{ + static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps + static const stbir__FP32 minval = { (127-13) << 23 }; + stbir_uint32 tab,bias,scale,t; + stbir__FP32 f; + + // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively. + // The tests are carefully written so that NaNs map to 0, same as in the reference + // implementation. + if (!(in > minval.f)) // written this way to catch NaNs + in = minval.f; + if (in > almostone.f) + in = almostone.f; + + // Do the table lookup and unpack bias, scale + f.f = in; + tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20]; + bias = (tab >> 16) << 9; + scale = tab & 0xffff; + + // Grab next-highest mantissa bits and perform linear interpolation + t = (f.u >> 12) & 0xff; + return (unsigned char) ((bias + scale*t) >> 16); +} + +#else +// sRGB transition values, scaled by 1<<28 +static int stbir__srgb_offset_to_linear_scaled[256] = +{ + 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603, + 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926, + 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148, + 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856, + 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731, + 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369, + 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021, + 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073, + 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389, + 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552, + 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066, + 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490, + 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568, + 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316, + 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096, + 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700, + 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376, + 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912, + 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648, + 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512, + 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072, + 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544, + 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832, + 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528, + 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968, + 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184, + 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992, + 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968, + 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480, + 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656, + 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464, + 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664, +}; + +static stbir_uint8 stbir__linear_to_srgb_uchar(float f) +{ + int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp + int v = 0; + int i; + + // Refine the guess with a short binary search. + i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + + return (stbir_uint8) v; +} +#endif + +static float stbir__filter_trapezoid(float x, float scale) +{ + float halfscale = scale / 2; + float t = 0.5f + halfscale; + STBIR_ASSERT(scale <= 1); + + x = (float)fabs(x); + + if (x >= t) + return 0; + else + { + float r = 0.5f - halfscale; + if (x <= r) + return 1; + else + return (t - x) / scale; + } +} + +static float stbir__support_trapezoid(float scale) +{ + STBIR_ASSERT(scale <= 1); + return 0.5f + scale / 2; +} + +static float stbir__filter_triangle(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x <= 1.0f) + return 1 - x; + else + return 0; +} + +static float stbir__filter_cubic(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return (4 + x*x*(3*x - 6))/6; + else if (x < 2.0f) + return (8 + x*(-12 + x*(6 - x)))/6; + + return (0.0f); +} + +static float stbir__filter_catmullrom(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return 1 - x*x*(2.5f - 1.5f*x); + else if (x < 2.0f) + return 2 - x*(4 + x*(0.5f*x - 2.5f)); + + return (0.0f); +} + +static float stbir__filter_mitchell(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return (16 + x*x*(21 * x - 36))/18; + else if (x < 2.0f) + return (32 + x*(-60 + x*(36 - 7*x)))/18; + + return (0.0f); +} + +static float stbir__support_zero(float s) +{ + STBIR__UNUSED_PARAM(s); + return 0; +} + +static float stbir__support_one(float s) +{ + STBIR__UNUSED_PARAM(s); + return 1; +} + +static float stbir__support_two(float s) +{ + STBIR__UNUSED_PARAM(s); + return 2; +} + +static stbir__filter_info stbir__filter_info_table[] = { + { NULL, stbir__support_zero }, + { stbir__filter_trapezoid, stbir__support_trapezoid }, + { stbir__filter_triangle, stbir__support_one }, + { stbir__filter_cubic, stbir__support_two }, + { stbir__filter_catmullrom, stbir__support_two }, + { stbir__filter_mitchell, stbir__support_two }, +}; + +stbir__inline static int stbir__use_upsampling(float ratio) +{ + return ratio > 1; +} + +stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info) +{ + return stbir__use_upsampling(stbir_info->horizontal_scale); +} + +stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info) +{ + return stbir__use_upsampling(stbir_info->vertical_scale); +} + +// This is the maximum number of input samples that can affect an output sample +// with the given filter +static int stbir__get_filter_pixel_width(stbir_filter filter, float scale) +{ + STBIR_ASSERT(filter != 0); + STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + + if (stbir__use_upsampling(scale)) + return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2); + else + return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale); +} + +// This is how much to expand buffers to account for filters seeking outside +// the image boundaries. +static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale) +{ + return stbir__get_filter_pixel_width(filter, scale) / 2; +} + +static int stbir__get_coefficient_width(stbir_filter filter, float scale) +{ + if (stbir__use_upsampling(scale)) + return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2); + else + return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2); +} + +static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size) +{ + if (stbir__use_upsampling(scale)) + return output_size; + else + return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2); +} + +static int stbir__get_total_horizontal_coefficients(stbir__info* info) +{ + return info->horizontal_num_contributors + * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); +} + +static int stbir__get_total_vertical_coefficients(stbir__info* info) +{ + return info->vertical_num_contributors + * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale); +} + +static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n) +{ + return &contributors[n]; +} + +// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample, +// if you change it here change it there too. +static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c) +{ + int width = stbir__get_coefficient_width(filter, scale); + return &coefficients[width*n + c]; +} + +static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max) +{ + switch (edge) + { + case STBIR_EDGE_ZERO: + return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later + + case STBIR_EDGE_CLAMP: + if (n < 0) + return 0; + + if (n >= max) + return max - 1; + + return n; // NOTREACHED + + case STBIR_EDGE_REFLECT: + { + if (n < 0) + { + if (n < max) + return -n; + else + return max - 1; + } + + if (n >= max) + { + int max2 = max * 2; + if (n >= max2) + return 0; + else + return max2 - n - 1; + } + + return n; // NOTREACHED + } + + case STBIR_EDGE_WRAP: + if (n >= 0) + return (n % max); + else + { + int m = (-n) % max; + + if (m != 0) + m = max - m; + + return (m); + } + // NOTREACHED + + default: + STBIR_ASSERT(!"Unimplemented edge type"); + return 0; + } +} + +stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max) +{ + // avoid per-pixel switch + if (n >= 0 && n < max) + return n; + return stbir__edge_wrap_slow(edge, n, max); +} + +// What input pixels contribute to this output pixel? +static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out) +{ + float out_pixel_center = (float)n + 0.5f; + float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius; + float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius; + + float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio; + float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio; + + *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio; + *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5)); + *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5)); +} + +// What output pixels does this input pixel contribute to? +static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in) +{ + float in_pixel_center = (float)n + 0.5f; + float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius; + float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius; + + float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift; + float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift; + + *out_center_of_in = in_pixel_center * scale_ratio - out_shift; + *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5)); + *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5)); +} + +static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group) +{ + int i; + float total_filter = 0; + float filter_scale; + + STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. + + contributor->n0 = in_first_pixel; + contributor->n1 = in_last_pixel; + + STBIR_ASSERT(contributor->n1 >= contributor->n0); + + for (i = 0; i <= in_last_pixel - in_first_pixel; i++) + { + float in_pixel_center = (float)(i + in_first_pixel) + 0.5f; + coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale); + + // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.) + if (i == 0 && !coefficient_group[i]) + { + contributor->n0 = ++in_first_pixel; + i--; + continue; + } + + total_filter += coefficient_group[i]; + } + + STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0); + + STBIR_ASSERT(total_filter > 0.9); + STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off. + + // Make sure the sum of all coefficients is 1. + filter_scale = 1 / total_filter; + + for (i = 0; i <= in_last_pixel - in_first_pixel; i++) + coefficient_group[i] *= filter_scale; + + for (i = in_last_pixel - in_first_pixel; i >= 0; i--) + { + if (coefficient_group[i]) + break; + + // This line has no weight. We can skip it. + contributor->n1 = contributor->n0 + i - 1; + } +} + +static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group) +{ + int i; + + STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. + + contributor->n0 = out_first_pixel; + contributor->n1 = out_last_pixel; + + STBIR_ASSERT(contributor->n1 >= contributor->n0); + + for (i = 0; i <= out_last_pixel - out_first_pixel; i++) + { + float out_pixel_center = (float)(i + out_first_pixel) + 0.5f; + float x = out_pixel_center - out_center_of_in; + coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio; + } + + STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0); + + for (i = out_last_pixel - out_first_pixel; i >= 0; i--) + { + if (coefficient_group[i]) + break; + + // This line has no weight. We can skip it. + contributor->n1 = contributor->n0 + i - 1; + } +} + +static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size) +{ + int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); + int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio); + int i, j; + int skip; + + for (i = 0; i < output_size; i++) + { + float scale; + float total = 0; + + for (j = 0; j < num_contributors; j++) + { + if (i >= contributors[j].n0 && i <= contributors[j].n1) + { + float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0); + total += coefficient; + } + else if (i < contributors[j].n0) + break; + } + + STBIR_ASSERT(total > 0.9f); + STBIR_ASSERT(total < 1.1f); + + scale = 1 / total; + + for (j = 0; j < num_contributors; j++) + { + if (i >= contributors[j].n0 && i <= contributors[j].n1) + *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale; + else if (i < contributors[j].n0) + break; + } + } + + // Optimize: Skip zero coefficients and contributions outside of image bounds. + // Do this after normalizing because normalization depends on the n0/n1 values. + for (j = 0; j < num_contributors; j++) + { + int range, max, width; + + skip = 0; + while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0) + skip++; + + contributors[j].n0 += skip; + + while (contributors[j].n0 < 0) + { + contributors[j].n0++; + skip++; + } + + range = contributors[j].n1 - contributors[j].n0 + 1; + max = stbir__min(num_coefficients, range); + + width = stbir__get_coefficient_width(filter, scale_ratio); + for (i = 0; i < max; i++) + { + if (i + skip >= width) + break; + + *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip); + } + + continue; + } + + // Using min to avoid writing into invalid pixels. + for (i = 0; i < num_contributors; i++) + contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1); +} + +// Each scan line uses the same kernel values so we should calculate the kernel +// values once and then we can use them for every scan line. +static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size) +{ + int n; + int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); + + if (stbir__use_upsampling(scale_ratio)) + { + float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio; + + // Looping through out pixels + for (n = 0; n < total_contributors; n++) + { + float in_center_of_out; // Center of the current out pixel in the in pixel space + int in_first_pixel, in_last_pixel; + + stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out); + + stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); + } + } + else + { + float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio; + + // Looping through in pixels + for (n = 0; n < total_contributors; n++) + { + float out_center_of_in; // Center of the current out pixel in the in pixel space + int out_first_pixel, out_last_pixel; + int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio); + + stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in); + + stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); + } + + stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size); + } +} + +static float* stbir__get_decode_buffer(stbir__info* stbir_info) +{ + // The 0 index of the decode buffer starts after the margin. This makes + // it okay to use negative indexes on the decode buffer. + return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels]; +} + +#define STBIR__DECODE(type, colorspace) ((type) * (STBIR_MAX_COLORSPACES) + (colorspace)) + +static void stbir__decode_scanline(stbir__info* stbir_info, int n) +{ + int c; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int input_w = stbir_info->input_w; + size_t input_stride_bytes = stbir_info->input_stride_bytes; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir_edge edge_horizontal = stbir_info->edge_horizontal; + stbir_edge edge_vertical = stbir_info->edge_vertical; + size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes; + const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset; + int max_x = input_w + stbir_info->horizontal_filter_pixel_margin; + int decode = STBIR__DECODE(type, colorspace); + + int x = -stbir_info->horizontal_filter_pixel_margin; + + // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input, + // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO + if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h)) + { + for (; x < max_x; x++) + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + return; + } + + switch (decode) + { + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]]; + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float)); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c]; + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel]; + } + + break; + + default: + STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); + break; + } + + if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED)) + { + for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++) + { + int decode_pixel_index = x * channels; + + // If the alpha value is 0 it will clobber the color values. Make sure it's not. + float alpha = decode_buffer[decode_pixel_index + alpha_channel]; +#ifndef STBIR_NO_ALPHA_EPSILON + if (stbir_info->type != STBIR_TYPE_FLOAT) { + alpha += STBIR_ALPHA_EPSILON; + decode_buffer[decode_pixel_index + alpha_channel] = alpha; + } +#endif + for (c = 0; c < channels; c++) + { + if (c == alpha_channel) + continue; + + decode_buffer[decode_pixel_index + c] *= alpha; + } + } + } + + if (edge_horizontal == STBIR_EDGE_ZERO) + { + for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++) + { + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + } + for (x = input_w; x < max_x; x++) + { + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + } + } +} + +static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length) +{ + return &ring_buffer[index * ring_buffer_length]; +} + +static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n) +{ + int ring_buffer_index; + float* ring_buffer; + + stbir_info->ring_buffer_last_scanline = n; + + if (stbir_info->ring_buffer_begin_index < 0) + { + ring_buffer_index = stbir_info->ring_buffer_begin_index = 0; + stbir_info->ring_buffer_first_scanline = n; + } + else + { + ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries; + STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index); + } + + ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float)); + memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes); + + return ring_buffer; +} + + +static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer) +{ + int x, k; + int output_w = stbir_info->output_w; + int channels = stbir_info->channels; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; + float* horizontal_coefficients = stbir_info->horizontal_coefficients; + int coefficient_width = stbir_info->horizontal_coefficient_width; + + for (x = 0; x < output_w; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int out_pixel_index = x * channels; + int coefficient_group = coefficient_width * x; + int coefficient_counter = 0; + + STBIR_ASSERT(n1 >= n0); + STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); + + switch (channels) { + case 1: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 1; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + } + break; + case 2: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 2; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + } + break; + case 3: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 3; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + } + break; + case 4: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 4; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; + } + break; + default: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * channels; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + int c; + STBIR_ASSERT(coefficient != 0); + for (c = 0; c < channels; c++) + output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; + } + break; + } + } +} + +static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer) +{ + int x, k; + int input_w = stbir_info->input_w; + int channels = stbir_info->channels; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; + float* horizontal_coefficients = stbir_info->horizontal_coefficients; + int coefficient_width = stbir_info->horizontal_coefficient_width; + int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin; + int max_x = input_w + filter_pixel_margin * 2; + + STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info)); + + switch (channels) { + case 1: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 1; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 1; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + } + } + break; + + case 2: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 2; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 2; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + } + } + break; + + case 3: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 3; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 3; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + } + } + break; + + case 4: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 4; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 4; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; + } + } + break; + + default: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * channels; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int c; + int out_pixel_index = k * channels; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + for (c = 0; c < channels; c++) + output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; + } + } + break; + } +} + +static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n) +{ + // Decode the nth scanline from the source image into the decode buffer. + stbir__decode_scanline(stbir_info, n); + + // Now resample it into the ring buffer. + if (stbir__use_width_upsampling(stbir_info)) + stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); + else + stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); + + // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling. +} + +static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n) +{ + // Decode the nth scanline from the source image into the decode buffer. + stbir__decode_scanline(stbir_info, n); + + memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float)); + + // Now resample it into the horizontal buffer. + if (stbir__use_width_upsampling(stbir_info)) + stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer); + else + stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer); + + // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers. +} + +// Get the specified scan line from the ring buffer. +static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length) +{ + int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries; + return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length); +} + + +static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode) +{ + int x; + int n; + int num_nonalpha; + stbir_uint16 nonalpha[STBIR_MAX_CHANNELS]; + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) + { + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + float alpha = encode_buffer[pixel_index + alpha_channel]; + float reciprocal_alpha = alpha ? 1.0f / alpha : 0; + + // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb + for (n = 0; n < channels; n++) + if (n != alpha_channel) + encode_buffer[pixel_index + n] *= reciprocal_alpha; + + // We added in a small epsilon to prevent the color channel from being deleted with zero alpha. + // Because we only add it for integer types, it will automatically be discarded on integer + // conversion, so we don't need to subtract it back out (which would be problematic for + // numeric precision reasons). + } + } + + // build a table of all channels that need colorspace correction, so + // we don't perform colorspace correction on channels that don't need it. + for (x = 0, num_nonalpha = 0; x < channels; ++x) + { + if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) + { + nonalpha[num_nonalpha++] = (stbir_uint16)x; + } + } + + #define STBIR__ROUND_INT(f) ((int) ((f)+0.5)) + #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5)) + + #ifdef STBIR__SATURATE_INT + #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float )) + #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float)) + #else + #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float ) + #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float) + #endif + + switch (decode) + { + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]); + } + + if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]); + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]); + } + + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((float*)output_buffer)[index] = encode_buffer[index]; + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel]; + } + break; + + default: + STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); + break; + } +} + +static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n) +{ + int x, k; + int output_w = stbir_info->output_w; + stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; + float* vertical_coefficients = stbir_info->vertical_coefficients; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int ring_buffer_entries = stbir_info->ring_buffer_num_entries; + void* output_data = stbir_info->output_data; + float* encode_buffer = stbir_info->encode_buffer; + int decode = STBIR__DECODE(type, colorspace); + int coefficient_width = stbir_info->vertical_coefficient_width; + int coefficient_counter; + int contributor = n; + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; + int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + + int n0,n1, output_row_start; + int coefficient_group = coefficient_width * contributor; + + n0 = vertical_contributors[contributor].n0; + n1 = vertical_contributors[contributor].n1; + + output_row_start = n * stbir_info->output_stride_bytes; + + STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); + + memset(encode_buffer, 0, output_w * sizeof(float) * channels); + + // I tried reblocking this for better cache usage of encode_buffer + // (using x_outer, k, x_inner), but it lost speed. -- stb + + coefficient_counter = 0; + switch (channels) { + case 1: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 1; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + } + } + break; + case 2: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 2; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + } + } + break; + case 3: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 3; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; + } + } + break; + case 4: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 4; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; + encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient; + } + } + break; + default: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * channels; + int c; + for (c = 0; c < channels; c++) + encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient; + } + } + break; + } + stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode); +} + +static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n) +{ + int x, k; + int output_w = stbir_info->output_w; + stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; + float* vertical_coefficients = stbir_info->vertical_coefficients; + int channels = stbir_info->channels; + int ring_buffer_entries = stbir_info->ring_buffer_num_entries; + float* horizontal_buffer = stbir_info->horizontal_buffer; + int coefficient_width = stbir_info->vertical_coefficient_width; + int contributor = n + stbir_info->vertical_filter_pixel_margin; + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; + int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + int n0,n1; + + n0 = vertical_contributors[contributor].n0; + n1 = vertical_contributors[contributor].n1; + + STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); + + for (k = n0; k <= n1; k++) + { + int coefficient_index = k - n0; + int coefficient_group = coefficient_width * contributor; + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + + switch (channels) { + case 1: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 1; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + } + break; + case 2: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 2; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + } + break; + case 3: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 3; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; + } + break; + case 4: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 4; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; + ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient; + } + break; + default: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * channels; + + int c; + for (c = 0; c < channels; c++) + ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient; + } + break; + } + } +} + +static void stbir__buffer_loop_upsample(stbir__info* stbir_info) +{ + int y; + float scale_ratio = stbir_info->vertical_scale; + float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio; + + STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); + + for (y = 0; y < stbir_info->output_h; y++) + { + float in_center_of_out = 0; // Center of the current out scanline in the in scanline space + int in_first_scanline = 0, in_last_scanline = 0; + + stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out); + + STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); + + if (stbir_info->ring_buffer_begin_index >= 0) + { + // Get rid of whatever we don't need anymore. + while (in_first_scanline > stbir_info->ring_buffer_first_scanline) + { + if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) + { + // We just popped the last scanline off the ring buffer. + // Reset it to the empty state. + stbir_info->ring_buffer_begin_index = -1; + stbir_info->ring_buffer_first_scanline = 0; + stbir_info->ring_buffer_last_scanline = 0; + break; + } + else + { + stbir_info->ring_buffer_first_scanline++; + stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; + } + } + } + + // Load in new ones. + if (stbir_info->ring_buffer_begin_index < 0) + stbir__decode_and_resample_upsample(stbir_info, in_first_scanline); + + while (in_last_scanline > stbir_info->ring_buffer_last_scanline) + stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1); + + // Now all buffers should be ready to write a row of vertical sampling. + stbir__resample_vertical_upsample(stbir_info, y); + + STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h); + } +} + +static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline) +{ + int output_stride_bytes = stbir_info->output_stride_bytes; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int output_w = stbir_info->output_w; + void* output_data = stbir_info->output_data; + int decode = STBIR__DECODE(type, colorspace); + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + + if (stbir_info->ring_buffer_begin_index >= 0) + { + // Get rid of whatever we don't need anymore. + while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline) + { + if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h) + { + int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes; + float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length); + stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode); + STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h); + } + + if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) + { + // We just popped the last scanline off the ring buffer. + // Reset it to the empty state. + stbir_info->ring_buffer_begin_index = -1; + stbir_info->ring_buffer_first_scanline = 0; + stbir_info->ring_buffer_last_scanline = 0; + break; + } + else + { + stbir_info->ring_buffer_first_scanline++; + stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; + } + } + } +} + +static void stbir__buffer_loop_downsample(stbir__info* stbir_info) +{ + int y; + float scale_ratio = stbir_info->vertical_scale; + int output_h = stbir_info->output_h; + float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio; + int pixel_margin = stbir_info->vertical_filter_pixel_margin; + int max_y = stbir_info->input_h + pixel_margin; + + STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); + + for (y = -pixel_margin; y < max_y; y++) + { + float out_center_of_in; // Center of the current out scanline in the in scanline space + int out_first_scanline, out_last_scanline; + + stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in); + + STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); + + if (out_last_scanline < 0 || out_first_scanline >= output_h) + continue; + + stbir__empty_ring_buffer(stbir_info, out_first_scanline); + + stbir__decode_and_resample_downsample(stbir_info, y); + + // Load in new ones. + if (stbir_info->ring_buffer_begin_index < 0) + stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline); + + while (out_last_scanline > stbir_info->ring_buffer_last_scanline) + stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1); + + // Now the horizontal buffer is ready to write to all ring buffer rows. + stbir__resample_vertical_downsample(stbir_info, y); + } + + stbir__empty_ring_buffer(stbir_info, stbir_info->output_h); +} + +static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels) +{ + info->input_w = input_w; + info->input_h = input_h; + info->output_w = output_w; + info->output_h = output_h; + info->channels = channels; +} + +static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform) +{ + info->s0 = s0; + info->t0 = t0; + info->s1 = s1; + info->t1 = t1; + + if (transform) + { + info->horizontal_scale = transform[0]; + info->vertical_scale = transform[1]; + info->horizontal_shift = transform[2]; + info->vertical_shift = transform[3]; + } + else + { + info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0); + info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0); + + info->horizontal_shift = s0 * info->output_w / (s1 - s0); + info->vertical_shift = t0 * info->output_h / (t1 - t0); + } +} + +static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter) +{ + if (h_filter == 0) + h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; + if (v_filter == 0) + v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; + info->horizontal_filter = h_filter; + info->vertical_filter = v_filter; +} + +static stbir_uint32 stbir__calculate_memory(stbir__info *info) +{ + int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); + int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale); + + info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w); + info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h); + + // One extra entry because floating point precision problems sometimes cause an extra to be necessary. + info->ring_buffer_num_entries = filter_height + 1; + + info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors); + info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float); + info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors); + info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float); + info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float); + info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float); + info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float); + info->encode_buffer_size = info->output_w * info->channels * sizeof(float); + + STBIR_ASSERT(info->horizontal_filter != 0); + STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late + STBIR_ASSERT(info->vertical_filter != 0); + STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late + + if (stbir__use_height_upsampling(info)) + // The horizontal buffer is for when we're downsampling the height and we + // can't output the result of sampling the decode buffer directly into the + // ring buffers. + info->horizontal_buffer_size = 0; + else + // The encode buffer is to retain precision in the height upsampling method + // and isn't used when height downsampling. + info->encode_buffer_size = 0; + + return info->horizontal_contributors_size + info->horizontal_coefficients_size + + info->vertical_contributors_size + info->vertical_coefficients_size + + info->decode_buffer_size + info->horizontal_buffer_size + + info->ring_buffer_size + info->encode_buffer_size; +} + +static int stbir__resize_allocated(stbir__info *info, + const void* input_data, int input_stride_in_bytes, + void* output_data, int output_stride_in_bytes, + int alpha_channel, stbir_uint32 flags, stbir_datatype type, + stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace, + void* tempmem, size_t tempmem_size_in_bytes) +{ + size_t memory_required = stbir__calculate_memory(info); + + int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type]; + int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type]; + +#ifdef STBIR_DEBUG_OVERWRITE_TEST +#define OVERWRITE_ARRAY_SIZE 8 + unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE]; + + size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type]; + memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE); +#endif + + STBIR_ASSERT(info->channels >= 0); + STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS); + + if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS) + return 0; + + STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + + if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) + return 0; + if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) + return 0; + + if (alpha_channel < 0) + flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED; + + if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) { + STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels); + } + + if (alpha_channel >= info->channels) + return 0; + + STBIR_ASSERT(tempmem); + + if (!tempmem) + return 0; + + STBIR_ASSERT(tempmem_size_in_bytes >= memory_required); + + if (tempmem_size_in_bytes < memory_required) + return 0; + + memset(tempmem, 0, tempmem_size_in_bytes); + + info->input_data = input_data; + info->input_stride_bytes = width_stride_input; + + info->output_data = output_data; + info->output_stride_bytes = width_stride_output; + + info->alpha_channel = alpha_channel; + info->flags = flags; + info->type = type; + info->edge_horizontal = edge_horizontal; + info->edge_vertical = edge_vertical; + info->colorspace = colorspace; + + info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); + info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale ); + info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale); + info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale ); + info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); + info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale ); + + info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float); + info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2; + +#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size) + + info->horizontal_contributors = (stbir__contributors *) tempmem; + info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float); + info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors); + info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float); + info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float); + + if (stbir__use_height_upsampling(info)) + { + info->horizontal_buffer = NULL; + info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); + info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float); + + STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); + } + else + { + info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); + info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float); + info->encode_buffer = NULL; + + STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); + } + +#undef STBIR__NEXT_MEMPTR + + // This signals that the ring buffer is empty + info->ring_buffer_begin_index = -1; + + stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w); + stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h); + + STBIR_PROGRESS_REPORT(0); + + if (stbir__use_height_upsampling(info)) + stbir__buffer_loop_upsample(info); + else + stbir__buffer_loop_downsample(info); + + STBIR_PROGRESS_REPORT(1); + +#ifdef STBIR_DEBUG_OVERWRITE_TEST + STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0); +#endif + + return 1; +} + + +static int stbir__resize_arbitrary( + void *alloc_context, + const void* input_data, int input_w, int input_h, int input_stride_in_bytes, + void* output_data, int output_w, int output_h, int output_stride_in_bytes, + float s0, float t0, float s1, float t1, float *transform, + int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type, + stbir_filter h_filter, stbir_filter v_filter, + stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace) +{ + stbir__info info; + int result; + size_t memory_required; + void* extra_memory; + + stbir__setup(&info, input_w, input_h, output_w, output_h, channels); + stbir__calculate_transform(&info, s0,t0,s1,t1,transform); + stbir__choose_filter(&info, h_filter, v_filter); + memory_required = stbir__calculate_memory(&info); + extra_memory = STBIR_MALLOC(memory_required, alloc_context); + + if (!extra_memory) + return 0; + + result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes, + output_data, output_stride_in_bytes, + alpha_channel, flags, type, + edge_horizontal, edge_vertical, + colorspace, extra_memory, memory_required); + + STBIR_FREE(extra_memory, alloc_context); + + return result; +} + +STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); +} + +STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); +} + +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB); +} + +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB); +} + +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + + +STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + + +STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + + +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float x_scale, float y_scale, + float x_offset, float y_offset) +{ + float transform[4]; + transform[0] = x_scale; + transform[1] = y_scale; + transform[2] = x_offset; + transform[3] = y_offset; + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + +STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float s0, float t0, float s1, float t1) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + +#endif // STB_IMAGE_RESIZE_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/ext/stb_image_write.h b/ext/stb_image_write.h index c05e9581..a9bf66c1 100644 --- a/ext/stb_image_write.h +++ b/ext/stb_image_write.h @@ -1,4 +1,4 @@ -/* stb_image_write - v1.09 - public domain - http://nothings.org/stb/stb_image_write.h +/* stb_image_write - v1.13 - public domain - http://nothings.org/stb writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 no warranty implied; use at your own risk @@ -10,15 +10,9 @@ Will probably not work correctly with strict-aliasing optimizations. - If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause - compilation warnings or even errors. To avoid this, also before #including, - - #define STBI_MSC_SECURE_CRT - ABOUT: - This header file is a library for writing images to C stdio. It could be - adapted to write to memory or a general streaming interface; let me know. + This header file is a library for writing images to C stdio or a callback. The PNG output is not optimal; it is 20-50% larger than the file written by a decent optimizing implementation; though providing a custom @@ -38,6 +32,14 @@ The returned data will be freed with STBIW_FREE() (free() by default), so it must be heap allocated with STBIW_MALLOC() (malloc() by default), +UNICODE: + + If compiling for Windows and you wish to use Unicode filenames, compile + with + #define STBIW_WINDOWS_UTF8 + and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert + Windows wchar_t filenames to utf8. + USAGE: There are five functions, one for each image file format: @@ -148,6 +150,8 @@ LICENSE #ifndef INCLUDE_STB_IMAGE_WRITE_H #define INCLUDE_STB_IMAGE_WRITE_H +#include + // if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' #ifndef STBIWDEF #ifdef STB_IMAGE_WRITE_STATIC @@ -173,6 +177,10 @@ STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); + +#ifdef STBI_WINDOWS_UTF8 +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif #endif typedef void stbi_write_func(void *context, void *data, int size); @@ -275,15 +283,52 @@ static void stbi__stdio_write(void *context, void *data, int size) fwrite(data,1,size,(FILE*) context); } -static int stbi__start_write_file(stbi__write_context *s, const char *filename) +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#ifdef __cplusplus +#define STBIW_EXTERN extern "C" +#else +#define STBIW_EXTERN extern +#endif +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); + +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbiw__fopen(char const *filename, char const *mode) { FILE *f; -#ifdef STBI_MSC_SECURE_CRT - if (fopen_s(&f, filename, "wb")) - f = NULL; +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; + +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; #else - f = fopen(filename, "wb"); + f = fopen(filename, mode); #endif + return f; +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = stbiw__fopen(filename, "wb"); stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); return f != NULL; } @@ -343,7 +388,7 @@ static void stbiw__putc(stbi__write_context *s, unsigned char c) static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) { unsigned char arr[3]; - arr[0] = a, arr[1] = b, arr[2] = c; + arr[0] = a; arr[1] = b; arr[2] = c; s->func(s->context, arr, 3); } @@ -391,10 +436,11 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i if (stbi__flip_vertically_on_write) vdir *= -1; - if (vdir < 0) - j_end = -1, j = y-1; - else - j_end = y, j = 0; + if (vdir < 0) { + j_end = -1; j = y-1; + } else { + j_end = y; j = 0; + } for (; j != j_end; j += vdir) { for (i=0; i < x; ++i) { @@ -552,7 +598,7 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) -void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) { int exponent; float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); @@ -569,7 +615,7 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) } } -void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) { unsigned char lengthbyte = STBIW_UCHAR(length+128); STBIW_ASSERT(length+128 <= 255); @@ -577,7 +623,7 @@ void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char dat s->func(s->context, &databyte, 1); } -void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) { unsigned char lengthbyte = STBIW_UCHAR(length); STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code @@ -585,7 +631,7 @@ void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *d s->func(s->context, data, length); } -void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) { unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; unsigned char rgbe[4]; @@ -686,15 +732,15 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; s->func(s->context, header, sizeof(header)-1); -#ifdef STBI_MSC_SECURE_CRT - len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#ifdef __STDC_WANT_SECURE_LIB__ + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #endif s->func(s->context, buffer, len); for(i=0; i < y; i++) - stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)*x); + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); STBIW_FREE(scratch); return 1; } @@ -809,7 +855,7 @@ static unsigned int stbiw__zhash(unsigned char *data) #endif // STBIW_ZLIB_COMPRESS -unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) { #ifdef STBIW_ZLIB_COMPRESS // user provided a zlib compress implementation, use that @@ -822,7 +868,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l unsigned int bitbuf=0; int i,j, bitcount=0; unsigned char *out = NULL; - unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); if (hash_table == NULL) return NULL; if (quality < 5) quality = 5; @@ -845,7 +891,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l for (j=0; j < n; ++j) { if (hlist[j]-data > i-32768) { // if entry lies within window int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); - if (d >= best) best=d,bestloc=hlist[j]; + if (d >= best) { best=d; bestloc=hlist[j]; } } } // when hash table entry is too long, delete half the entries @@ -904,8 +950,8 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l int blocklen = (int) (data_len % 5552); j=0; while (j < data_len) { - for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; - s1 %= 65521, s2 %= 65521; + for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } + s1 %= 65521; s2 %= 65521; j += blocklen; blocklen = 5552; } @@ -923,6 +969,9 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l static unsigned int stbiw__crc32(unsigned char *buffer, int len) { +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else static unsigned int crc_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, @@ -964,6 +1013,7 @@ static unsigned int stbiw__crc32(unsigned char *buffer, int len) for (i=0; i < len; ++i) crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; return ~crc; +#endif } #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) @@ -994,9 +1044,15 @@ static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int int type = mymap[filter_type]; unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel for (i = 0; i < n; ++i) { switch (type) { - case 0: line_buffer[i] = z[i]; break; case 1: line_buffer[i] = z[i]; break; case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; @@ -1005,20 +1061,17 @@ static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int case 6: line_buffer[i] = z[i]; break; } } - for (i=n; i < width*n; ++i) { - switch (type) { - case 0: line_buffer[i] = z[i]; break; - case 1: line_buffer[i] = z[i] - z[i-n]; break; - case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; - case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; - case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; - case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; - case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; - } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; } } -unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) { int force_filter = stbi_write_force_png_filter; int ctype[5] = { -1, 0, 4, 2, 6 }; @@ -1040,11 +1093,11 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in int filter_type; if (force_filter > -1) { filter_type = force_filter; - stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, force_filter, line_buffer); + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); } else { // Estimate the best filter by running through all of them: int best_filter = 0, best_filter_val = 0x7fffffff, est, i; for (filter_type = 0; filter_type < 5; filter_type++) { - stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, filter_type, line_buffer); + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); // Estimate the entropy of the line using this filter; the less, the better. est = 0; @@ -1057,7 +1110,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in } } if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it - stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, best_filter, line_buffer); + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); filter_type = best_filter; } } @@ -1109,14 +1162,10 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const { FILE *f; int len; - unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; -#ifdef STBI_MSC_SECURE_CRT - if (fopen_s(&f, filename, "wb")) - f = NULL; -#else - f = fopen(filename, "wb"); -#endif + + f = stbiw__fopen(filename, "wb"); if (!f) { STBIW_FREE(png); return 0; } fwrite(png, 1, len, f); fclose(f); @@ -1128,7 +1177,7 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) { int len; - unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; func(context, png, len); STBIW_FREE(png); @@ -1423,15 +1472,13 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in for(x = 0; x < width; x += 8) { float YDU[64], UDU[64], VDU[64]; for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; for(col = x; col < x+8; ++col, ++pos) { - int p = (stbi__flip_vertically_on_write ? height-1-row : row)*width*comp + col*comp; float r, g, b; - if(row >= height) { - p -= width*comp*(row+1 - height); - } - if(col >= width) { - p -= comp*(col+1 - width); - } + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; r = imageData[p+0]; g = imageData[p+ofsG]; @@ -1483,6 +1530,10 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const #endif // STB_IMAGE_WRITE_IMPLEMENTATION /* Revision history + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs 1.09 (2018-02-11) fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 1.08 (2018-01-29) diff --git a/ext/tcc-0.9.27/lib/gdi32.def b/ext/tcc-0.9.27/lib/gdi32.def deleted file mode 100644 index 02766da4..00000000 --- a/ext/tcc-0.9.27/lib/gdi32.def +++ /dev/null @@ -1,337 +0,0 @@ -LIBRARY gdi32.dll - -EXPORTS -AbortDoc -AbortPath -AddFontResourceA -AddFontResourceW -AngleArc -AnimatePalette -Arc -ArcTo -BeginPath -BitBlt -ByeByeGDI -CancelDC -CheckColorsInGamut -ChoosePixelFormat -Chord -CloseEnhMetaFile -CloseFigure -CloseMetaFile -ColorCorrectPalette -ColorMatchToTarget -CombineRgn -CombineTransform -CopyEnhMetaFileA -CopyEnhMetaFileW -CopyMetaFileA -CopyMetaFileW -CreateBitmap -CreateBitmapIndirect -CreateBrushIndirect -CreateColorSpaceA -CreateColorSpaceW -CreateCompatibleBitmap -CreateCompatibleDC -CreateDCA -CreateDCW -CreateDIBPatternBrush -CreateDIBPatternBrushPt -CreateDIBSection -CreateDIBitmap -CreateDiscardableBitmap -CreateEllipticRgn -CreateEllipticRgnIndirect -CreateEnhMetaFileA -CreateEnhMetaFileW -CreateFontA -CreateFontIndirectA -CreateFontIndirectW -CreateFontW -CreateHalftonePalette -CreateHatchBrush -CreateICA -CreateICW -CreateMetaFileA -CreateMetaFileW -CreatePalette -CreatePatternBrush -CreatePen -CreatePenIndirect -CreatePolyPolygonRgn -CreatePolygonRgn -CreateRectRgn -CreateRectRgnIndirect -CreateRoundRectRgn -CreateScalableFontResourceA -CreateScalableFontResourceW -CreateSolidBrush -DPtoLP -DeleteColorSpace -DeleteDC -DeleteEnhMetaFile -DeleteMetaFile -DeleteObject -DescribePixelFormat -DeviceCapabilitiesEx -DeviceCapabilitiesExA -DeviceCapabilitiesExW -DrawEscape -Ellipse -EnableEUDC -EndDoc -EndPage -EndPath -EnumEnhMetaFile -EnumFontFamiliesA -EnumFontFamiliesExA -EnumFontFamiliesExW -EnumFontFamiliesW -EnumFontsA -EnumFontsW -EnumICMProfilesA -EnumICMProfilesW -EnumMetaFile -EnumObjects -EqualRgn -Escape -ExcludeClipRect -ExtCreatePen -ExtCreateRegion -ExtEscape -ExtFloodFill -ExtSelectClipRgn -ExtTextOutA -ExtTextOutW -FillPath -FillRgn -FixBrushOrgEx -FlattenPath -FloodFill -FrameRgn -GdiComment -GdiFlush -GdiGetBatchLimit -GdiPlayDCScript -GdiPlayJournal -GdiPlayScript -GdiSetBatchLimit -GetArcDirection -GetAspectRatioFilterEx -GetBitmapBits -GetBitmapDimensionEx -GetBkColor -GetBkMode -GetBoundsRect -GetBrushOrgEx -GetCharABCWidthsA -GetCharABCWidthsFloatA -GetCharABCWidthsFloatW -GetCharABCWidthsW -GetCharWidth32A -GetCharWidth32W -GetCharWidthA -GetCharWidthFloatA -GetCharWidthFloatW -GetCharWidthW -GetCharacterPlacementA -GetCharacterPlacementW -GetClipBox -GetClipRgn -GetColorAdjustment -GetColorSpace -GetCurrentObject -GetCurrentPositionEx -GetDCOrgEx -GetDIBColorTable -GetDIBits -GetDeviceCaps -GetDeviceGammaRamp -GetEnhMetaFileA -GetEnhMetaFileBits -GetEnhMetaFileDescriptionA -GetEnhMetaFileDescriptionW -GetEnhMetaFileHeader -GetEnhMetaFilePaletteEntries -GetEnhMetaFileW -GetFontData -GetFontLanguageInfo -GetFontResourceInfo -GetGlyphOutline -GetGlyphOutlineA -GetGlyphOutlineW -GetGraphicsMode -GetICMProfileA -GetICMProfileW -GetKerningPairs -GetKerningPairsA -GetKerningPairsW -GetLayout -GetLogColorSpaceA -GetLogColorSpaceW -GetMapMode -GetMetaFileA -GetMetaFileBitsEx -GetMetaFileW -GetMetaRgn -GetMiterLimit -GetNearestColor -GetNearestPaletteIndex -GetObjectA -GetObjectType -GetObjectW -GetOutlineTextMetricsA -GetOutlineTextMetricsW -GetPaletteEntries -GetPath -GetPixel -GetPixelFormat -GetPolyFillMode -GetROP2 -GetRandomRgn -GetRasterizerCaps -GetRegionData -GetRgnBox -GetStockObject -GetStretchBltMode -GetSystemPaletteEntries -GetSystemPaletteUse -GetTextAlign -GetTextCharacterExtra -GetTextCharset -GetTextCharsetInfo -GetTextColor -GetTextExtentExPointA -GetTextExtentExPointW -GetTextExtentPoint32A -GetTextExtentPoint32W -GetTextExtentPointA -GetTextExtentPointW -GetTextFaceA -GetTextFaceW -GetTextMetricsA -GetTextMetricsW -GetViewportExtEx -GetViewportOrgEx -GetWinMetaFileBits -GetWindowExtEx -GetWindowOrgEx -GetWorldTransform -IntersectClipRect -InvertRgn -LPtoDP -LineDDA -LineTo -MaskBlt -ModifyWorldTransform -MoveToEx -OffsetClipRgn -OffsetRgn -OffsetViewportOrgEx -OffsetWindowOrgEx -PaintRgn -PatBlt -PathToRegion -Pie -PlayEnhMetaFile -PlayEnhMetaFileRecord -PlayMetaFile -PlayMetaFileRecord -PlgBlt -PolyBezier -PolyBezierTo -PolyDraw -PolyPolygon -PolyPolyline -PolyTextOutA -PolyTextOutW -Polygon -Polyline -PolylineTo -PtInRegion -PtVisible -RealizePalette -RectInRegion -RectVisible -Rectangle -RemoveFontResourceA -RemoveFontResourceW -ResetDCA -ResetDCW -ResizePalette -RestoreDC -RoundRect -SaveDC -ScaleViewportExtEx -ScaleWindowExtEx -SelectClipPath -SelectClipRgn -SelectObject -SelectPalette -SetAbortProc -SetArcDirection -SetBitmapBits -SetBitmapDimensionEx -SetBkColor -SetBkMode -SetBoundsRect -SetBrushOrgEx -SetColorAdjustment -SetColorSpace -SetDIBColorTable -SetDIBits -SetDIBitsToDevice -SetDeviceGammaRamp -SetEnhMetaFileBits -SetFontEnumeration -SetGraphicsMode -SetICMMode -SetICMProfileA -SetICMProfileW -SetLayout -SetMagicColors -SetMapMode -SetMapperFlags -SetMetaFileBitsEx -SetMetaRgn -SetMiterLimit -SetObjectOwner -SetPaletteEntries -SetPixel -SetPixelFormat -SetPixelV -SetPolyFillMode -SetROP2 -SetRectRgn -SetStretchBltMode -SetSystemPaletteUse -SetTextAlign -SetTextCharacterExtra -SetTextColor -SetTextJustification -SetViewportExtEx -SetViewportOrgEx -SetWinMetaFileBits -SetWindowExtEx -SetWindowOrgEx -SetWorldTransform -StartDocA -StartDocW -StartPage -StretchBlt -StretchDIBits -StrokeAndFillPath -StrokePath -SwapBuffers -TextOutA -TextOutW -TranslateCharsetInfo -UnrealizeObject -UpdateColors -UpdateICMRegKeyA -UpdateICMRegKeyW -WidenPath -gdiPlaySpoolStream -pfnRealizePalette -pfnSelectPalette diff --git a/ext/tcc-0.9.27/lib/kernel32.def b/ext/tcc-0.9.27/lib/kernel32.def deleted file mode 100644 index f03e17ba..00000000 --- a/ext/tcc-0.9.27/lib/kernel32.def +++ /dev/null @@ -1,770 +0,0 @@ -LIBRARY kernel32.dll - -EXPORTS -AddAtomA -AddAtomW -AllocConsole -AllocLSCallback -AllocSLCallback -AreFileApisANSI -BackupRead -BackupSeek -BackupWrite -Beep -BeginUpdateResourceA -BeginUpdateResourceW -BuildCommDCBA -BuildCommDCBAndTimeoutsA -BuildCommDCBAndTimeoutsW -BuildCommDCBW -CallNamedPipeA -CallNamedPipeW -Callback12 -Callback16 -Callback20 -Callback24 -Callback28 -Callback32 -Callback36 -Callback4 -Callback40 -Callback44 -Callback48 -Callback52 -Callback56 -Callback60 -Callback64 -Callback8 -CancelDeviceWakeupRequest -CancelIo -CancelWaitableTimer -ClearCommBreak -ClearCommError -CloseHandle -CloseProfileUserMapping -CloseSystemHandle -CommConfigDialogA -CommConfigDialogW -CompareFileTime -CompareStringA -CompareStringW -ConnectNamedPipe -ContinueDebugEvent -ConvertDefaultLocale -ConvertThreadToFiber -ConvertToGlobalHandle -CopyFileA -CopyFileExA -CopyFileExW -CopyFileW -CreateConsoleScreenBuffer -CreateDirectoryA -CreateDirectoryExA -CreateDirectoryExW -CreateDirectoryW -CreateEventA -CreateEventW -CreateFiber -CreateFileA -CreateFileMappingA -CreateFileMappingW -CreateFileW -CreateIoCompletionPort -CreateKernelThread -CreateMailslotA -CreateMailslotW -CreateMutexA -CreateMutexW -CreateNamedPipeA -CreateNamedPipeW -CreatePipe -CreateProcessA -CreateProcessW -CreateRemoteThread -CreateSemaphoreA -CreateSemaphoreW -CreateSocketHandle -CreateTapePartition -CreateThread -CreateToolhelp32Snapshot -CreateWaitableTimerA -CreateWaitableTimerW -DebugActiveProcess -DebugBreak -DefineDosDeviceA -DefineDosDeviceW -DeleteAtom -DeleteCriticalSection -DeleteFiber -DeleteFileA -DeleteFileW -DeviceIoControl -DisableThreadLibraryCalls -DisconnectNamedPipe -DosDateTimeToFileTime -DuplicateHandle -EndUpdateResourceA -EndUpdateResourceW -EnterCriticalSection -EnumCalendarInfoA -EnumCalendarInfoExA -EnumCalendarInfoExW -EnumCalendarInfoW -EnumDateFormatsA -EnumDateFormatsExA -EnumDateFormatsExW -EnumDateFormatsW -EnumLanguageGroupLocalesA -EnumLanguageGroupLocalesW -EnumResourceLanguagesA -EnumResourceLanguagesW -EnumResourceNamesA -EnumResourceNamesW -EnumResourceTypesA -EnumResourceTypesW -EnumSystemCodePagesA -EnumSystemCodePagesW -EnumSystemGeoID -EnumSystemLanguageGroupsA -EnumSystemLanguageGroupsW -EnumSystemLocalesA -EnumSystemLocalesW -EnumTimeFormatsA -EnumTimeFormatsW -EnumUILanguagesA -EnumUILanguagesW -EraseTape -EscapeCommFunction -ExitProcess -ExitThread -ExpandEnvironmentStringsA -ExpandEnvironmentStringsW -FT_Exit0 -FT_Exit12 -FT_Exit16 -FT_Exit20 -FT_Exit24 -FT_Exit28 -FT_Exit32 -FT_Exit36 -FT_Exit4 -FT_Exit40 -FT_Exit44 -FT_Exit48 -FT_Exit52 -FT_Exit56 -FT_Exit8 -FT_Prolog -FT_Thunk -FatalAppExitA -FatalAppExitW -FatalExit -FileTimeToDosDateTime -FileTimeToLocalFileTime -FileTimeToSystemTime -FillConsoleOutputAttribute -FillConsoleOutputCharacterA -FillConsoleOutputCharacterW -FindAtomA -FindAtomW -FindClose -FindCloseChangeNotification -FindFirstChangeNotificationA -FindFirstChangeNotificationW -FindFirstFileA -FindFirstFileExA -FindFirstFileExW -FindFirstFileW -FindNextChangeNotification -FindNextFileA -FindNextFileW -FindResourceA -FindResourceExA -FindResourceExW -FindResourceW -FlushConsoleInputBuffer -FlushFileBuffers -FlushInstructionCache -FlushViewOfFile -FoldStringA -FoldStringW -FormatMessageA -FormatMessageW -FreeConsole -FreeEnvironmentStringsA -FreeEnvironmentStringsW -FreeLSCallback -FreeLibrary -FreeLibraryAndExitThread -FreeResource -FreeSLCallback -GenerateConsoleCtrlEvent -GetACP -GetAtomNameA -GetAtomNameW -GetBinaryType -GetBinaryTypeA -GetBinaryTypeW -GetCPInfo -GetCPInfoExA -GetCPInfoExW -GetCalendarInfoA -GetCalendarInfoW -GetCommConfig -GetCommMask -GetCommModemStatus -GetCommProperties -GetCommState -GetCommTimeouts -GetCommandLineA -GetCommandLineW -GetCompressedFileSizeA -GetCompressedFileSizeW -GetComputerNameA -GetComputerNameW -GetConsoleCP -GetConsoleCursorInfo -GetConsoleMode -GetConsoleOutputCP -GetConsoleScreenBufferInfo -GetConsoleTitleA -GetConsoleTitleW -GetCurrencyFormatA -GetCurrencyFormatW -GetCurrentDirectoryA -GetCurrentDirectoryW -GetCurrentProcess -GetCurrentProcessId -GetCurrentThread -GetCurrentThreadId -GetDateFormatA -GetDateFormatW -GetDaylightFlag -GetDefaultCommConfigA -GetDefaultCommConfigW -GetDevicePowerState -GetDiskFreeSpaceA -GetDiskFreeSpaceExA -GetDiskFreeSpaceExW -GetDiskFreeSpaceW -GetDriveTypeA -GetDriveTypeW -GetEnvironmentStrings -GetEnvironmentStringsA -GetEnvironmentStringsW -GetEnvironmentVariableA -GetEnvironmentVariableW -GetErrorMode -GetExitCodeProcess -GetExitCodeThread -GetFileAttributesA -GetFileAttributesExA -GetFileAttributesExW -GetFileAttributesW -GetFileInformationByHandle -GetFileSize -GetFileTime -GetFileType -GetFullPathNameA -GetFullPathNameW -GetGeoInfoA -GetGeoInfoW -GetHandleContext -GetHandleInformation -GetLSCallbackTarget -GetLSCallbackTemplate -GetLargestConsoleWindowSize -GetLastError -GetLocalTime -GetLocaleInfoA -GetLocaleInfoW -GetLogicalDriveStringsA -GetLogicalDriveStringsW -GetLogicalDrives -GetLongPathNameA -GetLongPathNameW -GetMailslotInfo -GetModuleFileNameA -GetModuleFileNameW -GetModuleHandleA -GetModuleHandleW -GetModuleHandleExA -GetModuleHandleExW -GetNamedPipeHandleStateA -GetNamedPipeHandleStateW -GetNamedPipeInfo -GetNumberFormatA -GetNumberFormatW -GetNumberOfConsoleInputEvents -GetNumberOfConsoleMouseButtons -GetOEMCP -GetOverlappedResult -GetPriorityClass -GetPrivateProfileIntA -GetPrivateProfileIntW -GetPrivateProfileSectionA -GetPrivateProfileSectionNamesA -GetPrivateProfileSectionNamesW -GetPrivateProfileSectionW -GetPrivateProfileStringA -GetPrivateProfileStringW -GetPrivateProfileStructA -GetPrivateProfileStructW -GetProcAddress -GetProcessAffinityMask -GetProcessFlags -GetProcessHeap -GetProcessHeaps -GetProcessPriorityBoost -GetProcessShutdownParameters -GetProcessTimes -GetProcessVersion -GetProcessWorkingSetSize -GetProductName -GetProfileIntA -GetProfileIntW -GetProfileSectionA -GetProfileSectionW -GetProfileStringA -GetProfileStringW -GetQueuedCompletionStatus -GetSLCallbackTarget -GetSLCallbackTemplate -GetShortPathNameA -GetShortPathNameW -GetStartupInfoA -GetStartupInfoW -GetStdHandle -GetStringTypeA -GetStringTypeExA -GetStringTypeExW -GetStringTypeW -GetSystemDefaultLCID -GetSystemDefaultLangID -GetSystemDefaultUILanguage -GetSystemDirectoryA -GetSystemDirectoryW -GetSystemInfo -GetSystemPowerStatus -GetSystemTime -GetSystemTimeAdjustment -GetSystemTimeAsFileTime -GetTapeParameters -GetTapePosition -GetTapeStatus -GetTempFileNameA -GetTempFileNameW -GetTempPathA -GetTempPathW -GetThreadContext -GetThreadLocale -GetThreadPriority -GetThreadPriorityBoost -GetThreadSelectorEntry -GetThreadTimes -GetTickCount -GetTimeFormatA -GetTimeFormatW -GetTimeZoneInformation -GetUserDefaultLCID -GetUserDefaultLangID -GetUserDefaultUILanguage -GetUserGeoID -GetVersion -GetVersionExA -GetVersionExW -GetVolumeInformationA -GetVolumeInformationW -GetWindowsDirectoryA -GetWindowsDirectoryW -GetWriteWatch -GlobalAddAtomA -GlobalAddAtomW -GlobalAlloc -GlobalCompact -GlobalDeleteAtom -GlobalFindAtomA -GlobalFindAtomW -GlobalFix -GlobalFlags -GlobalFree -GlobalGetAtomNameA -GlobalGetAtomNameW -GlobalHandle -GlobalLock -GlobalMemoryStatus -GlobalReAlloc -GlobalSize -GlobalUnWire -GlobalUnfix -GlobalUnlock -GlobalWire -Heap32First -Heap32ListFirst -Heap32ListNext -Heap32Next -HeapAlloc -HeapCompact -HeapCreate -HeapDestroy -HeapFree -HeapLock -HeapReAlloc -HeapSetFlags -HeapSize -HeapUnlock -HeapValidate -HeapWalk -InitAtomTable -InitializeCriticalSection -InitializeCriticalSectionAndSpinCount -InterlockedCompareExchange -InterlockedDecrement -InterlockedExchange -InterlockedExchangeAdd -InterlockedIncrement -InvalidateNLSCache -IsBadCodePtr -IsBadHugeReadPtr -IsBadHugeWritePtr -IsBadReadPtr -IsBadStringPtrA -IsBadStringPtrW -IsBadWritePtr -IsDBCSLeadByte -IsDBCSLeadByteEx -IsDebuggerPresent -IsLSCallback -IsProcessorFeaturePresent -IsSLCallback -IsSystemResumeAutomatic -IsValidCodePage -IsValidLanguageGroup -IsValidLocale -K32Thk1632Epilog -K32Thk1632Prolog -K32_NtCreateFile -K32_RtlNtStatusToDosError -LCMapStringA -LCMapStringW -LeaveCriticalSection -LoadLibraryA -LoadLibraryExA -LoadLibraryExW -LoadLibraryW -LoadModule -LoadResource -LocalAlloc -LocalCompact -LocalFileTimeToFileTime -LocalFlags -LocalFree -LocalHandle -LocalLock -LocalReAlloc -LocalShrink -LocalSize -LocalUnlock -LockFile -LockFileEx -LockResource -MakeCriticalSectionGlobal -MapHInstLS -MapHInstLS_PN -MapHInstSL -MapHInstSL_PN -MapHModuleLS -MapHModuleSL -MapLS -MapSL -MapSLFix -MapViewOfFile -MapViewOfFileEx -Module32First -Module32Next -MoveFileA -MoveFileExA -MoveFileExW -MoveFileW -MulDiv -MultiByteToWideChar -NotifyNLSUserCache -OpenEventA -OpenEventW -OpenFile -OpenFileMappingA -OpenFileMappingW -OpenMutexA -OpenMutexW -OpenProcess -OpenProfileUserMapping -OpenSemaphoreA -OpenSemaphoreW -OpenThread -OpenVxDHandle -OpenWaitableTimerA -OpenWaitableTimerW -OutputDebugStringA -OutputDebugStringW -PeekConsoleInputA -PeekConsoleInputW -PeekNamedPipe -PostQueuedCompletionStatus -PrepareTape -Process32First -Process32Next -PulseEvent -PurgeComm -QT_Thunk -QueryDosDeviceA -QueryDosDeviceW -QueryNumberOfEventLogRecords -QueryOldestEventLogRecord -QueryPerformanceCounter -QueryPerformanceFrequency -QueueUserAPC -RaiseException -ReadConsoleA -ReadConsoleInputA -ReadConsoleInputW -ReadConsoleOutputA -ReadConsoleOutputAttribute -ReadConsoleOutputCharacterA -ReadConsoleOutputCharacterW -ReadConsoleOutputW -ReadConsoleW -ReadDirectoryChangesW -ReadFile -ReadFileEx -ReadFileScatter -ReadProcessMemory -RegisterServiceProcess -RegisterSysMsgHandler -ReinitializeCriticalSection -ReleaseMutex -ReleaseSemaphore -RemoveDirectoryA -RemoveDirectoryW -RequestDeviceWakeup -RequestWakeupLatency -ResetEvent -ResetNLSUserInfoCache -ResetWriteWatch -ResumeThread -RtlAddFunctionTable -RtlDeleteFunctionTable -RtlFillMemory -RtlInstallFunctionTableCallback -RtlMoveMemory -RtlUnwind -RtlUnwindEx -RtlZeroMemory -SMapLS -SMapLS_IP_EBP_12 -SMapLS_IP_EBP_16 -SMapLS_IP_EBP_20 -SMapLS_IP_EBP_24 -SMapLS_IP_EBP_28 -SMapLS_IP_EBP_32 -SMapLS_IP_EBP_36 -SMapLS_IP_EBP_40 -SMapLS_IP_EBP_8 -SUnMapLS -SUnMapLS_IP_EBP_12 -SUnMapLS_IP_EBP_16 -SUnMapLS_IP_EBP_20 -SUnMapLS_IP_EBP_24 -SUnMapLS_IP_EBP_28 -SUnMapLS_IP_EBP_32 -SUnMapLS_IP_EBP_36 -SUnMapLS_IP_EBP_40 -SUnMapLS_IP_EBP_8 -ScrollConsoleScreenBufferA -ScrollConsoleScreenBufferW -SearchPathA -SearchPathW -SetCalendarInfoA -SetCalendarInfoW -SetCommBreak -SetCommConfig -SetCommMask -SetCommState -SetCommTimeouts -SetComputerNameA -SetComputerNameW -SetConsoleActiveScreenBuffer -SetConsoleCP -SetConsoleCtrlHandler -SetConsoleCursorInfo -SetConsoleCursorPosition -SetConsoleMode -SetConsoleOutputCP -SetConsoleScreenBufferSize -SetConsoleTextAttribute -SetConsoleTitleA -SetConsoleTitleW -SetConsoleWindowInfo -SetCriticalSectionSpinCount -SetCurrentDirectoryA -SetCurrentDirectoryW -SetDaylightFlag -SetDefaultCommConfigA -SetDefaultCommConfigW -SetEndOfFile -SetEnvironmentVariableA -SetEnvironmentVariableW -SetErrorMode -SetEvent -SetFileApisToANSI -SetFileApisToOEM -SetFileAttributesA -SetFileAttributesW -SetFilePointer -SetFilePointerEx -SetFileTime -SetHandleContext -SetHandleCount -SetHandleInformation -SetLastError -SetLocalTime -SetLocaleInfoA -SetLocaleInfoW -SetMailslotInfo -SetMessageWaitingIndicator -SetNamedPipeHandleState -SetPriorityClass -SetProcessAffinityMask -SetProcessPriorityBoost -SetProcessShutdownParameters -SetProcessWorkingSetSize -SetStdHandle -SetSystemPowerState -SetSystemTime -SetSystemTimeAdjustment -SetTapeParameters -SetTapePosition -SetThreadAffinityMask -SetThreadContext -SetThreadExecutionState -SetThreadIdealProcessor -SetThreadLocale -SetThreadPriority -SetThreadPriorityBoost -SetTimeZoneInformation -SetUnhandledExceptionFilter -SetUserGeoID -SetVolumeLabelA -SetVolumeLabelW -SetWaitableTimer -SetupComm -SignalObjectAndWait -SignalSysMsgHandlers -SizeofResource -Sleep -SleepEx -SuspendThread -SwitchToFiber -SwitchToThread -SystemTimeToFileTime -SystemTimeToTzSpecificLocalTime -TerminateProcess -TerminateThread -Thread32First -Thread32Next -ThunkConnect32 -TlsAlloc -TlsAllocInternal -TlsFree -TlsFreeInternal -TlsGetValue -TlsSetValue -Toolhelp32ReadProcessMemory -TransactNamedPipe -TransmitCommChar -TryEnterCriticalSection -UTRegister -UTUnRegister -UnMapLS -UnMapSLFixArray -UnhandledExceptionFilter -UninitializeCriticalSection -UnlockFile -UnlockFileEx -UnmapViewOfFile -UpdateResourceA -UpdateResourceW -VerLanguageNameA -VerLanguageNameW -VirtualAlloc -VirtualAllocEx -VirtualFree -VirtualFreeEx -VirtualLock -VirtualProtect -VirtualProtectEx -VirtualQuery -VirtualQueryEx -VirtualUnlock -WaitCommEvent -WaitForDebugEvent -WaitForMultipleObjects -WaitForMultipleObjectsEx -WaitForSingleObject -WaitForSingleObjectEx -WaitNamedPipeA -WaitNamedPipeW -WideCharToMultiByte -WinExec -WriteConsoleA -WriteConsoleInputA -WriteConsoleInputW -WriteConsoleOutputA -WriteConsoleOutputAttribute -WriteConsoleOutputCharacterA -WriteConsoleOutputCharacterW -WriteConsoleOutputW -WriteConsoleW -WriteFile -WriteFileEx -WriteFileGather -WritePrivateProfileSectionA -WritePrivateProfileSectionW -WritePrivateProfileStringA -WritePrivateProfileStringW -WritePrivateProfileStructA -WritePrivateProfileStructW -WriteProcessMemory -WriteProfileSectionA -WriteProfileSectionW -WriteProfileStringA -WriteProfileStringW -WriteTapemark -_DebugOut -_DebugPrintf -_hread -_hwrite -_lclose -_lcreat -_llseek -_lopen -_lread -_lwrite -dprintf -lstrcat -lstrcatA -lstrcatW -lstrcmp -lstrcmpA -lstrcmpW -lstrcmpi -lstrcmpiA -lstrcmpiW -lstrcpy -lstrcpyA -lstrcpyW -lstrcpyn -lstrcpynA -lstrcpynW -lstrlen -lstrlenA -lstrlenW diff --git a/ext/tcc-0.9.27/lib/msvcrt.def b/ext/tcc-0.9.27/lib/msvcrt.def deleted file mode 100644 index 742acb8b..00000000 --- a/ext/tcc-0.9.27/lib/msvcrt.def +++ /dev/null @@ -1,1399 +0,0 @@ -LIBRARY msvcrt.dll - -EXPORTS -$I10_OUTPUT -??0__non_rtti_object@@QAE@ABV0@@Z -??0__non_rtti_object@@QAE@PBD@Z -??0bad_cast@@AAE@PBQBD@Z -??0bad_cast@@QAE@ABQBD@Z -??0bad_cast@@QAE@ABV0@@Z -??0bad_cast@@QAE@PBD@Z -??0bad_typeid@@QAE@ABV0@@Z -??0bad_typeid@@QAE@PBD@Z -??0exception@@QAE@ABQBD@Z -??0exception@@QAE@ABQBDH@Z -??0exception@@QAE@ABV0@@Z -??0exception@@QAE@XZ -??1__non_rtti_object@@UAE@XZ -??1bad_cast@@UAE@XZ -??1bad_typeid@@UAE@XZ -??1exception@@UAE@XZ -??1type_info@@UAE@XZ -??2@YAPAXI@Z -??2@YAPAXIHPBDH@Z -??3@YAXPAX@Z -??4__non_rtti_object@@QAEAAV0@ABV0@@Z -??4bad_cast@@QAEAAV0@ABV0@@Z -??4bad_typeid@@QAEAAV0@ABV0@@Z -??4exception@@QAEAAV0@ABV0@@Z -??8type_info@@QBEHABV0@@Z -??9type_info@@QBEHABV0@@Z -??_7__non_rtti_object@@6B@ -??_7bad_cast@@6B@ -??_7bad_typeid@@6B@ -??_7exception@@6B@ -??_E__non_rtti_object@@UAEPAXI@Z -??_Ebad_cast@@UAEPAXI@Z -??_Ebad_typeid@@UAEPAXI@Z -??_Eexception@@UAEPAXI@Z -??_Fbad_cast@@QAEXXZ -??_Fbad_typeid@@QAEXXZ -??_G__non_rtti_object@@UAEPAXI@Z -??_Gbad_cast@@UAEPAXI@Z -??_Gbad_typeid@@UAEPAXI@Z -??_Gexception@@UAEPAXI@Z -??_U@YAPAXI@Z -??_U@YAPAXIHPBDH@Z -??_V@YAXPAX@Z -?_query_new_handler@@YAP6AHI@ZXZ -?_query_new_mode@@YAHXZ -?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z -?_set_new_mode@@YAHH@Z -?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z -?before@type_info@@QBEHABV1@@Z -?name@type_info@@QBEPBDXZ -?raw_name@type_info@@QBEPBDXZ -?set_new_handler@@YAP6AXXZP6AXXZ@Z -?set_terminate@@YAP6AXXZP6AXXZ@Z -?set_unexpected@@YAP6AXXZP6AXXZ@Z -?terminate@@YAXXZ -?unexpected@@YAXXZ -?what@exception@@UBEPBDXZ -_CIacos -_CIasin -_CIatan -_CIatan2 -_CIcos -_CIcosh -_CIexp -_CIfmod -_CIlog -_CIlog10 -_CIpow -_CIsin -_CIsinh -_CIsqrt -_CItan -_CItanh -_CrtCheckMemory -_CrtDbgBreak -_CrtDbgReport -_CrtDbgReportV -_CrtDbgReportW -_CrtDbgReportWV -_CrtDoForAllClientObjects -_CrtDumpMemoryLeaks -_CrtIsMemoryBlock -_CrtIsValidHeapPointer -_CrtIsValidPointer -_CrtMemCheckpoint -_CrtMemDifference -_CrtMemDumpAllObjectsSince -_CrtMemDumpStatistics -_CrtReportBlockType -_CrtSetAllocHook -_CrtSetBreakAlloc -_CrtSetDbgBlockType -_CrtSetDbgFlag -_CrtSetDumpClient -_CrtSetReportFile -_CrtSetReportHook -_CrtSetReportHook2 -_CrtSetReportMode -_CxxThrowException -_EH_prolog -_Getdays -_Getmonths -_Gettnames -_HUGE -_Strftime -_XcptFilter -__CppXcptFilter -__CxxCallUnwindDelDtor -__CxxCallUnwindDtor -__CxxCallUnwindVecDtor -__CxxDetectRethrow -__CxxExceptionFilter -__CxxFrameHandler -__CxxFrameHandler2 -__CxxFrameHandler3 -__CxxLongjmpUnwind -__CxxQueryExceptionSize -__CxxRegisterExceptionObject -__CxxUnregisterExceptionObject -__DestructExceptionObject -__RTCastToVoid -__RTDynamicCast -__RTtypeid -__STRINGTOLD -___lc_codepage_func -___lc_collate_cp_func -___lc_handle_func -___mb_cur_max_func -___setlc_active_func -___unguarded_readlc_active_add_func -__argc -__argv -__badioinfo -__crtCompareStringA -__crtCompareStringW -__crtGetLocaleInfoW -__crtGetStringTypeW -__crtLCMapStringA -__crtLCMapStringW -__daylight -__dllonexit -__doserrno -__dstbias -__fpecode -__getmainargs -__initenv -__iob_func -__isascii -__iscsym -__iscsymf -__lc_codepage -__lc_collate_cp -__lc_handle -__lconv_init -__libm_sse2_acos -__libm_sse2_acosf -__libm_sse2_asin -__libm_sse2_asinf -__libm_sse2_atan -__libm_sse2_atan2 -__libm_sse2_atanf -__libm_sse2_cos -__libm_sse2_cosf -__libm_sse2_exp -__libm_sse2_expf -__libm_sse2_log -__libm_sse2_log10 -__libm_sse2_log10f -__libm_sse2_logf -__libm_sse2_pow -__libm_sse2_powf -__libm_sse2_sin -__libm_sse2_sinf -__libm_sse2_tan -__libm_sse2_tanf -__mb_cur_max -__p___argc -__p___argv -__p___initenv -__p___mb_cur_max -__p___wargv -__p___winitenv -__p__acmdln -__p__amblksiz -__p__commode -__p__daylight -__p__dstbias -__p__environ -__p__fileinfo -__p__fmode -__p__iob -__p__mbcasemap -__p__mbctype -__p__osver -__p__pctype -__p__pgmptr -__p__pwctype -__p__timezone -__p__tzname -__p__wcmdln -__p__wenviron -__p__winmajor -__p__winminor -__p__winver -__p__wpgmptr -__pctype_func -__pioinfo -__pwctype_func -__pxcptinfoptrs -__set_app_type -__setlc_active -__setusermatherr -__strncnt -__threadhandle -__threadid -__toascii -__unDName -__unDNameEx -__uncaught_exception -__unguarded_readlc_active -__wargv -__wcserror -__wcserror_s -__wcsncnt -__wgetmainargs -__winitenv -_abnormal_termination -_abs64 -_access -_access_s -_acmdln -_adj_fdiv_m16i -_adj_fdiv_m32 -_adj_fdiv_m32i -_adj_fdiv_m64 -_adj_fdiv_r -_adj_fdivr_m16i -_adj_fdivr_m32 -_adj_fdivr_m32i -_adj_fdivr_m64 -_adj_fpatan -_adj_fprem -_adj_fprem1 -_adj_fptan -_adjust_fdiv -_aexit_rtn -_aligned_free -_aligned_free_dbg -_aligned_malloc -_aligned_malloc_dbg -_aligned_offset_malloc -_aligned_offset_malloc_dbg -_aligned_offset_realloc -_aligned_offset_realloc_dbg -_aligned_realloc -_aligned_realloc_dbg -_amsg_exit -_assert -_atodbl -_atodbl_l -_atof_l -_atoflt_l -_atoi64 -_atoi64_l -_atoi_l -_atol_l -_atoldbl -_atoldbl_l -_beep -_beginthread -_beginthreadex -_c_exit -_cabs -_callnewh -_calloc_dbg -_cexit -_cgets -_cgets_s -_cgetws -_cgetws_s -_chdir -_chdrive -_chgsign -_chkesp -_chmod -_chsize -_chsize_s -_chvalidator -_chvalidator_l -_clearfp -_close -_commit -_commode -_control87 -_controlfp -_controlfp_s -_copysign -_cprintf -_cprintf_l -_cprintf_p -_cprintf_p_l -_cprintf_s -_cprintf_s_l -_cputs -_cputws -_creat -_crtAssertBusy -_crtBreakAlloc -_crtDbgFlag -_cscanf -_cscanf_l -_cscanf_s -_cscanf_s_l -_ctime32 -_ctime32_s -_ctime64 -_ctime64_s -_ctype -_cwait -_cwprintf -_cwprintf_l -_cwprintf_p -_cwprintf_p_l -_cwprintf_s -_cwprintf_s_l -_cwscanf -_cwscanf_l -_cwscanf_s -_cwscanf_s_l -_daylight -_difftime32 -_difftime64 -_dstbias -_dup -_dup2 -_ecvt -_ecvt_s -_endthread -_endthreadex -_environ -_eof -_errno -_except_handler2 -_except_handler3 -_except_handler4_common -_execl -_execle -_execlp -_execlpe -_execv -_execve -_execvp -_execvpe -_exit -_expand -_expand_dbg -_fcloseall -_fcvt -_fcvt_s -_fdopen -_fgetchar -_fgetwchar -_filbuf -_fileinfo -_filelength -_filelengthi64 -_fileno -_findclose -_findfirst -_findfirst64 -_findfirsti64 -_findnext -_findnext64 -_findnexti64 -_finite -_flsbuf -_flushall -_fmode -_fpclass -_fpieee_flt -_fpreset -_fprintf_l -_fprintf_p -_fprintf_p_l -_fprintf_s_l -_fputchar -_fputwchar -_free_dbg -_freea -_freea_s -_fscanf_l -_fscanf_s_l -_fseeki64 -_fsopen -_fstat -_fstat64 -_fstati64 -_ftime -_ftime32 -_ftime32_s -_ftime64 -_ftime64_s -_ftol -_ftol2 -_ftol2_sse -_ftol2_sse_excpt -_fullpath -_fullpath_dbg -_futime -_futime32 -_futime64 -_fwprintf_l -_fwprintf_p -_fwprintf_p_l -_fwprintf_s_l -_fwscanf_l -_fwscanf_s_l -_gcvt -_gcvt_s -_get_doserrno -_get_environ -_get_errno -_get_fileinfo -_get_fmode -_get_heap_handle -_get_osfhandle -_get_osplatform -_get_osver -_get_output_format -_get_pgmptr -_get_sbh_threshold -_get_wenviron -_get_winmajor -_get_winminor -_get_winver -_get_wpgmptr -_getch -_getche -_getcwd -_getdcwd -_getdiskfree -_getdllprocaddr -_getdrive -_getdrives -_getmaxstdio -_getmbcp -_getpid -_getsystime -_getw -_getwch -_getwche -_getws -_global_unwind2 -_gmtime32 -_gmtime32_s -_gmtime64 -_gmtime64_s -_heapadd -_heapchk -_heapmin -_heapset -_heapused -_heapwalk -_hypot -_i64toa -_i64toa_s -_i64tow -_i64tow_s -_initterm -_initterm_e -_inp -_inpd -_inpw -_invalid_parameter -_iob -_isalnum_l -_isalpha_l -_isatty -_iscntrl_l -_isctype -_isctype_l -_isdigit_l -_isgraph_l -_isleadbyte_l -_islower_l -_ismbbalnum -_ismbbalnum_l -_ismbbalpha -_ismbbalpha_l -_ismbbgraph -_ismbbgraph_l -_ismbbkalnum -_ismbbkalnum_l -_ismbbkana -_ismbbkana_l -_ismbbkprint -_ismbbkprint_l -_ismbbkpunct -_ismbbkpunct_l -_ismbblead -_ismbblead_l -_ismbbprint -_ismbbprint_l -_ismbbpunct -_ismbbpunct_l -_ismbbtrail -_ismbbtrail_l -_ismbcalnum -_ismbcalnum_l -_ismbcalpha -_ismbcalpha_l -_ismbcdigit -_ismbcdigit_l -_ismbcgraph -_ismbcgraph_l -_ismbchira -_ismbchira_l -_ismbckata -_ismbckata_l -_ismbcl0 -_ismbcl0_l -_ismbcl1 -_ismbcl1_l -_ismbcl2 -_ismbcl2_l -_ismbclegal -_ismbclegal_l -_ismbclower -_ismbclower_l -_ismbcprint -_ismbcprint_l -_ismbcpunct -_ismbcpunct_l -_ismbcspace -_ismbcspace_l -_ismbcsymbol -_ismbcsymbol_l -_ismbcupper -_ismbcupper_l -_ismbslead -_ismbslead_l -_ismbstrail -_ismbstrail_l -_isnan -_isprint_l -_isspace_l -_isupper_l -_iswalnum_l -_iswalpha_l -_iswcntrl_l -_iswctype_l -_iswdigit_l -_iswgraph_l -_iswlower_l -_iswprint_l -_iswpunct_l -_iswspace_l -_iswupper_l -_iswxdigit_l -_isxdigit_l -_itoa -_itoa_s -_itow -_itow_s -_j0 -_j1 -_jn -_kbhit -_lfind -_lfind_s -_loaddll -_local_unwind2 -_local_unwind4 -_localtime32 -_localtime32_s -_localtime64 -_localtime64_s -_lock -_locking -_logb -_longjmpex -_lrotl -_lrotr -_lsearch -_lsearch_s -_lseek -_lseeki64 -_ltoa -_ltoa_s -_ltow -_ltow_s -_makepath -_makepath_s -_malloc_dbg -_mbbtombc -_mbbtombc_l -_mbbtype -_mbcasemap -_mbccpy -_mbccpy_l -_mbccpy_s -_mbccpy_s_l -_mbcjistojms -_mbcjistojms_l -_mbcjmstojis -_mbcjmstojis_l -_mbclen -_mbclen_l -_mbctohira -_mbctohira_l -_mbctokata -_mbctokata_l -_mbctolower -_mbctolower_l -_mbctombb -_mbctombb_l -_mbctoupper -_mbctoupper_l -_mbctype -_mblen_l -_mbsbtype -_mbsbtype_l -_mbscat -_mbscat_s -_mbscat_s_l -_mbschr -_mbschr_l -_mbscmp -_mbscmp_l -_mbscoll -_mbscoll_l -_mbscpy -_mbscpy_s -_mbscpy_s_l -_mbscspn -_mbscspn_l -_mbsdec -_mbsdec_l -_mbsdup -_mbsicmp -_mbsicmp_l -_mbsicoll -_mbsicoll_l -_mbsinc -_mbsinc_l -_mbslen -_mbslen_l -_mbslwr -_mbslwr_l -_mbslwr_s -_mbslwr_s_l -_mbsnbcat -_mbsnbcat_l -_mbsnbcat_s -_mbsnbcat_s_l -_mbsnbcmp -_mbsnbcmp_l -_mbsnbcnt -_mbsnbcnt_l -_mbsnbcoll -_mbsnbcoll_l -_mbsnbcpy -_mbsnbcpy_l -_mbsnbcpy_s -_mbsnbcpy_s_l -_mbsnbicmp -_mbsnbicmp_l -_mbsnbicoll -_mbsnbicoll_l -_mbsnbset -_mbsnbset_l -_mbsnbset_s -_mbsnbset_s_l -_mbsncat -_mbsncat_l -_mbsncat_s -_mbsncat_s_l -_mbsnccnt -_mbsnccnt_l -_mbsncmp -_mbsncmp_l -_mbsncoll -_mbsncoll_l -_mbsncpy -_mbsncpy_l -_mbsncpy_s -_mbsncpy_s_l -_mbsnextc -_mbsnextc_l -_mbsnicmp -_mbsnicmp_l -_mbsnicoll -_mbsnicoll_l -_mbsninc -_mbsninc_l -_mbsnlen -_mbsnlen_l -_mbsnset -_mbsnset_l -_mbsnset_s -_mbsnset_s_l -_mbspbrk -_mbspbrk_l -_mbsrchr -_mbsrchr_l -_mbsrev -_mbsrev_l -_mbsset -_mbsset_l -_mbsset_s -_mbsset_s_l -_mbsspn -_mbsspn_l -_mbsspnp -_mbsspnp_l -_mbsstr -_mbsstr_l -_mbstok -_mbstok_l -_mbstok_s -_mbstok_s_l -_mbstowcs_l -_mbstowcs_s_l -_mbstrlen -_mbstrlen_l -_mbstrnlen -_mbstrnlen_l -_mbsupr -_mbsupr_l -_mbsupr_s -_mbsupr_s_l -_mbtowc_l -_memccpy -_memicmp -_memicmp_l -_mkdir -_mkgmtime -_mkgmtime32 -_mkgmtime64 -_mktemp -_mktemp_s -_mktime32 -_mktime64 -_msize -_msize_debug -_nextafter -_onexit -_open -_open_osfhandle -_osplatform -_osver -_outp -_outpd -_outpw -_pclose -_pctype -_pgmptr -_pipe -_popen -_printf_l -_printf_p -_printf_p_l -_printf_s_l -_purecall -_putch -_putenv -_putenv_s -_putw -_putwch -_putws -_pwctype -_read -_realloc_dbg -_resetstkoflw -_rmdir -_rmtmp -_rotl -_rotl64 -_rotr -_rotr64 -_safe_fdiv -_safe_fdivr -_safe_fprem -_safe_fprem1 -_scalb -_scanf_l -_scanf_s_l -_scprintf -_scprintf_l -_scprintf_p_l -_scwprintf -_scwprintf_l -_scwprintf_p_l -_searchenv -_searchenv_s -_seh_longjmp_unwind -_seh_longjmp_unwind4 -_set_SSE2_enable -_set_controlfp -_set_doserrno -_set_errno -_set_error_mode -_set_fileinfo -_set_fmode -_set_output_format -_set_sbh_threshold -_seterrormode -_setjmp -_setjmp3 -_setmaxstdio -_setmbcp -_setmode -_setsystime -_sleep -_snprintf -_snprintf_c -_snprintf_c_l -_snprintf_l -_snprintf_s -_snprintf_s_l -_snscanf -_snscanf_l -_snscanf_s -_snscanf_s_l -_snwprintf -_snwprintf_l -_snwprintf_s -_snwprintf_s_l -_snwscanf -_snwscanf_l -_snwscanf_s -_snwscanf_s_l -_sopen -_sopen_s -_spawnl -_spawnle -_spawnlp -_spawnlpe -_spawnv -_spawnve -_spawnvp -_spawnvpe -_splitpath -_splitpath_s -_sprintf_l -_sprintf_p_l -_sprintf_s_l -_sscanf_l -_sscanf_s_l -_stat -_stat64 -_stati64 -_statusfp -_strcmpi -_strcoll_l -_strdate -_strdate_s -_strdup -_strdup_dbg -_strerror -_strerror_s -_stricmp -_stricmp_l -_stricoll -_stricoll_l -_strlwr -_strlwr_l -_strlwr_s -_strlwr_s_l -_strncoll -_strncoll_l -_strnicmp -_strnicmp_l -_strnicoll -_strnicoll_l -_strnset -_strnset_s -_strrev -_strset -_strset_s -_strtime -_strtime_s -_strtod_l -_strtoi64 -_strtoi64_l -_strtol_l -_strtoui64 -_strtoui64_l -_strtoul_l -_strupr -_strupr_l -_strupr_s -_strupr_s_l -_strxfrm_l -_swab -_swprintf -_swprintf_c -_swprintf_c_l -_swprintf_p_l -_swprintf_s_l -_swscanf_l -_swscanf_s_l -_sys_errlist -_sys_nerr -_tell -_telli64 -_tempnam -_tempnam_dbg -_time32 -_time64 -_timezone -_tolower -_tolower_l -_toupper -_toupper_l -_towlower_l -_towupper_l -_tzname -_tzset -_ui64toa -_ui64toa_s -_ui64tow -_ui64tow_s -_ultoa -_ultoa_s -_ultow -_ultow_s -_umask -_umask_s -_ungetch -_ungetwch -_unlink -_unloaddll -_unlock -_utime -_utime32 -_utime64 -_vcprintf -_vcprintf_l -_vcprintf_p -_vcprintf_p_l -_vcprintf_s -_vcprintf_s_l -_vcwprintf -_vcwprintf_l -_vcwprintf_p -_vcwprintf_p_l -_vcwprintf_s -_vcwprintf_s_l -_vfprintf_l -_vfprintf_p -_vfprintf_p_l -_vfprintf_s_l -_vfwprintf_l -_vfwprintf_p -_vfwprintf_p_l -_vfwprintf_s_l -_vprintf_l -_vprintf_p -_vprintf_p_l -_vprintf_s_l -_vscprintf -_vscprintf_l -_vscprintf_p_l -_vscwprintf -_vscwprintf_l -_vscwprintf_p_l -_vsnprintf -_vsnprintf_c -_vsnprintf_c_l -_vsnprintf_l -_vsnprintf_s -_vsnprintf_s_l -_vsnwprintf -_vsnwprintf_l -_vsnwprintf_s -_vsnwprintf_s_l -_vsprintf_l -_vsprintf_p -_vsprintf_p_l -_vsprintf_s_l -_vswprintf -_vswprintf_c -_vswprintf_c_l -_vswprintf_l -_vswprintf_p_l -_vswprintf_s_l -_vwprintf_l -_vwprintf_p -_vwprintf_p_l -_vwprintf_s_l -_waccess -_waccess_s -_wasctime -_wasctime_s -_wassert -_wchdir -_wchmod -_wcmdln -_wcreat -_wcscoll_l -_wcsdup -_wcsdup_dbg -_wcserror -_wcserror_s -_wcsftime_l -_wcsicmp -_wcsicmp_l -_wcsicoll -_wcsicoll_l -_wcslwr -_wcslwr_l -_wcslwr_s -_wcslwr_s_l -_wcsncoll -_wcsncoll_l -_wcsnicmp -_wcsnicmp_l -_wcsnicoll -_wcsnicoll_l -_wcsnset -_wcsnset_s -_wcsrev -_wcsset -_wcsset_s -_wcstoi64 -_wcstoi64_l -_wcstol_l -_wcstombs_l -_wcstombs_s_l -_wcstoui64 -_wcstoui64_l -_wcstoul_l -_wcsupr -_wcsupr_l -_wcsupr_s -_wcsupr_s_l -_wcsxfrm_l -_wctime -_wctime32 -_wctime32_s -_wctime64 -_wctime64_s -_wctomb_l -_wctomb_s_l -_wctype -_wenviron -_wexecl -_wexecle -_wexeclp -_wexeclpe -_wexecv -_wexecve -_wexecvp -_wexecvpe -_wfdopen -_wfindfirst -_wfindfirst64 -_wfindfirsti64 -_wfindnext -_wfindnext64 -_wfindnexti64 -_wfopen -_wfopen_s -_wfreopen -_wfreopen_s -_wfsopen -_wfullpath -_wfullpath_dbg -_wgetcwd -_wgetdcwd -_wgetenv -_wgetenv_s -_winmajor -_winminor -_winput_s -_winver -_wmakepath -_wmakepath_s -_wmkdir -_wmktemp -_wmktemp_s -_wopen -_woutput_s -_wperror -_wpgmptr -_wpopen -_wprintf_l -_wprintf_p -_wprintf_p_l -_wprintf_s_l -_wputenv -_wputenv_s -_wremove -_wrename -_write -_wrmdir -_wscanf_l -_wscanf_s_l -_wsearchenv -_wsearchenv_s -_wsetlocale -_wsopen -_wsopen_s -_wspawnl -_wspawnle -_wspawnlp -_wspawnlpe -_wspawnv -_wspawnve -_wspawnvp -_wspawnvpe -_wsplitpath -_wsplitpath_s -_wstat -_wstat64 -_wstati64 -_wstrdate -_wstrdate_s -_wstrtime -_wstrtime_s -_wsystem -_wtempnam -_wtempnam_dbg -_wtmpnam -_wtmpnam_s -_wtof -_wtof_l -_wtoi -_wtoi64 -_wtoi64_l -_wtoi_l -_wtol -_wtol_l -_wunlink -_wutime -_wutime32 -_wutime64 -_y0 -_y1 -_yn -abort -abs -acos -asctime -asctime_s -asin -atan -atan2 -atexit -atof -atoi -atol -bsearch -bsearch_s -btowc -calloc -ceil -clearerr -clearerr_s -clock -cos -cosh -ctime -difftime -div -exit -exp -fabs -fclose -feof -ferror -fflush -fgetc -fgetpos -fgets -fgetwc -fgetws -floor -fmod -fopen -fopen_s -fprintf -fprintf_s -fputc -fputs -fputwc -fputws -fread -free -freopen -freopen_s -frexp -fscanf -fscanf_s -fseek -fsetpos -ftell -fwprintf -fwprintf_s -fwrite -fwscanf -fwscanf_s -getc -getchar -getenv -getenv_s -gets -getwc -getwchar -gmtime -is_wctype -isalnum -isalpha -iscntrl -isdigit -isgraph -isleadbyte -islower -isprint -ispunct -isspace -isupper -iswalnum -iswalpha -iswascii -iswcntrl -iswctype -iswdigit -iswgraph -iswlower -iswprint -iswpunct -iswspace -iswupper -iswxdigit -isxdigit -labs -ldexp -ldiv -localeconv -localtime -log -log10 -longjmp -malloc -mblen -mbrlen -mbrtowc -mbsdup_dbg -mbsrtowcs -mbsrtowcs_s -mbstowcs -mbstowcs_s -mbtowc -memchr -memcmp -memcpy -memcpy_s -memmove -memmove_s -memset -mktime -modf -perror -pow -printf -printf_s -putc -putchar -puts -putwc -putwchar -qsort -qsort_s -raise -rand -rand_s -realloc -remove -rename -rewind -scanf -scanf_s -setbuf -setlocale -setvbuf -signal -sin -sinh -sprintf -sprintf_s -sqrt -srand -sscanf -sscanf_s -strcat -strcat_s -strchr -strcmp -strcoll -strcpy -strcpy_s -strcspn -strerror -strerror_s -strftime -strlen -strncat -strncat_s -strncmp -strncpy -strncpy_s -strnlen -strpbrk -strrchr -strspn -strstr -strtod -strtok -strtok_s -strtol -strtoul -strxfrm -swprintf -swprintf_s -swscanf -swscanf_s -system -tan -tanh -time -tmpfile -tmpfile_s -tmpnam -tmpnam_s -tolower -toupper -towlower -towupper -ungetc -ungetwc -utime -vfprintf -vfprintf_s -vfwprintf -vfwprintf_s -vprintf -vprintf_s -vsnprintf -vsprintf -vsprintf_s -vswprintf -vswprintf_s -vwprintf -vwprintf_s -wcrtomb -wcrtomb_s -wcscat -wcscat_s -wcschr -wcscmp -wcscoll -wcscpy -wcscpy_s -wcscspn -wcsftime -wcslen -wcsncat -wcsncat_s -wcsncmp -wcsncpy -wcsncpy_s -wcsnlen -wcspbrk -wcsrchr -wcsrtombs -wcsrtombs_s -wcsspn -wcsstr -wcstod -wcstok -wcstok_s -wcstol -wcstombs -wcstombs_s -wcstoul -wcsxfrm -wctob -wctomb -wctomb_s -wprintf -wprintf_s -wscanf -wscanf_s diff --git a/ext/tcc-0.9.27/lib/user32.def b/ext/tcc-0.9.27/lib/user32.def deleted file mode 100644 index a034dac2..00000000 --- a/ext/tcc-0.9.27/lib/user32.def +++ /dev/null @@ -1,658 +0,0 @@ -LIBRARY user32.dll - -EXPORTS -ActivateKeyboardLayout -AdjustWindowRect -AdjustWindowRectEx -AlignRects -AllowSetForegroundWindow -AnimateWindow -AnyPopup -AppendMenuA -AppendMenuW -ArrangeIconicWindows -AttachThreadInput -BeginDeferWindowPos -BeginPaint -BlockInput -BringWindowToTop -BroadcastSystemMessage -BroadcastSystemMessageA -BroadcastSystemMessageW -CalcChildScroll -CallMsgFilter -CallMsgFilterA -CallMsgFilterW -CallNextHookEx -CallWindowProcA -CallWindowProcW -CascadeChildWindows -CascadeWindows -ChangeClipboardChain -ChangeDisplaySettingsA -ChangeDisplaySettingsExA -ChangeDisplaySettingsExW -ChangeDisplaySettingsW -ChangeMenuA -ChangeMenuW -CharLowerA -CharLowerBuffA -CharLowerBuffW -CharLowerW -CharNextA -CharNextExA -CharNextExW -CharNextW -CharPrevA -CharPrevExA -CharPrevExW -CharPrevW -CharToOemA -CharToOemBuffA -CharToOemBuffW -CharToOemW -CharUpperA -CharUpperBuffA -CharUpperBuffW -CharUpperW -CheckDlgButton -CheckMenuItem -CheckMenuRadioItem -CheckRadioButton -ChildWindowFromPoint -ChildWindowFromPointEx -ClientThreadConnect -ClientToScreen -ClipCursor -CloseClipboard -CloseDesktop -CloseWindow -CloseWindowStation -CopyAcceleratorTableA -CopyAcceleratorTableW -CopyIcon -CopyImage -CopyRect -CountClipboardFormats -CreateAcceleratorTableA -CreateAcceleratorTableW -CreateCaret -CreateCursor -CreateDesktopA -CreateDesktopW -CreateDialogIndirectParamA -CreateDialogIndirectParamW -CreateDialogParamA -CreateDialogParamW -CreateIcon -CreateIconFromResource -CreateIconFromResourceEx -CreateIconIndirect -CreateMDIWindowA -CreateMDIWindowW -CreateMenu -CreatePopupMenu -CreateWindowExA -CreateWindowExW -CreateWindowStationA -CreateWindowStationW -DdeAbandonTransaction -DdeAccessData -DdeAddData -DdeClientTransaction -DdeCmpStringHandles -DdeConnect -DdeConnectList -DdeCreateDataHandle -DdeCreateStringHandleA -DdeCreateStringHandleW -DdeDisconnect -DdeDisconnectList -DdeEnableCallback -DdeFreeDataHandle -DdeFreeStringHandle -DdeGetData -DdeGetLastError -DdeImpersonateClient -DdeInitializeA -DdeInitializeW -DdeKeepStringHandle -DdeNameService -DdePostAdvise -DdeQueryConvInfo -DdeQueryNextServer -DdeQueryStringA -DdeQueryStringW -DdeReconnect -DdeSetQualityOfService -DdeSetUserHandle -DdeUnaccessData -DdeUninitialize -DefDlgProcA -DefDlgProcW -DefFrameProcA -DefFrameProcW -DefMDIChildProcA -DefMDIChildProcW -DefWindowProcA -DefWindowProcW -DeferWindowPos -DeleteMenu -DestroyAcceleratorTable -DestroyCaret -DestroyCursor -DestroyIcon -DestroyMenu -DestroyWindow -DialogBoxIndirectParamA -DialogBoxIndirectParamW -DialogBoxParamA -DialogBoxParamW -DispatchMessageA -DispatchMessageW -DlgDirListA -DlgDirListComboBoxA -DlgDirListComboBoxW -DlgDirListW -DlgDirSelectComboBoxExA -DlgDirSelectComboBoxExW -DlgDirSelectExA -DlgDirSelectExW -DragDetect -DragObject -DrawAnimatedRects -DrawCaption -DrawCaptionTempA -DrawCaptionTempW -DrawEdge -DrawFocusRect -DrawFrame -DrawFrameControl -DrawIcon -DrawIconEx -DrawMenuBar -DrawMenuBarTemp -DrawStateA -DrawStateW -DrawTextA -DrawTextExA -DrawTextExW -DrawTextW -EditWndProc -EmptyClipboard -EnableMenuItem -EnableScrollBar -EnableWindow -EndDeferWindowPos -EndDialog -EndMenu -EndPaint -EndTask -EnumChildWindows -EnumClipboardFormats -EnumDesktopWindows -EnumDesktopsA -EnumDesktopsW -EnumDisplayDevicesA -EnumDisplayDevicesW -EnumDisplayMonitors -EnumDisplaySettingsA -EnumDisplaySettingsExA -EnumDisplaySettingsExW -EnumDisplaySettingsW -EnumPropsA -EnumPropsExA -EnumPropsExW -EnumPropsW -EnumThreadWindows -EnumWindowStationsA -EnumWindowStationsW -EnumWindows -EqualRect -ExcludeUpdateRgn -ExitWindowsEx -FillRect -FindWindowA -FindWindowExA -FindWindowExW -FindWindowW -FlashWindow -FlashWindowEx -FrameRect -FreeDDElParam -GetActiveWindow -GetAltTabInfo -GetAncestor -GetAsyncKeyState -GetCapture -GetCaretBlinkTime -GetCaretPos -GetClassInfoA -GetClassInfoExA -GetClassInfoExW -GetClassInfoW -GetClassLongA -GetClassLongW -GetClassNameA -GetClassNameW -GetClassWord -GetClientRect -GetClipCursor -GetClipboardData -GetClipboardFormatNameA -GetClipboardFormatNameW -GetClipboardOwner -GetClipboardSequenceNumber -GetClipboardViewer -GetComboBoxInfo -GetCursor -GetCursorInfo -GetCursorPos -GetDC -GetDCEx -GetDesktopWindow -GetDialogBaseUnits -GetDlgCtrlID -GetDlgItem -GetDlgItemInt -GetDlgItemTextA -GetDlgItemTextW -GetDoubleClickTime -GetFocus -GetForegroundWindow -GetGUIThreadInfo -GetGuiResources -GetIconInfo -GetInputDesktop -GetInputState -GetInternalWindowPos -GetKBCodePage -GetKeyNameTextA -GetKeyNameTextW -GetKeyState -GetKeyboardLayout -GetKeyboardLayoutList -GetKeyboardLayoutNameA -GetKeyboardLayoutNameW -GetKeyboardState -GetKeyboardType -GetLastActivePopup -GetListBoxInfo -GetMenu -GetMenuBarInfo -GetMenuCheckMarkDimensions -GetMenuContextHelpId -GetMenuDefaultItem -GetMenuInfo -GetMenuItemCount -GetMenuItemID -GetMenuItemInfoA -GetMenuItemInfoW -GetMenuItemRect -GetMenuState -GetMenuStringA -GetMenuStringW -GetMessageA -GetMessageExtraInfo -GetMessagePos -GetMessageTime -GetMessageW -GetMonitorInfoA -GetMonitorInfoW -GetMouseMovePoints -GetMouseMovePointsEx -GetNextDlgGroupItem -GetNextDlgTabItem -GetNextQueueWindow -GetOpenClipboardWindow -GetParent -GetPriorityClipboardFormat -GetProcessDefaultLayout -GetProcessWindowStation -GetPropA -GetPropW -GetQueueStatus -GetScrollBarInfo -GetScrollInfo -GetScrollPos -GetScrollRange -GetShellWindow -GetSubMenu -GetSysColor -GetSysColorBrush -GetSystemMenu -GetSystemMetrics -GetTabbedTextExtentA -GetTabbedTextExtentW -GetThreadDesktop -GetTitleBarInfo -GetTopWindow -GetUpdateRect -GetUpdateRgn -GetUserObjectInformationA -GetUserObjectInformationW -GetUserObjectSecurity -GetWindow -GetWindowContextHelpId -GetWindowDC -GetWindowInfo -GetWindowLongPtrA -GetWindowLongPtrW -SetWindowLongPtrA -SetWindowLongPtrW -GetWindowLongA -GetWindowLongW -GetWindowModuleFileNameA -GetWindowModuleFileNameW -GetWindowPlacement -GetWindowRect -GetWindowRgn -GetWindowTextA -GetWindowTextLengthA -GetWindowTextLengthW -GetWindowTextW -GetWindowThreadProcessId -GetWindowWord -GrayStringA -GrayStringW -HasSystemSleepStarted -HideCaret -HiliteMenuItem -IMPGetIMEA -IMPGetIMEW -IMPQueryIMEA -IMPQueryIMEW -IMPSetIMEA -IMPSetIMEW -ImpersonateDdeClientWindow -InSendMessage -InSendMessageEx -InflateRect -InitSharedTable -InitTask -InsertMenuA -InsertMenuItemA -InsertMenuItemW -InsertMenuW -InternalGetWindowText -IntersectRect -InvalidateRect -InvalidateRgn -InvertRect -IsCharAlphaA -IsCharAlphaNumericA -IsCharAlphaNumericW -IsCharAlphaW -IsCharLowerA -IsCharLowerW -IsCharUpperA -IsCharUpperW -IsChild -IsClipboardFormatAvailable -IsDialogMessage -IsDialogMessageA -IsDialogMessageW -IsDlgButtonChecked -IsHungThread -IsIconic -IsMenu -IsRectEmpty -IsWindow -IsWindowEnabled -IsWindowUnicode -IsWindowVisible -IsZoomed -KillTimer -LoadAcceleratorsA -LoadAcceleratorsW -LoadBitmapA -LoadBitmapW -LoadCursorA -LoadCursorFromFileA -LoadCursorFromFileW -LoadCursorW -LoadIconA -LoadIconW -LoadImageA -LoadImageW -LoadKeyboardLayoutA -LoadKeyboardLayoutW -LoadMenuA -LoadMenuIndirectA -LoadMenuIndirectW -LoadMenuW -LoadStringA -LoadStringW -LockSetForegroundWindow -LockWindowStation -LockWindowUpdate -LookupIconIdFromDirectory -LookupIconIdFromDirectoryEx -MapDialogRect -MapVirtualKeyA -MapVirtualKeyExA -MapVirtualKeyExW -MapVirtualKeyW -MapWindowPoints -MenuItemFromPoint -MessageBeep -MessageBoxA -MessageBoxExA -MessageBoxExW -MessageBoxIndirectA -MessageBoxIndirectW -MessageBoxW -ModifyAccess -ModifyMenuA -ModifyMenuW -MonitorFromPoint -MonitorFromRect -MonitorFromWindow -MoveWindow -MsgWaitForMultipleObjects -MsgWaitForMultipleObjectsEx -NotifyWinEvent -OemKeyScan -OemToCharA -OemToCharBuffA -OemToCharBuffW -OemToCharW -OffsetRect -OpenClipboard -OpenDesktopA -OpenDesktopW -OpenIcon -OpenInputDesktop -OpenWindowStationA -OpenWindowStationW -PackDDElParam -PaintDesktop -PeekMessageA -PeekMessageW -PlaySoundEvent -PostMessageA -PostMessageW -PostQuitMessage -PostThreadMessageA -PostThreadMessageW -PtInRect -RealChildWindowFromPoint -RealGetWindowClass -RedrawWindow -RegisterClassA -RegisterClassExA -RegisterClassExW -RegisterClassW -RegisterClipboardFormatA -RegisterClipboardFormatW -RegisterDeviceNotificationA -RegisterDeviceNotificationW -RegisterHotKey -RegisterLogonProcess -RegisterNetworkCapabilities -RegisterSystemThread -RegisterTasklist -RegisterWindowMessageA -RegisterWindowMessageW -ReleaseCapture -ReleaseDC -RemoveMenu -RemovePropA -RemovePropW -ReplyMessage -ReuseDDElParam -ScreenToClient -ScrollDC -ScrollWindow -ScrollWindowEx -SendDlgItemMessageA -SendDlgItemMessageW -SendIMEMessageExA -SendIMEMessageExW -SendInput -SendMessageA -SendMessageCallbackA -SendMessageCallbackW -SendMessageTimeoutA -SendMessageTimeoutW -SendMessageW -SendNotifyMessageA -SendNotifyMessageW -SetActiveWindow -SetCapture -SetCaretBlinkTime -SetCaretPos -SetClassLongA -SetClassLongW -SetClassWord -SetClipboardData -SetClipboardViewer -SetCursor -SetCursorPos -SetDebugErrorLevel -SetDeskWallpaper -SetDesktopBitmap -SetDlgItemInt -SetDlgItemTextA -SetDlgItemTextW -SetDoubleClickTime -SetFocus -SetForegroundWindow -SetInternalWindowPos -SetKeyboardState -SetLastErrorEx -SetLogonNotifyWindow -SetMenu -SetMenuContextHelpId -SetMenuDefaultItem -SetMenuInfo -SetMenuItemBitmaps -SetMenuItemInfoA -SetMenuItemInfoW -SetMessageExtraInfo -SetMessageQueue -SetParent -SetProcessDefaultLayout -SetProcessWindowStation -SetPropA -SetPropW -SetRect -SetRectEmpty -SetScrollInfo -SetScrollPos -SetScrollRange -SetShellWindow -SetSysColors -SetSysColorsTemp -SetSystemCursor -SetThreadDesktop -SetTimer -SetUserObjectInformationA -SetUserObjectInformationW -SetUserObjectSecurity -SetWinEventHook -SetWindowContextHelpId -SetWindowFullScreenState -SetWindowLongA -SetWindowLongW -SetWindowPlacement -SetWindowPos -SetWindowRgn -SetWindowTextA -SetWindowTextW -SetWindowWord -SetWindowsHookA -SetWindowsHookExA -SetWindowsHookExW -SetWindowsHookW -ShowCaret -ShowCursor -ShowOwnedPopups -ShowScrollBar -ShowWindow -ShowWindowAsync -SubtractRect -SwapMouseButton -SwitchDesktop -SwitchToThisWindow -SysErrorBox -SystemParametersInfoA -SystemParametersInfoW -TabbedTextOutA -TabbedTextOutW -TileChildWindows -TileWindows -ToAscii -ToAsciiEx -ToUnicode -ToUnicodeEx -TrackMouseEvent -TrackPopupMenu -TrackPopupMenuEx -TranslateAccelerator -TranslateAcceleratorA -TranslateAcceleratorW -TranslateMDISysAccel -TranslateMessage -UnhookWinEvent -UnhookWindowsHook -UnhookWindowsHookEx -UnionRect -UnloadKeyboardLayout -UnlockWindowStation -UnpackDDElParam -UnregisterClassA -UnregisterClassW -UnregisterDeviceNotification -UnregisterHotKey -UpdateWindow -UserClientDllInitialize -UserIsSystemResumeAutomatic -UserSetDeviceHoldState -UserSignalProc -UserTickleTimer -ValidateRect -ValidateRgn -VkKeyScanA -VkKeyScanExA -VkKeyScanExW -VkKeyScanW -WINNLSEnableIME -WINNLSGetEnableStatus -WINNLSGetIMEHotkey -WNDPROC_CALLBACK -WaitForInputIdle -WaitMessage -WinHelpA -WinHelpW -WinOldAppHackoMatic -WindowFromDC -WindowFromPoint -YieldTask -_SetProcessDefaultLayout -keybd_event -mouse_event -wsprintfA -wsprintfW -wvsprintfA -wvsprintfW diff --git a/ext/tcc-0.9.27/libtcc/libtcc.def b/ext/tcc-0.9.27/libtcc/libtcc.def deleted file mode 100644 index 7f391f99..00000000 --- a/ext/tcc-0.9.27/libtcc/libtcc.def +++ /dev/null @@ -1,35 +0,0 @@ -EXPORTS -tcc_add_file -tcc_add_include_path -tcc_add_library -tcc_add_library_err -tcc_add_library_path -tcc_add_symbol -tcc_add_sysinclude_path -tcc_basename -tcc_compile_string -tcc_define_symbol -tcc_delete -tcc_error -tcc_error_noabort -tcc_fileextension -tcc_free -tcc_get_dllexports -tcc_get_symbol -tcc_malloc -tcc_mallocz -tcc_memcheck -tcc_new -tcc_output_file -tcc_parse_args -tcc_print_stats -tcc_realloc -tcc_relocate -tcc_run -tcc_set_error_func -tcc_set_lib_path -tcc_set_options -tcc_set_output_type -tcc_strdup -tcc_undefine_symbol -tcc_warning diff --git a/ext/tcc-0.9.27/libtcc/libtcc.h b/ext/tcc-0.9.27/libtcc/libtcc.h deleted file mode 100644 index a1b31e30..00000000 --- a/ext/tcc-0.9.27/libtcc/libtcc.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef LIBTCC_H -#define LIBTCC_H - -#ifndef LIBTCCAPI -# define LIBTCCAPI -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct TCCState; - -typedef struct TCCState TCCState; - -/* create a new TCC compilation context */ -LIBTCCAPI TCCState *tcc_new(void); - -/* free a TCC compilation context */ -LIBTCCAPI void tcc_delete(TCCState *s); - -/* set CONFIG_TCCDIR at runtime */ -LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); - -/* set error/warning display callback */ -LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, - void (*error_func)(void *opaque, const char *msg)); - -/* set options as from command line (multiple supported) */ -LIBTCCAPI void tcc_set_options(TCCState *s, const char *str); - -/*****************************/ -/* preprocessor */ - -/* add include path */ -LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname); - -/* add in system include path */ -LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname); - -/* define preprocessor symbol 'sym'. Can put optional value */ -LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value); - -/* undefine preprocess symbol 'sym' */ -LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym); - -/*****************************/ -/* compiling */ - -/* add a file (C file, dll, object, library, ld script). Return -1 if error. */ -LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename); - -/* compile a string containing a C source. Return -1 if error. */ -LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); - -/*****************************/ -/* linking commands */ - -/* set output type. MUST BE CALLED before any compilation */ -LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); -#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory (default) */ -#define TCC_OUTPUT_EXE 2 /* executable file */ -#define TCC_OUTPUT_DLL 3 /* dynamic library */ -#define TCC_OUTPUT_OBJ 4 /* object file */ -#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess (used internally) */ - -/* equivalent to -Lpath option */ -LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); - -/* the library name is the same as the argument of the '-l' option */ -LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname); - -/* add a symbol to the compiled program */ -LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val); - -/* output an executable, library or object file. DO NOT call - tcc_relocate() before. */ -LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename); - -/* link and run main() function and return its value. DO NOT call - tcc_relocate() before. */ -LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); - -/* do all relocations (needed before using tcc_get_symbol()) */ -LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); -/* possible values for 'ptr': - - TCC_RELOCATE_AUTO : Allocate and manage memory internally - - NULL : return required memory size for the step below - - memory address : copy code to memory passed by the caller - returns -1 if error. */ -#define TCC_RELOCATE_AUTO (void*)1 - -/* return symbol value or NULL if not found */ -LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ext/tcc-0.9.27/libtcc/libtcc.lib b/ext/tcc-0.9.27/libtcc/libtcc.lib deleted file mode 100644 index d541d9c3..00000000 Binary files a/ext/tcc-0.9.27/libtcc/libtcc.lib and /dev/null differ diff --git a/src/Animation.cpp b/src/Animation.cpp new file mode 100644 index 00000000..42cf93dc --- /dev/null +++ b/src/Animation.cpp @@ -0,0 +1,111 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "MetaNodes.h" +#include "Animation.h" +#include "Types.h" +#include "Cam.h" + +AnimationBase::AnimationPointer AnimationBase::GetPointer(int32_t frame, bool bSetting) const +{ + if (mFrames.empty()) + return { bSetting ? -1 : 0, 0, 0, 0, 0.f }; + if (frame <= mFrames[0]) + return { bSetting ? -1 : 0, 0, 0, 0, 0.f }; + if (frame > mFrames.back()) + { + int32_t last = int32_t(mFrames.size() - (bSetting ? 0 : 1)); + return { last, mFrames.back(), last, mFrames.back(), 0.f }; + } + for (int i = 0; i < int(mFrames.size()) - 1; i++) + { + if (mFrames[i] <= frame && mFrames[i + 1] >= frame) + { + float ratio = float(frame - mFrames[i]) / float(mFrames[i + 1] - mFrames[i]); + return { i, mFrames[i], i + 1, mFrames[i + 1], ratio }; + } + } + assert(0); + return { bSetting ? -1 : 0, 0, 0, 0, 0.f }; +} + +AnimTrack& AnimTrack::operator=(const AnimTrack& other) +{ + mNodeIndex = other.mNodeIndex; + mParamIndex = other.mParamIndex; + mValueType = other.mValueType; + delete mAnimation; + mAnimation = AllocateAnimation(mValueType); + mAnimation->Copy(other.mAnimation); + return *this; +} + + +AnimationBase* AllocateAnimation(uint32_t valueType) +{ + switch (valueType) + { + case Con_Float: + return new Animation; + case Con_Float2: + return new Animation; + case Con_Float3: + return new Animation; + case Con_Float4: + return new Animation; + case Con_Color4: + return new Animation; + case Con_Int: + return new Animation; + case Con_Int2: + return new Animation; + case Con_Ramp: + return new Animation; + case Con_Angle: + return new Animation; + case Con_Angle2: + return new Animation; + case Con_Angle3: + return new Animation; + case Con_Angle4: + return new Animation; + case Con_Enum: + return new Animation; + case Con_Structure: + case Con_FilenameRead: + case Con_FilenameWrite: + case Con_ForceEvaluate: + return NULL; + case Con_Bool: + return new Animation; + case Con_Ramp4: + return new Animation; + case Con_Camera: + return new Animation; + case Con_Multiplexer: + return new Animation; + } + return NULL; +} \ No newline at end of file diff --git a/src/Animation.h b/src/Animation.h new file mode 100644 index 00000000..fdef8446 --- /dev/null +++ b/src/Animation.h @@ -0,0 +1,298 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include +#include +#include +#include "Utils.h" + +struct AnimationBase +{ + AnimationBase() + { + } + + AnimationBase(const AnimationBase&& animation) + { + mFrames = animation.mFrames; + } + + AnimationBase(const AnimationBase& animation) + { + mFrames = animation.mFrames; + } + + virtual void Allocate(size_t elementCount) + { + assert(0); + } + + virtual void* GetData() + { + assert(0); + return nullptr; + } + + virtual const void* GetDataConst() const + { + assert(0); + return nullptr; + } + + virtual size_t GetValuesByteLength() const + { + assert(0); + return 0; + } + + virtual void GetValue(uint32_t frame, void* destination) + { + assert(0); + } + + virtual void SetValue(uint32_t frame, void* source) + { + assert(0); + } + + virtual float GetFloatValue(uint32_t index, int componentIndex) + { + assert(0); + return 0.f; + } + + virtual void SetFloatValue(uint32_t index, int componentIndex, float value) + { + assert(0); + } + + virtual void Copy(AnimationBase* source) + { + mFrames = source->mFrames; + } + + struct AnimationPointer + { + int mPreviousIndex; + int mPreviousFrame; + int mNextIndex; + int mNextFrame; + float mRatio; + }; + + AnimationPointer GetPointer(int32_t frame, bool bSetting) const; + + bool operator!=(const AnimationBase& other) const + { + if (mFrames != other.mFrames) + return true; + + size_t la = GetValuesByteLength(); + size_t lb = other.GetValuesByteLength(); + if (la != lb) + return true; + if (memcmp(this->GetDataConst(), other.GetDataConst(), la)) + return true; + return false; + } + + std::vector mFrames; +}; + +template +struct Animation : public AnimationBase +{ + Animation() + { + } + + Animation(const Animation&& animation) : AnimationBase(animation) + { + mValues = animation.mValues; + } + + Animation(const Animation& animation) : AnimationBase(animation) + { + mValues = animation.mValues; + } + + virtual void Allocate(size_t elementCount) + { + mFrames.resize(elementCount); + mValues.resize(elementCount); + } + + virtual void* GetData() + { + return mValues.data(); + } + + virtual const void* GetDataConst() const + { + return mValues.data(); + } + + virtual size_t GetValuesByteLength() const + { + return mValues.size() * sizeof(T); + } + + virtual float GetFloatValue(uint32_t index, int componentIndex) + { + unsigned char* ptr = (unsigned char*)GetData(); + T& v = ((T*)ptr)[index]; + return GetComponent(componentIndex, v); + } + + virtual void SetFloatValue(uint32_t index, int componentIndex, float value) + { + unsigned char* ptr = (unsigned char*)GetData(); + T& v = ((T*)ptr)[index]; + SetComponent(componentIndex, v, value); + } + + virtual void GetValue(uint32_t frame, void* destination) + { + if (mValues.empty()) + return; + AnimationPointer pointer = GetPointer(frame, false); + T* dest = (T*)destination; + *dest = Lerp(mValues[pointer.mPreviousIndex], mValues[pointer.mNextIndex], pointer.mRatio); + } + + virtual void SetValue(uint32_t frame, void* source) + { + auto pointer = GetPointer(frame, true); + T value = *(T*)source; + if (frame == pointer.mPreviousFrame && !mValues.empty()) + { + mValues[pointer.mPreviousIndex] = value; + } + else + { + if (mFrames.empty() || pointer.mPreviousIndex >= mFrames.size()) + { + mFrames.push_back(frame); + mValues.push_back(value); + } + else + { + mFrames.insert(mFrames.begin() + pointer.mPreviousIndex + 1, frame); + mValues.insert(mValues.begin() + pointer.mPreviousIndex + 1, value); + } + } + } + + virtual void Copy(AnimationBase* source) + { + AnimationBase::Copy(source); + Allocate(source->mFrames.size()); + size_t valuesSize = GetValuesByteLength(); + if (valuesSize) + memcpy(GetData(), source->GetData(), valuesSize); + } + + std::vector mValues; + +protected: + template + float GetComponent(int componentIndex, U& v) + { + return float(v[componentIndex]); + } + + template + void SetComponent(int componentIndex, U& v, float value) + { + v[componentIndex] = decltype(v[componentIndex])(value); + } + + float GetComponent(int componentIndex, unsigned char& v) + { + return float(v); + } + + float GetComponent(int componentIndex, int& v) + { + return float(v); + } + + float GetComponent(int componentIndex, float& v) + { + return v; + } + + void SetComponent(int componentIndex, unsigned char& v, float value) + { + v = (unsigned char)(value); + } + + void SetComponent(int componentIndex, int& v, float value) + { + v = int(value); + } + + void SetComponent(int componentIndex, float& v, float value) + { + v = value; + } +}; + +struct AnimTrack +{ + AnimTrack() + { + } + + AnimTrack(const AnimTrack& other) + { + *this = other; + } + + AnimTrack& operator=(const AnimTrack& other); + + bool operator!=(const AnimTrack& other) const + { + if (mNodeIndex != other.mNodeIndex) + return true; + if (mParamIndex != other.mParamIndex) + return true; + if (mValueType != other.mValueType) + return true; + if (mAnimation->operator!=(*other.mAnimation)) + return true; + return false; + } + + uint32_t mNodeIndex{0xFFFFFFFF}; + uint32_t mParamIndex{0xFFFFFFFF}; + uint32_t mValueType; // Con_ + AnimationBase* mAnimation{nullptr}; +}; + +AnimationBase* AllocateAnimation(uint32_t valueType); + +typedef std::vector AnimationTracks; diff --git a/src/Bitmap.cpp b/src/Bitmap.cpp index eea5ac47..2eccf569 100644 --- a/src/Bitmap.cpp +++ b/src/Bitmap.cpp @@ -27,116 +27,63 @@ #include #include "Bitmap.h" #include "Utils.h" - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" +#include "Mem.h" +#include +#include +#include +#include +#include +#include "JSGlue.h" +#include "Library.h" +//#define STB_IMAGE_WRITE_IMPLEMENTATION +//#include "stb_image_write.h" #define NANOSVG_ALL_COLOR_KEYWORDS // Include full list of color keywords. #define NANOSVG_IMPLEMENTATION // Expands implementation #include "nanosvg.h" #define NANOSVGRAST_IMPLEMENTATION #include "nanosvgrast.h" - -#include "cmft/image.h" +#define STB_IMAGE_RESIZE_IMPLEMENTATION +#include "stb_image_resize.h" +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "stb_image_write.h" #if USE_FFMPEG #include "ffmpegCodec.h" #endif ImageCache gImageCache; -DefaultShaders gDefaultShader; -#ifdef GL_BGR -const unsigned int glInputFormats[] = { - GL_BGR, - GL_RGB, - GL_RGB16, - GL_RGB16F, - GL_RGB32F, - GL_RGBA, // RGBE - - GL_BGRA, - GL_RGBA, - GL_RGBA16, - GL_RGBA16F, - GL_RGBA32F, - - GL_RGBA, // RGBM -}; -const unsigned int glInternalFormats[] = { - GL_RGB, - GL_RGB, - GL_RGB16, - GL_RGB16F, - GL_RGB32F, - GL_RGBA, // RGBE - - GL_RGBA, - GL_RGBA, - GL_RGBA16, - GL_RGBA16F, - GL_RGBA32F, - - GL_RGBA, // RGBM -}; -#else -const unsigned int glInputFormats[] = { - GL_RGB, - GL_RGB, - GL_RGB, - GL_RGB, - GL_RGB, - GL_RGBA, // RGBE - - GL_RGBA, - GL_RGBA, - GL_RGBA, - GL_RGBA, - GL_RGBA, - - GL_RGBA, // RGBM -}; -const unsigned int glInternalFormats[] = { - GL_RGB, - GL_RGB, - GL_RGB, - GL_RGB, - GL_RGB, - GL_RGBA, // RGBE - - GL_RGBA, - GL_RGBA, - GL_RGBA, - GL_RGBA, - GL_RGBA, - - GL_RGBA, // RGBM -}; -#endif -const unsigned int glCubeFace[] = { - GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, -}; -const unsigned int textureFormatSize[] = {3, 3, 6, 6, 12, 4, 4, 4, 8, 8, 16, 4}; -const unsigned int textureComponentCount[] = {3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4}; - -void SaveCapture(const std::string& filemane, int x, int y, int w, int h) +bx::AllocatorI* getDefaultAllocator() { - w &= 0xFFFFFFFC; - h &= 0xFFFFFFFC; + static bx::DefaultAllocator s_allocator; + return &s_allocator; +} - int viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); +bimg::Quality::Enum GetQuality(int quality) +{ + switch (quality) + { + case 0: + case 1: + case 2: + return bimg::Quality::Highest; + case 7: + case 8: + case 9: + return bimg::Quality::Fastest; + default: + return bimg::Quality::Default; + } +} - unsigned char* imgBits = new unsigned char[w * h * 4]; +void SaveCapture(const std::string& filename, int x, int y, int w, int h) +{ + w &= 0xFFFFFFFC; + h &= 0xFFFFFFFC; - glReadPixels(x, viewport[3] - y - h, w, h, GL_RGB, GL_UNSIGNED_BYTE, imgBits); + char filenameInfos[512]; + sprintf(filenameInfos, "%d|%d|%d|%d|%s", x, y, w, h, filename.c_str()); - stbi_write_png(filemane.c_str(), w, h, 3, imgBits, w * 3); - delete[] imgBits; + bgfx::FrameBufferHandle fbh = BGFX_INVALID_HANDLE; + bgfx::requestScreenShot(fbh, filenameInfos); } #if USE_FFMPEG @@ -145,9 +92,9 @@ Image Image::DecodeImage(FFMPEGCodec::Decoder* decoder, int frame) decoder->ReadFrame(frame); Image image; image.mDecoder = decoder; - image.mNumMips = 1; - image.mNumFaces = 1; - image.mFormat = TextureFormat::BGR8; + image.mHasMipmaps = false; + image.mIsCubemap = false; + image.mFormat = bgfx::TextureFormat::RGB8; // todo:shoud be bgr8 image.mWidth = int(decoder->mWidth); image.mHeight = int(decoder->mHeight); size_t lineSize = image.mWidth * 3; @@ -192,11 +139,12 @@ int Image::LoadSVG(const char* filename, Image* image, float dpi) image->SetBits(img, imgSize); image->mWidth = width; image->mHeight = height; - image->mNumMips = 1; - image->mNumFaces = 1; - image->mFormat = TextureFormat::RGBA8; + image->mHasMipmaps = false; + image->mIsCubemap = false; + image->mFormat = bgfx::TextureFormat::RGBA8; image->mDecoder = NULL; + free(img); Image::VFlip(image); nsvgDelete(svgImage); nsvgDeleteRasterizer(rast); @@ -214,38 +162,19 @@ int Image::Read(const char* filename, Image* image) } FILE* fp = fopen(filename, "rb"); if (!fp) + { + Log("Unable to open image %s\n", filename); return EVAL_ERR; + } fclose(fp); - int components; - unsigned char* bits = stbi_load(filename, &image->mWidth, &image->mHeight, &components, 0); - if (!bits) + auto buffer = ReadFile(filename); + + if (buffer.size()) { - cmft::Image img; - if (!cmft::imageLoad(img, filename)) - { - return EVAL_ERR; - } - cmft::imageTransformUseMacroInstead(&img, cmft::IMAGE_OP_FLIP_X, UINT32_MAX); - image->SetBits((unsigned char*)img.m_data, img.m_dataSize); - image->mWidth = img.m_width; - image->mHeight = img.m_height; - image->mNumMips = img.m_numMips; - image->mNumFaces = img.m_numFaces; - image->mFormat = img.m_format; - image->mDecoder = NULL; - gImageCache.AddImage(filenameStr, image); - return EVAL_OK; + return ReadMem((unsigned char*)buffer.data(), buffer.size(), image, filename); } - - image->SetBits(bits, image->mWidth * image->mHeight * components); - image->mNumMips = 1; - image->mNumFaces = 1; - image->mFormat = (components == 3) ? TextureFormat::RGB8 : TextureFormat::RGBA8; - image->mDecoder = NULL; - stbi_image_free(bits); - gImageCache.AddImage(filenameStr, image); - return EVAL_OK; + return EVAL_ERR; } int Image::Free(Image* image) @@ -254,45 +183,103 @@ int Image::Free(Image* image) return EVAL_OK; } -unsigned int Image::Upload(Image* image, unsigned int textureId, int cubeFace) +bgfx::TextureHandle Image::Upload(const Image* image, bgfx::TextureHandle textureHandle, int cubeFace, int mipmap) { - if (!textureId) - glGenTextures(1, &textureId); - - unsigned int targetType = (cubeFace == -1) ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP; - glBindTexture(targetType, textureId); - - unsigned int inputFormat = glInputFormats[image->mFormat]; - unsigned int internalFormat = glInternalFormats[image->mFormat]; - glTexImage2D((cubeFace == -1) ? GL_TEXTURE_2D : glCubeFace[cubeFace], - 0, - internalFormat, - image->mWidth, - image->mHeight, - 0, - inputFormat, - GL_UNSIGNED_BYTE, - image->GetBits()); - TexParam(GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, targetType); - - glBindTexture(targetType, 0); - return textureId; + bool allocTexture = false; + if (textureHandle.idx == bgfx::kInvalidHandle) + { + textureHandle = bgfx::createTexture2D( + uint16_t(image->mWidth) + , uint16_t(image->mHeight) + , image->mHasMipmaps + , uint16_t(1) + , image->mFormat + , uint64_t(0) + , nullptr + ); + allocTexture = true; + } + assert(textureHandle.idx != bgfx::kInvalidHandle); + + unsigned int texelSize = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(image->mFormat))/8; + assert(texelSize == 4); + unsigned int offset = 0; + if (image->mIsCubemap) + { + for (int face = 0; face < cubeFace; face++) + { + for (size_t i = 0; i < image->GetMipmapCount(); i++) + { + offset += (image->mWidth >> i) * (image->mWidth >> i) * texelSize; + } + } + } + for (int i = 0; i < mipmap; i++) + { + offset += (image->mWidth >> i) * (image->mWidth >> i) * texelSize; + } + + uint16_t w = uint16_t(image->mWidth >> mipmap); + uint16_t h = uint16_t(image->mHeight >> mipmap); + + if (cubeFace != -1) + { + bgfx::updateTextureCube(textureHandle, 0, cubeFace, mipmap, 0, 0, image->mWidth, image->mWidth, + bgfx::copy(image->GetBits() + offset, w * h * texelSize)); + } + else + { + bgfx::updateTexture2D( + textureHandle + , 0 + , mipmap + , 0 + , 0 + , w + , h + , bgfx::copy(image->GetBits() + offset, w * h * texelSize) + ); + } + if (allocTexture) + { + vramTextureAlloc((image->mWidth >> mipmap) * (image->mHeight >> mipmap) * (bimg::getBitsPerPixel(bimg::TextureFormat::Enum(image->mFormat))/8)); + } + + return textureHandle; } -int Image::ReadMem(unsigned char* data, size_t dataSize, Image* image) +int Image::ReadMem(unsigned char* data, size_t dataSize, Image* image, const char* filename) { - int components; - unsigned char* bits = stbi_load_from_memory(data, int(dataSize), &image->mWidth, &image->mHeight, &components, 0); - if (!bits) - return EVAL_ERR; - image->SetBits(bits, image->mWidth * image->mHeight * components); - stbi_image_free(bits); + if (!dataSize) + { + return EVAL_ERR; + } + + bx::AllocatorI* g_allocator = getDefaultAllocator(); + bimg::ImageContainer* imageContainer = bimg::imageParse(g_allocator, data, (uint32_t)dataSize, bimg::TextureFormat::RGBA8); // todo handle HDR float + + if (!imageContainer) + { + return EVAL_ERR; + } + image->SetBits((unsigned char*)imageContainer->m_data, imageContainer->m_size); + image->mWidth = imageContainer->m_width; + image->mHeight = imageContainer->m_height; + image->mHasMipmaps = imageContainer->m_numMips > 1; + image->mIsCubemap = imageContainer->m_cubeMap; + image->mFormat = (imageContainer->m_format == bgfx::TextureFormat::RGB8) ? bgfx::TextureFormat::RGB8 : bgfx::TextureFormat::RGBA8; + image->mDecoder = NULL; + if (filename) + { + gImageCache.AddImage(filename, image); + } + bimg::imageFree(imageContainer); return EVAL_OK; } void Image::VFlip(Image* image) { - int pixelSize = (image->mFormat == TextureFormat::RGB8) ? 3 : 4; + int pixelSize = (image->mFormat == bgfx::TextureFormat::RGB8) ? 3 : 4; int stride = image->mWidth * pixelSize; for (int y = 0; y < image->mHeight / 2; y++) { @@ -305,128 +292,196 @@ void Image::VFlip(Image* image) } } +template void stbi_writer(void* context, void* data, int size) +{ + Writer* writer = static_cast(context); + bx::Error err; + writer->write(data, size, &err); +} + int Image::Write(const char* filename, Image* image, int format, int quality) { - int components = textureComponentCount[image->mFormat]; - switch (format) + if (!image->mWidth || !image->mHeight) { - case 0: - if (!stbi_write_jpg(filename, image->mWidth, image->mHeight, components, image->GetBits(), quality)) - return EVAL_ERR; + return EVAL_ERR; + } + + const int components = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(image->mFormat))/8; + + bx::AllocatorI* g_allocator = getDefaultAllocator(); + bx::Error err; +#ifdef __EMSCRIPTEN__ + bx::MemoryBlock mb(g_allocator); + bx::MemoryWriter writer(&mb); +#else + bx::FileWriter writer; + if (bx::open(&writer, filename, false, &err)) +#endif + { + //auto texformat = image->mFormat;//GetBIMGFormat((TextureFormat::Enum)image->mFormat); + + switch (format) + { + case 0: // jpeg + stbi_write_jpg_to_func(stbi_writer, &writer, image->mWidth, image->mHeight, components, image->GetBits(), quality); break; - case 1: - if (!stbi_write_png( - filename, image->mWidth, image->mHeight, components, image->GetBits(), image->mWidth * components)) - return EVAL_ERR; + case 1: // png + stbi_write_png_to_func(stbi_writer, &writer, image->mWidth, image->mHeight, components, image->GetBits(), 0); break; - case 2: - if (!stbi_write_tga(filename, image->mWidth, image->mHeight, components, image->GetBits())) - return EVAL_ERR; + case 2: // tga + stbi_write_tga_to_func(stbi_writer, &writer, image->mWidth, image->mHeight, components, image->GetBits()); break; - case 3: - if (!stbi_write_bmp(filename, image->mWidth, image->mHeight, components, image->GetBits())) - return EVAL_ERR; + case 3: // bmp + stbi_write_bmp_to_func(stbi_writer, &writer, image->mWidth, image->mHeight, components, image->GetBits()); + break; + case 4: // hdr + bimg::imageWriteHdr(&writer + , image->mWidth + , image->mHeight + , image->mWidth * components + , image->GetBits() + , bimg::TextureFormat::RGBA8//, image->mFormat + , false/*_yflip*/ + , &err); break; - case 4: - // if (stbi_write_hdr(filename, image->width, image->height, image->components, image->bits)) - return EVAL_ERR; + case 5: // dds + { + bimg::ImageContainer* imageContainer = bimg::imageAlloc( + g_allocator + , bimg::TextureFormat::RGBA8 + , image->mWidth + , image->mHeight + , 1 + , 1 + , image->mIsCubemap + , image->mHasMipmaps + , image->GetBits() + ); + + if (imageContainer) + { + bimg::imageWriteDds( + &writer + , *imageContainer + , image->GetBits() + , image->mDataSize + , &err + ); + bimg::imageFree(imageContainer); + } + } + break; + case 6: // ktx + bimg::imageWriteKtx( + &writer + , bimg::TextureFormat::RGBA8//, image->mFormat + , image->mIsCubemap + , image->mWidth + , image->mHeight + , 1 + , image->GetMipmapCount() + , 1 + , image->GetBits() + , &err + ); + break; + case 7: // exr + bimg::imageWriteExr(&writer, image->mWidth, image->mHeight, image->mWidth * components, image->GetBits(), bimg::TextureFormat::Enum(image->mFormat), false/*_yflip*/, &err); break; - case 5: - { - cmft::Image img; - img.m_format = (cmft::TextureFormat::Enum)image->mFormat; - img.m_width = image->mWidth; - img.m_height = image->mHeight; - img.m_numFaces = image->mNumFaces; - img.m_numMips = image->mNumMips; - img.m_data = image->GetBits(); - img.m_dataSize = image->mDataSize; - if (img.m_format == cmft::TextureFormat::RGBA8) - cmft::imageConvert(img, cmft::TextureFormat::BGRA8); - else if (img.m_format == cmft::TextureFormat::RGB8) - cmft::imageConvert(img, cmft::TextureFormat::BGR8); - image->SetBits((unsigned char*)img.m_data, img.m_dataSize); - if (!cmft::imageSave(img, filename, cmft::ImageFileType::DDS)) - return EVAL_ERR; - } - break; - case 6: - { - cmft::Image img; - img.m_format = (cmft::TextureFormat::Enum)image->mFormat; - img.m_width = image->mWidth; - img.m_height = image->mHeight; - img.m_numFaces = image->mNumFaces; - img.m_numMips = image->mNumMips; - img.m_data = image->GetBits(); - img.m_dataSize = image->mDataSize; - if (!cmft::imageSave(img, filename, cmft::ImageFileType::KTX)) - return EVAL_ERR; - } - break; - case 7: - { - assert(0); } - break; +#ifdef __EMSCRIPTEN__ + DownloadImage(filename, strlen(filename), (const char*)mb.more(0), mb.getSize()); +#else + bx::close(&writer); +#endif + return EVAL_OK; } - return EVAL_OK; + return EVAL_ERR; } int Image::EncodePng(Image* image, std::vector& pngImage) { - int outlen; - int components = 4; // TODO - unsigned char* bits = stbi_write_png_to_mem( - image->GetBits(), image->mWidth * components, image->mWidth, image->mHeight, components, &outlen); - if (!bits) - return EVAL_ERR; - pngImage.resize(outlen); - memcpy(pngImage.data(), bits, outlen); - - free(bits); +#if 0 + bx::AllocatorI* g_allocator = getDefaultAllocator(); + bx::MemoryBlock mb(g_allocator); + bx::MemoryWriter writer(&mb); + bx::Error err; + + bimg::imageWritePng(&writer, image->mWidth, image->mHeight, image->mWidth * 4, image->GetBits(), bimg::TextureFormat::RGBA8, false/*_yflip*/, &err); + pngImage.resize(mb.getSize()); + memcpy(pngImage.data(), mb.more(), mb.getSize()); +#endif + const int components = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(image->mFormat)) / 8; + bx::AllocatorI* g_allocator = getDefaultAllocator(); + bx::MemoryBlock mb(g_allocator); + bx::MemoryWriter writer(&mb); + stbi_write_png_to_func(stbi_writer, &writer, image->mWidth, image->mHeight, components, image->GetBits(), 0); + pngImage.resize(mb.getSize()); + memcpy(pngImage.data(), mb.more(), mb.getSize()); return EVAL_OK; } -void DefaultShaders::Init() +int Image::Resize(Image* image, int width, int height, const InputSampler& sampler) { - std::ifstream prgStr("Stock/ProgressingNode.glsl"); - std::ifstream cubStr("Stock/DisplayCubemap.glsl"); - std::ifstream nodeErrStr("Stock/NodeError.glsl"); - - mProgressShader = - prgStr.good() - ? LoadShader(std::string(std::istreambuf_iterator(prgStr), std::istreambuf_iterator()), - "progressShader") - : 0; - mDisplayCubemapShader = - cubStr.good() - ? LoadShader(std::string(std::istreambuf_iterator(cubStr), std::istreambuf_iterator()), - "cubeDisplay") - : 0; - mNodeErrorShader = - nodeErrStr.good() - ? LoadShader(std::string(std::istreambuf_iterator(nodeErrStr), std::istreambuf_iterator()), - "nodeError") - : 0; + if (image->mWidth == width && image->mHeight == height) + { + return EVAL_OK; + } + if (image->GetMipmapCount() > 1) + { + // don't resize images with mipmaps + return EVAL_ERR; + } + const int channelCount = 4; + const int faceCount = image->GetFaceCount(); + const size_t sourceFaceSize = image->mWidth * image->mHeight * channelCount; + const size_t faceSize = width * height * channelCount; + size_t size = faceSize * faceCount; + const auto filter = sampler.mFilterMin ? STBIR_FILTER_BOX : STBIR_FILTER_DEFAULT; + unsigned char* output = new unsigned char [size]; + for (int face = 0; face < faceCount; face++) + { + stbir__resize_arbitrary(NULL, &image->mBits[sourceFaceSize * face], image->mWidth, image->mHeight, image->mWidth * channelCount, + &output[faceSize * face], width, height, width * channelCount, + 0, 0, 1, 1, NULL, channelCount, -1, 0, STBIR_TYPE_UINT8, filter, filter, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); + } + image->mWidth = width; + image->mHeight = height; + image->SetBits(output, size); + delete [] output; + return EVAL_OK; } -unsigned int ImageCache::GetTexture(const std::string& filename) +bgfx::TextureHandle ImageCache::GetTexture(const std::string& filename) { auto iter = mSynchronousTextureCache.find(filename); if (iter != mSynchronousTextureCache.end()) + { return iter->second; + } Image image; - unsigned int textureId = 0; + bgfx::TextureHandle textureHandle{0}; if (Image::Read(filename.c_str(), &image) == EVAL_OK) { - textureId = Image::Upload(&image, 0); + mImageSizes[filename] = std::make_pair(uint16_t(image.mWidth), uint16_t(image.mHeight)); + textureHandle = Image::Upload(&image, {bgfx::kInvalidHandle}); Image::Free(&image); } - mSynchronousTextureCache[filename] = textureId; - return textureId; + mSynchronousTextureCache[filename] = textureHandle; + return textureHandle; +} + +const std::pair ImageCache::GetImageSize(const std::string& filename) +{ + auto iter = mImageSizes.find(filename); + if (iter != mImageSizes.end()) + { + return iter->second; + } + return std::make_pair(0, 0); } Image* ImageCache::GetImage(const std::string& filepath) @@ -448,213 +503,84 @@ void ImageCache::AddImage(const std::string& filepath, Image* image) auto iter = mImageCache.find(filepath); if (iter == mImageCache.end()) { + mImageSizes[filepath] = std::make_pair(uint16_t(image->mWidth), uint16_t(image->mHeight)); mImageCache.insert(std::make_pair(filepath, *image)); } mCacheAccess.unlock(); } -void RenderTarget::BindAsTarget() const -{ - glBindFramebuffer(GL_FRAMEBUFFER, mFbo); - glViewport(0, 0, mImage->mWidth, mImage->mHeight); -} - -void RenderTarget::BindAsCubeTarget() const -{ - glBindTexture(GL_TEXTURE_CUBE_MAP, mGLTexID); - glBindFramebuffer(GL_FRAMEBUFFER, mFbo); -} - -void RenderTarget::BindCubeFace(size_t face, int mipmap, int faceWidth) +void ImageTexture::Destroy() { - glFramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GLenum(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mGLTexID, mipmap); - glViewport(0, 0, faceWidth >> mipmap, faceWidth >> mipmap); -} - -void RenderTarget::Destroy() -{ - if (mGLTexID) - glDeleteTextures(1, &mGLTexID); - if (mGLTexDepth) - glDeleteTextures(1, &mGLTexDepth); - if (mFbo) + if (mTexture.idx != bgfx::kInvalidHandle) { - if (glIsFramebuffer(mFbo)) - { - glDeleteFramebuffers(1, &mFbo); - } - else - { - Log("Trying to delete FBO %d that is unknown to OpenGL\n", mFbo); - } + bgfx::destroy(mTexture); + mTexture = { bgfx::kInvalidHandle }; } - if (mDepthBuffer) - glDeleteRenderbuffers(1, &mDepthBuffer); - mFbo = 0; - mImage->mWidth = mImage->mHeight = 0; - mGLTexID = 0; -} - -void RenderTarget::Clone(const RenderTarget& other) -{ - // TODO: clone other type of render target - InitBuffer(other.mImage->mWidth, other.mImage->mHeight, other.mDepthBuffer); + mImage = Image(); } -void RenderTarget::Swap(RenderTarget& other) -{ - ::Swap(mImage, other.mImage); - ::Swap(mGLTexID, other.mGLTexID); - ::Swap(mGLTexDepth, other.mGLTexDepth); - ::Swap(mDepthBuffer, other.mDepthBuffer); - ::Swap(mFbo, other.mFbo); +bgfx::TextureFormat::Enum GetRTTextureFormat() +{ + bgfx::TextureFormat::Enum tft; + if (bgfx::isTextureValid(0, false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT)) + { + tft = bgfx::TextureFormat::BGRA8; + } + else if (bgfx::isTextureValid(0, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT)) + { + tft = bgfx::TextureFormat::RGBA8; + } + else + { + assert(0); + } + return tft; } -void RenderTarget::InitBuffer(int width, int height, bool depthBuffer) +void ImageTexture::Init2D(int width, int height, bool depthBuffer) { - if ((width == mImage->mWidth) && (mImage->mHeight == height) && mImage->mNumFaces == 1 && - (!(depthBuffer ^ (mDepthBuffer != 0)))) + if ((width == mImage.mWidth) && (mImage.mHeight == height) && !mImage.mIsCubemap /*&& + (!(depthBuffer ^ (mGLTexDepth.idx != 0)))*/) + { return; + } Destroy(); + + mImage.mWidth = width; + mImage.mHeight = height; + mImage.mHasMipmaps = false; + mImage.mIsCubemap = false; + mImage.mFormat = GetRTTextureFormat(); + if (!width || !height) { Log("Trying to init FBO with 0 sized dimension.\n"); + return; } - mImage->mWidth = width; - mImage->mHeight = height; - mImage->mNumMips = 1; - mImage->mNumFaces = 1; - mImage->mFormat = TextureFormat::RGBA8; - - glGenFramebuffers(1, &mFbo); - glBindFramebuffer(GL_FRAMEBUFFER, mFbo); - - // diffuse - glGenTextures(1, &mGLTexID); - glBindTexture(GL_TEXTURE_2D, mGLTexID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - TexParam(GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_TEXTURE_2D); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mGLTexID, 0); - - if (depthBuffer) - { - // Z - glGenTextures(1, &mGLTexDepth); - glBindTexture(GL_TEXTURE_2D, mGLTexDepth); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); - TexParam(GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_TEXTURE_2D); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, mGLTexDepth, 0); - } - - static const GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0}; - glDrawBuffers(sizeof(drawBuffers) / sizeof(GLenum), drawBuffers); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - CheckFBO(); - - GLint last_viewport[4]; - glGetIntegerv(GL_VIEWPORT, last_viewport); - BindAsTarget(); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT | (depthBuffer ? GL_DEPTH_BUFFER_BIT : 0)); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); + mTexture = bgfx::createTexture2D(width, height, false/*hasMipmaps*/, 1, mImage.mFormat, BGFX_TEXTURE_BLIT_DST); } -void RenderTarget::InitCube(int width, int mipmapCount) +void ImageTexture::InitCube(int width, bool hasMipmaps) { - if ((width == mImage->mWidth) && (mImage->mHeight == width) && mImage->mNumFaces == 6 && - (mImage->mNumMips == mipmapCount)) + if ((width == mImage.mWidth) && (mImage.mHeight == width) && mImage.mIsCubemap && + (mImage.mHasMipmaps == hasMipmaps)) + { return; + } Destroy(); + mImage.mWidth = width; + mImage.mHeight = width; + mImage.mHasMipmaps = hasMipmaps; + mImage.mIsCubemap = true; + mImage.mFormat = GetRTTextureFormat(); + if (!width) { Log("Trying to init FBO with 0 sized dimension.\n"); + return; } - mImage->mWidth = width; - mImage->mHeight = width; - mImage->mNumMips = mipmapCount; - mImage->mNumFaces = 6; - mImage->mFormat = TextureFormat::RGBA8; - - glGenFramebuffers(1, &mFbo); - glBindFramebuffer(GL_FRAMEBUFFER, mFbo); - - glGenTextures(1, &mGLTexID); - glBindTexture(GL_TEXTURE_CUBE_MAP, mGLTexID); - - for (int mip = 0; mip < mipmapCount; mip++) - { - for (int i = 0; i < 6; i++) - { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, - mip, - GL_RGBA, - width >> mip, - width >> mip, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - NULL); - } - } - - TexParam(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_TEXTURE_CUBE_MAP); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X, mGLTexID, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - CheckFBO(); -} - -void RenderTarget::CheckFBO() -{ - glBindFramebuffer(GL_FRAMEBUFFER, mFbo); - - int status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - switch (status) - { - case GL_FRAMEBUFFER_COMPLETE: - // Log("Framebuffer complete.\n"); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - Log("[ERROR] Framebuffer incomplete: Attachment is NOT complete."); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - Log("[ERROR] Framebuffer incomplete: No image is attached to FBO."); - break; - /* - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - Log("[ERROR] Framebuffer incomplete: Attached images have different dimensions."); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS: - Log("[ERROR] Framebuffer incomplete: Color attached images have different internal formats."); - break; - */ -#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - Log("[ERROR] Framebuffer incomplete: Draw buffer.\n"); - break; -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - Log("[ERROR] Framebuffer incomplete: Read buffer.\n"); - break; -#endif - case GL_FRAMEBUFFER_UNSUPPORTED: - Log("[ERROR] Unsupported by FBO implementation.\n"); - break; - - default: - Log("[ERROR] Unknow error.\n"); - break; - } - - glBindFramebuffer(GL_FRAMEBUFFER, 0); + mTexture = bgfx::createTextureCube(width, hasMipmaps, 1, mImage.mFormat, BGFX_TEXTURE_BLIT_DST); } diff --git a/src/Bitmap.h b/src/Bitmap.h index 52a61d64..51b22a68 100644 --- a/src/Bitmap.h +++ b/src/Bitmap.h @@ -31,6 +31,8 @@ #include #include #include +#include "Mem.h" +#include #if USE_FFMPEG namespace FFMPEGCodec @@ -38,35 +40,35 @@ namespace FFMPEGCodec class Decoder; }; #endif -struct TextureFormat -{ - enum Enum - { - BGR8, - RGB8, - RGB16, - RGB16F, - RGB32F, - RGBE, - - BGRA8, - RGBA8, - RGBA16, - RGBA16F, - RGBA32F, - - RGBM, - - Count, - Null = -1, - }; -}; +bimg::Quality::Enum GetQuality(int quality); +struct InputSampler; struct Image { - Image() : mDecoder(NULL), mWidth(0), mHeight(0), mNumMips(0), mNumFaces(0), mBits(NULL), mDataSize(0) + Image() : mDecoder(NULL), mWidth(0), mHeight(0), mHasMipmaps(false), mIsCubemap(false), mBits(NULL), mDataSize(0) + { + } + Image(Image&& other) { + mDecoder = other.mDecoder; + mWidth = other.mWidth; + mHeight = other.mHeight; + mDataSize = other.mDataSize; + mHasMipmaps = other.mHasMipmaps; + mIsCubemap = other.mIsCubemap; + mFormat = other.mFormat; + mBits = other.mBits; + + other.mDecoder = 0; + other.mWidth = 0; + other.mHeight = 0; + other.mDataSize = 0; + other.mHasMipmaps = false; + other.mIsCubemap = 0; + other.mFormat = bgfx::TextureFormat::Unknown; + other.mBits = 0; } + Image(const Image& other) : mBits(NULL), mDataSize(0) { *this = other; @@ -79,114 +81,119 @@ struct Image void* mDecoder; int mWidth, mHeight; uint32_t mDataSize; - uint8_t mNumMips; - uint8_t mNumFaces; - uint8_t mFormat; + bool mHasMipmaps; + bool mIsCubemap; + bgfx::TextureFormat::Enum mFormat; Image& operator=(const Image& other) { mDecoder = other.mDecoder; mWidth = other.mWidth; mHeight = other.mHeight; - mNumMips = other.mNumMips; - mNumFaces = other.mNumFaces; + mHasMipmaps = other.mHasMipmaps; + mIsCubemap = other.mIsCubemap; mFormat = other.mFormat; SetBits(other.mBits, other.mDataSize); return *this; } + uint8_t GetMipmapCount() const + { + if (!mHasMipmaps) + { + return 1; + } + return uint8_t(log2(mWidth)); + } + uint8_t GetFaceCount() const + { + return mIsCubemap ? 6 : 1; + } + unsigned char* GetBits() const { return mBits; } + void SetBits(unsigned char* bits, size_t size) { Allocate(size); memcpy(mBits, bits, size); } + + void SetBits(int width, int height, int component, unsigned char* ptr, int pitch) + { + Allocate(width * height * component); + for (int y = 0; y < height; y++) + { + memcpy(&mBits[(y * width) * component], &ptr[pitch * y], width * component); + } + mWidth = width; + mHeight = height; + mHasMipmaps = false; + mIsCubemap = false; + mFormat = (component == 3)?bgfx::TextureFormat::RGB8:bgfx::TextureFormat::RGBA8; + } + void Allocate(size_t size) { if (mBits && mDataSize != size) - free(mBits); + { + imageFree(mBits); + } if (size) - mBits = (unsigned char*)malloc(size); + { + mBits = (unsigned char*)imageMalloc(size); + } mDataSize = uint32_t(size); } void DoFree() { - free(mBits); + imageFree(mBits); mBits = NULL; mDataSize = 0; } static int Read(const char* filename, Image* image); static int Free(Image* image); - static unsigned int Upload(Image* image, unsigned int textureId, int cubeFace = -1); + static bgfx::TextureHandle Upload(const Image* image, bgfx::TextureHandle textureHandle, int cubeFace = -1, int mipmap = 0); static int LoadSVG(const char* filename, Image* image, float dpi); - static int ReadMem(unsigned char* data, size_t dataSize, Image* image); + static int ReadMem(unsigned char* data, size_t dataSize, Image* image, const char* filename = nullptr); static void VFlip(Image* image); static int Write(const char* filename, Image* image, int format, int quality); static int EncodePng(Image* image, std::vector& pngImage); + static int Resize(Image* image, int width, int height, const InputSampler& sampler); #if USE_FFMPEG static Image DecodeImage(FFMPEGCodec::Decoder* decoder, int frame); #endif protected: unsigned char* mBits; }; - -extern const unsigned int glInternalFormats[]; -extern const unsigned int glInputFormats[]; -extern const unsigned int textureFormatSize[]; - +bgfx::TextureFormat::Enum GetRTTextureFormat(); struct ImageCache { // synchronous texture cache // use for simple textures(stock) or to replace with a more efficient one - unsigned int GetTexture(const std::string& filename); + bgfx::TextureHandle GetTexture(const std::string& filename); Image* GetImage(const std::string& filepath); void AddImage(const std::string& filepath, Image* image); - + const std::pair GetImageSize(const std::string& filename); protected: - std::map mSynchronousTextureCache; + std::map mSynchronousTextureCache; std::map mImageCache; + std::map < std::string, std::pair > mImageSizes; std::mutex mCacheAccess; }; extern ImageCache gImageCache; -struct DefaultShaders -{ - // ui callback shaders - unsigned int mProgressShader; - unsigned int mDisplayCubemapShader; - // error shader - unsigned int mNodeErrorShader; - - void Init(); -}; - -extern DefaultShaders gDefaultShader; void SaveCapture(const std::string& filemane, int x, int y, int w, int h); -class RenderTarget +class ImageTexture { public: - RenderTarget() : mGLTexID(0), mGLTexDepth(0), mFbo(0), mDepthBuffer(0) - { - mImage = std::make_shared(); - } - void InitBuffer(int width, int height, bool depthBuffer); - void InitCube(int width, int mipmapCount); - void BindAsTarget() const; - void BindAsCubeTarget() const; - void BindCubeFace(size_t face, int mipmap, int faceWidth); + void Init2D(int width, int height, bool depthBuffer); + void InitCube(int width, bool hasMipmaps); void Destroy(); - void CheckFBO(); - void Clone(const RenderTarget& other); - void Swap(RenderTarget& other); - - std::shared_ptr mImage; - unsigned int mGLTexID; - unsigned int mGLTexDepth; - unsigned int mDepthBuffer; - unsigned int mFbo; + Image mImage; + bgfx::TextureHandle mTexture = { bgfx::kInvalidHandle }; }; diff --git a/src/Cam.cpp b/src/Cam.cpp new file mode 100644 index 00000000..d2095cb0 --- /dev/null +++ b/src/Cam.cpp @@ -0,0 +1,93 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "Cam.h" +#include "Utils.h" + +Camera Camera::Lerp(const Camera& target, float t) +{ + Camera ret; + ret.mPosition = ::Lerp(mPosition, target.mPosition, t); + ret.mDirection = ::Lerp(mDirection, target.mDirection, t); + ret.mDirection.Normalize(); + ret.mUp = ::Lerp(mUp, target.mUp, t); + ret.mUp.Normalize(); + ret.mLens = ::Lerp(mLens, target.mLens, t); + return ret; +} + +void Camera::LookAt(const Vec4& eye, const Vec4& target, const Vec4& up) +{ + mPosition = eye; + mDirection = (target - eye).Normalize(); + mUp = up; + mLens.y = (target - eye).Length(); +} + +float& Camera::operator[](int index) +{ + switch (index) + { + case 0: + case 1: + case 2: + return mPosition[index]; + case 3: + case 4: + case 5: + return mDirection[index - 3]; + case 6: + return mDirection[index - 6]; + } + return mPosition[0]; +} + +void Camera::ComputeViewProjectionMatrix(float* viewProj, float* viewInverse) const +{ + Mat4x4 view, proj; + Mat4x4& vi = *(Mat4x4*)viewInverse; + Mat4x4& vp = *(Mat4x4*)viewProj; + ComputeViewMatrix(view.m16, vi.m16); + + proj.glhPerspectivef2(53.f, 1.f, 0.01f, 100.f); + vp = view * proj; +} + +void Camera::ComputeViewMatrix(float* view, float* viewInverse) const +{ + Mat4x4& v = *(Mat4x4*)view; + v.lookAtRH(mPosition, mPosition + mDirection, Vec4(0.f, 1.f, 0.f, 0.f)); + Mat4x4& vi = *(Mat4x4*)viewInverse; + vi.LookAt(mPosition, mPosition + mDirection, Vec4(0.f, 1.f, 0.f, 0.f)); +} + +void Camera::SetViewMatrix(float* view) +{ + Mat4x4 matrix = *(Mat4x4*)view; + matrix.Inverse(); + mPosition.TransformPoint(Vec4(0.f, 0.f, 0.f), matrix); + mDirection.TransformVector(Vec4(0.f, 0.f, -1.f), matrix); + mUp.TransformVector(Vec4(0.f, 1.f, 0.f), matrix); +} \ No newline at end of file diff --git a/src/Cam.h b/src/Cam.h new file mode 100644 index 00000000..da69dd5b --- /dev/null +++ b/src/Cam.h @@ -0,0 +1,48 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once + +#include "Types.h" + +struct Camera +{ + Vec4 mPosition; + Vec4 mDirection; + Vec4 mUp; + Vec4 mLens; // fov, distanceToTarget .... + + Camera Lerp(const Camera& target, float t); + void LookAt(const Vec4& eye, const Vec4& target, const Vec4& up); + float& operator[](int index); + void SetViewMatrix(float* view); + void ComputeViewProjectionMatrix(float* viewProj, float* viewInverse) const; + void ComputeViewMatrix(float* view, float* viewInverse) const; +}; + +inline Camera Lerp(Camera a, Camera b, float t) +{ + return a.Lerp(b, t); +} \ No newline at end of file diff --git a/src/EvaluationContext.cpp b/src/EvaluationContext.cpp index 1802aaaa..f0269347 100644 --- a/src/EvaluationContext.cpp +++ b/src/EvaluationContext.cpp @@ -1,1148 +1,1152 @@ -// https://github.com/CedricGuillemet/Imogen -// -// The MIT License(MIT) -// -// Copyright(c) 2019 Cedric Guillemet -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -#include "Platform.h" -#include -#include "EvaluationContext.h" -#include "Evaluators.h" -#include "NodeGraphControler.h" - -#ifdef GL_CLAMP_TO_BORDER -static const unsigned int wrap[] = {GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, GL_MIRRORED_REPEAT}; -#else -static const unsigned int wrap[] = {GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT}; -#endif -static const unsigned int filter[] = {GL_LINEAR, GL_NEAREST}; -static const char* sampler2DName[] = { - "Sampler0", "Sampler1", "Sampler2", "Sampler3", "Sampler4", "Sampler5", "Sampler6", "Sampler7"}; -static const char* samplerCubeName[] = {"CubeSampler0", - "CubeSampler1", - "CubeSampler2", - "CubeSampler3", - "CubeSampler4", - "CubeSampler5", - "CubeSampler6", - "CubeSampler7"}; - -static const unsigned int GLBlends[] = {GL_ZERO, - GL_ONE, - GL_SRC_COLOR, - GL_ONE_MINUS_SRC_COLOR, - GL_DST_COLOR, - GL_ONE_MINUS_DST_COLOR, - GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, - GL_DST_ALPHA, - GL_ONE_MINUS_DST_ALPHA, - GL_CONSTANT_COLOR, - GL_ONE_MINUS_CONSTANT_COLOR, - GL_CONSTANT_ALPHA, - GL_ONE_MINUS_CONSTANT_ALPHA, - GL_SRC_ALPHA_SATURATE}; - -static const float rotMatrices[6][16] = { - // toward +x - {0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1}, - - // -x - {0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1}, - - //+y - {1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1}, - - // -y - {1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, - - // +z - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, - - //-z - {-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1}}; - - -EvaluationContext::EvaluationContext(EvaluationStages& evaluation, - bool synchronousEvaluation, - int defaultWidth, - int defaultHeight) - : mEvaluationStages(evaluation) -#ifdef __EMSCRIPTEN - , mbSynchronousEvaluation(true) -#else - , mbSynchronousEvaluation(synchronousEvaluation) -#endif - , mDefaultWidth(defaultWidth) - , mDefaultHeight(defaultHeight) - , mRuntimeUniqueId(-1) -{ - mFSQuad.Init(); - - // evaluation statedes - glGenBuffers(1, &mEvaluationStateGLSLBuffer); - glBindBuffer(GL_UNIFORM_BUFFER, mEvaluationStateGLSLBuffer); - - glBufferData(GL_UNIFORM_BUFFER, sizeof(EvaluationInfo), NULL, GL_DYNAMIC_DRAW); - glBindBufferBase(GL_UNIFORM_BUFFER, 2, mEvaluationStateGLSLBuffer); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - // parameters - glGenBuffers(1, &mParametersGLSLBuffer); -} - -EvaluationContext::~EvaluationContext() -{ -#ifdef USE_FFMPEG - for (auto& stream : mWriteStreams) - { - stream.second->Finish(); - delete stream.second; - } - - mWriteStreams.clear(); -#endif - mFSQuad.Finish(); - - glDeleteBuffers(1, &mEvaluationStateGLSLBuffer); - glDeleteBuffers(1, &mParametersGLSLBuffer); - - Clear(); -} - -static void SetKeyboardMouseInfos(EvaluationInfo& evaluationInfo, const EvaluationStage& evaluationStage) -{ - evaluationInfo.mouse[0] = evaluationStage.mRx; - evaluationInfo.mouse[1] = evaluationStage.mRy; - evaluationInfo.mouse[2] = evaluationStage.mLButDown ? 1.f : 0.f; - evaluationInfo.mouse[3] = evaluationStage.mRButDown ? 1.f : 0.f; - - evaluationInfo.keyModifier[0] = evaluationStage.mbCtrl ? 1 : 0; - evaluationInfo.keyModifier[1] = evaluationStage.mbAlt ? 1 : 0; - evaluationInfo.keyModifier[2] = evaluationStage.mbShift ? 1 : 0; - evaluationInfo.keyModifier[3] = 0; -} - -void EvaluationContext::Clear() -{ - for (auto tgt : mStageTarget) - { - if (!tgt) - { - continue; - } - tgt->Destroy(); - } - mStageTarget.clear(); - for (auto& buffer : mComputeBuffers) - { - glDeleteBuffers(1, &buffer.mBuffer); - } - mComputeBuffers.clear(); - mDirtyFlags.clear(); - mbProcessing.clear(); - mProgress.clear(); -} - -unsigned int EvaluationContext::GetEvaluationTexture(size_t target) -{ - if (target >= mStageTarget.size()) - return 0; - if (!mStageTarget[target]) - return 0; - return mStageTarget[target]->mGLTexID; -} - -unsigned int bladesVertexArray; -unsigned int bladesVertexSize = 2 * sizeof(float); - -unsigned int UploadIndices(const unsigned short* indices, unsigned int indexCount) -{ - unsigned int indexArray; - glGenBuffers(1, &indexArray); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexArray); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(unsigned short), indices, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - return indexArray; -} - -void UploadVertices(const void* vertices, unsigned int vertexArraySize) +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "Platform.h" +#include +#include "EvaluationContext.h" +#include "Evaluators.h" +#include "GraphControler.h" +#include "Types.h" +#include "Cam.h" +#include "ParameterBlock.h" + +static const float rotMatrices[6][16] = { + // toward +x + { 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1}, + + // -x + { 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1}, + + //+y + { 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1}, + + // -y + { 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1}, + + // +z + { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, + + //-z + {-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1}}; + + +void EvaluationThumbnails::Clear() +{ + for (auto& atlas : mAtlases) + { + if (atlas.mFrameBuffer.idx != bgfx::kInvalidHandle) + { + bgfx::destroy(atlas.mFrameBuffer); + } + } + mAtlases.clear(); +} + +EvaluationThumbnails::Thumb EvaluationThumbnails::AddThumbInAtlas(size_t atlasIndex) +{ + auto& atlas = mAtlases[atlasIndex]; + for (size_t thumbIndex = 0; thumbIndex < ThumbnailsPerAtlas; thumbIndex++) + { + if (!atlas.mbUsed[thumbIndex]) + { + atlas.mbUsed[thumbIndex] = true; + atlas.mUsedCount++; + return { (unsigned short)atlasIndex, (unsigned short)thumbIndex }; + } + } + // mUsedCount not in sync with used map + assert(0); + return {}; +} + +EvaluationThumbnails::Thumb EvaluationThumbnails::AddThumb() +{ + for (size_t atlasIndex = 0; atlasIndex < mAtlases.size(); atlasIndex++) + { + const auto& atlas = mAtlases[atlasIndex]; + if (atlas.mUsedCount < ThumbnailsPerAtlas) + { + return AddThumbInAtlas(atlasIndex); + } + } + // no atlas, create new one + mAtlases.push_back(ThumbAtlas(ThumbnailsPerAtlas)); + + auto fb = bgfx::createFrameBuffer(AtlasSize, AtlasSize, GetRTTextureFormat()); + mAtlases.back().mFrameBuffer = fb; + bgfx::frame(); + bgfx::setViewFrameBuffer(1, fb); + bgfx::setViewRect(1, 0, 0, AtlasSize, AtlasSize); + bgfx::setViewClear(1, BGFX_CLEAR_COLOR /*| BGFX_CLEAR_DEPTH*/, 0x00000000, 1.0f, 0); + bgfx::touch(1); + bgfx::frame(); + + return AddThumbInAtlas(mAtlases.size() - 1); +} + +void EvaluationThumbnails::DelThumb(const Thumb thumb) +{ + auto& atlas = mAtlases[thumb.mAtlasIndex]; + assert(atlas.mbUsed[thumb.mThumbIndex]); + atlas.mbUsed[thumb.mThumbIndex] = false; + atlas.mUsedCount--; +} + +void EvaluationThumbnails::GetThumb(const Thumb thumb, bgfx::TextureHandle& textureHandle, ImRect& uvs) const +{ + textureHandle = bgfx::getTexture(mAtlases[thumb.mAtlasIndex].mFrameBuffer); + uvs = ComputeUVFromIndexInAtlas(thumb.mThumbIndex); +} + +bgfx::FrameBufferHandle& EvaluationThumbnails::GetThumbFrameBuffer(const Thumb thumb) +{ + return mAtlases[thumb.mAtlasIndex].mFrameBuffer; +} + +ImRect EvaluationThumbnails::ComputeUVFromIndexInAtlas(size_t thumbIndex) const +{ + const size_t thumbnailsPerSide = AtlasSize / ThumbnailSize; + const size_t indexY = thumbIndex / thumbnailsPerSide; + const size_t indexX = thumbIndex % thumbnailsPerSide; + + const float u = float(indexX) / float(thumbnailsPerSide); + const float v = float(indexY) / float(thumbnailsPerSide); + const float suv = 1.f / float(thumbnailsPerSide); + if (bgfx::getCaps()->originBottomLeft) + { + return ImRect(ImVec2(u, 1.f - (v + suv)), ImVec2(u + suv, 1.f - v)); + } + else + { + return ImRect(ImVec2(u, v), ImVec2(u + suv, (v + suv))); + } +} + +void EvaluationThumbnails::GetThumbCoordinates(const Thumb thumb, int* coordinates) const +{ + const uint16_t index = thumb.mThumbIndex; + const uint16_t thumbnailsPerSide = AtlasSize / ThumbnailSize; + const uint16_t indexY = index / thumbnailsPerSide; + const uint16_t indexX = index % thumbnailsPerSide; + + coordinates[0] = int(indexX * ThumbnailSize); + coordinates[1] = int(indexY * ThumbnailSize); + coordinates[2] = int(coordinates[0] + ThumbnailSize - 1); + coordinates[3] = int(coordinates[1] + ThumbnailSize - 1); +} + +std::vector EvaluationThumbnails::GetAtlasTextures() const +{ + std::vector ret; + for (auto& atlas : mAtlases) + { + ret.push_back(bgfx::getTexture(atlas.mFrameBuffer)); + } + return ret; +} + +EvaluationContext::EvaluationContext(EvaluationStages& evaluation + , bool building + , bool synchronousEvaluation + , int defaultWidth + , int defaultHeight + , bool useThumbnail) + : mEvaluationStages(evaluation) +#ifdef __EMSCRIPTEN + , mbSynchronousEvaluation(true) +#else + , mbSynchronousEvaluation(synchronousEvaluation) +#endif + , mDefaultWidth(defaultWidth) + , mDefaultHeight(defaultHeight) + , mRuntimeUniqueId(evaluation.mMaterialUniqueId) + , mInputNodeIndex(-1) + , mUseThumbnail(useThumbnail) + , mBuilding(building) +{ + + mEvaluations.resize(evaluation.mStages.size()); +} + +EvaluationContext::~EvaluationContext() +{ +#ifdef USE_FFMPEG + for (auto& stream : mWriteStreams) + { + stream.second->Finish(); + delete stream.second; + } + + mWriteStreams.clear(); +#endif + + Clear(); +} + +void EvaluationContext::AddEvaluation(NodeIndex nodeIndex) +{ + mEvaluations.insert(mEvaluations.begin() + nodeIndex, Evaluation()); + if (mUseThumbnail) + { + mEvaluations[nodeIndex].mThumb = mThumbnails.AddThumb(); + } +} + +void EvaluationContext::DelEvaluation(NodeIndex nodeIndex) +{ + if (mUseThumbnail) + { + mThumbnails.DelThumb(mEvaluations[nodeIndex].mThumb); + } + + if (mEvaluations[nodeIndex].mTarget) + { + mEvaluations[nodeIndex].mTarget->Destroy(); + delete mEvaluations[nodeIndex].mTarget; + } + mEvaluations.erase(mEvaluations.begin() + nodeIndex); +} + +void EvaluationContext::Evaluate() +{ + //Has dirty? be smart and discard nodes from mRemaining when tagged as dirty + bool hasDirty = false; + for (auto& evaluation : mEvaluations) + { + if (evaluation.mDirtyFlag) + { + hasDirty = true; + break; + } + } + + // clear todo list + if (hasDirty) + { + mRemaining.clear(); + + auto evaluationOrderList = mEvaluationStages.GetForwardEvaluationOrder(); + for (size_t index = 0; index < evaluationOrderList.size(); index++) + { + size_t currentNodeIndex = evaluationOrderList[index]; + if (mEvaluations[currentNodeIndex].mDirtyFlag) + { + mRemaining.push_back(int32_t(currentNodeIndex)); + } + } + ComputeTargetUseCount(); + } + + // do something from the list + if (!mRemaining.empty()) + { + static const int nodeCountPerIteration = 100; + for (int i = 0;i< nodeCountPerIteration;i++) + { + int nodeIndex = mRemaining.front(); + mRemaining.erase(mRemaining.begin()); //TODOEVA don't remove from remaining(or push it back after) when node needs more work to be done (raytracer) + auto& evaluation = mEvaluations[nodeIndex]; + evaluation.mbActive = mCurrentTime >= mEvaluationStages.mStages[nodeIndex].mStartFrame && + mCurrentTime <= mEvaluationStages.mStages[nodeIndex].mEndFrame; + /*if (!evaluation.mbActive) TODOEVA + { + continue; + }*/ + + RunNode(nodeIndex); + + if (mRemaining.empty()) + { + break; + } + } + } +} + +void EvaluationContext::SetKeyboardMouse(NodeIndex nodeIndex, const UIInput& input) +{ + mUIInputs = input; + mInputNodeIndex = nodeIndex; +} + +void EvaluationContext::SetKeyboardMouseInfos(EvaluationInfo& evaluationInfo, NodeIndex nodeIndex) const +{ + if (mInputNodeIndex == evaluationInfo.targetIndex) + { + Vec4 mousePos(mUIInputs.mRx, mUIInputs.mRy, 0.f); + mousePos.TransformPoint(*mEvaluationStages.GetParameterViewMatrix(nodeIndex)); + evaluationInfo.mouse[0] = mousePos.x; + evaluationInfo.mouse[1] = mousePos.y; + evaluationInfo.mouse[2] = mUIInputs.mLButDown ? 1.f : 0.f; + evaluationInfo.mouse[3] = mUIInputs.mRButDown ? 1.f : 0.f; + + evaluationInfo.keyModifier[0] = mUIInputs.mbCtrl ? 1.f : 0.f; + evaluationInfo.keyModifier[1] = mUIInputs.mbAlt ? 1.f : 0.f; + evaluationInfo.keyModifier[2] = mUIInputs.mbShift ? 1.f : 0.f; + evaluationInfo.keyModifier[3] = 0; + } + else + { + evaluationInfo.mouse[0] = -99999.f; + evaluationInfo.mouse[1] = -99999.f; + evaluationInfo.mouse[2] = 0.f; + evaluationInfo.mouse[3] = 0.f; + + evaluationInfo.keyModifier[0] = 0; + evaluationInfo.keyModifier[1] = 0; + evaluationInfo.keyModifier[2] = 0; + evaluationInfo.keyModifier[3] = 0; + } +} + +void EvaluationContext::Clear() +{ + for (auto& eval : mEvaluations) + { + if (eval.mTarget) + { + eval.mTarget->Destroy(); + } + } + mEvaluations.clear(); + for (auto& renderTarget : mAvailableRenderTargets) + { + renderTarget->Destroy(); + } + mAvailableRenderTargets.clear(); + for (auto& proxy : mProxies) + { + //Log("Destroyed proxy FB %d\n", proxy.second.idx); + bgfx::destroy(proxy.second); + } + mProxies.clear(); + + mThumbnails.Clear(); + mInputNodeIndex = -1; +} + +bgfx::TextureHandle EvaluationContext::GetEvaluationTexture(NodeIndex nodeIndex) const +{ + assert (nodeIndex < mEvaluations.size()); + const auto& tgt = mEvaluations[nodeIndex].mTarget; + if (!tgt) + { + return {bgfx::kInvalidHandle}; + } + return tgt->mTexture; +} + +void EvaluationContext::BindTextures(EvaluationInfo& evaluationInfo, const EvaluationStage& evaluationStage, + NodeIndex nodeIndex, + ImageTexture* reusableTarget) +{ + const Input& input = mEvaluationStages.mInputs[nodeIndex]; + for (int inputIndex = 0; inputIndex < 8; inputIndex++) + { + NodeIndex targetIndex = input.mOverrideInputs[inputIndex]; + if (!targetIndex.IsValid()) + { + targetIndex = input.mInputs[inputIndex]; + } + if (targetIndex.IsValid()) + { + ImageTexture* tgt; + if (inputIndex == 0 && reusableTarget) + { + tgt = reusableTarget; + } + else + { + tgt = mEvaluations[targetIndex].mTarget; + } + + if (tgt) + { + const InputSampler& inputSampler = mEvaluationStages.mInputSamplers[nodeIndex][inputIndex]; + evaluationInfo.textureSize[inputIndex * 4] = float(tgt->mImage.mWidth); + evaluationInfo.textureSize[inputIndex * 4 + 1] = float(tgt->mImage.mHeight); + + if (!tgt->mImage.mIsCubemap) + { + bgfx::setTexture(inputIndex, gEvaluators.mSamplers2D[inputIndex], tgt->mTexture, inputSampler.Value()); + } + else + { + bgfx::setTexture(inputIndex+8, gEvaluators.mSamplersCube[inputIndex], tgt->mTexture, inputSampler.Value()); + } + } + } + } +} + +void EvaluationContext::SetUniforms(NodeIndex nodeIndex) +{ + float tempUniforms[8 * 4]; // max size for ramp + const ParameterBlock& parameterBlock = mEvaluationStages.mParameterBlocks[nodeIndex]; + const auto& evaluationStage = mEvaluationStages.mStages[nodeIndex]; + auto nodeType = evaluationStage.mType; + const auto& evaluator = gEvaluators.GetEvaluator(evaluationStage.mType); + const unsigned char* ptr = (const unsigned char*)parameterBlock.Data(); + int paramIndex = 0; + for (const auto& uniform : evaluator.mUniformHandles) + { + const auto& parameter = gMetaNodes[nodeType].mParams[paramIndex]; + auto paramSize = GetParameterTypeSize(parameter.mType); + int count = 1; + bool *ptrb = (bool*)ptr; + int* ptri = (int*)ptr; + float *ptrf = (float*)ptr; + enum SubType + { + ST_Float, + ST_Bool, + ST_Int + }; + SubType st = ST_Float; + switch (parameter.mType) + { + case Con_Float: + break; + case Con_Float2: + break; + case Con_Float3: + break; + case Con_Float4: + break; + case Con_Color4: + break; + case Con_Int: + st = ST_Int; + break; + case Con_Int2: + st = ST_Int; + break; + case Con_Ramp: + count = 8; + break; + case Con_Angle: + break; + case Con_Angle2: + break; + case Con_Angle3: + break; + case Con_Angle4: + break; + case Con_Enum: + st = ST_Int; + break; + case Con_Any: + case Con_Multiplexer: + case Con_Camera: + case Con_Structure: + case Con_FilenameRead: + case Con_FilenameWrite: + case Con_ForceEvaluate: + count = 0; + continue; + case Con_Bool: + st = ST_Bool; + break; + case Con_Ramp4: + count = 8; + break; + } + + if (count) + { + switch(st) + { + case ST_Bool: + for (int i = 0; i < paramSize / sizeof(int); i++) + { + tempUniforms[i] = (float)((* ptrb++)?1.f:0.f); + } + break; + case ST_Float: + memcpy(tempUniforms, ptr, paramSize); + break; + case ST_Int: + for (int i = 0; i < paramSize/sizeof(int); i++) + { + tempUniforms[i] = (float)*ptri++; + } + break; + } + bgfx::setUniform(uniform, tempUniforms, count); + } + paramIndex++; + ptr += paramSize; + } +} + +void EvaluationContext::GetRenderProxy(bgfx::FrameBufferHandle& currentFramebuffer, int16_t width, uint16_t height, bool depthBuffer) { - glGenBuffers(1, &bladesVertexArray); - glBindBuffer(GL_ARRAY_BUFFER, bladesVertexArray); - glBufferData(GL_ARRAY_BUFFER, vertexArraySize, vertices, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -static const int tess = 10; -static unsigned int bladeIA = -1; -void drawBlades(int indexCount, int instanceCount, int elementCount) -{ - // instances - for (int i = 0; i < elementCount; i++) - glVertexAttribDivisor(1 + i, 1); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bladeIA); - - glDrawElementsInstanced(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_SHORT, (void*)0, instanceCount); - - for (int i = 0; i < elementCount; i++) - glVertexAttribDivisor(1 + i, 0); - - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -void EvaluationContext::BindTextures(const EvaluationStage& evaluationStage, - unsigned int program, - std::shared_ptr reusableTarget) -{ - const Input& input = evaluationStage.mInput; - for (int inputIndex = 0; inputIndex < 8; inputIndex++) - { - glActiveTexture(GL_TEXTURE0 + inputIndex); - int targetIndex = input.mOverrideInputs[inputIndex]; - if (targetIndex < 0) - targetIndex = input.mInputs[inputIndex]; - if (targetIndex < 0) - { - glBindTexture(GL_TEXTURE_2D, 0); - } - else - { - unsigned int parameter = glGetUniformLocation(program, sampler2DName[inputIndex]); - if (parameter == 0xFFFFFFFF) - parameter = glGetUniformLocation(program, samplerCubeName[inputIndex]); - if (parameter == 0xFFFFFFFF) - { - glBindTexture(GL_TEXTURE_2D, 0); - continue; - } - glUniform1i(parameter, inputIndex); - - std::shared_ptr tgt; - if (inputIndex == 0 && reusableTarget) - { - tgt = reusableTarget; - } - else - { - tgt = mStageTarget[targetIndex]; - } - - if (tgt) - { - const InputSampler& inputSampler = evaluationStage.mInputSamplers[inputIndex]; - if (tgt->mImage->mNumFaces == 1) - { - glBindTexture(GL_TEXTURE_2D, tgt->mGLTexID); - TexParam(filter[inputSampler.mFilterMin], - filter[inputSampler.mFilterMag], - wrap[inputSampler.mWrapU], - wrap[inputSampler.mWrapV], - GL_TEXTURE_2D); - } - else - { - glBindTexture(GL_TEXTURE_CUBE_MAP, tgt->mGLTexID); - TexParam(filter[inputSampler.mFilterMin], - filter[inputSampler.mFilterMag], - wrap[inputSampler.mWrapU], - wrap[inputSampler.mWrapV], - GL_TEXTURE_CUBE_MAP); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); - // glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - if (tgt->mImage->mNumMips > 1) - { - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, tgt->mImage->mNumMips - 1); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - } - } - } - } -} - -int EvaluationContext::GetBindedComputeBuffer(const EvaluationStage& evaluationStage) const -{ - const Input& input = evaluationStage.mInput; - for (int inputIndex = 0; inputIndex < 8; inputIndex++) - { - int targetIndex = input.mInputs[inputIndex]; - if (targetIndex != -1 && targetIndex < mComputeBuffers.size() && mComputeBuffers[targetIndex].mBuffer && - mActive[targetIndex]) - { - return targetIndex; - } - } - return -1; -} - -void EvaluationContext::EvaluateGLSLCompute(const EvaluationStage& evaluationStage, - size_t index, - EvaluationInfo& evaluationInfo) -{ - if (bladeIA == -1) - { - float bladeVertices[4 * tess]; - unsigned short bladeIndices[2 * tess]; - - for (int i = 0; i < tess; i++) - { - bladeVertices[i * 4] = -1.f; - bladeVertices[i * 4 + 1] = bladeVertices[i * 4 + 3] = float(i) / float(tess - 1); - bladeVertices[i * 4 + 2] = 1.f; - } - for (int i = 0; i < tess * 2; i++) - { - bladeIndices[i] = i; - } - - bladeIA = UploadIndices(bladeIndices, sizeof(bladeIndices) / sizeof(unsigned short)); - UploadVertices(bladeVertices, sizeof(bladeVertices)); - } - - const Evaluator& evaluator = gEvaluators.GetEvaluator(evaluationStage.mType); - const unsigned int program = evaluator.mGLSLProgram; - - // allocate buffer - unsigned int feedbackVertexArray = 0; - ComputeBuffer* destinationBuffer = NULL; - ComputeBuffer* sourceBuffer = NULL; - ComputeBuffer tempBuffer; - int computeBufferIndex = GetBindedComputeBuffer(evaluationStage); - if (computeBufferIndex != -1) - { - if (mComputeBuffers.size() <= index || (!mComputeBuffers[index].mBuffer)) - { - // only allocate if needed - AllocateComputeBuffer(int(index), - mComputeBuffers[computeBufferIndex].mElementCount, - mComputeBuffers[computeBufferIndex].mElementSize); - } - sourceBuffer = &mComputeBuffers[computeBufferIndex]; - } - else - { - // - if (index < mComputeBuffers.size()) - { - Swap(mComputeBuffers[index], tempBuffer); - - AllocateComputeBuffer(int(index), tempBuffer.mElementCount, tempBuffer.mElementSize); - sourceBuffer = &tempBuffer; - } - } - - if (mComputeBuffers.size() <= index) - return; // no compute buffer destination, no source either -> non connected node -> early exit - - /// build source VAO - glGenVertexArrays(1, &feedbackVertexArray); - glBindVertexArray(feedbackVertexArray); - glBindBuffer(GL_ARRAY_BUFFER, sourceBuffer->mBuffer); - const int transformElementCount = sourceBuffer->mElementSize / (4 * sizeof(float)); - for (int i = 0; i < transformElementCount; i++) - { - glVertexAttribPointer( - i, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * transformElementCount, (void*)(4 * sizeof(float) * i)); - glEnableVertexAttribArray(i); - } - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glBindVertexArray(0); - - - destinationBuffer = &mComputeBuffers[index]; - - // compute buffer - if (destinationBuffer->mElementCount) - { - glUseProgram(program); - - glBindBuffer(GL_UNIFORM_BUFFER, mEvaluationStateGLSLBuffer); - evaluationInfo.mVertexSpace = evaluationStage.mVertexSpace; - glBufferData(GL_UNIFORM_BUFFER, sizeof(EvaluationInfo), &evaluationInfo, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - glBindBuffer(GL_UNIFORM_BUFFER, mParametersGLSLBuffer); - glBufferData( - GL_UNIFORM_BUFFER, evaluationStage.mParameters.size(), evaluationStage.mParameters.data(), GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - - glBindBufferBase(GL_UNIFORM_BUFFER, 1, mParametersGLSLBuffer); - glBindBufferBase(GL_UNIFORM_BUFFER, 2, mEvaluationStateGLSLBuffer); - - - BindTextures(evaluationStage, program, std::shared_ptr()); - glEnable(GL_RASTERIZER_DISCARD); - glBindVertexArray(feedbackVertexArray); - glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, - 0, - destinationBuffer->mBuffer, - 0, - destinationBuffer->mElementCount * destinationBuffer->mElementSize); - - glBeginTransformFeedback(GL_POINTS); - glDrawArrays(GL_POINTS, 0, destinationBuffer->mElementCount); - glEndTransformFeedback(); - - glDisable(GL_RASTERIZER_DISCARD); - glBindVertexArray(0); - glUseProgram(0); - } - if (feedbackVertexArray) - glDeleteVertexArrays(1, &feedbackVertexArray); - - if (tempBuffer.mBuffer) + uint32_t key = ((width & 0x7FFF) << 15) + (height&0x7FFF) + (depthBuffer?0x80000000:0); + auto iter = mProxies.find(key); + if (iter != mProxies.end()) + { + currentFramebuffer = iter->second; + return; + } + // limit the number of proxy RT + if (mProxies.size() >= 10) { - glDeleteBuffers(1, &tempBuffer.mBuffer); + auto proxy = mProxies.begin(); + bgfx::destroy(proxy->second); + mProxies.erase(proxy); } + if (!depthBuffer) + { + currentFramebuffer = bgfx::createFrameBuffer(width, height, GetRTTextureFormat(), BGFX_TEXTURE_BLIT_DST); + } + else + { + bgfx::TextureHandle fbTextures[2]; + fbTextures[0] = bgfx::createTexture2D(width, height, false, 1, GetRTTextureFormat(), BGFX_TEXTURE_RT_WRITE_ONLY); + fbTextures[1] = bgfx::createTexture2D(width, height, false, 1, bgfx::TextureFormat::D24S8, BGFX_TEXTURE_RT_WRITE_ONLY); + currentFramebuffer = bgfx::createFrameBuffer(2, fbTextures, true); + } + assert(currentFramebuffer.idx != bgfx::kInvalidHandle); + mProxies[key] = currentFramebuffer; } - -void EvaluationContext::EvaluateGLSL(const EvaluationStage& evaluationStage, - size_t index, - EvaluationInfo& evaluationInfo) -{ - const Input& input = evaluationStage.mInput; - - auto tgt = mStageTarget[index]; - - const Evaluator& evaluator = gEvaluators.GetEvaluator(evaluationStage.mType); - const unsigned int program = evaluator.mGLSLProgram; - const int blendOps[] = {evaluationStage.mBlendingSrc, evaluationStage.mBlendingDst}; - unsigned int blend[] = {GL_ONE, GL_ZERO}; - - if (!program) + +void EvaluationContext::RunSingle(NodeIndex nodeIndex, bgfx::ViewId viewId, EvaluationInfo& evaluationInfo) +{ + const auto& currentStage = mEvaluationStages.mStages[nodeIndex]; + const Input& input = mEvaluationStages.mInputs[nodeIndex]; + + evaluationInfo.targetIndex = float(nodeIndex); + evaluationInfo.frame = float(mCurrentTime); + //mEvaluationInfo.dirtyFlag = evaluation.mDirtyFlag; + for (int i = 0; i < 8; i++) + { + evaluationInfo.inputIndices[i] = input.mInputs[i].IsValid() ? (float)input.mInputs[i] : -1.f; + } + SetKeyboardMouseInfos(evaluationInfo, nodeIndex); + int evaluationMask = gEvaluators.GetMask(currentStage.mType); + + if (evaluationMask & EvaluationC) + { + EvaluateC(currentStage, nodeIndex, evaluationInfo); + } +#ifdef USE_PYTHON + if (evaluationMask & EvaluationPython) + { + EvaluatePython(currentStage, nodeIndex, evaluationInfo); + } +#endif + + if (evaluationMask & EvaluationGLSL) + { + EvaluateGLSL(currentStage, nodeIndex, evaluationInfo, viewId); + } +} + +void EvaluationContext::EvaluateGLSL(const EvaluationStage& evaluationStage, + NodeIndex nodeIndex, + EvaluationInfo& evaluationInfo, + bgfx::ViewId baseViewId) +{ + const Input& input = mEvaluationStages.mInputs[nodeIndex]; + const auto& evaluation = mEvaluations[nodeIndex]; + const auto tgt = evaluation.mTarget; + const auto& evaluator = gEvaluators.GetEvaluator(evaluationStage.mType); + const bgfx::ProgramHandle program = evaluator.mProgram; + const auto& parameters = mEvaluationStages.GetParameterBlock(nodeIndex); + const auto nodeType = mEvaluationStages.GetNodeType(nodeIndex); + + if (!program.idx) + { + return; + } + + const Camera* camera = parameters.GetCamera(); + if (camera) + { + camera->ComputeViewProjectionMatrix(evaluationInfo.viewProjection, evaluationInfo.viewInverse); + } + + int passCount = parameters.GetIntParameter("passCount", 1); + + bgfx::FrameBufferHandle blitFramebuffer{ bgfx::kInvalidHandle }; + if (!evaluationInfo.uiPass) { - glUseProgram(gDefaultShader.mNodeErrorShader); - // mFSQuad.Render(); - evaluationStage.mGScene->Draw(this, evaluationInfo); - return; - } - for (int i = 0; i < 2; i++) - { - if (blendOps[i] < BLEND_LAST) - blend[i] = GLBlends[blendOps[i]]; - } - - // parameters - glBindBuffer(GL_UNIFORM_BUFFER, mParametersGLSLBuffer); - - glBufferData( - GL_UNIFORM_BUFFER, evaluationStage.mParameters.size(), evaluationStage.mParameters.data(), GL_DYNAMIC_DRAW); - glBindBufferBase(GL_UNIFORM_BUFFER, 1, mParametersGLSLBuffer); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - glEnable(GL_BLEND); - glBlendFunc(blend[0], blend[1]); - - glUseProgram(program); - - Camera* camera = mEvaluationStages.GetCameraParameter(index); - if (camera) - { - camera->ComputeViewProjectionMatrix(evaluationInfo.viewProjection, evaluationInfo.viewInverse); - } - - int passCount = mEvaluationStages.GetIntParameter(index, "passCount", 1); - auto transientTarget = std::make_shared(RenderTarget()); - if (passCount > 1) - { - // new transient target - transientTarget->Clone(*tgt); - } - - uint8_t mipmapCount = tgt->mImage->mNumMips; - for (int passNumber = 0; passNumber < passCount; passNumber++) - { - for (int mip = 0; mip < mipmapCount; mip++) - { + GetRenderProxy(blitFramebuffer, 16, 16, false); + } + + auto w = tgt->mImage.mWidth; + auto h = tgt->mImage.mHeight; + const auto faceCount = evaluationInfo.uiPass ? 1 : (tgt->mImage.mIsCubemap ? 6 : 1); + const auto mipmapCount = tgt->mImage.GetMipmapCount(); + + for (int passNumber = 0; passNumber < passCount; passNumber++) + { + for (auto mip = 0; mip < mipmapCount; mip++) + { + const int viewportWidth = w >> mip; + const int viewportHeight = h >> mip; + + bgfx::FrameBufferHandle currentFramebuffer{ bgfx::kInvalidHandle }; if (!evaluationInfo.uiPass) { - if (tgt->mImage->mNumFaces == 6) - { - tgt->BindAsCubeTarget(); - } - else - { - tgt->BindAsTarget(); - } - } - - size_t faceCount = evaluationInfo.uiPass ? 1 : tgt->mImage->mNumFaces; - for (size_t face = 0; face < faceCount; face++) - { - if (tgt->mImage->mNumFaces == 6) - tgt->BindCubeFace(face, mip, tgt->mImage->mWidth); - - memcpy(evaluationInfo.viewRot, rotMatrices[face], sizeof(float) * 16); - memcpy(evaluationInfo.inputIndices, input.mInputs, sizeof(input.mInputs)); - float sizeDiv = float(mip + 1); - evaluationInfo.viewport[0] = float(tgt->mImage->mWidth) / sizeDiv; - evaluationInfo.viewport[1] = float(tgt->mImage->mHeight) / sizeDiv; - evaluationInfo.passNumber = passNumber; - evaluationInfo.mipmapNumber = mip; - evaluationInfo.mipmapCount = mipmapCount; - - glBindBuffer(GL_UNIFORM_BUFFER, mEvaluationStateGLSLBuffer); - evaluationInfo.mVertexSpace = evaluationStage.mVertexSpace; - glBufferData(GL_UNIFORM_BUFFER, sizeof(EvaluationInfo), &evaluationInfo, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - - - glBindBufferBase(GL_UNIFORM_BUFFER, 1, mParametersGLSLBuffer); - glBindBufferBase(GL_UNIFORM_BUFFER, 2, mEvaluationStateGLSLBuffer); - - BindTextures(evaluationStage, program, passNumber ? transientTarget : std::shared_ptr()); - - glDisable(GL_CULL_FACE); - // glCullFace(GL_BACK); -#ifdef __EMSCRIPTEN__ - glClearDepthf(1.f); -#else - glClearDepth(1.f); -#endif - if (evaluationStage.mbClearBuffer) - { - glClear(GL_COLOR_BUFFER_BIT | (evaluationStage.mbDepthBuffer ? GL_DEPTH_BUFFER_BIT : 0)); - } - if (evaluationStage.mbDepthBuffer) - { - glDepthFunc(GL_LEQUAL); - glEnable(GL_DEPTH_TEST); - } - // - - if (evaluationStage.mTypename == "FurDisplay") - { - /*const ComputeBuffer* buffer*/ int sourceBuffer = GetBindedComputeBuffer(evaluationStage); - if (sourceBuffer != -1) - { - const ComputeBuffer* buffer = &mComputeBuffers[sourceBuffer]; - unsigned int vao; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - - // blade vertices - glBindBuffer(GL_ARRAY_BUFFER, bladesVertexArray); - glVertexAttribPointer(0 /*SemUV*/, 2, GL_FLOAT, GL_FALSE, bladesVertexSize, 0); - glEnableVertexAttribArray(0 /*SemUV*/); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - // blade instances - const size_t transformElementCount = buffer->mElementSize / (sizeof(float) * 4); - glBindBuffer(GL_ARRAY_BUFFER, buffer->mBuffer); - for (unsigned int vp = 0; vp < transformElementCount; vp++) - { - glVertexAttribPointer(1 + vp, - 4, - GL_FLOAT, - GL_FALSE, - GLsizei(sizeof(float) * 4 * transformElementCount), - (void*)(4 * sizeof(float) * vp)); - glEnableVertexAttribArray(1 + vp); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glBindVertexArray(vao); - drawBlades(tess * 2, buffer->mElementCount, int(transformElementCount)); - glBindVertexArray(0); - glDeleteVertexArrays(1, &vao); - } - } - else - { - evaluationStage.mGScene->Draw(this, evaluationInfo); - } - } // face - } // mip - // swap target for multipass - // set previous target as source - if (passCount > 1 && passNumber != (passCount - 1)) - { - transientTarget->Swap(*tgt); - } - } // passNumber - glDisable(GL_BLEND); -} - -void EvaluationContext::EvaluateC(const EvaluationStage& evaluationStage, size_t index, EvaluationInfo& evaluationInfo) -{ - try // todo: find a better solution than a try catch - { - const Evaluator& evaluator = gEvaluators.GetEvaluator(evaluationStage.mType); - if (evaluator.mCFunction) - { - int res = evaluator.mCFunction((unsigned char*)evaluationStage.mParameters.data(), &evaluationInfo, this); - if (res == EVAL_DIRTY) - { - mStillDirty.push_back(uint32_t(index)); - } - } - } - catch (...) - { - } -} - -#if USE_PYTHON -void EvaluationContext::EvaluatePython(const EvaluationStage& evaluationStage, - size_t index, - EvaluationInfo& evaluationInfo) -{ - try // todo: find a better solution than a try catch - { - const Evaluator& evaluator = gEvaluators.GetEvaluator(evaluationStage.mType); - evaluator.RunPython(); - } - catch (...) - { - } -} -#endif - -void EvaluationContext::AllocRenderTargetsForEditingPreview() -{ - // alloc targets - mStageTarget.resize(mEvaluationStages.GetStagesCount(), NULL); - for (size_t i = 0; i < mEvaluationStages.GetStagesCount(); i++) - { - if (!mStageTarget[i]) - { - mStageTarget[i] = std::make_shared(); - } - } -} - -void EvaluationContext::AllocRenderTargetsForBaking(const std::vector& nodesToEvaluate) -{ - if (!mStageTarget.empty()) - return; - - // auto evaluationOrderList = mEvaluationStages.GetForwardEvaluationOrder(); - size_t stageCount = mEvaluationStages.GetStagesCount(); - mStageTarget.resize(stageCount, NULL); - std::vector> freeRenderTargets; - std::vector useCount(stageCount, 0); - for (size_t i = 0; i < stageCount; i++) - { - useCount[i] = mEvaluationStages.GetEvaluationStage(i).mUseCountByOthers; - } - - for (auto index : nodesToEvaluate) - { - const EvaluationStage& evaluation = mEvaluationStages.GetEvaluationStage(index); - if (!evaluation.mUseCountByOthers) - continue; - - if (freeRenderTargets.empty()) - { - mStageTarget[index] = std::make_shared(); - } - else - { - mStageTarget[index] = freeRenderTargets.back(); - freeRenderTargets.pop_back(); - } - - const Input& input = evaluation.mInput; - for (auto targetIndex : input.mInputs) - { - if (targetIndex == -1) - continue; - - useCount[targetIndex]--; - if (!useCount[targetIndex]) - { - freeRenderTargets.push_back(mStageTarget[targetIndex]); - } - } - } -} -void EvaluationContext::PreRun() -{ - mDirtyFlags.resize(mEvaluationStages.GetStagesCount(), 0); - mbProcessing.resize(mEvaluationStages.GetStagesCount(), 0); - mProgress.resize(mEvaluationStages.GetStagesCount(), 0.f); - mActive.resize(mEvaluationStages.GetStagesCount(), false); -} - -void EvaluationContext::RunNode(size_t nodeIndex) -{ - auto& currentStage = mEvaluationStages.GetEvaluationStage(nodeIndex); - const Input& input = currentStage.mInput; - - // check processing - for (auto& inp : input.mInputs) - { - if (inp < 0) - continue; - if (mbProcessing[inp]) - { - mbProcessing[nodeIndex] = 1; - return; - } - } - - mbProcessing[nodeIndex] = 0; - - mEvaluationInfo.targetIndex = int(nodeIndex); - mEvaluationInfo.mFrame = mCurrentTime; - mEvaluationInfo.mDirtyFlag = mDirtyFlags[nodeIndex]; - memcpy(mEvaluationInfo.inputIndices, input.mInputs, sizeof(mEvaluationInfo.inputIndices)); - SetKeyboardMouseInfos(mEvaluationInfo, currentStage); - -#if USE_LIBTCC - if (currentStage.gEvaluationMask & EvaluationC) - EvaluateC(currentStage, nodeIndex, mEvaluationInfo); -#endif -#if USE_PYTHON - if (currentStage.gEvaluationMask & EvaluationPython) - EvaluatePython(currentStage, nodeIndex, mEvaluationInfo); -#endif - if (currentStage.gEvaluationMask & EvaluationGLSLCompute) - { - EvaluateGLSLCompute(currentStage, nodeIndex, mEvaluationInfo); - } - - if (currentStage.gEvaluationMask & EvaluationGLSL) - { - if (!mStageTarget[nodeIndex]->mGLTexID) - mStageTarget[nodeIndex]->InitBuffer(mDefaultWidth, mDefaultHeight, currentStage.mbDepthBuffer); - - EvaluateGLSL(currentStage, nodeIndex, mEvaluationInfo); - } - mDirtyFlags[nodeIndex] = 0; -} - -bool EvaluationContext::RunNodeList(const std::vector& nodesToEvaluate) -{ - GLint last_viewport[4]; - glGetIntegerv(GL_VIEWPORT, last_viewport); - - // run C nodes - bool anyNodeIsProcessing = false; - for (size_t nodeIndex : nodesToEvaluate) - { - mActive[nodeIndex] = mCurrentTime >= mEvaluationStages.mStages[nodeIndex].mStartFrame && - mCurrentTime <= mEvaluationStages.mStages[nodeIndex].mEndFrame; - if (!mActive[nodeIndex]) - continue; - RunNode(nodeIndex); - anyNodeIsProcessing |= mbProcessing[nodeIndex] != 0; - } - // set dirty nodes that tell so - for (auto index : mStillDirty) - SetTargetDirty(index, Dirty::Input); - mStillDirty.clear(); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glUseProgram(0); - glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); - return anyNodeIsProcessing; -} - -void EvaluationContext::RunSingle(size_t nodeIndex, EvaluationInfo& evaluationInfo) -{ - GLint last_viewport[4]; - glGetIntegerv(GL_VIEWPORT, last_viewport); - - PreRun(); - - mEvaluationInfo = evaluationInfo; - - RunNode(nodeIndex); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glUseProgram(0); - glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); -} - -void EvaluationContext::RecurseBackward(size_t target, std::vector& usedNodes) -{ - const EvaluationStage& evaluation = mEvaluationStages.GetEvaluationStage(target); - const Input& input = evaluation.mInput; - - for (size_t inputIndex = 0; inputIndex < 8; inputIndex++) - { - int targetIndex = input.mInputs[inputIndex]; - if (targetIndex == -1) - continue; - RecurseBackward(targetIndex, usedNodes); - } - - if (std::find(usedNodes.begin(), usedNodes.end(), target) == usedNodes.end()) - usedNodes.push_back(target); -} - -void EvaluationContext::RunDirty() -{ - PreRun(); - memset(&mEvaluationInfo, 0, sizeof(EvaluationInfo)); - auto evaluationOrderList = mEvaluationStages.GetForwardEvaluationOrder(); - std::vector nodesToEvaluate; - for (size_t index = 0; index < evaluationOrderList.size(); index++) - { - size_t currentNodeIndex = evaluationOrderList[index]; - if (currentNodeIndex < mDirtyFlags.size() && mDirtyFlags[currentNodeIndex]) // TODOUNDO - nodesToEvaluate.push_back(currentNodeIndex); - } - AllocRenderTargetsForEditingPreview(); - RunNodeList(nodesToEvaluate); -} - -void EvaluationContext::DirtyAll() -{ - // tag all as dirty - mDirtyFlags.resize(mEvaluationStages.GetStagesCount(), 0); - for (auto& dirty : mDirtyFlags) - { - dirty = Dirty::All; - } -} - -void EvaluationContext::RunAll() -{ - PreRun(); - DirtyAll(); - // get list of nodes to run - memset(&mEvaluationInfo, 0, sizeof(EvaluationInfo)); - auto evaluationOrderList = mEvaluationStages.GetForwardEvaluationOrder(); - AllocRenderTargetsForEditingPreview(); - RunNodeList(evaluationOrderList); -} - -bool EvaluationContext::RunBackward(size_t nodeIndex) -{ - PreRun(); - memset(&mEvaluationInfo, 0, sizeof(EvaluationInfo)); - mEvaluationInfo.forcedDirty = true; - std::vector nodesToEvaluate; - RecurseBackward(nodeIndex, nodesToEvaluate); - AllocRenderTargetsForBaking(nodesToEvaluate); - return RunNodeList(nodesToEvaluate); -} -#if USE_FFMPEG -FFMPEGCodec::Encoder* EvaluationContext::GetEncoder(const std::string& filename, int width, int height) -{ - FFMPEGCodec::Encoder* encoder; - auto iter = mWriteStreams.find(filename); - if (iter != mWriteStreams.end()) - { - encoder = iter->second; - } - else - { - encoder = new FFMPEGCodec::Encoder; - mWriteStreams[filename] = encoder; - encoder->Init(filename, align(width, 4), align(height, 4), 25, 400000); - } - return encoder; -} -#endif -void EvaluationContext::SetTargetDirty(size_t target, DirtyFlag dirtyFlag, bool onlyChild) -{ - mDirtyFlags.resize(mEvaluationStages.GetStagesCount(), 0); - auto evaluationOrderList = mEvaluationStages.GetForwardEvaluationOrder(); - mDirtyFlags[target] = dirtyFlag; - for (size_t i = 0; i < evaluationOrderList.size(); i++) - { - size_t currentNodeIndex = evaluationOrderList[i]; - if (currentNodeIndex != target) - continue; - - for (i++; i < evaluationOrderList.size(); i++) - { - currentNodeIndex = evaluationOrderList[i]; - if (currentNodeIndex >= mDirtyFlags.size() || mDirtyFlags[currentNodeIndex]) // TODOUNDO - continue; - - auto& currentEvaluation = mEvaluationStages.GetEvaluationStage(currentNodeIndex); - for (auto inp : currentEvaluation.mInput.mInputs) - { - if (inp >= 0 && mDirtyFlags[inp]) - { - mDirtyFlags[currentNodeIndex] = Dirty::Input; - break; - } - } - } - } - if (onlyChild) - { - mDirtyFlags[target] = false; - } -} - -void EvaluationContext::UserAddStage() -{ - URAdd> undoRedoAddRenderTarget(int(mStageTarget.size()), - [&]() { return &mStageTarget; }); - URAdd undoRedoAddDirty(int(mDirtyFlags.size()), [&]() { return &mDirtyFlags; }); - URAdd undoRedoAddProcessing(int(mbProcessing.size()), [&]() { return &mbProcessing; }); - URAdd undoRedoAddProgress(int(mProgress.size()), [&]() { return &mProgress; }); - - mStageTarget.push_back(std::make_shared()); - mDirtyFlags.push_back(Dirty::All); - mbProcessing.push_back(0); - mProgress.push_back(0.f); -} - -void EvaluationContext::UserDeleteStage(size_t index) -{ - URDel> undoRedoDelRenderTarget(int(index), [&]() { return &mStageTarget; }); - URDel undoRedoDelDirty(int(index), [&]() { return &mDirtyFlags; }); - URDel undoRedoDelProcessing(int(index), [&]() { return &mbProcessing; }); - URDel undoRedoDelProgress(int(index), [&]() { return &mProgress; }); - - mStageTarget.erase(mStageTarget.begin() + index); - mDirtyFlags.erase(mDirtyFlags.begin() + index); - mbProcessing.erase(mbProcessing.begin() + index); - mProgress.erase(mProgress.begin() + index); -} - -void EvaluationContext::AllocateComputeBuffer(int target, int elementCount, int elementSize) -{ - if (mComputeBuffers.size() <= target) - mComputeBuffers.resize(target + 1); - ComputeBuffer& buffer = mComputeBuffers[target]; - buffer.mElementCount = elementCount; - buffer.mElementSize = elementSize; - if (!buffer.mBuffer) - glGenBuffers(1, &buffer.mBuffer); - - glBindBuffer(GL_ARRAY_BUFFER, buffer.mBuffer); - glBufferData(GL_ARRAY_BUFFER, elementSize * elementCount, NULL, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -const EvaluationContext::ComputeBuffer* EvaluationContext::GetComputeBuffer(size_t index) const -{ - ComputeBuffer res; - if (mComputeBuffers.size() <= index) - return nullptr; - return &mComputeBuffers[index]; -} - -void EvaluationContext::StageSetProcessing(size_t target, int processing) -{ - mbProcessing.resize(mEvaluationStages.GetStagesCount(), 0); - if (target >= mbProcessing.size()) - { - return; - } - if (mbProcessing[target] != processing) - { - mProgress.resize(mEvaluationStages.GetStagesCount(), 0.f); - mProgress[target] = 0.f; - } - mbProcessing[target] = processing; -} - -void EvaluationContext::StageSetProgress(size_t target, float progress) -{ - mProgress.resize(mEvaluationStages.GetStagesCount(), 0.f); - if (target >= mProgress.size()) - { - return; - } - mProgress[target] = progress; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -Builder::Builder() : mbRunning(true) -{ -#ifndef __EMSCRIPTEN__ - mThread = std::thread([&]() { BuildEntries(); }); -#endif -} - -Builder::~Builder() -{ - mbRunning = false; - mThread.join(); -} - -void Builder::Add(const char* graphName, const EvaluationStages& stages) -{ - mMutex.lock(); - mEntries.push_back({graphName, 0.f, stages}); - mMutex.unlock(); -} - -EvaluationStages BuildEvaluationFromMaterial(Material& material) -{ - EvaluationStages evaluationStages; - for (size_t i = 0; i < material.mMaterialNodes.size(); i++) - { - MaterialNode& node = material.mMaterialNodes[i]; - evaluationStages.AddSingleEvaluation(node.mType); - auto& lastNode = evaluationStages.mStages.back(); - lastNode.mParameters = node.mParameters; - lastNode.mInputSamplers = node.mInputSamplers; - evaluationStages.SetEvaluationSampler(i, node.mInputSamplers); - } - for (size_t i = 0; i < material.mMaterialConnections.size(); i++) - { - MaterialConnection& materialConnection = material.mMaterialConnections[i]; - evaluationStages.AddEvaluationInput( - materialConnection.mOutputNode, materialConnection.mInputSlot, materialConnection.mInputNode); - } - - evaluationStages.SetAnimTrack(material.mAnimTrack); - evaluationStages.mFrameMin = material.mFrameMin; - evaluationStages.mFrameMax = material.mFrameMax; - evaluationStages.mPinnedParameters = material.mPinnedParameters; - - return evaluationStages; -} - -void Builder::Add(Material* material) -{ - try - { - Add(material->mName.c_str(), BuildEvaluationFromMaterial(*material)); - } - catch (std::exception e) - { - Log("Exception : %s\n", e.what()); - } -} - -bool Builder::UpdateBuildInfo(std::vector& buildInfo) -{ - if (mMutex.try_lock()) - { - buildInfo.clear(); - for (auto& entry : mEntries) - { - buildInfo.push_back({entry.mName, entry.mProgress}); - } - mMutex.unlock(); - return true; - } - return false; -} - -void Builder::DoBuild(Entry& entry) -{ - auto& evaluationStages = entry.mEvaluationStages; - size_t stageCount = evaluationStages.mStages.size(); - for (size_t i = 0; i < stageCount; i++) - { - const auto& node = evaluationStages.mStages[i]; - const MetaNode& currentMeta = gMetaNodes[node.mType]; - bool forceEval = false; - for (auto& param : currentMeta.mParams) - { - if (!param.mName.c_str()) - break; - if (param.mType == Con_ForceEvaluate) - { - forceEval = true; - break; - } - } - if (forceEval) - { - EvaluationContext writeContext(evaluationStages, true, 1024, 1024); - for (int frame = node.mStartFrame; frame <= node.mEndFrame; frame++) - { - writeContext.SetCurrentTime(frame); - evaluationStages.SetTime(&writeContext, frame, false); - evaluationStages.ApplyAnimation(&writeContext, frame); - EvaluationInfo evaluationInfo; - evaluationInfo.forcedDirty = 1; - evaluationInfo.uiPass = 0; - writeContext.RunSingle(i, evaluationInfo); + GetRenderProxy(currentFramebuffer, viewportWidth, viewportHeight, evaluation.mbDepthBuffer); } - } - entry.mProgress = float(i + 1) / float(stageCount); - if (!mbRunning) - break; - } -} - -void MakeThreadContext(); -void Builder::BuildEntries() -{ - MakeThreadContext(); - - while (mbRunning) - { - if (mMutex.try_lock()) - { - if (!mEntries.empty()) - { - auto& entry = *mEntries.begin(); - entry.mProgress = 0.01f; - DoBuild(entry); - entry.mProgress = 1.f; - if (entry.mProgress >= 1.f) - { - mEntries.erase(mEntries.begin()); + + for (auto face = 0; face < faceCount; face++) + { + bgfx::ViewId viewId = baseViewId; + + if (!evaluation.mbClearBuffer && !evaluationInfo.uiPass) + { + bgfx::setViewName(viewId, "blit"); + bgfx::setViewMode(viewId, bgfx::ViewMode::Sequential); + bgfx::setViewRect(viewId, 0, 0, viewportWidth, viewportHeight); + bgfx::setViewFrameBuffer(viewId, blitFramebuffer); + bgfx::touch(viewId); + bgfx::blit(viewId, bgfx::getTexture(currentFramebuffer), mip, 0, 0, face, tgt->mTexture, 0, 0, 0, 0, viewportWidth, viewportHeight, 0); + } + + if (!evaluationInfo.uiPass) + { + bgfx::setViewName(viewId, gMetaNodes[evaluator.mType].mName.c_str()); + bgfx::setViewMode(viewId, bgfx::ViewMode::Sequential); + bgfx::setViewFrameBuffer(viewId, currentFramebuffer); + bgfx::setViewRect(viewId, 0, 0, viewportWidth , viewportHeight); + } + + memcpy(evaluationInfo.viewRot, rotMatrices[face], sizeof(float) * 16); + for (int i = 0; i < 8; i++) + { + evaluationInfo.inputIndices[i] = input.mInputs[i].IsValid() ? float(input.mInputs[i]) : -1.f; + } + + evaluationInfo.viewport[0] = float(viewportWidth); + evaluationInfo.viewport[1] = float(viewportHeight); + evaluationInfo.passNumber = float(passNumber); + evaluationInfo.mipmapNumber = float(mip); + evaluationInfo.mipmapCount = mipmapCount; + evaluationInfo.vertexSpace = (float)evaluation.mVertexSpace; + BindTextures(evaluationInfo, evaluationStage, nodeIndex, passNumber ? tgt : nullptr); + + bgfx::setViewClear(viewId, evaluation.mbClearBuffer ? (BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH) : 0, 0x000000ff, 1.0f, 0); + + SetUniforms(nodeIndex); + + { + uint64_t state = 0 + | BGFX_STATE_WRITE_RGB + | BGFX_STATE_WRITE_A + | BGFX_STATE_BLEND_FUNC(evaluation.mBlendingSrc, evaluation.mBlendingDst) + | (evaluation.mbDepthBuffer ? (BGFX_STATE_DEPTH_TEST_LEQUAL| BGFX_STATE_WRITE_Z) : BGFX_STATE_DEPTH_TEST_ALWAYS) + ; + + bgfx::setState(state); + if (!evaluationInfo.uiPass) + { + static const float uvt[4] = { 2.f, -2.f, -1.0f, 1.0f }; + bgfx::setUniform(gEvaluators.u_uvTransform, uvt); + } + + evaluationStage.mGScene->Draw(evaluationInfo, viewId, program); + } + + // copy from proxy to destination + if (!evaluationInfo.uiPass) + { + viewId++; + bgfx::frame(); + // blit + bgfx::setViewName(viewId, "blit"); + bgfx::setViewMode(viewId, bgfx::ViewMode::Sequential); + bgfx::setViewRect(viewId, 0, 0, viewportWidth, viewportHeight); + bgfx::setViewFrameBuffer(viewId, blitFramebuffer); + bgfx::touch(viewId); + bgfx::blit(viewId, tgt->mTexture, mip, 0, 0, face, bgfx::getTexture(currentFramebuffer), 0, 0, 0, 0, viewportWidth, viewportHeight, 0); + viewId++; + + bgfx::frame(); } - } - mMutex.unlock(); - } -#ifdef Sleep - Sleep(100); -#endif - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace DrawUICallbacks -{ - void DrawUIProgress(EvaluationContext* context, size_t nodeIndex) - { - glUseProgram(gDefaultShader.mProgressShader); - glUniform1f(glGetUniformLocation(gDefaultShader.mProgressShader, "time"), - float(double(SDL_GetTicks()) / 1000.0)); - context->mFSQuad.Render(); - } - - void DrawUISingle(EvaluationContext* context, size_t nodeIndex) - { - EvaluationInfo evaluationInfo; - evaluationInfo.forcedDirty = 1; - evaluationInfo.uiPass = 1; - context->RunSingle(nodeIndex, evaluationInfo); - } - - void DrawUICubemap(EvaluationContext* context, size_t nodeIndex) - { - glUseProgram(gDefaultShader.mDisplayCubemapShader); - int tgt = glGetUniformLocation(gDefaultShader.mDisplayCubemapShader, "samplerCubemap"); - glUniform1i(tgt, 0); - glActiveTexture(GL_TEXTURE0); - TexParam(GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_TEXTURE_CUBE_MAP); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); - glBindTexture(GL_TEXTURE_CUBE_MAP, context->GetEvaluationTexture(nodeIndex)); - context->mFSQuad.Render(); - } -} // namespace DrawUICallbacks \ No newline at end of file + } // face + } // mip + } // passNumber +} + +void EvaluationContext::GenerateThumbnail(NodeIndex nodeIndex) +{ + assert(mUseThumbnail); + bgfx::ViewId viewId = 20; + const auto& evaluation = mEvaluations[nodeIndex]; + const auto thumb = evaluation.mThumb; + if (!thumb.Valid()) + { + return; + } + const auto tgt = evaluation.mTarget; + if (!tgt) + { + return; // can be null for file read/file write + } + const int width = tgt->mImage.mWidth; + const int height = tgt->mImage.mHeight; + + if (!width || !height) + { + return; + } + // create thumbnail + auto thumbFrameBuffer = mThumbnails.GetThumbFrameBuffer(thumb); + + auto def = Scene::BuildDefaultScene(); + int sourceCoords[4]; + mThumbnails.GetThumbCoordinates(thumb, sourceCoords); + bgfx::setViewName(viewId, "Make Thumbnail"); + bgfx::setViewMode(viewId, bgfx::ViewMode::Sequential); + bgfx::setViewFrameBuffer(viewId, thumbFrameBuffer); + auto h = sourceCoords[3] - sourceCoords[1]; + bgfx::setViewRect(viewId, sourceCoords[0], sourceCoords[1], sourceCoords[2] - sourceCoords[0], h); + bgfx::setViewClear(viewId, BGFX_CLEAR_COLOR /*| BGFX_CLEAR_DEPTH*/, 0xF08010ff, 1.0f, 0); + uint64_t state = BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_DEPTH_TEST_ALWAYS; + bgfx::touch(viewId); + bgfx::setState(state); + + static const float uvt[4] = { 2.f, -2.f, -1.0f, 1.0f }; + bgfx::setUniform(gEvaluators.u_uvTransform, uvt); + EvaluationInfo evaluationInfo = { 0 }; + if (tgt->mImage.mIsCubemap) + { + bgfx::setTexture(0, gEvaluators.mSamplersCube[0], tgt->mTexture); + def->Draw(evaluationInfo, viewId, gEvaluators.mDisplayCubemapProgram); + } + else + { + bgfx::setTexture(0, gEvaluators.mSamplers2D[0], tgt->mTexture); + def->Draw(evaluationInfo, viewId, gEvaluators.mBlitProgram); + } + bgfx::frame(); +} + +void EvaluationContext::EvaluateC(const EvaluationStage& evaluationStage, NodeIndex nodeIndex, EvaluationInfo& evaluationInfo) +{ + try + { + const auto& evaluator = gEvaluators.GetEvaluator(evaluationStage.mType); + int res = evaluator.mCFunction(mEvaluationStages.mParameterBlocks[nodeIndex].Data(), &evaluationInfo, this); + } + catch (std::exception e) + { + printf("Duktape exception %s\n", e.what()); + } +} + +#if USE_PYTHON +void EvaluationContext::EvaluatePython(const EvaluationStage& evaluationStage, + NodeIndex index, + EvaluationInfo& evaluationInfo) +{ + try // todo: find a better solution than a try catch + { + const auto& evaluator = gEvaluators.GetEvaluator(evaluationStage.mType); + evaluator.RunPython(); + } + catch (...) + { + } +} +#endif + +void EvaluationContext::ComputeTargetUseCount() +{ + for (auto& evaluation : mEvaluations) + { + evaluation.mUseCount = 0; + } + for (auto j = 0; j < mEvaluationStages.mStages.size(); j++) + { + for (auto i = 0; i < 8; i++) + { + const auto input = mEvaluationStages.mInputs[j].mInputs[i]; + if (input.IsValid()) + { + mEvaluations[input].mUseCount ++; + } + } + } +} + +void EvaluationContext::ReleaseInputs(NodeIndex nodeIndex) +{ + if (!mBuilding) + { + return; + } + // is this node used anytime soon? + if (!mEvaluations[nodeIndex].mUseCount && mEvaluations[nodeIndex].mTarget && !mEvaluations[nodeIndex].mbPersistent) + { + ReleaseRenderTarget(mEvaluations[nodeIndex].mTarget); + mEvaluations[nodeIndex].mTarget = nullptr; + } + // decrement use of inputs + for (auto i = 0; i < 8; i++) + { + const auto input = mEvaluationStages.mInputs[nodeIndex].mInputs[i]; + if (input.IsValid()) + { + // use count must be positive + assert(mEvaluations[input].mUseCount); + + mEvaluations[input].mUseCount--; + if (mEvaluations[input].mUseCount <= 0 && mEvaluations[input].mTarget && !mEvaluations[input].mbPersistent) + { + ReleaseRenderTarget(mEvaluations[input].mTarget); + mEvaluations[input].mTarget = nullptr; + } + } + } +} + +void EvaluationContext::RunNode(NodeIndex nodeIndex) +{ + auto& currentStage = mEvaluationStages.mStages[nodeIndex]; + const Input& input = mEvaluationStages.mInputs[nodeIndex]; + auto& evaluation = mEvaluations[nodeIndex]; + + // check processing + for (auto& inp : input.mInputs) + { + if (!inp.IsValid()) + { + continue; + } + if (mEvaluations[inp].mProcessing) + { + evaluation.mProcessing = 1; + return; + } + } + + evaluation.mProcessing = 0; + memset(&mEvaluationInfo, 0, sizeof(EvaluationInfo)); + mEvaluationInfo.targetIndex = float(nodeIndex); + mEvaluationInfo.frame = float(mCurrentTime); + mEvaluationInfo.dirtyFlag = evaluation.mDirtyFlag; + for (int i = 0; i < 8; i++) + { + mEvaluationInfo.inputIndices[i] = input.mInputs[i].IsValid() ? (float)input.mInputs[i] : -1.f; + } + SetKeyboardMouseInfos(mEvaluationInfo, nodeIndex); + int evaluationMask = gEvaluators.GetMask(currentStage.mType); + + if (evaluationMask & EvaluationC) + { + EvaluateC(currentStage, nodeIndex, mEvaluationInfo); + } +#ifdef USE_PYTHON + if (evaluationMask & EvaluationPython) + { + EvaluatePython(currentStage, nodeIndex, mEvaluationInfo); + } +#endif + + if (evaluationMask & EvaluationGLSL) + { + // target might be allocated by any node evaluator before + if (!evaluation.mTarget) + { + evaluation.mTarget = AcquireRenderTarget(mDefaultWidth, mDefaultHeight, evaluation.mbDepthBuffer); + } + EvaluateGLSL(currentStage, nodeIndex, mEvaluationInfo); + } + + if (mUseThumbnail) + { + GenerateThumbnail(nodeIndex); + } + + ReleaseInputs(nodeIndex); + evaluation.mDirtyFlag = 0; +} + +#if USE_FFMPEG +FFMPEGCodec::Encoder* EvaluationContext::GetEncoder(const std::string& filename, int width, int height) +{ + FFMPEGCodec::Encoder* encoder; + auto iter = mWriteStreams.find(filename); + if (iter != mWriteStreams.end()) + { + encoder = iter->second; + } + else + { + encoder = new FFMPEGCodec::Encoder; + mWriteStreams[filename] = encoder; + encoder->Init(filename, align(width, 4), align(height, 4), 25, 400000); + } + return encoder; +} +#endif + +void EvaluationContext::SetTargetDirty(NodeIndex target, uint32_t dirtyFlag, bool onlyChild) +{ + assert(dirtyFlag != Dirty::AddedNode); + assert(dirtyFlag != Dirty::DeletedNode); + + auto evaluationOrderList = mEvaluationStages.GetForwardEvaluationOrder(); + uint32_t dirtyFlagSource = mEvaluations[target].mDirtyFlag; + mEvaluations[target].mDirtyFlag |= dirtyFlag; + for (size_t i = 0; i < evaluationOrderList.size(); i++) + { + size_t currentNodeIndex = evaluationOrderList[i]; + if (currentNodeIndex != target) + { + continue; + } + for (i++; i < evaluationOrderList.size(); i++) + { + currentNodeIndex = evaluationOrderList[i]; + if (mEvaluations[currentNodeIndex].mDirtyFlag) + { + continue; + } + for (auto inp : mEvaluationStages.mInputs[currentNodeIndex].mInputs) + { + if (inp.IsValid() && mEvaluations[inp].mDirtyFlag) + { + mEvaluations[currentNodeIndex].mDirtyFlag |= Dirty::Input; + break; + } + } + } + } + if (onlyChild) + { + mEvaluations[target].mDirtyFlag = dirtyFlagSource; + } +} + +void EvaluationContext::SetTargetPersistent(NodeIndex nodeIndex, bool persistent) +{ + mEvaluations[nodeIndex].mbPersistent = persistent; +} + +void EvaluationContext::StageSetProcessing(NodeIndex target, int processing) +{ + if (mEvaluations[target].mProcessing != processing) + { + mEvaluations[target].mProgress = 0.f; + } + mEvaluations[target].mProcessing = processing; +} + +void EvaluationContext::StageSetProgress(NodeIndex target, float progress) +{ + mEvaluations[target].mProgress = progress; +} + + +ImageTexture* EvaluationContext::AcquireRenderTarget(int width, int height, bool depthBuffer) +{ + for (size_t i = 0; i < mAvailableRenderTargets.size(); i++) + { + ImageTexture* rt = mAvailableRenderTargets[i]; + if (rt->mImage.mWidth == width && rt->mImage.mHeight == height /*&& (rt->mGLTexDepth.idx != bgfx::kInvalidHandle) == depthBuffer*/) + { + mAvailableRenderTargets.erase(mAvailableRenderTargets.begin() + i); + return rt; + } + } + ImageTexture* rt = new ImageTexture; + rt->Init2D(width, height, depthBuffer); + return rt; +} + +ImageTexture* EvaluationContext::AcquireClone(ImageTexture* source) +{ + return AcquireRenderTarget(source->mImage.mWidth, source->mImage.mHeight, false/*source->mGLTexDepth.idx != bgfx::kInvalidHandle*/); +} + +void EvaluationContext::ReleaseRenderTarget(ImageTexture* renderTarget) +{ + assert(renderTarget); + mAvailableRenderTargets.push_back(renderTarget); +} + +int EvaluationContext::GetStageIndexFromRuntimeId(RuntimeId runtimeUniqueId) const +{ + for (unsigned int i = 0; i < mEvaluations.size(); i++) + { + if (mEvaluations[i].mRuntimeUniqueId == runtimeUniqueId) + { + return int(i); + } + } + return -1; +} + +RuntimeId EvaluationContext::GetStageRuntimeId(NodeIndex nodeIndex) const +{ + return mEvaluations[nodeIndex].mRuntimeUniqueId; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +Builder::Builder() : mbRunning(true) +{ +#ifndef __EMSCRIPTEN__ + mThread = std::thread([&]() { BuildEntries(); }); +#endif +} + +Builder::~Builder() +{ + mbRunning = false; + mThread.join(); +} + +void Builder::Add(const char* graphName, const EvaluationStages& stages) +{ + /* aync + mMutex.lock(); + mEntries.push_back({graphName, 0.f, stages}); + mMutex.unlock(); + */ + // sync + Builder::Entry entry{ graphName, 0.f, stages }; + DoBuild(entry); +} + +void Builder::Add(Material* material) +{ + try + { + EvaluationStages stages; + stages.BuildEvaluationFromMaterial(*material); + Add(material->mName.c_str(), stages); + } + catch (std::exception e) + { + Log("Exception : %s\n", e.what()); + } +} + +bool Builder::UpdateBuildInfo(std::vector& buildInfo) +{ + if (mMutex.try_lock()) + { + buildInfo.clear(); + for (auto& entry : mEntries) + { + buildInfo.push_back({entry.mName, entry.mProgress}); + } + mMutex.unlock(); + return true; + } + return false; +} + +void Builder::DoBuild(Entry& entry) +{ + auto & evaluationStages = entry.mEvaluationStages; + int startFrame(INT_MAX), endFrame(INT_MIN); + for (auto& evaluation : evaluationStages.mStages) + { + startFrame = std::min(startFrame, evaluation.mStartFrame); + endFrame = std::max(endFrame, evaluation.mEndFrame); + } + EvaluationContext writeContext(evaluationStages, true, true, 4096, 4096, false); + + // dirty all or parameters might not be taken into consideration + for (auto& evaluation : writeContext.mEvaluations) + { + evaluation.mDirtyFlag = -1; + } + for (int frame = startFrame; frame < endFrame; frame++) + { + writeContext.SetCurrentTime(frame); + evaluationStages.SetTime(&writeContext, frame, false); + evaluationStages.ApplyAnimation(&writeContext, frame); + writeContext.Evaluate(); + } +} + +void MakeThreadContext(); +void Builder::BuildEntries() +{ + MakeThreadContext(); + + while (mbRunning) + { + if (mMutex.try_lock()) + { + if (!mEntries.empty()) + { + auto& entry = *mEntries.begin(); + entry.mProgress = 0.01f; + DoBuild(entry); + entry.mProgress = 1.f; + if (entry.mProgress >= 1.f) + { + mEntries.erase(mEntries.begin()); + } + } + mMutex.unlock(); + } +#ifdef Sleep + Sleep(100); +#endif + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace DrawUICallbacks +{ + void DrawUIProgress(EvaluationContext* context, NodeIndex nodeIndex) + { + auto def = Scene::BuildDefaultScene(); + + uint64_t state = 0 + | BGFX_STATE_WRITE_RGB + | BGFX_STATE_WRITE_A + | BGFX_STATE_DEPTH_TEST_ALWAYS + ; + + bgfx::setState(state); + float uniform[] = { float(double(SDL_GetTicks()) / 1000.0), 0.f, 0.f, 0.f}; + bgfx::setUniform(gEvaluators.u_time, uniform); + + EvaluationInfo evaluationInfo; + def->Draw(evaluationInfo, 0, gEvaluators.mProgressProgram); + } + + void DrawUISingle(EvaluationContext* context, NodeIndex nodeIndex) + { + EvaluationInfo evaluationInfo; + //evaluationInfo.forcedDirty = 1; + evaluationInfo.uiPass = 1; + context->RunSingle(nodeIndex, 0, evaluationInfo); + } +} // namespace DrawUICallbacks + + diff --git a/src/EvaluationContext.h b/src/EvaluationContext.h index edc54216..4e935bdc 100644 --- a/src/EvaluationContext.h +++ b/src/EvaluationContext.h @@ -23,87 +23,118 @@ // SOFTWARE. // #pragma once + #include #include #include #include +#include "Types.h" #include "EvaluationStages.h" +#include "Evaluators.h" -struct EvaluationInfo +struct UIInput { - float viewRot[16]; - float viewProjection[16]; - float viewInverse[16]; - float model[16]; - float modelViewProjection[16]; - float viewport[4]; - - int targetIndex; - int forcedDirty; - int uiPass; - int passNumber; - float mouse[4]; - int keyModifier[4]; - int inputIndices[8]; - - int mFrame; - int mLocalFrame; - int mVertexSpace; - int mDirtyFlag; - - int mipmapNumber; - int mipmapCount; + float mRx; + float mRy; + float mDx; + float mDy; + float mWheel; + uint8_t mLButDown : 1; + uint8_t mRButDown : 1; + uint8_t mbCtrl : 1; + uint8_t mbAlt : 1; + uint8_t mbShift : 1; }; -struct Dirty +struct EvaluationThumbnails { - enum - { - Input = 1 << 0, - Parameter = 1 << 1, - Mouse = 1 << 2, - Camera = 1 << 3, - Time = 1 << 4, - Sampler = 1 << 5, - All = 0xFF - }; + struct Thumb + { + unsigned short mAtlasIndex = 0xFFFF; + unsigned short mThumbIndex = 0xFFFF; + bool Valid() const + { + return mAtlasIndex != 0xFFFF && mThumbIndex != 0xFFFF; + } + }; + + void Clear(); + Thumb AddThumb(); + void DelThumb(const Thumb thumb); + void GetThumb(const Thumb thumb, bgfx::TextureHandle& textureId, ImRect& uvs) const; + bgfx::FrameBufferHandle& GetThumbFrameBuffer(const Thumb thumb); + void GetThumbCoordinates(const Thumb thumb, int* coordinates) const; + std::vector GetAtlasTextures() const; +protected: + + const uint16_t AtlasSize = 4096; + const uint16_t ThumbnailSize = 256; + const uint16_t ThumbnailsPerAtlas = (AtlasSize / ThumbnailSize) * (AtlasSize / ThumbnailSize); + + ImRect ComputeUVFromIndexInAtlas(size_t thumbIndex) const; + Thumb AddThumbInAtlas(size_t atlasIndex); + + struct ThumbAtlas + { + ThumbAtlas(size_t thumbnailsPerAtlas) + { + mbUsed.resize(thumbnailsPerAtlas, false); + } + bgfx::FrameBufferHandle mFrameBuffer; + std::vector mbUsed; + size_t mUsedCount = 0; + }; + + std::vector mAtlases; + std::vector mThumbs; }; -typedef unsigned char DirtyFlag; + struct EvaluationContext { - EvaluationContext(EvaluationStages& evaluation, bool synchronousEvaluation, int defaultWidth, int defaultHeight); + EvaluationContext(EvaluationStages& evaluation, bool building, bool synchronousEvaluation, int defaultWidth, int defaultHeight, bool useThumbnail); ~EvaluationContext(); - void RunAll(); - // return true if any node is in processing state - bool RunBackward(size_t nodeIndex); - void RunSingle(size_t nodeIndex, EvaluationInfo& evaluationInfo); - void RunDirty(); + // iterative editing + void AddEvaluation(NodeIndex nodeIndex); + void DelEvaluation(NodeIndex nodeIndex); - int GetCurrentTime() const - { - return mCurrentTime; - } - void SetCurrentTime(int currentTime) - { - mCurrentTime = currentTime; - } + void Evaluate(); - unsigned int GetEvaluationTexture(size_t target); - std::shared_ptr GetRenderTarget(size_t target) - { - if (target >= mStageTarget.size()) - return NULL; - return mStageTarget[target]; + void RunSingle(NodeIndex nodeIndex, bgfx::ViewId viewId, EvaluationInfo& evaluationInfo); + void SetKeyboardMouse(NodeIndex nodeIndex, const UIInput& input); + int GetCurrentTime() const { return mCurrentTime; } + void SetCurrentTime(int currentTime) { mCurrentTime = currentTime; } + + void GetThumb(NodeIndex nodeIndex, bgfx::TextureHandle& textureHandle, ImRect& uvs) const + { + assert(mUseThumbnail); + mThumbnails.GetThumb(mEvaluations[nodeIndex].mThumb, textureHandle, uvs); } + void GenerateThumbnail(NodeIndex nodeIndex); + + bgfx::TextureHandle GetEvaluationTexture(NodeIndex nodeIndex) const; - const std::shared_ptr GetRenderTarget(size_t target) const + ImageTexture* GetRenderTarget(NodeIndex nodeIndex) + { + assert(nodeIndex < mEvaluations.size()); + return mEvaluations[nodeIndex].mTarget; + } + + const ImageTexture* GetRenderTarget(NodeIndex nodeIndex) const { - if (target >= mStageTarget.size()) - return NULL; - return mStageTarget[target]; + assert(nodeIndex < mEvaluations.size()); + return mEvaluations[nodeIndex].mTarget; } + + ImageTexture* CreateRenderTarget(NodeIndex nodeIndex) + { + assert(nodeIndex < mEvaluations.size()); + assert(!mEvaluations[nodeIndex].mTarget); + mEvaluations[nodeIndex].mTarget = new ImageTexture; + return mEvaluations[nodeIndex].mTarget; + } + #if USE_FFMPEG FFMPEGCodec::Encoder* GetEncoder(const std::string& filename, int width, int height); #endif @@ -115,93 +146,136 @@ struct EvaluationContext { mbSynchronousEvaluation = synchronous; } - void SetTargetDirty(size_t target, DirtyFlag dirtyflag, bool onlyChild = false); - int StageIsProcessing(size_t target) const + bool IsBuilding() const { return mBuilding; } + void SetTargetDirty(NodeIndex target, uint32_t dirtyflag, bool onlyChild = false); + void SetTargetPersistent(NodeIndex nodeIndex, bool persistent); + int StageIsProcessing(NodeIndex target) const { - if (target >= mbProcessing.size()) - return 0; - return mbProcessing[target]; + assert (target < mEvaluations.size()); + return mEvaluations[target].mProcessing; } - float StageGetProgress(size_t target) const + float StageGetProgress(NodeIndex target) const { - if (target >= mProgress.size()) - return 0.f; - return mProgress[target]; + assert(target < mEvaluations.size()); + return mEvaluations[target].mProgress; } - void StageSetProcessing(size_t target, int processing); - void StageSetProgress(size_t target, float progress); + void StageSetProcessing(NodeIndex target, int processing); + void StageSetProgress(NodeIndex target, float progress); - void AllocRenderTargetsForEditingPreview(); + int GetStageIndexFromRuntimeId(RuntimeId runtimeUniqueId) const; + RuntimeId GetStageRuntimeId(NodeIndex stageIndex) const; - void AllocateComputeBuffer(int target, int elementCount, int elementSize); - // edit context only - void UserAddStage(); - void UserDeleteStage(size_t index); - - struct ComputeBuffer - { - unsigned int mBuffer{0}; - unsigned int mElementCount; - unsigned int mElementSize; - }; + const EvaluationThumbnails& GetThumbnails() const + { + assert(mUseThumbnail); + return mThumbnails; + } - const ComputeBuffer* GetComputeBuffer(size_t index) const; void Clear(); - unsigned int GetMaterialUniqueId() const - { - return mRuntimeUniqueId; - } - void SetMaterialUniqueId(unsigned int uniqueId) - { - mRuntimeUniqueId = uniqueId; - } + RuntimeId GetMaterialUniqueId() const { return mRuntimeUniqueId; } + void SetMaterialUniqueId(RuntimeId runtimeId) { mRuntimeUniqueId = runtimeId; } EvaluationStages& mEvaluationStages; - FullScreenTriangle mFSQuad; - unsigned int mEvaluationStateGLSLBuffer; - void DirtyAll(); + + + struct Evaluation + { + Evaluation() + : mbDepthBuffer(false) + , mbClearBuffer(true) + , mbActive(false) + , mbPersistent(false) + { + } + + ImageTexture* mTarget = nullptr; + + EvaluationThumbnails::Thumb mThumb; + float mProgress = 0.f; + + uint64_t mBlendingSrc = BGFX_STATE_BLEND_ONE; + uint64_t mBlendingDst = BGFX_STATE_BLEND_ZERO; + uint32_t mDirtyFlag = 0; + uint8_t mProcessing = false; + uint8_t mVertexSpace = 0; // UV, worldspace + int mUseCount; + RuntimeId mRuntimeUniqueId; + union + { + uint8_t u; + struct + { + uint8_t mbDepthBuffer : 1; + uint8_t mbClearBuffer : 1; + uint8_t mbActive : 1; + uint8_t mbPersistent : 1; // target isn't deleted when not used anymore by subsequent nodes + }; + }; + }; + + std::vector mEvaluations; + + + + UIInput mUIInputs; + size_t mInputNodeIndex; protected: - void PreRun(); - void EvaluateGLSL(const EvaluationStage& evaluationStage, size_t index, EvaluationInfo& evaluationInfo); - void EvaluateC(const EvaluationStage& evaluationStage, size_t index, EvaluationInfo& evaluationInfo); - void EvaluatePython(const EvaluationStage& evaluationStage, size_t index, EvaluationInfo& evaluationInfo); - void EvaluateGLSLCompute(const EvaluationStage& evaluationStage, size_t index, EvaluationInfo& evaluationInfo); + + EvaluationThumbnails mThumbnails; + + void EvaluateGLSL(const EvaluationStage& evaluationStage, NodeIndex nodeIndex, EvaluationInfo& evaluationInfo, bgfx::ViewId baseViewId = 10); + void EvaluateC(const EvaluationStage& evaluationStage, NodeIndex nodeIndex, EvaluationInfo& evaluationInfo); +#ifdef USE_PYTHON + void EvaluatePython(const EvaluationStage& evaluationStage, NodeIndex nodeIndex, EvaluationInfo& evaluationInfo); +#endif // return true if any node is still in processing state - bool RunNodeList(const std::vector& nodesToEvaluate); - void RunNode(size_t nodeIndex); + //bool RunNodeList(const std::vector& nodesToEvaluate); + + void RunNode(NodeIndex nodeIndex); + - void RecurseBackward(size_t target, std::vector& usedNodes); + - void BindTextures(const EvaluationStage& evaluationStage, - unsigned int program, - std::shared_ptr reusableTarget); - void AllocRenderTargetsForBaking(const std::vector& nodesToEvaluate); + //void RecurseBackward(size_t nodeIndex, std::vector& usedNodes); + void BindTextures(EvaluationInfo& evaluationInfo, + const EvaluationStage& evaluationStage, + NodeIndex nodeIndex, + ImageTexture* reusableTarget); + //void AllocRenderTargetsForBaking(const std::vector& nodesToEvaluate); - int GetBindedComputeBuffer(const EvaluationStage& evaluationStage) const; + void ComputeTargetUseCount(); + void ReleaseInputs(NodeIndex nodeIndex); + ImageTexture* AcquireRenderTarget(int width, int height, bool depthBuffer); + ImageTexture* AcquireClone(ImageTexture* source); + void ReleaseRenderTarget(ImageTexture* renderTarget); - std::vector> mStageTarget; // 1 per stage - std::vector mComputeBuffers; + + std::vector mAvailableRenderTargets; #if USE_FFMPEG std::map mWriteStreams; #endif - std::vector mDirtyFlags; - std::vector mbProcessing; - std::vector mProgress; - std::vector mActive; + EvaluationInfo mEvaluationInfo; - std::vector mStillDirty; int mDefaultWidth; int mDefaultHeight; bool mbSynchronousEvaluation; - unsigned int mRuntimeUniqueId; // material unique Id for thumbnail update + bool mUseThumbnail; + bool mBuilding; + RuntimeId mRuntimeUniqueId; // material unique Id for thumbnail update int mCurrentTime; - unsigned int mParametersGLSLBuffer; + std::vector mRemaining; + + std::map mProxies; + void GetRenderProxy(bgfx::FrameBufferHandle& currentFramebuffer, int16_t width, uint16_t height, bool depthBuffer); + + void SetKeyboardMouseInfos(EvaluationInfo& evaluationInfo, NodeIndex nodeIndex) const; + void SetUniforms(NodeIndex nodeIndex); }; struct Builder @@ -239,7 +313,6 @@ struct Builder namespace DrawUICallbacks { - void DrawUICubemap(EvaluationContext* context, size_t nodeIndex); - void DrawUISingle(EvaluationContext* context, size_t nodeIndex); - void DrawUIProgress(EvaluationContext* context, size_t nodeIndex); + void DrawUISingle(EvaluationContext* context, NodeIndex nodeIndex); + void DrawUIProgress(EvaluationContext* context, NodeIndex nodeIndex); } // namespace DrawUICallbacks \ No newline at end of file diff --git a/src/EvaluationStages.cpp b/src/EvaluationStages.cpp index ba2567b3..6fb471d9 100644 --- a/src/EvaluationStages.cpp +++ b/src/EvaluationStages.cpp @@ -31,177 +31,77 @@ #include #include - -EvaluationStages::EvaluationStages() : mFrameMin(0), mFrameMax(1) +EvaluationStages::EvaluationStages() { } -void EvaluationStages::AddSingleEvaluation(size_t nodeType) +void EvaluationStages::AddEvaluation(NodeIndex nodeIndex, size_t nodeType) { EvaluationStage evaluation; //#ifdef _DEBUG needed for fur evaluation.mTypename = gMetaNodes[nodeType].mName; //#endif - #if USE_FFMPEG +#if USE_FFMPEG evaluation.mDecoder = NULL; - #endif - evaluation.mUseCountByOthers = 0; - evaluation.mType = nodeType; - evaluation.mBlendingSrc = ONE; - evaluation.mBlendingDst = ZERO; +#endif + evaluation.mType = uint16_t(nodeType); evaluation.mLocalTime = 0; - evaluation.gEvaluationMask = gEvaluators.GetMask(nodeType); - evaluation.mbDepthBuffer = false; - evaluation.mbClearBuffer = false; - evaluation.mVertexSpace = 0; - static std::shared_ptr defaultScene; - if (!defaultScene) - { - defaultScene = std::make_shared(); - defaultScene->mMeshes.resize(1); - auto& mesh = defaultScene->mMeshes.back(); - mesh.mPrimitives.resize(1); - auto& prim = mesh.mPrimitives.back(); - static const float fsVts[] = {0.f, 0.f, 2.f, 0.f, 0.f, 2.f}; - prim.AddBuffer(fsVts, Scene::Mesh::Format::UV, 2 * sizeof(float), 3); - // add node and transform - defaultScene->mWorldTransforms.resize(1); - defaultScene->mWorldTransforms[0].Identity(); - defaultScene->mMeshIndex.resize(1, 0); - } evaluation.mScene = nullptr; - evaluation.mGScene = defaultScene; + evaluation.mGScene = Scene::BuildDefaultScene(); evaluation.renderer = nullptr; - evaluation.mRuntimeUniqueId = GetRuntimeId(); const size_t inputCount = gMetaNodes[nodeType].mInputs.size(); - evaluation.mInputSamplers.resize(inputCount); - evaluation.mStartFrame = mFrameMin; - evaluation.mEndFrame = mFrameMax; - - InitDefaultParameters(evaluation); - mStages.push_back(evaluation); - mPinnedIO.push_back(0); + + mParameterBlocks.insert(mParameterBlocks.begin() + nodeIndex, ParameterBlock(nodeType)); + mStages.insert(mStages.begin() + nodeIndex, evaluation); + mInputSamplers.insert(mInputSamplers.begin() + nodeIndex, InputSamplers()); + mInputSamplers[nodeIndex].resize(gMetaNodes[nodeType].mInputs.size()); + mInputs.insert(mInputs.begin() + nodeIndex, Input()); + mMultiplex.insert(mMultiplex.begin() + nodeIndex, MultiplexArray()); } -void EvaluationStages::StageIsAdded(int index) +void EvaluationStages::DelEvaluation(NodeIndex nodeIndex) { - for (size_t i = 0; i < mStages.size(); i++) - { - if (i == index) - continue; - auto& evaluation = mStages[i]; - for (auto& inp : evaluation.mInput.mInputs) - { - if (inp >= index) - inp++; - } - } + mStages.erase(mStages.begin() + nodeIndex); + mInputs.erase(mInputs.begin() + nodeIndex); + mInputSamplers.erase(mInputSamplers.begin() + nodeIndex); + mParameterBlocks.erase(mParameterBlocks.begin() + nodeIndex); + mMultiplex.erase(mMultiplex.begin() + nodeIndex); } -void EvaluationStages::StageIsDeleted(int index) +void EvaluationStages::SetParameterBlock(NodeIndex nodeIndex, const ParameterBlock& parameters) { - EvaluationStage& ev = mStages[index]; - - // shift all connections - for (auto& evaluation : mStages) - { - for (auto& inp : evaluation.mInput.mInputs) - { - if (inp >= index) - inp--; - } - } -} - -void EvaluationStages::UserAddEvaluation(size_t nodeType) -{ - URAdd undoRedoAddStage(int(mStages.size()), - [&]() { return &mStages; }, - [&](int index) { StageIsDeleted(index); }, - [&](int index) { StageIsAdded(index); }); - - AddSingleEvaluation(nodeType); -} - -void EvaluationStages::UserDeleteEvaluation(size_t target) -{ - URDel undoRedoDelStage(int(target), - [&]() { return &mStages; }, - [&](int index) { StageIsDeleted(index); }, - [&](int index) { StageIsAdded(index); }); - - StageIsDeleted(int(target)); - mStages.erase(mStages.begin() + target); -} - -void EvaluationStages::SetEvaluationParameters(size_t target, const std::vector& parameters) -{ - EvaluationStage& stage = mStages[target]; - stage.mParameters = parameters; + EvaluationStage& stage = mStages[nodeIndex]; + mParameterBlocks[nodeIndex] = parameters; #if USE_FFMPEG if (stage.mDecoder) + { stage.mDecoder = NULL; + } #endif } -void EvaluationStages::SetEvaluationSampler(size_t target, const std::vector& inputSamplers) -{ - mStages[target].mInputSamplers = inputSamplers; -} - -void EvaluationStages::AddEvaluationInput(size_t target, int slot, int source) -{ - if (mStages.size() <= target || mStages[target].mInput.mInputs[slot] == source) - return; - mStages[target].mInput.mInputs[slot] = source; - mStages[source].mUseCountByOthers++; -} - -void EvaluationStages::DelEvaluationInput(size_t target, int slot) -{ - mStages[mStages[target].mInput.mInputs[slot]].mUseCountByOthers--; - mStages[target].mInput.mInputs[slot] = -1; -} - -void EvaluationStages::SetEvaluationOrder(const std::vector nodeOrderList) -{ - mEvaluationOrderList = nodeOrderList; -} - void EvaluationStages::Clear() { mStages.clear(); - mEvaluationOrderList.clear(); - mAnimTrack.clear(); + mInputs.clear(); + mInputSamplers.clear(); + mParameterBlocks.clear(); + if (mAnimationTracks) + { + mAnimationTracks->clear(); + } + mOrderList.clear(); } -void EvaluationStages::SetKeyboardMouse( - int target, float rx, float ry, bool lButDown, bool rButDown, bool bCtrl, bool bAlt, bool bShift) +void EvaluationStages::SetMaterialUniqueId(RuntimeId runtimeId) { - for (auto& ev : mStages) - { - ev.mRx = -9999.f; - ev.mRy = -9999.f; - ev.mLButDown = false; - ev.mRButDown = false; - ev.mbCtrl = false; - ev.mbAlt = false; - ev.mbShift = false; - } - auto& ev = mStages[target]; - ev.mRx = rx; - ev.mRy = 1.f - ry; // inverted for UI - ev.mLButDown = lButDown; - ev.mRButDown = rButDown; - ev.mbCtrl = bCtrl; - ev.mbAlt = bAlt; - ev.mbShift = bShift; + mMaterialUniqueId = runtimeId; } -size_t EvaluationStages::GetEvaluationImageDuration(size_t target) +size_t EvaluationStages::GetEvaluationImageDuration(NodeIndex nodeIndex) { - #if USE_FFMPEG - auto& stage = mStages[target]; +#if USE_FFMPEG + auto& stage = mStages[nodeIndex]; if (!stage.mDecoder) return 1; if (stage.mDecoder->mFrameCount > 2000) @@ -209,28 +109,28 @@ size_t EvaluationStages::GetEvaluationImageDuration(size_t target) int a = 1; } return stage.mDecoder->mFrameCount; - #else +#else return 1; - #endif +#endif } void EvaluationStages::SetStageLocalTime(EvaluationContext* evaluationContext, - size_t target, + NodeIndex nodeIndex, int localTime, bool updateDecoder) { - auto& stage = mStages[target]; - int newLocalTime = ImMin(localTime, int(GetEvaluationImageDuration(target))); - #if USE_FFMPEG + auto& stage = mStages[nodeIndex]; + int newLocalTime = ImMin(localTime, int(GetEvaluationImageDuration(nodeIndex))); +#if USE_FFMPEG if (stage.mDecoder && updateDecoder && stage.mLocalTime != newLocalTime) { stage.mLocalTime = newLocalTime; Image image = stage.DecodeImage(); - EvaluationAPI::SetEvaluationImage(evaluationContext, int(target), &image); + EvaluationAPI::SetEvaluationImage(evaluationContext, nodeIndex, &image); Image::Free(&image); } else - #endif +#endif { stage.mLocalTime = newLocalTime; } @@ -241,80 +141,15 @@ FFMPEGCodec::Decoder* EvaluationStages::FindDecoder(const std::string& filename) for (auto& evaluation : mStages) { if (evaluation.mDecoder && evaluation.mDecoder->GetFilename() == filename) + { return evaluation.mDecoder.get(); + } } auto decoder = new FFMPEGCodec::Decoder; decoder->Open(filename); return decoder; } #endif -Camera* EvaluationStages::GetCameraParameter(size_t index) -{ - if (index >= mStages.size()) - return NULL; - EvaluationStage& stage = mStages[index]; - const MetaNode* metaNodes = gMetaNodes.data(); - const MetaNode& currentMeta = metaNodes[stage.mType]; - const size_t paramsSize = ComputeNodeParametersSize(stage.mType); - stage.mParameters.resize(paramsSize); - unsigned char* paramBuffer = stage.mParameters.data(); - for (const MetaParameter& param : currentMeta.mParams) - { - if (param.mType == Con_Camera) - { - Camera* cam = (Camera*)paramBuffer; - return cam; - } - paramBuffer += GetParameterTypeSize(param.mType); - } - - return NULL; -} -// TODO : create parameter struct with templated accessors -int EvaluationStages::GetIntParameter(size_t index, const char* parameterName, int defaultValue) -{ - if (index >= mStages.size()) - return NULL; - EvaluationStage& stage = mStages[index]; - const MetaNode* metaNodes = gMetaNodes.data(); - const MetaNode& currentMeta = metaNodes[stage.mType]; - const size_t paramsSize = ComputeNodeParametersSize(stage.mType); - stage.mParameters.resize(paramsSize); - unsigned char* paramBuffer = stage.mParameters.data(); - for (const MetaParameter& param : currentMeta.mParams) - { - if (param.mType == Con_Int) - { - if (!strcmp(param.mName.c_str(), parameterName)) - { - int* value = (int*)paramBuffer; - return *value; - } - } - paramBuffer += GetParameterTypeSize(param.mType); - } - return defaultValue; -} - -void EvaluationStages::InitDefaultParameters(EvaluationStage& stage) -{ - const MetaNode* metaNodes = gMetaNodes.data(); - const MetaNode& currentMeta = metaNodes[stage.mType]; - const size_t paramsSize = ComputeNodeParametersSize(stage.mType); - stage.mParameters.resize(paramsSize); - unsigned char* paramBuffer = stage.mParameters.data(); - memset(paramBuffer, 0, paramsSize); - int i = 0; - for (const MetaParameter& param : currentMeta.mParams) - { - if (!param.mDefaultValue.empty()) - { - memcpy(paramBuffer, param.mDefaultValue.data(), param.mDefaultValue.size()); - } - - paramBuffer += GetParameterTypeSize(param.mType); - } -} #if USE_FFMPEG Image EvaluationStage::DecodeImage() @@ -322,23 +157,26 @@ Image EvaluationStage::DecodeImage() return Image::DecodeImage(mDecoder.get(), mLocalTime); } #endif -void EvaluationStages::ApplyAnimationForNode(EvaluationContext* context, size_t nodeIndex, int frame) + +void EvaluationStages::ApplyAnimationForNode(EvaluationContext* context, NodeIndex nodeIndex, int frame) { bool animatedNodes = false; EvaluationStage& stage = mStages[nodeIndex]; - for (auto& animTrack : mAnimTrack) + ParameterBlock parameterBlock = mParameterBlocks[nodeIndex]; + if (mAnimationTracks) { - if (animTrack.mNodeIndex == nodeIndex) + for (auto& animTrack : *mAnimationTracks) { - size_t parameterOffset = GetParameterOffset(uint32_t(stage.mType), animTrack.mParamIndex); - animTrack.mAnimation->GetValue(frame, &stage.mParameters[parameterOffset]); - - animatedNodes = true; + if (animTrack.mNodeIndex == nodeIndex) + { + animTrack.mAnimation->GetValue(frame, parameterBlock.Data(animTrack.mParamIndex)); + animatedNodes = true; + } } } if (animatedNodes) { - SetEvaluationParameters(nodeIndex, stage.mParameters); + SetParameterBlock(nodeIndex, parameterBlock); context->SetTargetDirty(nodeIndex, Dirty::Parameter); } } @@ -347,114 +185,24 @@ void EvaluationStages::ApplyAnimation(EvaluationContext* context, int frame) { std::vector animatedNodes; animatedNodes.resize(mStages.size(), false); - for (auto& animTrack : mAnimTrack) + if (mAnimationTracks) { - EvaluationStage& stage = mStages[animTrack.mNodeIndex]; - - animatedNodes[animTrack.mNodeIndex] = true; - size_t parameterOffset = GetParameterOffset(uint32_t(stage.mType), animTrack.mParamIndex); - animTrack.mAnimation->GetValue(frame, &stage.mParameters[parameterOffset]); + for (auto& animTrack : *mAnimationTracks) + { + EvaluationStage& stage = mStages[animTrack.mNodeIndex]; + animatedNodes[animTrack.mNodeIndex] = true; + animTrack.mAnimation->GetValue(frame, mParameterBlocks[animTrack.mNodeIndex].Data(animTrack.mParamIndex)); + } } for (size_t i = 0; i < animatedNodes.size(); i++) { if (!animatedNodes[i]) continue; - SetEvaluationParameters(i, mStages[i].mParameters); + SetParameterBlock(i, mParameterBlocks[i]); context->SetTargetDirty(i, Dirty::Parameter); } } -void EvaluationStages::RemoveAnimation(size_t nodeIndex) -{ - if (mAnimTrack.empty()) - return; - std::vector tracks; - for (int i = 0; i < int(mAnimTrack.size()); i++) - { - const AnimTrack& animTrack = mAnimTrack[i]; - if (animTrack.mNodeIndex == nodeIndex) - tracks.push_back(i); - } - if (tracks.empty()) - return; - - for (int i = 0; i < int(tracks.size()); i++) - { - int index = tracks[i] - i; - URDel urDel(index, [&] { return &mAnimTrack; }); - mAnimTrack.erase(mAnimTrack.begin() + index); - } -} - -void EvaluationStages::RemovePins(size_t nodeIndex) -{ - auto iter = mPinnedParameters.begin(); - for (; iter != mPinnedParameters.end();) - { - uint32_t pin = *iter; - if (((pin >> 16) & 0xFFFF) == nodeIndex) - { - URDel undoRedoDelPin(int(&(*iter) - mPinnedParameters.data()), - [&]() { return &mPinnedParameters; }); - iter = mPinnedParameters.erase(iter); - } - else - ++iter; - } - - URDel undoRedoDelPinIO(int(nodeIndex), [&]() { return &mPinnedIO; }); - iter = mPinnedIO.erase(mPinnedIO.begin() + nodeIndex); -} - -float EvaluationStages::GetParameterComponentValue(size_t index, int parameterIndex, int componentIndex) -{ - EvaluationStage& stage = mStages[index]; - size_t paramOffset = GetParameterOffset(uint32_t(stage.mType), parameterIndex); - unsigned char* ptr = &stage.mParameters.data()[paramOffset]; - const MetaNode* metaNodes = gMetaNodes.data(); - const MetaNode& currentMeta = metaNodes[stage.mType]; - switch (currentMeta.mParams[parameterIndex].mType) - { - case Con_Angle: - case Con_Float: - return ((float*)ptr)[componentIndex]; - case Con_Angle2: - case Con_Float2: - return ((float*)ptr)[componentIndex]; - case Con_Angle3: - case Con_Float3: - return ((float*)ptr)[componentIndex]; - case Con_Angle4: - case Con_Color4: - case Con_Float4: - return ((float*)ptr)[componentIndex]; - case Con_Ramp: - return 0; - case Con_Ramp4: - return 0; - case Con_Enum: - case Con_Int: - return float(((int*)ptr)[componentIndex]); - case Con_Int2: - return float(((int*)ptr)[componentIndex]); - case Con_FilenameRead: - case Con_FilenameWrite: - return 0; - case Con_ForceEvaluate: - return 0; - case Con_Bool: - return float(((bool*)ptr)[componentIndex]); - case Con_Camera: - return float((*(Camera*)ptr)[componentIndex]); - } - return 0.f; -} - -void EvaluationStages::SetAnimTrack(const std::vector& animTrack) -{ - mAnimTrack = animTrack; -} - void EvaluationStages::SetTime(EvaluationContext* evaluationContext, int time, bool updateDecoder) { for (size_t i = 0; i < mStages.size(); i++) @@ -469,138 +217,100 @@ void EvaluationStages::SetTime(EvaluationContext* evaluationContext, int time, b } } -bool EvaluationStages::IsIOPinned(size_t nodeIndex, size_t io, bool forOutput) const +void EvaluationStages::BuildEvaluationFromMaterial(Material& material) { - if (nodeIndex >= mPinnedIO.size()) - { - return false; - } - uint32_t mask = 0; - if (forOutput) - { - mask = (1 << io) & 0xFF; - } - else - { - mask = (1 << (8 + io)); - } - return mPinnedIO[nodeIndex] & mask; -} + mStages.clear(); + mInputs.clear(); + mInputSamplers.clear(); + mParameterBlocks.clear(); -void EvaluationStages::SetIOPin(size_t nodeIndex, size_t io, bool forOutput, bool pinned) -{ - uint32_t mask = 0; - if (forOutput) + auto nodeCount = material.mMaterialNodes.size(); + mStages.reserve(nodeCount); + mInputs.reserve(nodeCount); + mInputSamplers.reserve(nodeCount); + mParameterBlocks.reserve(nodeCount); + + for (size_t i = 0; i < nodeCount; i++) { - mask = (1 << io) & 0xFF; + MaterialNode& node = material.mMaterialNodes[i]; + AddEvaluation(i, node.mNodeType); + auto& lastNode = mStages.back(); + mParameterBlocks[i] = ParameterBlock(node.mNodeType, node.mParameters); + //mInputSamplers[i] = node.mInputSamplers; } - else + for (size_t i = 0; i < material.mMaterialConnections.size(); i++) { - mask = (1 << (8 + io)); + MaterialConnection& materialConnection = material.mMaterialConnections[i]; + //SetEvaluationInput( + // materialConnection.mOutputNodeIndex, materialConnection.mInputSlotIndex, materialConnection.mInputNodeIndex); } - mPinnedIO[nodeIndex] &= ~mask; - mPinnedIO[nodeIndex] += pinned ? mask : 0; + ComputeEvaluationOrder(); + mMaterialUniqueId = material.mRuntimeUniqueId; + //SetAnimTrack(material.mAnimTrack); + mAnimationTracks = std::make_shared(material.mAnimTrack); } -/////////////////////////////////////////////////////////////////////////////////////// +size_t EvaluationStages::PickBestNode(const std::vector& orders) const +{ + for (auto& order : orders) + { + if (order.mNodePriority == 0) + return order.mNodeIndex; + } + // issue! + assert(0); + return -1; +} -void Scene::Mesh::Primitive::Draw() const +void EvaluationStages::RecurseSetPriority(std::vector& orders, + size_t currentIndex, + size_t currentPriority, + size_t& undeterminedNodeCount) const { - unsigned int vao; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); + if (!orders[currentIndex].mNodePriority) + undeterminedNodeCount--; - for (auto& buffer : mBuffers) + orders[currentIndex].mNodePriority = std::max(orders[currentIndex].mNodePriority, currentPriority + 1); + for (auto input : mInputs[currentIndex].mInputs) { - glBindBuffer(GL_ARRAY_BUFFER, buffer.id); - switch (buffer.format) + if (!input.IsValid()) { - case Format::UV: - glVertexAttribPointer(SemUV0, 2, GL_FLOAT, GL_FALSE, 8, 0); - glEnableVertexAttribArray(SemUV0); - break; - case Format::COL: - glVertexAttribPointer(SemUV0 + 1, 4, GL_FLOAT, GL_FALSE, 16, 0); - glEnableVertexAttribArray(SemUV0 + 1); - break; - case Format::POS: - glVertexAttribPointer(SemUV0 + 2, 3, GL_FLOAT, GL_FALSE, 12, 0); - glEnableVertexAttribArray(SemUV0 + 2); - break; - case Format::NORM: - glVertexAttribPointer(SemUV0 + 3, 3, GL_FLOAT, GL_FALSE, 12, 0); - glEnableVertexAttribArray(SemUV0 + 3); - break; + continue; } - } - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glBindVertexArray(vao); - - if (!mIndexBuffer.id) - { - glDrawArrays(GL_TRIANGLES, 0, mBuffers[0].count); - } - else - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer.id); - glDrawElements(GL_TRIANGLES, - mIndexBuffer.count, - (mIndexBuffer.stride == 4) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, - (void*)0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + RecurseSetPriority(orders, input, currentPriority + 1, undeterminedNodeCount); } - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - glDeleteVertexArrays(1, &vao); -} -void Scene::Mesh::Primitive::AddBuffer(const void* data, unsigned int format, unsigned int stride, unsigned int count) -{ - unsigned int va; - glGenBuffers(1, &va); - glBindBuffer(GL_ARRAY_BUFFER, va); - glBufferData(GL_ARRAY_BUFFER, stride * count, data, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - mBuffers.push_back({va, format, stride, count}); } -void Scene::Mesh::Primitive::AddIndexBuffer(const void* data, unsigned int stride, unsigned int count) +std::vector EvaluationStages::ComputeEvaluationOrders() { - unsigned int ia; - glGenBuffers(1, &ia); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ia); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, stride * count, data, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - mIndexBuffer = {ia, stride, count}; -} -void Scene::Mesh::Draw() const -{ - for (auto& prim : mPrimitives) + size_t nodeCount = mStages.size(); + + std::vector orders(nodeCount); + for (size_t i = 0; i < nodeCount; i++) { - prim.Draw(); + orders[i].mNodeIndex = i; + orders[i].mNodePriority = 0; } + size_t undeterminedNodeCount = nodeCount; + while (undeterminedNodeCount) + { + size_t currentIndex = PickBestNode(orders); + RecurseSetPriority(orders, currentIndex, orders[currentIndex].mNodePriority, undeterminedNodeCount); + }; + // + return orders; } -void Scene::Draw(EvaluationContext *context, EvaluationInfo& evaluationInfo) const + +void EvaluationStages::ComputeEvaluationOrder() { - for (unsigned int i = 0; i < mMeshIndex.size(); i++) + mOrderList.clear(); + + auto orders = ComputeEvaluationOrders(); + std::sort(orders.begin(), orders.end()); + mOrderList.resize(orders.size()); + for (size_t i = 0; i < orders.size(); i++) { - int index = mMeshIndex[i]; - if (index == -1) - continue; - glBindBuffer(GL_UNIFORM_BUFFER, context->mEvaluationStateGLSLBuffer); - memcpy(evaluationInfo.model, mWorldTransforms[i], sizeof(Mat4x4)); - FPU_MatrixF_x_MatrixF(evaluationInfo.model, evaluationInfo.viewProjection, evaluationInfo.modelViewProjection); - glBufferData(GL_UNIFORM_BUFFER, sizeof(EvaluationInfo), &evaluationInfo, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - mMeshes[index].Draw(); + mOrderList[i] = orders[i].mNodeIndex; } } - -Scene::~Scene() -{ - // todo : clear ia/va -} \ No newline at end of file diff --git a/src/EvaluationStages.h b/src/EvaluationStages.h index ec749af3..d9bd877e 100644 --- a/src/EvaluationStages.h +++ b/src/EvaluationStages.h @@ -22,8 +22,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // - #pragma once + #include #include #include @@ -34,92 +34,53 @@ #include #include "Utils.h" #include "Bitmap.h" +#include "Scene.h" +#include "Types.h" +#include "ParameterBlock.h" + struct ImDrawList; struct ImDrawCmd; struct EvaluationContext; struct EvaluationInfo; -enum BlendOp +struct Dirty { - ZERO, - ONE, - SRC_COLOR, - ONE_MINUS_SRC_COLOR, - DST_COLOR, - ONE_MINUS_DST_COLOR, - SRC_ALPHA, - ONE_MINUS_SRC_ALPHA, - DST_ALPHA, - ONE_MINUS_DST_ALPHA, - CONSTANT_COLOR, - ONE_MINUS_CONSTANT_COLOR, - CONSTANT_ALPHA, - ONE_MINUS_CONSTANT_ALPHA, - SRC_ALPHA_SATURATE, - BLEND_LAST + enum Type + { + Input = 1 << 0, + Parameter = 1 << 1, + Mouse = 1 << 2, + Camera = 1 << 3, + Time = 1 << 4, + Sampler = 1 << 5, + AddedNode = 1 << 6, + DeletedNode = 1 << 7, + StartEndTime = 1 << 8, + RugChanged = 1 << 9, + VisualGraph = 1 << 10, // node selection, node position + }; }; - -struct Input +struct DirtyList { - Input() - { - memset(mInputs, -1, sizeof(int) * 8); - memset(mOverrideInputs, -1, sizeof(int) * 8); - } - int mInputs[8]; - int mOverrideInputs[8]; + NodeIndex mNodeIndex; + SlotIndex mSlotIndex; + Dirty::Type mFlags; }; - -struct Scene +struct Input { - Scene() + Input() { + for (auto i = 0; i < 8 ; i++) + { + mInputs[i] = { InvalidNodeIndex }; + mOverrideInputs[i] = { InvalidNodeIndex }; + } } - virtual ~Scene(); - struct Mesh - { - struct Format - { - enum - { - POS = 1 << 0, - NORM = 1 << 1, - COL = 1 << 2, - UV = 1 << 3, - }; - }; - struct Buffer - { - unsigned int id; - unsigned int format; - unsigned int stride; - unsigned int count; - }; - struct IndexBuffer - { - unsigned int id; - unsigned int stride; - unsigned int count; - }; - struct Primitive - { - std::vector mBuffers; - IndexBuffer mIndexBuffer = {0, 0, 0}; - void AddBuffer(const void* data, unsigned int format, unsigned int stride, unsigned int count); - void AddIndexBuffer(const void* data, unsigned int stride, unsigned int count); - void Draw() const; - }; - std::vector mPrimitives; - void Draw() const; - }; - std::vector mMeshes; - std::vector mWorldTransforms; - std::vector mMeshIndex; - std::string mName; - void Draw(EvaluationContext* context, EvaluationInfo& evaluationInfo) const; + NodeIndex mInputs[8]; + NodeIndex mOverrideInputs[8]; }; struct EvaluationStage @@ -130,30 +91,13 @@ struct EvaluationStage #if USE_FFMPEG std::shared_ptr mDecoder; #endif - size_t mType; - unsigned int mRuntimeUniqueId; - std::vector mParameters; - Input mInput; - std::vector mInputSamplers; - int gEvaluationMask; // see EvaluationMask - int mUseCountByOthers; - int mBlendingSrc; - int mBlendingDst; - int mLocalTime; + uint16_t mType; + RuntimeId mRuntimeUniqueId; + int mStartFrame, mEndFrame; - int mVertexSpace; // UV, worldspace - bool mbDepthBuffer; - bool mbClearBuffer; + // Camera Mat4x4 mParameterViewMatrix = Mat4x4::GetIdentity(); - // mouse - float mRx; - float mRy; - uint8_t mLButDown : 1; - uint8_t mRButDown : 1; - uint8_t mbCtrl : 1; - uint8_t mbAlt : 1; - uint8_t mbShift : 1; // scene render void* mScene; // for path tracer @@ -161,115 +105,78 @@ struct EvaluationStage void* renderer; Image DecodeImage(); - bool operator!=(const EvaluationStage& other) const - { - if (mType != other.mType) - return true; - if (mParameters != other.mParameters) - return true; - if (mRuntimeUniqueId != other.mRuntimeUniqueId) - return true; - if (mStartFrame != other.mStartFrame) - return true; - if (mEndFrame != other.mEndFrame) - return true; - if (mInputSamplers.size() != other.mInputSamplers.size()) - return true; - /* - for (size_t i = 0; i < mInputSamplers.size(); i++) - { - if (mInputSamplers[i] != other.mInputSamplers[i]) - return true; - } - */ - if (mParameterViewMatrix != other.mParameterViewMatrix) - return true; - return false; - } + int mLocalTime; +}; + +struct MultiplexArray +{ + std::vector mMultiplexPerInputs[8]; }; // simple API struct EvaluationStages { EvaluationStages(); + void BuildEvaluationFromMaterial(Material& material); - void AddSingleEvaluation(size_t nodeType); - void UserAddEvaluation(size_t nodeType); - void UserDeleteEvaluation(size_t target); + void AddEvaluation(NodeIndex nodeIndex, size_t nodeType); + void DelEvaluation(NodeIndex nodeIndex); - // - size_t GetStagesCount() const - { - return mStages.size(); - } - size_t GetStageType(size_t target) const - { - return mStages[target].mType; - } - size_t GetEvaluationImageDuration(size_t target); - - void SetEvaluationParameters(size_t target, const std::vector& parameters); - void SetEvaluationSampler(size_t target, const std::vector& inputSamplers); - void AddEvaluationInput(size_t target, int slot, int source); - void DelEvaluationInput(size_t target, int slot); - void SetEvaluationOrder(const std::vector nodeOrderList); - void SetKeyboardMouse(int target, float rx, float ry, bool lButDown, bool rButDown, bool bCtrl, bool bAlt, bool bShift); - void SetStageLocalTime(EvaluationContext* evaluationContext, size_t target, int localTime, bool updateDecoder); void Clear(); + size_t GetEvaluationImageDuration(NodeIndex target); - const std::vector& GetForwardEvaluationOrder() const - { - return mEvaluationOrderList; - } - + void SetStageLocalTime(EvaluationContext* evaluationContext, NodeIndex nodeIndex, int localTime, bool updateDecoder); + void SetSamplers(NodeIndex nodeIndex, InputSamplers samplers) { mInputSamplers[nodeIndex] = samplers; } - const EvaluationStage& GetEvaluationStage(size_t index) const - { - return mStages[index]; - } - - - Camera* GetCameraParameter(size_t index); - int GetIntParameter(size_t index, const char* parameterName, int defaultValue); - Mat4x4* GetParameterViewMatrix(size_t index) - { - if (index >= mStages.size()) - return NULL; - return &mStages[index].mParameterViewMatrix; - } - float GetParameterComponentValue(size_t index, int parameterIndex, int componentIndex); + Mat4x4* GetParameterViewMatrix(NodeIndex nodeIndex) { return &mStages[nodeIndex].mParameterViewMatrix; } + const ParameterBlock& GetParameterBlock(NodeIndex nodeIndex) const { return mParameterBlocks[nodeIndex]; } + void SetParameterBlock(NodeIndex nodeIndex, const ParameterBlock& parameterBlock); + uint16_t GetNodeType(NodeIndex nodeIndex) const { return mStages[nodeIndex].mType; } + size_t GetStagesCount() const { return mStages.size(); } + void SetMaterialUniqueId(RuntimeId runtimeId); // animation - const std::vector& GetAnimTrack() const - { - return mAnimTrack; - } - void ApplyAnimationForNode(EvaluationContext* context, size_t nodeIndex, int frame); + void ApplyAnimationForNode(EvaluationContext* context, NodeIndex nodeIndex, int frame); void ApplyAnimation(EvaluationContext* context, int frame); - void RemoveAnimation(size_t nodeIndex); - void SetAnimTrack(const std::vector& animTrack); - void SetTime(EvaluationContext* evaluationContext, int time, bool updateDecoder); - // pins - void RemovePins(size_t nodeIndex); - bool IsIOPinned(size_t nodeIndex, size_t io, bool forOutput) const; - void SetIOPin(size_t nodeIndex, size_t io, bool forOutput, bool pinned); + void SetTime(EvaluationContext* evaluationContext, int time, bool updateDecoder); // ffmpeg encoders - #if USE_FFMPEG +#if USE_FFMPEG FFMPEGCodec::Decoder* FindDecoder(const std::string& filename); #endif // Data - std::vector mAnimTrack; + const std::vector& GetForwardEvaluationOrder() const { return mOrderList; } std::vector mStages; - std::vector mEvaluationOrderList; - std::vector mPinnedParameters; - std::vector mPinnedIO; // 24bits input, 8 bits output - int mFrameMin, mFrameMax; + std::vector mInputs; // merged with multiplexed + std::vector mDirectInputs; // without multiplexed + std::vector mMultiplex; // multiplex list per node + + std::vector mInputSamplers; + std::vector mParameterBlocks; + + std::shared_ptr mAnimationTracks; + RuntimeId mMaterialUniqueId; + + void ComputeEvaluationOrder(); + void SetStartEndFrame(NodeIndex nodeIndex, int startFrame, int endFrame) { mStages[nodeIndex].mStartFrame = startFrame; mStages[nodeIndex].mEndFrame = endFrame; } protected: - void StageIsAdded(int index); - void StageIsDeleted(int index); - void InitDefaultParameters(EvaluationStage& stage); + std::vector mOrderList; + + // evaluation order + struct NodeOrder + { + size_t mNodeIndex; + size_t mNodePriority; + bool operator<(const NodeOrder& other) const + { + return other.mNodePriority < mNodePriority; // reverse order compared to priority value: lower last + } + }; + + std::vector ComputeEvaluationOrders(); + void RecurseSetPriority(std::vector& orders, size_t currentIndex, size_t currentPriority, size_t& undeterminedNodeCount) const; + size_t PickBestNode(const std::vector& orders) const; }; diff --git a/src/Evaluators.cpp b/src/Evaluators.cpp index 2de5aca2..c51dbe28 100644 --- a/src/Evaluators.cpp +++ b/src/Evaluators.cpp @@ -35,12 +35,18 @@ #include "TiledRenderer.h" #include "ProgressiveRenderer.h" #include "GPUBVH.h" -#include "Camera.h" +#include "Cam.h" #include #define CGLTF_IMPLEMENTATION #include "cgltf.h" -#include "NodeGraphControler.h" - +#include "GraphControler.h" +#include +#include +#include +#ifndef __EMSCRIPTEN__ +#include +#include "EmbeddedShaders.cpp" +#endif Evaluators gEvaluators; extern TaskScheduler g_TS; @@ -51,55 +57,6 @@ struct EValuationFunction void* function; }; -static const EValuationFunction evaluationFunctions[] = { - {"Log", (void*)Log}, - {"log2", (void*)static_cast(log2)}, - {"ReadImage", (void*)EvaluationAPI::Read}, - {"WriteImage", (void*)EvaluationAPI::Write}, - {"GetEvaluationImage", (void*)EvaluationAPI::GetEvaluationImage}, - {"SetEvaluationImage", (void*)EvaluationAPI::SetEvaluationImage}, - {"SetEvaluationImageCube", (void*)EvaluationAPI::SetEvaluationImageCube}, - {"AllocateImage", (void*)EvaluationAPI::AllocateImage}, - {"FreeImage", (void*)Image::Free}, - {"SetThumbnailImage", (void*)EvaluationAPI::SetThumbnailImage}, - {"Evaluate", (void*)EvaluationAPI::Evaluate}, - {"SetBlendingMode", (void*)EvaluationAPI::SetBlendingMode}, - {"EnableDepthBuffer", (void*)EvaluationAPI::EnableDepthBuffer}, - {"EnableFrameClear", (void*)EvaluationAPI::EnableFrameClear}, - {"SetVertexSpace", (void*)EvaluationAPI::SetVertexSpace}, - - {"GetEvaluationSize", (void*)EvaluationAPI::GetEvaluationSize}, - {"SetEvaluationSize", (void*)EvaluationAPI::SetEvaluationSize}, - {"SetEvaluationCubeSize", (void*)EvaluationAPI::SetEvaluationCubeSize}, - {"AllocateComputeBuffer", (void*)EvaluationAPI::AllocateComputeBuffer}, - {"SetProcessing", (void*)EvaluationAPI::SetProcessing}, - {"Job", (void*)EvaluationAPI::Job}, - {"JobMain", (void*)EvaluationAPI::JobMain}, - {"memmove", (void*)memmove}, - {"strcpy", (void*)strcpy}, - {"strlen", (void*)strlen}, - {"fabsf", (void*)fabsf}, - {"strcmp", (void*)strcmp}, - {"LoadSVG", (void*)Image::LoadSVG}, - {"LoadScene", (void*)EvaluationAPI::LoadScene}, - {"SetEvaluationScene", (void*)EvaluationAPI::SetEvaluationScene}, - {"GetEvaluationScene", (void*)EvaluationAPI::GetEvaluationScene}, - {"SetEvaluationRTScene", (void*)EvaluationAPI::SetEvaluationRTScene}, - {"GetEvaluationRTScene", (void*)EvaluationAPI::GetEvaluationRTScene}, - {"GetEvaluationSceneName", (void*)EvaluationAPI::GetEvaluationSceneName}, - {"GetEvaluationRenderer", (void*)EvaluationAPI::GetEvaluationRenderer}, - {"OverrideInput", (void*)EvaluationAPI::OverrideInput}, - {"InitRenderer", (void*)EvaluationAPI::InitRenderer}, - {"UpdateRenderer", (void*)EvaluationAPI::UpdateRenderer}, - {"ReadGLTF", (void*)EvaluationAPI::ReadGLTF}, -}; - -static void libtccErrorFunc(void* opaque, const char* msg) -{ - Log(msg); - Log("\n"); -} - void LogPython(const std::string& str) { Log(str.c_str()); @@ -124,10 +81,8 @@ extern std::vector mHotkeys; void RenderImogenFrame(); -void NodeGraphLayout(); -void NodeGraphUpdateScrolling(); -void NodeGraphUpdateEvaluationOrder(NodeGraphControlerBase* delegate); - +void GraphEditorUpdateScrolling(GraphEditorDelegate* model); +const char* GetRendererType(); PYBIND11_EMBEDDED_MODULE(Imogen, m) { @@ -142,24 +97,188 @@ PYBIND11_EMBEDDED_MODULE(Imogen, m) m.def("SetSynchronousEvaluation", [](bool synchronous) { Imogen::instance->GetNodeGraphControler()->mEditingContext.SetSynchronous(synchronous); }); - m.def("NewGraph", [](const std::string& graphName) { Imogen::instance->NewMaterial(graphName); }); - m.def("AddNode", [](const std::string& nodeType) -> int { return Imogen::instance->AddNode(nodeType); }); + m.def("NewGraph", [](const std::string& graphName) + { + Imogen::instance->NewMaterial(graphName); + }); + m.def("GetRendererType", [](){ + return std::string(GetRendererType()); + }); + m.def("Build", []() + { + extern Builder* gBuilder; + auto controler = Imogen::instance->GetNodeGraphControler(); + controler->ApplyDirtyList(); + gBuilder->Add("Graph", controler->mEvaluationStages); + }); + m.def("AddNode", [](const std::string& nodeType) -> int { + return Imogen::instance->AddNode(nodeType); + }); + m.def("DelNode", [](int nodeIndex){ + Imogen::instance->DelNode(nodeIndex); + }); m.def("SetParameter", [](int nodeIndex, const std::string& paramName, const std::string& value) { - Imogen::instance->GetNodeGraphControler()->SetParameter(nodeIndex, paramName, value); + auto& model = Imogen::instance->GetNodeGraphControler()->mModel; + model.BeginTransaction(false); + model.SetParameter(nodeIndex, paramName, value); + model.EndTransaction(); }); + m.def("SetParameters", [](int nodeIndex, pybind11::dict& dict) { + Imogen::instance->GetNodeGraphControler()->mModel.BeginTransaction(false); + for (auto& kv : dict) + { + Imogen::instance->GetNodeGraphControler()->mModel.SetParameter(nodeIndex, kv.first.str(), kv.second.str()); + } + Imogen::instance->GetNodeGraphControler()->mModel.EndTransaction(); + }); + m.def("SetCameraLookAt", [](int nodeIndex, float eyeX, float eyeY, float eyeZ, float targetX, float targetY, float targetZ) { + auto& model = Imogen::instance->GetNodeGraphControler()->mModel; + model.BeginTransaction(false); + model.SetCameraLookAt(nodeIndex, Vec4(eyeX, eyeY, eyeZ, 0.f), Vec4(targetX, targetY, targetZ, 0.f)); + model.EndTransaction(); + }); m.def("Connect", [](int nodeSource, int slotSource, int nodeDestination, int slotDestination) { - // Imogen::instance->GetNodeGraphControler()->AddLink(nodeSource, slotSource, nodeDestination, slotDestination); - NodeGraphAddLink( - Imogen::instance->GetNodeGraphControler(), nodeSource, slotSource, nodeDestination, slotDestination); + auto& model = Imogen::instance->GetNodeGraphControler()->mModel; + model.BeginTransaction(false); + model.AddLink(nodeSource, slotSource, nodeDestination, slotDestination); + model.EndTransaction(); }); m.def("AutoLayout", []() { - NodeGraphUpdateEvaluationOrder(Imogen::instance->GetNodeGraphControler()); - NodeGraphLayout(); - NodeGraphUpdateScrolling(); + auto controler = Imogen::instance->GetNodeGraphControler(); + controler->ApplyDirtyList(); + controler->mModel.NodeGraphLayout(controler->mEvaluationStages.GetForwardEvaluationOrder()); + controler->ApplyDirtyList(); + GraphEditorUpdateScrolling(controler); }); m.def("DeleteGraph", []() { Imogen::instance->DeleteCurrentMaterial(); }); - - + // samplers + m.def("GetSamplers", [](int target) { + auto d = pybind11::list(); + const auto& model = Imogen::instance->GetNodeGraphControler()->mModel; + const auto& samplers = model.GetSamplers(target); + for (const auto& sampler : samplers) + { + auto s = pybind11::dict(); + s["wrapU"] = sampler.mWrapU; + s["wrapV"] = sampler.mWrapU; + s["filterMin"] = sampler.mFilterMin; + s["filterMag"] = sampler.mFilterMag; + d.append(s); + } + return d; + }); + m.def("SetSamplers", [](int target, int input, pybind11::dict& dict) { + auto& model = Imogen::instance->GetNodeGraphControler()->mModel; + const auto& samplers = model.GetSamplers(target); + if (input < 0 || input >= samplers.size()) + { + return; + } + model.BeginTransaction(false); + auto sampler = samplers[input]; + for (auto& kv : dict) + { + if (kv.first.str().operator std::string() == "wrapU") + { + sampler.mWrapU = atoi(kv.second.str().operator std::string().c_str()); + } + else if (kv.first.str().operator std::string() == "wrapV") + { + sampler.mWrapV = atoi(kv.second.str().operator std::string().c_str()); + } + else if (kv.first.str().operator std::string() == "filterMin") + { + sampler.mFilterMin = atoi(kv.second.str().operator std::string().c_str()); + } + else if (kv.first.str().operator std::string() == "filterMag") + { + sampler.mFilterMag = atoi(kv.second.str().operator std::string().c_str()); + } + } + model.SetSampler(target, input, sampler); + model.EndTransaction(); + }); + + m.def("GetMultiplexList", [](int target, int input) { + auto d = pybind11::list(); + const auto controler = Imogen::instance->GetNodeGraphControler(); + const auto& multiplex = controler->mEvaluationStages.mMultiplex; + if (target >= 0 && target < multiplex.size() && + input >= 0 && input < 8) + { + for (auto multiplexEntry : multiplex[target].mMultiplexPerInputs[input]) + { + d.append(int(multiplexEntry)); + } + } + return d; + }); + + m.def("SelectMultiplexIndex", [](int target, int input, int indexInList) { + const auto controler = Imogen::instance->GetNodeGraphControler(); + auto& model = controler->mModel; + const auto& multiplex = controler->mEvaluationStages.mMultiplex; + if (target >= 0 && target < multiplex.size() && + input >= 0 && input < 8) + { + const auto& multiplexInputs = multiplex[target].mMultiplexPerInputs[input]; + if (indexInList >= 0 && indexInList < multiplexInputs.size()) + { + model.BeginTransaction(false); + model.SetMultiplexed(target, input, int(multiplexInputs[indexInList])); + model.EndTransaction(); + } + } + }); + + m.def("SelectMultiplex", [](int target, int input, int multiplexInput) { + const auto controler = Imogen::instance->GetNodeGraphControler(); + auto& model = controler->mModel; + const auto& multiplex = controler->mEvaluationStages.mMultiplex; + if (target >= 0 && target < multiplex.size() && + input >= 0 && input < 8) + { + const auto& multiplexInputs = multiplex[target].mMultiplexPerInputs[input]; + if (std::find(multiplexInputs.begin(), multiplexInputs.end(), NodeIndex(multiplexInput)) != multiplexInputs.end()) + { + model.BeginTransaction(false); + model.SetMultiplexed(target, input, multiplexInput); + model.EndTransaction(); + } + } + }); + + m.def("GetSelectedMultiplex", [](int target, int input) { + const auto controler = Imogen::instance->GetNodeGraphControler(); + const auto& model = controler->mModel; + const auto nodes = model.GetNodes(); + if (target >= 0 && target < nodes.size() && + input >= 0 && input < 8) + { + NodeIndex nodeIndex = nodes[target].mMultiplexInput.mInputs[input]; + if (nodeIndex.IsValid()) + { + return int(nodeIndex); + } + } + return -1; + }); + + m.def("Disconnect", [](int target, int input) { + auto& model = Imogen::instance->GetNodeGraphControler()->mModel; + model.BeginTransaction(false); + model.DelLink(target, input); + model.EndTransaction(); + }); + m.def("NewLibrary", [](const std::string& directory, const std::string& name, bool addDefaultMaterial) { + return Imogen::instance->NewLibrary(directory, name, addDefaultMaterial); + }); + m.def("OpenLibrary", [](int libraryIndex, bool saveCurrent) { + Imogen::instance->OpenLibrary(libraryIndex, saveCurrent); + }); + m.def("CloseCurrentLibrary", []() { + Imogen::instance->CloseLibrary(); + }); m.def("GetMetaNodes", []() { auto d = pybind11::list(); @@ -190,7 +309,7 @@ PYBIND11_EMBEDDED_MODULE(Imogen, m) auto e = pybind11::list(); p["enum"] = e; - char *pch = strtok((char*)param.mEnumList.c_str(), "|"); + char* pch = strtok((char*)param.mEnumList.c_str(), "|"); while (pch != NULL) { e.append(std::string(pch)); @@ -231,14 +350,6 @@ PYBIND11_EMBEDDED_MODULE(Imogen, m) } return d; }); - graph.def("Build", [](PyGraph& pyGraph) { - extern Builder* gBuilder; - if (gBuilder) - { - Material* material = pyGraph.mGraph; - gBuilder->Add(material); - } - }); auto node = pybind11::class_(m, "Node"); node.def("GetType", [](PyNode& node) { std::string& s = node.mNode->mTypeName; @@ -249,20 +360,22 @@ PYBIND11_EMBEDDED_MODULE(Imogen, m) node.def("GetInputs", [](PyNode& node) { // auto d = pybind11::list(); - if (node.mNode->mType == 0xFFFFFFFF) + if (node.mNode->mNodeType == 0xFFFFFFFF) + { return d; + } - MetaNode& metaNode = gMetaNodes[node.mNode->mType]; + MetaNode& metaNode = gMetaNodes[node.mNode->mNodeType]; for (auto& con : node.mGraph->mMaterialConnections) { - if (con.mOutputNode == node.mNodeIndex) + if (con.mOutputNodeIndex == node.mNodeIndex) { auto e = pybind11::dict(); d.append(e); - e["nodeIndex"] = pybind11::int_(con.mInputNode); - e["name"] = metaNode.mInputs[con.mOutputSlot].mName; + e["nodeIndex"] = pybind11::int_(con.mInputNodeIndex); + e["name"] = metaNode.mInputs[con.mOutputSlotIndex].mName; } } return d; @@ -270,9 +383,11 @@ PYBIND11_EMBEDDED_MODULE(Imogen, m) node.def("GetParameters", [](PyNode& node) { // name, type, value auto d = pybind11::list(); - if (node.mNode->mType == 0xFFFFFFFF) + if (node.mNode->mNodeType == 0xFFFFFFFF) + { return d; - MetaNode& metaNode = gMetaNodes[node.mNode->mType]; + } + MetaNode& metaNode = gMetaNodes[node.mNode->mNodeType]; for (uint32_t index = 0; index < metaNode.mParams.size(); index++) { @@ -282,7 +397,7 @@ PYBIND11_EMBEDDED_MODULE(Imogen, m) e["name"] = param.mName; e["type"] = pybind11::int_(int(param.mType)); - size_t parameterOffset = GetParameterOffset(node.mNode->mType, index); + size_t parameterOffset = GetParameterOffset(node.mNode->mNodeType, index); if (parameterOffset >= node.mNode->mParameters.size()) { e["value"] = std::string(""); @@ -363,6 +478,15 @@ PYBIND11_EMBEDDED_MODULE(Imogen, m) } return d; }); + m.def("GetThumbnailImage", [](std::string& materialName) { + Image image; + Material* material = library.GetByName(materialName.c_str()); + if (material) + { + Image::ReadMem(material->mThumbnail.data(), material->mThumbnail.size(), &image); + } + return image; + }); m.def("RegisterPlugin", [](std::string& name, std::string command) { mRegisteredPlugins.push_back({name, command}); Log("Plugin registered : %s \n", name.c_str()); @@ -392,16 +516,14 @@ PYBIND11_EMBEDDED_MODULE(Imogen, m) return std::string(); }); m.def("Log", LogPython); - m.def("log2", static_cast(log2)); + m.def("log2", static_cast(log2f)); m.def("ReadImage", Image::Read); m.def("WriteImage", Image::Write); m.def("GetEvaluationImage", EvaluationAPI::GetEvaluationImage); m.def("SetEvaluationImage", EvaluationAPI::SetEvaluationImage); m.def("SetEvaluationImageCube", EvaluationAPI::SetEvaluationImageCube); - m.def("AllocateImage", EvaluationAPI::AllocateImage); m.def("FreeImage", Image::Free); m.def("SetThumbnailImage", EvaluationAPI::SetThumbnailImage); - m.def("Evaluate", EvaluationAPI::Evaluate); m.def("SetBlendingMode", EvaluationAPI::SetBlendingMode); m.def("GetEvaluationSize", EvaluationAPI::GetEvaluationSize); m.def("SetEvaluationSize", EvaluationAPI::SetEvaluationSize); @@ -463,176 +585,194 @@ PYBIND11_EMBEDDED_MODULE(Imogen, m) } #endif -std::string Evaluators::GetEvaluator(const std::string& filename) +Evaluators::Evaluators() { - return mEvaluatorScripts[filename].mText; } -void Evaluators::SetEvaluators(const std::vector& evaluatorfilenames) +Evaluators::~Evaluators() { - ClearEvaluators(); - - mEvaluatorPerNodeType.clear(); - mEvaluatorPerNodeType.resize(evaluatorfilenames.size(), Evaluator()); +} - // GLSL - for (auto& file : evaluatorfilenames) +bgfx::ShaderHandle LoadShader(const char* shaderName) +{ +#ifdef __EMSCRIPTEN__ + std::string filePath = std::string("Nodes/Shaders/") + shaderName + ".bin"; + auto buffer = ReadFile(filePath.c_str()); + if (buffer.size()) { - if (file.mEvaluatorType != EVALUATOR_GLSL && file.mEvaluatorType != EVALUATOR_GLSLCOMPUTE) - continue; - const std::string filename = file.mFilename; - - std::ifstream t(file.mDirectory + filename); - if (t.good()) - { - std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); - if (mEvaluatorScripts.find(filename) == mEvaluatorScripts.end()) - mEvaluatorScripts[filename] = EvaluatorScript(str); - else - mEvaluatorScripts[filename].mText = str; - } + auto shader = bgfx::createShader(bgfx::copy(buffer.data(), buffer.size())); + bgfx::frame(); + return shader; } - - // GLSL - std::string baseShader = mEvaluatorScripts["Shader.glsl"].mText; - for (auto& file : evaluatorfilenames) + else { - if (file.mEvaluatorType != EVALUATOR_GLSL) - continue; - const std::string filename = file.mFilename; - - if (filename == "Shader.glsl") - continue; - - EvaluatorScript& shader = mEvaluatorScripts[filename]; - std::string shaderText = ReplaceAll(baseShader, "__NODE__", shader.mText); - std::string nodeName = ReplaceAll(filename, ".glsl", ""); - shaderText = ReplaceAll(shaderText, "__FUNCTION__", nodeName + "()"); - - unsigned int program = LoadShader(shaderText, filename.c_str()); - int parameterBlockIndex = glGetUniformBlockIndex(program, (nodeName + "Block").c_str()); - if (parameterBlockIndex != -1) - glUniformBlockBinding(program, parameterBlockIndex, 1); - - parameterBlockIndex = glGetUniformBlockIndex(program, "EvaluationBlock"); - if (parameterBlockIndex != -1) - glUniformBlockBinding(program, parameterBlockIndex, 2); - - shader.mProgram = program; - if (shader.mType != -1) - mEvaluatorPerNodeType[shader.mType].mGLSLProgram = program; + return {bgfx::kInvalidHandle}; } +#else + const bgfx::RendererType::Enum type = bgfx::getRendererType(); + return bgfx::createEmbeddedShader(s_embeddedShaders, type, shaderName); +#endif +} - - TagTime("GLSL init"); - - // GLSL compute - for (auto& file : evaluatorfilenames) +void Evaluators::SetEvaluators() +{ + Clear(); + + bgfx::ShaderHandle nodeVSShader = LoadShader("Node_vs"); + mShaderHandles.push_back(nodeVSShader); + + // default shaders + mBlitProgram = bgfx::createProgram(nodeVSShader, LoadShader("Blit_fs"), false); + mProgressProgram = bgfx::createProgram(nodeVSShader, LoadShader("ProgressingNode_fs"), false); + mDisplayCubemapProgram = bgfx::createProgram(nodeVSShader, LoadShader("DisplayCubemap_fs"), false); + + // evaluation uniforms + u_viewRot = bgfx::createUniform("u_viewRot", bgfx::UniformType::Mat4, 1); + u_viewProjection = bgfx::createUniform("u_viewProjection", bgfx::UniformType::Mat4, 1); + u_viewInverse = bgfx::createUniform("u_viewInverse", bgfx::UniformType::Mat4, 1); + u_world = bgfx::createUniform("u_world", bgfx::UniformType::Mat4, 1); + u_worldViewProjection = bgfx::createUniform("u_worldViewProjection", bgfx::UniformType::Mat4, 1); + u_mouse = bgfx::createUniform("u_mouse", bgfx::UniformType::Vec4, 1); + u_keyModifier = bgfx::createUniform("u_keyModifier", bgfx::UniformType::Vec4, 1); + u_inputIndices = bgfx::createUniform("u_inputIndices", bgfx::UniformType::Vec4, 2); + u_target = bgfx::createUniform("u_target", bgfx::UniformType::Vec4, 1); + u_pass = bgfx::createUniform("u_pass", bgfx::UniformType::Vec4, 1); + u_viewport = bgfx::createUniform("u_viewport", bgfx::UniformType::Vec4, 1); + u_textureSize = bgfx::createUniform("u_textureSize", bgfx::UniformType::Vec4, 8); + + // specific uniforms + u_time = bgfx::createUniform("u_time", bgfx::UniformType::Vec4, 1); + u_uvTransform = bgfx::createUniform("u_uvTransform", bgfx::UniformType::Vec4, 1); + + // default samplers + for (int i = 0;i<8;i++) { - if (file.mEvaluatorType != EVALUATOR_GLSLCOMPUTE) - continue; - const std::string filename = file.mFilename; + char tmps[512]; + sprintf(tmps,"Sampler%d", i); + bgfx::UniformHandle sampler2D = bgfx::createUniform(tmps, bgfx::UniformType::Sampler, 1); + sprintf(tmps, "CubeSampler%d", i); + bgfx::UniformHandle samplerCube = bgfx::createUniform(tmps, bgfx::UniformType::Sampler, 1); + mSamplers2D.push_back(sampler2D); + mSamplersCube.push_back(samplerCube); + } + + mEvaluatorPerNodeType.clear(); + mEvaluatorPerNodeType.resize(gMetaNodes.size(), nullptr); - EvaluatorScript& shader = mEvaluatorScripts[filename]; - // std::string shaderText = ReplaceAll(baseShader, "__NODE__", shader.mText); - std::string nodeName = ReplaceAll(filename, ".glslc", ""); - // shaderText = ReplaceAll(shaderText, "__FUNCTION__", nodeName + "()"); + extern std::map nodeFunctions; - unsigned int program = 0; - if (nodeName == filename) + for (int i = 0; i < gMetaNodes.size(); i++) + { + int mask = 0; + const std::string& nodeName = gMetaNodes[i].mName; + std::string vsShaderName = nodeName + "_vs"; + std::string fsShaderName = nodeName + "_fs"; + + bgfx::ShaderHandle vsShader = LoadShader(vsShaderName.c_str()); + bgfx::ShaderHandle fsShader = LoadShader(fsShaderName.c_str()); +#ifndef __EMSCRIPTEN__ + std::string csShaderName = nodeName + "_cs"; + bgfx::ShaderHandle csShader = LoadShader(csShaderName.c_str()); +#endif + bgfx::ProgramHandle program{bgfx::kInvalidHandle}; + if (vsShader.idx != bgfx::kInvalidHandle && fsShader.idx != bgfx::kInvalidHandle) { - // glsl in compute directory - nodeName = ReplaceAll(filename, ".glsl", ""); - program = LoadShader(shader.mText, filename.c_str()); + // valid VS/FS + program = bgfx::createProgram(vsShader, fsShader, false); + mask |= EvaluationGLSL; + mShaderHandles.push_back(vsShader); + mShaderHandles.push_back(fsShader); + //assert(program.idx); } - else + else if (fsShader.idx != bgfx::kInvalidHandle) { - program = LoadShaderTransformFeedback(shader.mText, filename.c_str()); + // valid FS -> use nodeVS + program = bgfx::createProgram(nodeVSShader, fsShader, false); + mask |= EvaluationGLSL; + mShaderHandles.push_back(fsShader); + assert(program.idx); } - - int parameterBlockIndex = glGetUniformBlockIndex(program, (nodeName + "Block").c_str()); - if (parameterBlockIndex != -1) - glUniformBlockBinding(program, parameterBlockIndex, 1); - - parameterBlockIndex = glGetUniformBlockIndex(program, "EvaluationBlock"); - if (parameterBlockIndex != -1) - glUniformBlockBinding(program, parameterBlockIndex, 2); - - shader.mProgram = program; - if (shader.mType != -1) - mEvaluatorPerNodeType[shader.mType].mGLSLProgram = program; - } - TagTime("GLSL compute init"); - #if USE_LIBTCC - // C - for (auto& file : evaluatorfilenames) - { - if (file.mEvaluatorType != EVALUATOR_C) - continue; - const std::string filename = file.mFilename; - try +#ifndef __EMSCRIPTEN__ + else if (csShader.idx != bgfx::kInvalidHandle) { - std::ifstream t(file.mDirectory + filename); - if (!t.good()) - { - Log("%s - Unable to load file.\n", filename.c_str()); - continue; - } - Log("%s\n", filename.c_str()); - std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); - if (mEvaluatorScripts.find(filename) == mEvaluatorScripts.end()) - mEvaluatorScripts[filename] = EvaluatorScript(str); - else - mEvaluatorScripts[filename].mText = str; - - EvaluatorScript& program = mEvaluatorScripts[filename]; - TCCState* s = tcc_new(); - - int* noLib = (int*)s; - noLib[2] = 1; // no stdlib - - tcc_set_error_func(s, 0, libtccErrorFunc); - tcc_add_include_path(s, "Nodes/C/"); - tcc_set_output_type(s, TCC_OUTPUT_MEMORY); - - if (tcc_compile_string(s, program.mText.c_str()) != 0) - { - Log("%s - Compilation error!\n", filename.c_str()); - continue; - } - - for (auto& evaluationFunction : evaluationFunctions) - tcc_add_symbol(s, evaluationFunction.szFunctionName, evaluationFunction.function); - - int size = tcc_relocate(s, NULL); - if (size == -1) - { - Log("%s - Libtcc unable to relocate program!\n", filename.c_str()); - continue; - } - program.mMem = malloc(size); - tcc_relocate(s, program.mMem); - - *(void**)(&program.mCFunction) = tcc_get_symbol(s, "main"); - if (!program.mCFunction) - { - Log("%s - No main function!\n", filename.c_str()); - } - tcc_delete(s); + // valid CS + mask |= EvaluationGLSLCompute; + mShaderHandles.push_back(csShader); + } +#endif + EvaluatorScript& script = mEvaluatorScripts[nodeName]; + + if (program.idx) + { + script.mProgram = program; - if (program.mType != -1) + // uniforms + for (const auto& parameter : gMetaNodes[i].mParams) { - mEvaluatorPerNodeType[program.mType].mCFunction = program.mCFunction; - mEvaluatorPerNodeType[program.mType].mMem = program.mMem; + int count = 1; + switch (parameter.mType) + { + case Con_Float: + break; + case Con_Float2: + break; + case Con_Float3: + break; + case Con_Float4: + break; + case Con_Color4: + break; + case Con_Int: + break; + case Con_Int2: + break; + case Con_Ramp: + count = 8; + break; + case Con_Angle: + break; + case Con_Angle2: + break; + case Con_Angle3: + break; + case Con_Angle4: + break; + case Con_Enum: + break; + case Con_Structure: + case Con_FilenameRead: + case Con_FilenameWrite: + case Con_ForceEvaluate: + continue; + case Con_Bool: + break; + case Con_Ramp4: + count = 8; + break; + } + bgfx::UniformHandle handle = bgfx::createUniform(parameter.mName.c_str(), bgfx::UniformType::Vec4, count); + script.mUniformHandles.push_back(handle); } } - catch (...) + + // C++ functions + auto iter = nodeFunctions.find(nodeName); + if (iter != nodeFunctions.end()) { - Log("Error at compiling %s", filename.c_str()); + script.mCFunction = iter->second; + mask |= EvaluationC; } + script.mMask = mask; + script.mType = i; + mEvaluatorPerNodeType[i] = &script; + auto& evalNode = mEvaluatorPerNodeType[i]; + //assert(mask); enable when compute shaders are back } - TagTime("C init"); - #endif + + + + + /* #if USE_PYTHON for (auto& file : evaluatorfilenames) { @@ -644,70 +784,80 @@ void Evaluators::SetEvaluators(const std::vector& evaluatorfilena try { shader.mPyModule = pybind11::module::import("Nodes.Python.testnode"); - if (shader.mType != -1) - mEvaluatorPerNodeType[shader.mType].mPyModule = shader.mPyModule; } catch (...) { Log("Python exception\n"); } } - - TagTime("Python init"); - #endif +#endif +*/ + } -void Evaluators::ClearEvaluators() +void Evaluators::EvaluatorScript::Clear() { - // clear - for (auto& program : mEvaluatorPerNodeType) + for (auto& sampler : mUniformHandles) { - if (program.mGLSLProgram) - glDeleteProgram(program.mGLSLProgram); - if (program.mMem) - free(program.mMem); + bgfx::destroy(sampler); + } + if (mProgram.idx != bgfx::kInvalidHandle) + { + bgfx::destroy(mProgram); } } -int Evaluators::GetMask(size_t nodeType) +void Evaluators::Clear() { - const std::string& nodeName = gMetaNodes[nodeType].mName; -#ifdef _DEBUG - mEvaluatorPerNodeType[nodeType].mName = nodeName; -#endif - int mask = 0; - auto iter = mEvaluatorScripts.find(nodeName + ".glsl"); - if (iter != mEvaluatorScripts.end()) + for (auto& sampler : mSamplers2D) { - mask |= EvaluationGLSL; - iter->second.mType = int(nodeType); - mEvaluatorPerNodeType[nodeType].mGLSLProgram = iter->second.mProgram; + bgfx::destroy(sampler); } - iter = mEvaluatorScripts.find(nodeName + ".glslc"); - if (iter != mEvaluatorScripts.end()) + for (auto& sampler : mSamplersCube) { - mask |= EvaluationGLSLCompute; - iter->second.mType = int(nodeType); - mEvaluatorPerNodeType[nodeType].mGLSLProgram = iter->second.mProgram; + bgfx::destroy(sampler); } - iter = mEvaluatorScripts.find(nodeName + ".c"); - if (iter != mEvaluatorScripts.end()) + for (auto& script : mEvaluatorScripts) { - mask |= EvaluationC; - iter->second.mType = int(nodeType); - mEvaluatorPerNodeType[nodeType].mCFunction = iter->second.mCFunction; - mEvaluatorPerNodeType[nodeType].mMem = iter->second.mMem; + script.second.Clear(); } - #if USE_PYTHON - iter = mEvaluatorScripts.find(nodeName + ".py"); - if (iter != mEvaluatorScripts.end()) + for (auto& shader : mShaderHandles) { - mask |= EvaluationPython; - iter->second.mType = int(nodeType); - mEvaluatorPerNodeType[nodeType].mPyModule = iter->second.mPyModule; + bgfx::destroy(shader); } - #endif - return mask; + mEvaluatorScripts.clear(); + mEvaluatorPerNodeType.clear(); + mShaderHandles.clear(); + + if (u_time.idx != bgfx::kInvalidHandle) + { + bgfx::destroy(u_time); + bgfx::destroy(mBlitProgram); + bgfx::destroy(mProgressProgram); + bgfx::destroy(mDisplayCubemapProgram); + } + + if (u_viewRot.idx != bgfx::kInvalidHandle) + { + bgfx::destroy(u_viewRot); + bgfx::destroy(u_viewProjection); + bgfx::destroy(u_viewInverse); + bgfx::destroy(u_world); + bgfx::destroy(u_worldViewProjection); + bgfx::destroy(u_mouse); + bgfx::destroy(u_keyModifier); + bgfx::destroy(u_inputIndices); + bgfx::destroy(u_target); + bgfx::destroy(u_pass); + bgfx::destroy(u_viewport); + bgfx::destroy(u_textureSize); + } +} + +int Evaluators::GetMask(size_t nodeType) const +{ + auto& evalNode = mEvaluatorPerNodeType[nodeType]; + return evalNode->mMask; } #if USE_PYTHON @@ -761,34 +911,42 @@ void Evaluators::ReloadPlugins() #endif } #if USE_PYTHON -void Evaluator::RunPython() const +void Evaluators::EvaluatorScript::RunPython() const { mPyModule.attr("main")(gEvaluators.mImogenModule.attr("accessor_api")()); } #endif + +void Evaluators::ApplyEvaluationInfo(const EvaluationInfo& evaluationInfo) +{ + bgfx::setUniform(u_viewRot, evaluationInfo.viewRot); + bgfx::setUniform(u_viewProjection, evaluationInfo.viewProjection); + bgfx::setUniform(u_viewInverse, evaluationInfo.viewInverse); + bgfx::setUniform(u_world, evaluationInfo.world); + bgfx::setUniform(u_worldViewProjection, evaluationInfo.worldViewProjection); + bgfx::setUniform(u_mouse, evaluationInfo.mouse); + bgfx::setUniform(u_keyModifier, evaluationInfo.keyModifier); + bgfx::setUniform(u_inputIndices, evaluationInfo.inputIndices, 2); + bgfx::setUniform(u_target, &evaluationInfo.targetIndex); + bgfx::setUniform(u_pass, &evaluationInfo.uiPass); + bgfx::setUniform(u_viewport, evaluationInfo.viewport); + bgfx::setUniform(u_textureSize, evaluationInfo.textureSize, 8); +} + namespace EvaluationAPI { - int SetEvaluationImageCube(EvaluationContext* evaluationContext, int target, Image* image, int cubeFace) + int SetEvaluationImageCube(EvaluationContext* evaluationContext, NodeIndex target, const Image* image, int cubeFace) { - if (image->mNumFaces != 1) - { - return EVAL_ERR; - } auto tgt = evaluationContext->GetRenderTarget(target); if (!tgt) { - return EVAL_ERR; + tgt = evaluationContext->CreateRenderTarget(target); } - tgt->InitCube(image->mWidth, image->mNumMips); - - Image::Upload(image, tgt->mGLTexID, cubeFace); - evaluationContext->SetTargetDirty(target, true); - return EVAL_OK; - } + tgt->InitCube(image->mWidth, image->mHasMipmaps); - int AllocateImage(Image* image) - { + Image::Upload(image, tgt->mTexture, cubeFace); + evaluationContext->SetTargetDirty(target, Dirty::Parameter, true); return EVAL_OK; } @@ -796,97 +954,123 @@ namespace EvaluationAPI { std::vector pngImage; if (Image::EncodePng(image, pngImage) == EVAL_ERR) + { return EVAL_ERR; - + } Material* material = library.Get(std::make_pair(0, context->GetMaterialUniqueId())); if (material) { material->mThumbnail = pngImage; - material->mThumbnailTextureId = 0; + material->mThumbnailTextureHandle = {bgfx::kInvalidHandle}; } return EVAL_OK; } - void SetBlendingMode(EvaluationContext* evaluationContext, int target, int blendSrc, int blendDst) + void SetBlendingMode(EvaluationContext* evaluationContext, NodeIndex target, uint64_t blendSrc, uint64_t blendDst) { - EvaluationStage& evaluation = evaluationContext->mEvaluationStages.mStages[target]; + EvaluationContext::Evaluation& evaluation = evaluationContext->mEvaluations[target]; evaluation.mBlendingSrc = blendSrc; evaluation.mBlendingDst = blendDst; } - void EnableDepthBuffer(EvaluationContext* evaluationContext, int target, int enable) + void EnableDepthBuffer(EvaluationContext* evaluationContext, NodeIndex target, int enable) { - EvaluationStage& evaluation = evaluationContext->mEvaluationStages.mStages[target]; + EvaluationContext::Evaluation& evaluation = evaluationContext->mEvaluations[target]; evaluation.mbDepthBuffer = enable != 0; } - void EnableFrameClear(EvaluationContext* evaluationContext, int target, int enable) + void EnableFrameClear(EvaluationContext* evaluationContext, NodeIndex target, int enable) { - EvaluationStage& evaluation = evaluationContext->mEvaluationStages.mStages[target]; + EvaluationContext::Evaluation& evaluation = evaluationContext->mEvaluations[target]; evaluation.mbClearBuffer = enable != 0; } - void SetVertexSpace(EvaluationContext* evaluationContext, int target, int vertexSpace) + void SetVertexSpace(EvaluationContext* evaluationContext, NodeIndex target, int vertexSpace) { - EvaluationStage& evaluation = evaluationContext->mEvaluationStages.mStages[target]; + EvaluationContext::Evaluation& evaluation = evaluationContext->mEvaluations[target]; evaluation.mVertexSpace = vertexSpace; } - int GetEvaluationSize(const EvaluationContext* evaluationContext, int target, int* imageWidth, int* imageHeight) + int GetEvaluationSize(const EvaluationContext* evaluationContext, NodeIndex target, int* imageWidth, int* imageHeight) { - if (target < 0 || target >= evaluationContext->mEvaluationStages.mStages.size()) + if ((!target.IsValid()) || target >= evaluationContext->mEvaluationStages.mStages.size()) + { return EVAL_ERR; + } auto renderTarget = evaluationContext->GetRenderTarget(target); if (!renderTarget) + { + *imageWidth = *imageHeight = 0; return EVAL_ERR; - *imageWidth = renderTarget->mImage->mWidth; - *imageHeight = renderTarget->mImage->mHeight; + } + *imageWidth = renderTarget->mImage.mWidth; + *imageHeight = renderTarget->mImage.mHeight; return EVAL_OK; } - int SetEvaluationSize(EvaluationContext* evaluationContext, int target, int imageWidth, int imageHeight) + int SetEvaluationSize(EvaluationContext* evaluationContext, NodeIndex target, int imageWidth, int imageHeight) { - if (target < 0 || target >= evaluationContext->mEvaluationStages.mStages.size()) + if ((!target.IsValid()) || target >= evaluationContext->mEvaluationStages.mStages.size()) + { return EVAL_ERR; + } auto renderTarget = evaluationContext->GetRenderTarget(target); if (!renderTarget) - return EVAL_ERR; + { + renderTarget = evaluationContext->CreateRenderTarget(target); + } // if (gCurrentContext->GetEvaluationInfo().uiPass) // return EVAL_OK; - renderTarget->InitBuffer( - imageWidth, imageHeight, evaluationContext->mEvaluationStages.mStages[target].mbDepthBuffer); + renderTarget->Init2D( + imageWidth, imageHeight, evaluationContext->mEvaluations[target].mbDepthBuffer); + return EVAL_OK; } - int SetEvaluationCubeSize(EvaluationContext* evaluationContext, int target, int faceWidth, int mipmapCount) + int SetEvaluationPersistent(EvaluationContext* evaluationContext, NodeIndex target, int persistent) + { + if ((!target.IsValid()) || target >= evaluationContext->mEvaluationStages.mStages.size()) + { + return EVAL_ERR; + } + evaluationContext->mEvaluations[target].mbPersistent = persistent != 0; + return EVAL_OK; + } + + int SetEvaluationCubeSize(EvaluationContext* evaluationContext, NodeIndex target, int faceWidth, int hasMipmap) { - if (target < 0 || target >= evaluationContext->mEvaluationStages.mStages.size()) + if ((!target.IsValid()) || target >= evaluationContext->mEvaluationStages.mStages.size()) + { return EVAL_ERR; + } auto renderTarget = evaluationContext->GetRenderTarget(target); if (!renderTarget) - return EVAL_ERR; - renderTarget->InitCube(faceWidth, mipmapCount); + { + renderTarget = evaluationContext->CreateRenderTarget(target); + } + renderTarget->InitCube(faceWidth, hasMipmap != 0); + return EVAL_OK; } std::map> gSceneCache; - int SetEvaluationRTScene(EvaluationContext* evaluationContext, int target, void* scene) + int SetEvaluationRTScene(EvaluationContext* evaluationContext, NodeIndex target, void* scene) { evaluationContext->mEvaluationStages.mStages[target].mScene = scene; return EVAL_OK; } - int GetEvaluationRTScene(EvaluationContext* evaluationContext, int target, void** scene) + int GetEvaluationRTScene(EvaluationContext* evaluationContext, NodeIndex target, void** scene) { *scene = evaluationContext->mEvaluationStages.mStages[target].mScene; return EVAL_OK; } - int SetEvaluationScene(EvaluationContext* evaluationContext, int target, void* scene) + int SetEvaluationScene(EvaluationContext* evaluationContext, NodeIndex target, void* scene) { const std::string& name = ((Scene*)scene)->mName; auto& stage = evaluationContext->mEvaluationStages.mStages[target]; @@ -907,9 +1091,9 @@ namespace EvaluationAPI return EVAL_OK; } - int GetEvaluationScene(EvaluationContext* evaluationContext, int target, void** scene) + int GetEvaluationScene(EvaluationContext* evaluationContext, NodeIndex target, void** scene) { - if (target >= 0 && target < evaluationContext->mEvaluationStages.mStages.size()) + if (target.IsValid() && target < evaluationContext->mEvaluationStages.mStages.size()) { *scene = evaluationContext->mEvaluationStages.mStages[target].mGScene.get(); return EVAL_OK; @@ -917,7 +1101,12 @@ namespace EvaluationAPI return EVAL_ERR; } - const char* GetEvaluationSceneName(EvaluationContext* evaluationContext, int target) + int IsBuilding(EvaluationContext* evaluationContext) + { + return evaluationContext->IsBuilding() ? 1 : 0; + } + + const char* GetEvaluationSceneName(EvaluationContext* evaluationContext, NodeIndex target) { void* scene; if (GetEvaluationScene(evaluationContext, target, &scene) == EVAL_OK && scene) @@ -928,22 +1117,22 @@ namespace EvaluationAPI return ""; } - int GetEvaluationRenderer(EvaluationContext* evaluationContext, int target, void** renderer) + int GetEvaluationRenderer(EvaluationContext* evaluationContext, NodeIndex target, void** renderer) { *renderer = evaluationContext->mEvaluationStages.mStages[target].renderer; return EVAL_OK; } - int OverrideInput(EvaluationContext* evaluationContext, int target, int inputIndex, int newInputTarget) + int OverrideInput(EvaluationContext* evaluationContext, NodeIndex target, int inputIndex, int newInputTarget) { - evaluationContext->mEvaluationStages.mStages[target].mInput.mOverrideInputs[inputIndex] = newInputTarget; + evaluationContext->mEvaluationStages.mInputs[target].mOverrideInputs[inputIndex] = newInputTarget; return EVAL_OK; } - int GetEvaluationImage(EvaluationContext* evaluationContext, int target, Image* image) + int GetEvaluationImage(EvaluationContext* evaluationContext, NodeIndex target, Image* image) { - if (target == -1 || target >= evaluationContext->mEvaluationStages.mStages.size()) + if (!target.IsValid() || target >= evaluationContext->mEvaluationStages.mStages.size()) { return EVAL_ERR; } @@ -953,115 +1142,103 @@ namespace EvaluationAPI { return EVAL_ERR; } - + auto sourceImage = tgt->mImage; + bgfx::TextureHandle transient = bgfx::createTexture2D( + uint16_t(sourceImage.mWidth) + , uint16_t(sourceImage.mHeight) + , sourceImage.mHasMipmaps + , uint16_t(1) + , bgfx::TextureFormat::Enum(sourceImage.mFormat) + , BGFX_TEXTURE_READ_BACK + , nullptr + ); + // compute total size auto img = tgt->mImage; - unsigned int texelSize = textureFormatSize[img->mFormat]; - unsigned int texelFormat = glInternalFormats[img->mFormat]; - uint32_t size = 0; // img.mNumFaces * img.mWidth * img.mHeight * texelSize; - for (int i = 0; i < img->mNumMips; i++) - size += img->mNumFaces * (img->mWidth >> i) * (img->mHeight >> i) * texelSize; + unsigned int texelSize = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(img.mFormat))/8; + uint32_t size = 0; + + for (size_t i = 0; i < img.GetMipmapCount(); i++) + { + size += img.GetFaceCount() * (img.mWidth >> i) * (img.mHeight >> i) * texelSize; + } image->Allocate(size); - image->mWidth = img->mWidth; - image->mHeight = img->mHeight; - image->mNumMips = img->mNumMips; - image->mFormat = img->mFormat; - image->mNumFaces = img->mNumFaces; -#ifdef glGetTexImage + image->mWidth = img.mWidth; + image->mHeight = img.mHeight; + image->mHasMipmaps = img.mHasMipmaps; + image->mFormat = img.mFormat; + image->mIsCubemap = img.mIsCubemap; + bgfx::frame(); // Ensure every previous draw call has been issued or a blank target is expected. + uint32_t availableFrame; unsigned char* ptr = image->GetBits(); - if (img->mNumFaces == 1) + if (!img.mIsCubemap) { - glBindTexture(GL_TEXTURE_2D, tgt->mGLTexID); - for (int i = 0; i < img->mNumMips; i++) + for (auto i = 0; i < img.GetMipmapCount(); i++) { - glGetTexImage(GL_TEXTURE_2D, i, texelFormat, GL_UNSIGNED_BYTE, ptr); - ptr += (img->mWidth >> i) * (img->mHeight >> i) * texelSize; + int currentWidth = img.mWidth >> i; + int currentHeight = img.mHeight >> i; + bgfx::blit(2, transient, i, 0, 0, 0, tgt->mTexture, i, 0, 0, 0, currentWidth, currentHeight); + availableFrame = bgfx::readTexture(transient, ptr, i); + ptr += currentWidth * currentHeight * texelSize; + while (bgfx::frame() != availableFrame) {}; } } else { - glBindTexture(GL_TEXTURE_CUBE_MAP, tgt->mGLTexID); - for (int cube = 0; cube < img->mNumFaces; cube++) + for (auto cube = 0; cube < 6; cube++) { - for (int i = 0; i < img->mNumMips; i++) + for (auto i = 0; i < img.GetMipmapCount(); i++) { - glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cube, i, texelFormat, GL_UNSIGNED_BYTE, ptr); - ptr += (img->mWidth >> i) * (img->mHeight >> i) * texelSize; + int currentWidth = img.mWidth >> i; + int currentHeight = img.mHeight >> i; + bgfx::blit(2, transient, i, 0, 0, 0, tgt->mTexture, i, 0, 0, cube, currentWidth, currentHeight); + availableFrame = bgfx::readTexture(transient, ptr, i); + ptr += currentWidth * currentHeight * texelSize; + while (bgfx::frame() != availableFrame) {}; } } } -#endif + + bgfx::destroy(transient); return EVAL_OK; } - int SetEvaluationImage(EvaluationContext* evaluationContext, int target, Image* image) + int SetEvaluationImage(EvaluationContext* evaluationContext, NodeIndex target, const Image* image) { EvaluationStage& stage = evaluationContext->mEvaluationStages.mStages[target]; auto tgt = evaluationContext->GetRenderTarget(target); if (!tgt) - return EVAL_ERR; - unsigned int texelSize = textureFormatSize[image->mFormat]; - unsigned int inputFormat = glInputFormats[image->mFormat]; - unsigned int internalFormat = glInternalFormats[image->mFormat]; - unsigned char* ptr = image->GetBits(); - if (image->mNumFaces == 1) { - tgt->InitBuffer(image->mWidth, image->mHeight, stage.mbDepthBuffer); - - glBindTexture(GL_TEXTURE_2D, tgt->mGLTexID); - - for (int i = 0; i < image->mNumMips; i++) - { - glTexImage2D(GL_TEXTURE_2D, - i, - internalFormat, - image->mWidth >> i, - image->mHeight >> i, - 0, - inputFormat, - GL_UNSIGNED_BYTE, - ptr); - ptr += (image->mWidth >> i) * (image->mHeight >> i) * texelSize; - } - - if (image->mNumMips > 1) - TexParam(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_TEXTURE_2D); - else - TexParam(GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_TEXTURE_2D); + tgt = evaluationContext->CreateRenderTarget(target); + } + + if (!image->mIsCubemap) + { + tgt->Init2D(image->mWidth, image->mHeight, evaluationContext->mEvaluations[target].mbDepthBuffer); } else { - tgt->InitCube(image->mWidth, image->mNumMips); - glBindTexture(GL_TEXTURE_CUBE_MAP, tgt->mGLTexID); + tgt->InitCube(image->mWidth, image->mHasMipmaps); + } - for (int face = 0; face < image->mNumFaces; face++) + for (size_t face = 0; face < image->GetFaceCount(); face++) + { + int cubeFace = image->mIsCubemap ? int(face) : -1; + for (auto i = 0; i < image->GetMipmapCount(); i++) { - for (int i = 0; i < image->mNumMips; i++) - { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, - i, - internalFormat, - image->mWidth >> i, - image->mWidth >> i, - 0, - inputFormat, - GL_UNSIGNED_BYTE, - ptr); - ptr += (image->mWidth >> i) * (image->mWidth >> i) * texelSize; - } + Image::Upload(image, tgt->mTexture, cubeFace, i); } - - if (image->mNumMips > 1) - TexParam(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_TEXTURE_CUBE_MAP); - else - TexParam(GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_TEXTURE_CUBE_MAP); } - #if USE_FFMPEG + +#if USE_FFMPEG if (stage.mDecoder.get() != (FFMPEGCodec::Decoder*)image->mDecoder) + { stage.mDecoder = std::shared_ptr((FFMPEGCodec::Decoder*)image->mDecoder); - #endif + } +#endif evaluationContext->SetTargetDirty(target, Dirty::Input, true); + return EVAL_OK; } @@ -1112,7 +1289,7 @@ namespace EvaluationAPI scene->texData.metallicRoughnessTexCount * 3 + scene->texData.normalTextureSize.x * scene->texData.normalTextureSize.y * scene->texData.normalTexCount * 3 + - scene->hdrLoaderRes.width * scene->hdrLoaderRes.height * sizeof(GL_FLOAT) * 3; + scene->hdrLoaderRes.width * scene->hdrLoaderRes.height * sizeof(float) * 3; Log("GPU Memory used for Textures: %d MB\n", tex_data_bytes / 1048576); @@ -1121,7 +1298,7 @@ namespace EvaluationAPI return EVAL_OK; } - int InitRenderer(EvaluationContext* evaluationContext, int target, int mode, void* scene) + int InitRenderer(EvaluationContext* evaluationContext, NodeIndex target, int mode, void* scene) { GLSLPathTracer::Scene* rdscene = (GLSLPathTracer::Scene*)scene; evaluationContext->mEvaluationStages.mStages[target].mScene = scene; @@ -1138,13 +1315,13 @@ namespace EvaluationAPI return EVAL_OK; } - int UpdateRenderer(EvaluationContext* evaluationContext, int target) + int UpdateRenderer(EvaluationContext* evaluationContext, NodeIndex target) { - auto& eval = evaluationContext->mEvaluationStages; + /*auto& eval = evaluationContext->mEvaluationStages; GLSLPathTracer::Renderer* renderer = (GLSLPathTracer::Renderer*)eval.mStages[target].renderer; GLSLPathTracer::Scene* rdscene = (GLSLPathTracer::Scene*)eval.mStages[target].mScene; - Camera* camera = eval.GetCameraParameter(target); + const Camera* camera = GetCameraParameter(eval.mStages[target].mType, eval.mParameters[target]); if (camera) { Vec4 pos = camera->mPosition; @@ -1158,34 +1335,27 @@ namespace EvaluationAPI auto tgt = evaluationContext->GetRenderTarget(target); renderer->render(); - tgt->BindAsTarget(); + //tgt->BindAsTarget(); renderer->present(); float progress = renderer->getProgress(); evaluationContext->StageSetProgress(target, progress); bool renderDone = progress >= 1.f - FLT_EPSILON; - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glUseProgram(0); if (renderDone) { evaluationContext->StageSetProcessing(target, false); return EVAL_OK; - } + } TODOEVA + */ return EVAL_DIRTY; } - void SetProcessing(EvaluationContext* context, int target, int processing) + void SetProcessing(EvaluationContext* context, NodeIndex target, int processing) { context->StageSetProcessing(target, processing); } - int AllocateComputeBuffer(EvaluationContext* context, int target, int elementCount, int elementSize) - { - context->AllocateComputeBuffer(target, elementCount, elementSize); - return EVAL_OK; - } - typedef int (*jobFunction)(void*); struct CFunctionTaskSet : TaskSet @@ -1205,6 +1375,20 @@ namespace EvaluationAPI void* mBuffer; }; + struct FunctionTaskSet : TaskSet + { + FunctionTaskSet(std::function function) + : TaskSet(), mFunction(function) + { + } + virtual void ExecuteRange(TaskSetPartition range, uint32_t threadnum) + { + mFunction(); + delete this; + } + std::function mFunction; + }; + struct CFunctionMainTask : PinnedTask { CFunctionMainTask(jobFunction function, void* ptr, unsigned int size) @@ -1224,6 +1408,48 @@ namespace EvaluationAPI void* mBuffer; }; + + struct FunctionMainTask : PinnedTask + { + FunctionMainTask(std::function function) + : PinnedTask(0) // set pinned thread to 0 + , mFunction(function) + { + } + virtual void Execute() + { + mFunction(); + delete this; + } + std::function mFunction; + }; + + int Job(EvaluationContext* evaluationContext, std::function function) + { + if (evaluationContext->IsSynchronous()) + { + return function(); + } + else + { + g_TS.AddTaskSetToPipe(new FunctionTaskSet(function)); + } + return EVAL_OK; + } + + int JobMain(EvaluationContext* evaluationContext, std::function function) + { + if (evaluationContext->IsSynchronous()) + { + return function(); + } + else + { + g_TS.AddPinnedTask(new FunctionMainTask(function)); + } + return EVAL_OK; + } + int Job(EvaluationContext* evaluationContext, int (*jobFunction)(void*), void* ptr, unsigned int size) { if (evaluationContext->IsSynchronous()) @@ -1280,36 +1506,6 @@ namespace EvaluationAPI return Image::Write(filename, image, format, quality); } - int Evaluate(EvaluationContext* evaluationContext, int target, int width, int height, Image* image) - { - EvaluationContext context(evaluationContext->mEvaluationStages, true, width, height); - context.SetCurrentTime(evaluationContext->GetCurrentTime()); - // set all nodes as dirty so that evaluation (in build) will not bypass most nodes - context.DirtyAll(); - while (context.RunBackward(target)) - { - // processing... maybe good on next run - } - GetEvaluationImage(&context, target, image); - return EVAL_OK; - } - - inline char* ReadFile(const char* szFileName, int& bufSize) - { - FILE* fp = fopen(szFileName, "rb"); - if (fp) - { - fseek(fp, 0, SEEK_END); - bufSize = ftell(fp); - fseek(fp, 0, SEEK_SET); - char* buf = new char[bufSize]; - fread(buf, bufSize, 1, fp); - fclose(fp); - return buf; - } - return NULL; - } - int ReadGLTF(EvaluationContext* evaluationContext, const char* filename, Scene** scene) { std::string strFilename(filename); @@ -1324,81 +1520,178 @@ namespace EvaluationAPI cgltf_data* data = NULL; cgltf_result result = cgltf_parse_file(&options, filename, &data); if (result != cgltf_result_success) + { return EVAL_ERR; + } result = cgltf_load_buffers(&options, data, filename); if (result != cgltf_result_success) + { + cgltf_free(data); return EVAL_ERR; + } Scene* sc = new Scene; sc->mName = strFilename; - // gSceneCache.insert(std::make_pair(strFilename, sc)); - // gScenePointerCache.insert(std::make_pair(sc.get(), sc)); + *scene = sc; - sc->mMeshes.resize(data->meshes_count); - for (unsigned int i = 0; i < data->meshes_count; i++) - { - auto& gltfMesh = data->meshes[i]; - auto& mesh = sc->mMeshes[i]; - mesh.mPrimitives.resize(gltfMesh.primitives_count); - // attributes - for (unsigned int j = 0; j < gltfMesh.primitives_count; j++) + JobMain(evaluationContext, [evaluationContext, sc, data]() { + sc->mMeshes.resize(data->meshes_count); + sc->mBounds.resize(data->meshes_count); + for (unsigned int i = 0; i < data->meshes_count; i++) { - auto& gltfPrim = gltfMesh.primitives[j]; - auto& prim = mesh.mPrimitives[j]; - - for (unsigned int k = 0; k < gltfPrim.attributes_count; k++) + auto& gltfMesh = data->meshes[i]; + auto& mesh = sc->mMeshes[i]; + auto& bounds = sc->mBounds[i]; + mesh.mPrimitives.resize(gltfMesh.primitives_count); + // attributes + for (unsigned int j = 0; j < gltfMesh.primitives_count; j++) { - unsigned int format = 0; - auto attr = gltfPrim.attributes[k]; - switch (attr.type) + auto& gltfPrim = gltfMesh.primitives[j]; + auto& prim = mesh.mPrimitives[j]; + + for (unsigned int k = 0; k < gltfPrim.attributes_count; k++) { - case cgltf_attribute_type_position: - format = Scene::Mesh::Format::POS; - break; - case cgltf_attribute_type_normal: - format = Scene::Mesh::Format::NORM; - break; - case cgltf_attribute_type_texcoord: - format = Scene::Mesh::Format::UV; - break; - case cgltf_attribute_type_color: - format = Scene::Mesh::Format::COL; - break; + unsigned int format = 0; + auto attr = gltfPrim.attributes[k]; + switch (attr.type) + { + case cgltf_attribute_type_position: + format = Scene::Mesh::Format::POS; + break; + case cgltf_attribute_type_normal: + format = Scene::Mesh::Format::NORM; + break; + case cgltf_attribute_type_texcoord: + format = Scene::Mesh::Format::UV; + break; + case cgltf_attribute_type_color: + format = Scene::Mesh::Format::COL; + break; + } + const char* buffer = ((char*)attr.data->buffer_view->buffer->data) + + attr.data->buffer_view->offset + attr.data->offset; + prim.AddBuffer(buffer, format, (unsigned int)attr.data->stride, (unsigned int)attr.data->count); + if (format == Scene::Mesh::Format::POS) + { + const Vec3* pos = (Vec3*)buffer; + const unsigned int posCount = ((unsigned int)attr.data->count * (unsigned int)attr.data->stride) / (3 * sizeof(float)); + for (size_t iBound = 0; iBound < posCount; iBound++) + { + bounds.AddPoint(pos[iBound]); + } + } } - const char* buffer = ((char*)attr.data->buffer_view->buffer->data) + - attr.data->buffer_view->offset + attr.data->offset; - prim.AddBuffer(buffer, format, (unsigned int)attr.data->stride, (unsigned int)attr.data->count); + + // indices + const char* buffer = ((char*)gltfPrim.indices->buffer_view->buffer->data) + + gltfPrim.indices->buffer_view->offset + gltfPrim.indices->offset; + prim.AddIndexBuffer( + buffer, (unsigned int)gltfPrim.indices->stride, (unsigned int)gltfPrim.indices->count); } + } - // indices - const char* buffer = ((char*)gltfPrim.indices->buffer_view->buffer->data) + - gltfPrim.indices->buffer_view->offset + gltfPrim.indices->offset; - prim.AddIndexBuffer( - buffer, (unsigned int)gltfPrim.indices->stride, (unsigned int)gltfPrim.indices->count); + sc->mWorldTransforms.resize(data->nodes_count); + sc->mMeshIndex.resize(data->nodes_count, -1); + + // transforms + for (unsigned int i = 0; i < data->nodes_count; i++) + { + cgltf_node_transform_world(&data->nodes[i], sc->mWorldTransforms[i]); } - } - sc->mWorldTransforms.resize(data->nodes_count); - sc->mMeshIndex.resize(data->nodes_count, -1); + for (unsigned int i = 0; i < data->nodes_count; i++) + { + if (!data->nodes[i].mesh) + continue; + sc->mMeshIndex[i] = int(data->nodes[i].mesh - data->meshes); + } - // transforms - for (unsigned int i = 0; i < data->nodes_count; i++) - { - cgltf_node_transform_world(&data->nodes[i], sc->mWorldTransforms[i]); - } - for (unsigned int i = 0; i < data->nodes_count; i++) - { - if (!data->nodes[i].mesh) - continue; - sc->mMeshIndex[i] = int(data->nodes[i].mesh - data->meshes); - } + cgltf_free(data); + return EVAL_OK; + }); + return EVAL_OK; + } + int GLTFReadAsync(EvaluationContext* context, const char* filename, NodeIndex target) + { + SetProcessing(context, target, 1); + std::string strFilename = filename; + RuntimeId runtimeId = context->GetStageRuntimeId(target); + Job(context, [context, runtimeId, strFilename](){ + Scene *scene; + if (ReadGLTF(context, strFilename.c_str(), &scene) == EVAL_OK) + { + JobMain(context, [context, scene, runtimeId](){ + int stageIndex = context->GetStageIndexFromRuntimeId(runtimeId); + if (stageIndex != -1) + { + SetEvaluationScene(context, stageIndex, scene); + SetProcessing(context, stageIndex, 0); + + Camera *camera = context->mEvaluationStages.mParameterBlocks[stageIndex].GetCamera(); + if (camera && camera->mLens.y < FLT_EPSILON) + { + Bounds bound = scene->ComputeBounds(); + camera->LookAt(Vec4(bound.mMax.x, bound.mMax.y, bound.mMax.z), bound.Center(), Vec4(0.f, 1.f, 0.f, 0.f)); + } - cgltf_free(data); - *scene = sc; + } + return EVAL_OK; + }); + } + else + { + int stageIndex = context->GetStageIndexFromRuntimeId(runtimeId); + if (stageIndex != -1) + { + SetProcessing(context, stageIndex, 0); + } + } + return EVAL_OK; + }); return EVAL_OK; } + int ReadImageAsync(EvaluationContext* context, const char *filename, NodeIndex target, int face) + { + std::string strFilename = filename; + RuntimeId runtimeId = context->GetStageRuntimeId(target); + Job(context, [runtimeId, context, strFilename, face]() { + Image image; + if (Image::Read(strFilename.c_str(), &image) == EVAL_OK) + { + JobMain(context, [runtimeId, image, face, context](){ + int stageIndex = context->GetStageIndexFromRuntimeId(runtimeId); + if (stageIndex != -1) + { + if (face != -1) + { + SetEvaluationImageCube(context, stageIndex, &image, face); + } + else + { + SetEvaluationImage(context, stageIndex, &image); + } + //FreeImage(&data->image); + SetProcessing(context, stageIndex, 0); + // don't set childOnly or the node will not be evaluated and we wont get the thumbnail + context->SetTargetDirty(stageIndex, Dirty::Input, false); + } + return EVAL_OK; + }); + } + else + { + int stageIndex = context->GetStageIndexFromRuntimeId(runtimeId); + if (stageIndex != -1) + { + SetProcessing(context, stageIndex, 0); + } + } + return EVAL_OK; + }); + return EVAL_OK; + } } // namespace EvaluationAPI diff --git a/src/Evaluators.h b/src/Evaluators.h index 6fd3cc7a..328ebaca 100644 --- a/src/Evaluators.h +++ b/src/Evaluators.h @@ -28,79 +28,118 @@ #include #include #include "Imogen.h" +#include "Types.h" #if USE_PYTHON #include "pybind11/embed.h" #endif +struct EvaluationContext; + enum EvaluationMask { EvaluationC = 1 << 0, EvaluationGLSL = 1 << 1, EvaluationPython = 1 << 2, - EvaluationGLSLCompute = 1 << 3, + EvaluationGLSLCompute = 1 << 3 }; -struct Evaluator +struct EvaluationInfo { - Evaluator() : mGLSLProgram(0), mCFunction(0), mMem(0) - { - } - unsigned int mGLSLProgram; - int (*mCFunction)(void* parameters, void* evaluationInfo, void* context); - void* mMem; -#if USE_PYTHON - pybind11::module mPyModule; - - void RunPython() const; -#endif - -#ifdef _DEBUG - std::string mName; -#endif + float viewRot[16]; + float viewProjection[16]; + float viewInverse[16]; + float world[16]; + float worldViewProjection[16]; + float viewport[4]; + + float mouse[4]; + float keyModifier[4]; + float inputIndices[8]; + + + float uiPass; // pass + float passNumber; + float frame; + float localFrame; + + + float targetIndex; //target + float vertexSpace; + float mipmapNumber; + float mipmapCount; + + float textureSize[8 * 4]; + // not used by shaders + uint32_t dirtyFlag; }; +typedef int(*NodeFunction)(void* parameters, EvaluationInfo* evaluation, EvaluationContext* context); + struct Evaluators { - Evaluators() - { - } - void SetEvaluators(const std::vector& evaluatorfilenames); - std::string GetEvaluator(const std::string& filename); - static void InitPython(); - int GetMask(size_t nodeType); - void ClearEvaluators(); + Evaluators(); + ~Evaluators(); - const Evaluator& GetEvaluator(size_t nodeType) const - { - return mEvaluatorPerNodeType[nodeType]; - } + void SetEvaluators(); + static void InitPython(); + int GetMask(size_t nodeType) const; + void Clear(); void InitPythonModules(); #if USE_PYTHON pybind11::module mImogenModule; #endif static void ReloadPlugins(); - protected: - struct EvaluatorScript + + struct EvaluatorScript { - EvaluatorScript() : mProgram(0), mCFunction(0), mMem(0), mType(-1) - { - } - EvaluatorScript(const std::string& text) : mText(text), mProgram(0), mCFunction(0), mMem(0), mType(-1) + EvaluatorScript() : mProgram({0}), mCFunction(0), mType(-1), mMask(0) { } - std::string mText; - unsigned int mProgram; - int (*mCFunction)(void* parameters, void* evaluationInfo, void* context); - void* mMem; + void Clear(); + + bgfx::ProgramHandle mProgram; + NodeFunction mCFunction; int mType; -#if USE_PYTHON + int mMask; + std::vector mUniformHandles; +#if USE_PYTHON pybind11::module mPyModule; + + void RunPython() const; #endif }; + const EvaluatorScript& GetEvaluator(size_t nodeType) const + { + return *mEvaluatorPerNodeType[nodeType]; + } + void ApplyEvaluationInfo(const EvaluationInfo& evaluationInfo); +protected: std::map mEvaluatorScripts; - std::vector mEvaluatorPerNodeType; + std::vector mEvaluatorPerNodeType; + std::vector mShaderHandles; +public: + bgfx::UniformHandle u_viewRot{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_viewProjection{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_viewInverse{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_world{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_worldViewProjection{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_mouse{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_keyModifier{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_inputIndices{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_target{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_pass{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_viewport{ bgfx::kInvalidHandle }; + + bgfx::ProgramHandle mBlitProgram{ bgfx::kInvalidHandle }; + bgfx::ProgramHandle mProgressProgram{ bgfx::kInvalidHandle }; + bgfx::ProgramHandle mDisplayCubemapProgram{ bgfx::kInvalidHandle }; + std::vector mSamplers2D; + std::vector mSamplersCube; + bgfx::UniformHandle u_time{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_uvTransform{ bgfx::kInvalidHandle }; + bgfx::UniformHandle u_textureSize{ bgfx::kInvalidHandle }; }; extern Evaluators gEvaluators; @@ -112,42 +151,41 @@ struct Scene; namespace EvaluationAPI { // API - int GetEvaluationImage(EvaluationContext* evaluationContext, int target, Image* image); - int SetEvaluationImage(EvaluationContext* evaluationContext, int target, Image* image); - int SetEvaluationImageCube(EvaluationContext* evaluationContext, int target, Image* image, int cubeFace); + int GetEvaluationImage(EvaluationContext* evaluationContext, NodeIndex target, Image* image); + int SetEvaluationImage(EvaluationContext* evaluationContext, NodeIndex target, const Image* image); + int SetEvaluationImageCube(EvaluationContext* evaluationContext, NodeIndex target, const Image* image, int cubeFace); int SetThumbnailImage(EvaluationContext* evaluationContext, Image* image); - int AllocateImage(Image* image); - - // static int Evaluate(int target, int width, int height, Image *image); - void SetBlendingMode(EvaluationContext* evaluationContext, int target, int blendSrc, int blendDst); - void EnableDepthBuffer(EvaluationContext* evaluationContext, int target, int enable); - void EnableFrameClear(EvaluationContext* evaluationContext, int target, int enable); - void SetVertexSpace(EvaluationContext* evaluationContext, int target, int vertexSpace); - int OverrideInput(EvaluationContext* evaluationContext, int target, int inputIndex, int newInputTarget); - - // int SetNodeImage(int target, Image *image); - int GetEvaluationSize(const EvaluationContext* evaluationContext, int target, int* imageWidth, int* imageHeight); - int SetEvaluationSize(EvaluationContext* evaluationContext, int target, int imageWidth, int imageHeight); - int SetEvaluationCubeSize(EvaluationContext* evaluationContext, int target, int faceWidth, int mipmapCount); + + void SetBlendingMode(EvaluationContext* evaluationContext, NodeIndex target, uint64_t blendSrc, uint64_t blendDst); + void EnableDepthBuffer(EvaluationContext* evaluationContext, NodeIndex target, int enable); + void EnableFrameClear(EvaluationContext* evaluationContext, NodeIndex target, int enable); + void SetVertexSpace(EvaluationContext* evaluationContext, NodeIndex target, int vertexSpace); + int OverrideInput(EvaluationContext* evaluationContext, NodeIndex target, int inputIndex, int newInputTarget); + int IsBuilding(EvaluationContext* evaluationContext); + + int GetEvaluationSize(const EvaluationContext* evaluationContext, NodeIndex target, int* imageWidth, int* imageHeight); + int SetEvaluationSize(EvaluationContext* evaluationContext, NodeIndex target, int imageWidth, int imageHeight); + int SetEvaluationPersistent(EvaluationContext* evaluationContext, NodeIndex target, int persistent); + int SetEvaluationCubeSize(EvaluationContext* evaluationContext, NodeIndex target, int faceWidth, int hasMipmap); int Job(EvaluationContext* evaluationContext, int (*jobFunction)(void*), void* ptr, unsigned int size); int JobMain(EvaluationContext* evaluationContext, int (*jobMainFunction)(void*), void* ptr, unsigned int size); - void SetProcessing(EvaluationContext* context, int target, int processing); - int AllocateComputeBuffer(EvaluationContext* context, int target, int elementCount, int elementSize); + void SetProcessing(EvaluationContext* context, NodeIndex target, int processing); int LoadScene(const char* filename, void** scene); - int SetEvaluationScene(EvaluationContext* evaluationContext, int target, void* scene); - int GetEvaluationScene(EvaluationContext* evaluationContext, int target, void** scene); - int SetEvaluationRTScene(EvaluationContext* evaluationContext, int target, void* scene); - int GetEvaluationRTScene(EvaluationContext* evaluationContext, int target, void** scene); + int SetEvaluationScene(EvaluationContext* evaluationContext, NodeIndex target, void* scene); + int GetEvaluationScene(EvaluationContext* evaluationContext, NodeIndex target, void** scene); + int SetEvaluationRTScene(EvaluationContext* evaluationContext, NodeIndex target, void* scene); + int GetEvaluationRTScene(EvaluationContext* evaluationContext, NodeIndex target, void** scene); - const char* GetEvaluationSceneName(EvaluationContext* evaluationContext, int target); - int GetEvaluationRenderer(EvaluationContext* evaluationContext, int target, void** renderer); - int InitRenderer(EvaluationContext* evaluationContext, int target, int mode, void* scene); - int UpdateRenderer(EvaluationContext* evaluationContext, int target); + const char* GetEvaluationSceneName(EvaluationContext* evaluationContext, NodeIndex target); + int GetEvaluationRenderer(EvaluationContext* evaluationContext, NodeIndex target, void** renderer); + int InitRenderer(EvaluationContext* evaluationContext, NodeIndex target, int mode, void* scene); + int UpdateRenderer(EvaluationContext* evaluationContext, NodeIndex target); int Read(EvaluationContext* evaluationContext, const char* filename, Image* image); int Write(EvaluationContext* evaluationContext, const char* filename, Image* image, int format, int quality); - int Evaluate(EvaluationContext* evaluationContext, int target, int width, int height, Image* image); int ReadGLTF(EvaluationContext* evaluationContext, const char* filename, Scene** scene); + int GLTFReadAsync(EvaluationContext* context, const char* filename, NodeIndex target); + int ReadImageAsync(EvaluationContext* context, const char *filename, NodeIndex target, int face); } // namespace EvaluationAPI \ No newline at end of file diff --git a/src/GraphControler.cpp b/src/GraphControler.cpp new file mode 100644 index 00000000..2d8d9f54 --- /dev/null +++ b/src/GraphControler.cpp @@ -0,0 +1,1173 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "Platform.h" +#include "GraphControler.h" +#include "EvaluationStages.h" +#include "Library.h" +#include "EvaluationContext.h" +#include "Evaluators.h" +#include "UI.h" +#include "Utils.h" +#include "JSGlue.h" +#include "imgui_color_gradient.h" +#include "Cam.h" +#include "IconsFontAwesome5.h" + +void AddExtractedView(size_t nodeIndex); + +GraphControler::GraphControler() + : mbMouseDragging(false) + , mbUsingMouse(false) + , mEditingContext(mEvaluationStages, false, false, 1024, 1024, true) +{ + mSelectedNodeIndex = { InvalidNodeIndex }; + mBackgroundNode = { InvalidNodeIndex }; +} + +void GraphControler::Clear() +{ + mSelectedNodeIndex = { InvalidNodeIndex }; + mBackgroundNode = { InvalidNodeIndex }; + mModel.Clear(); + mEvaluationStages.Clear(); + mEditingContext.Clear(); + ComputeGraphArrays(); +} + +void GraphControler::SetMaterialUniqueId(RuntimeId runtimeId) +{ + mEditingContext.SetMaterialUniqueId(runtimeId); + mEvaluationStages.SetMaterialUniqueId(runtimeId); +} + +bool GraphControler::EditSingleParameter(NodeIndex nodeIndex, + unsigned int parameterIndex, + void* paramBuffer, + const MetaParameter& param) +{ + if (param.mbHidden) + { + return false; + } + bool dirty = false; + uint32_t parameterPair = (uint32_t(nodeIndex) << 16) + parameterIndex; + ImGui::PushID(parameterPair * 4); + PinnedParameterUI(nodeIndex, parameterIndex); + ImGui::SameLine(); + switch (param.mType) + { + case Con_Float: + if (param.mControlType == Control_Slider) + { + dirty |= ImGui::SliderFloat(param.mName.c_str(), (float*)paramBuffer, param.mSliderMinX, param.mSliderMaxX); + } + else + { + dirty |= ImGui::InputFloat(param.mName.c_str(), (float*)paramBuffer); + } + break; + case Con_Float2: + dirty |= ImGui::InputFloat2(param.mName.c_str(), (float*)paramBuffer); + break; + case Con_Float3: + dirty |= ImGui::InputFloat3(param.mName.c_str(), (float*)paramBuffer); + break; + case Con_Float4: + dirty |= ImGui::InputFloat4(param.mName.c_str(), (float*)paramBuffer); + break; + case Con_Color4: + dirty |= ImGui::ColorPicker4(param.mName.c_str(), (float*)paramBuffer); + break; + case Con_Int: + dirty |= ImGui::InputInt(param.mName.c_str(), (int*)paramBuffer); + break; + case Con_Int2: + dirty |= ImGui::InputInt2(param.mName.c_str(), (int*)paramBuffer); + break; + case Con_Ramp: + { + RampEdit curveEditDelegate; + curveEditDelegate.mPointCount = 0; + for (int k = 0; k < 8; k++) + { + curveEditDelegate.mPts[k] = ImVec2(((float*)paramBuffer)[k * 2], ((float*)paramBuffer)[k * 2 + 1]); + if (k && curveEditDelegate.mPts[k - 1].x > curveEditDelegate.mPts[k].x) + break; + curveEditDelegate.mPointCount++; + } + float regionWidth = ImGui::GetWindowContentRegionWidth(); + if (ImCurveEdit::Edit(curveEditDelegate, ImVec2(regionWidth, regionWidth), 974)) + { + for (size_t k = 0; k < curveEditDelegate.mPointCount; k++) + { + ((float*)paramBuffer)[k * 2] = curveEditDelegate.mPts[k].x; + ((float*)paramBuffer)[k * 2 + 1] = curveEditDelegate.mPts[k].y; + } + ((float*)paramBuffer)[0] = 0.f; + ((float*)paramBuffer)[(curveEditDelegate.mPointCount - 1) * 2] = 1.f; + for (size_t k = curveEditDelegate.mPointCount; k < 8; k++) + { + ((float*)paramBuffer)[k * 2] = -1.f; + } + dirty = true; + } + } + break; + case Con_Ramp4: + { + static NodeIndex previousNodeIndex; + static unsigned int previousParameterIndex{ 0xFFFFFFFF }; + + static ImGradient gradient; + static ImGradientMark* draggingMark = nullptr; + static ImGradientMark* selectedMark = nullptr; + + bool sameParameter = previousNodeIndex == nodeIndex && previousParameterIndex == parameterIndex; + if (!sameParameter) + { + draggingMark = nullptr; + selectedMark = nullptr; + + float previousPt = 0.f; + for (int k = 0; k < 8; k++) + { + ImVec4 pt = ((ImVec4*)paramBuffer)[k]; + if (k && previousPt > pt.w) + { + break; + } + previousPt = pt.w; + gradient.addMark(pt.w, ImColor(pt.x, pt.y, pt.z)); + } + } + + dirty |= ImGui::GradientEditor(&gradient, draggingMark, selectedMark); + if (dirty) + { + int k = 0; + ImVec4* ptrc = (ImVec4*)paramBuffer; + for (auto* colors : gradient.getMarks()) + { + *ptrc++ = ImVec4(colors->color[0], colors->color[1], colors->color[2], colors->position); + k++; + if (k == 7) + { + break; + } + } + ptrc->w = -1.f; + } + + previousNodeIndex = nodeIndex; + previousParameterIndex = parameterIndex; + } + break; + case Con_Angle: + ((float*)paramBuffer)[0] = RadToDeg(((float*)paramBuffer)[0]); + dirty |= ImGui::InputFloat(param.mName.c_str(), (float*)paramBuffer); + ((float*)paramBuffer)[0] = DegToRad(((float*)paramBuffer)[0]); + break; + case Con_Angle2: + ((float*)paramBuffer)[0] = RadToDeg(((float*)paramBuffer)[0]); + ((float*)paramBuffer)[1] = RadToDeg(((float*)paramBuffer)[1]); + dirty |= ImGui::InputFloat2(param.mName.c_str(), (float*)paramBuffer); + ((float*)paramBuffer)[0] = DegToRad(((float*)paramBuffer)[0]); + ((float*)paramBuffer)[1] = DegToRad(((float*)paramBuffer)[1]); + break; + case Con_Angle3: + ((float*)paramBuffer)[0] = RadToDeg(((float*)paramBuffer)[0]); + ((float*)paramBuffer)[1] = RadToDeg(((float*)paramBuffer)[1]); + ((float*)paramBuffer)[2] = RadToDeg(((float*)paramBuffer)[2]); + dirty |= ImGui::InputFloat3(param.mName.c_str(), (float*)paramBuffer); + ((float*)paramBuffer)[0] = DegToRad(((float*)paramBuffer)[0]); + ((float*)paramBuffer)[1] = DegToRad(((float*)paramBuffer)[1]); + ((float*)paramBuffer)[2] = DegToRad(((float*)paramBuffer)[2]); + break; + case Con_Angle4: + ((float*)paramBuffer)[0] = RadToDeg(((float*)paramBuffer)[0]); + ((float*)paramBuffer)[1] = RadToDeg(((float*)paramBuffer)[1]); + ((float*)paramBuffer)[2] = RadToDeg(((float*)paramBuffer)[2]); + ((float*)paramBuffer)[3] = RadToDeg(((float*)paramBuffer)[3]); + dirty |= ImGui::InputFloat4(param.mName.c_str(), (float*)paramBuffer); + ((float*)paramBuffer)[0] = DegToRad(((float*)paramBuffer)[0]); + ((float*)paramBuffer)[1] = DegToRad(((float*)paramBuffer)[1]); + ((float*)paramBuffer)[2] = DegToRad(((float*)paramBuffer)[2]); + ((float*)paramBuffer)[3] = DegToRad(((float*)paramBuffer)[3]); + break; + case Con_FilenameWrite: + case Con_FilenameRead: + ImGui::PushID(parameterPair * 4 + 1); + dirty |= ImGui::InputText("", (char*)paramBuffer, 1024); + ImGui::SameLine(); + if (ImGui::Button("...")) + { +#if defined(_NFD_H) + nfdchar_t* outPath = NULL; + nfdresult_t result = (param.mType == Con_FilenameRead) ? NFD_OpenDialog(NULL, NULL, &outPath) + : NFD_SaveDialog(NULL, NULL, &outPath); + + if (result == NFD_OKAY) + { + strcpy((char*)paramBuffer, outPath); + free(outPath); + dirty = true; + } +#else +#ifdef __EMSCRIPTEN__ + UploadDialog([nodeIndex, parameterIndex](const std::string& filename){ + GraphModel& model = Imogen::instance->GetNodeGraphControler()->mModel; + auto& parameters = model.GetParameters(nodeIndex); + char* paramBuffer = ((char*)parameters.data()) + GetParameterOffset(model.GetNodeType(nodeIndex), parameterIndex); + Log("File Parameter updated async %s\n", filename.c_str()); + memcpy(paramBuffer, filename.c_str(), filename.size()); + ((char*)paramBuffer)[filename.size()] = 0; + //Imogen::instance->GetNodeGraphControler()->mEditingContext.SetTargetDirty(nodeIndex, Dirty::Parameter); + + model.BeginTransaction(true); + model.SetParameters(nodeIndex, parameters); + model.EndTransaction(); + }); +#endif +#endif + + } + ImGui::PopID(); + ImGui::SameLine(); + ImGui::Text("%s", param.mName.c_str()); + break; + case Con_Enum: + { + std::string cbString = param.mEnumList; + for (auto& c : cbString) + { + if (c == '|') + c = '\0'; + } + dirty |= ImGui::Combo(param.mName.c_str(), (int*)paramBuffer, cbString.c_str()); + } + break; + case Con_Bool: + { + bool checked = (*(int*)paramBuffer) != 0; + if (ImGui::Checkbox(param.mName.c_str(), &checked)) + { + *(int*)paramBuffer = checked ? 1 : 0; + dirty = true; + } + } + break; + case Con_Camera: + if (ImGui::Button("Reset")) + { + Camera* cam = (Camera*)paramBuffer; + auto *scene = mEvaluationStages.mStages[nodeIndex].mGScene.get(); + if (scene) + { + Bounds bound = scene->ComputeBounds(); + cam->LookAt(Vec4(bound.mMax.x, bound.mMax.y, bound.mMax.z), bound.Center(), Vec4(0.f, 1.f, 0.f, 0.f)); + } + else + { + cam->mPosition = Vec4(0.f, 0.f, 0.f); + cam->mDirection = Vec4(0.f, 0.f, 1.f); + cam->mUp = Vec4(0.f, 1.f, 0.f); + } + dirty = true; + } + break; + case Con_Multiplexer: + break; + default: + break; + } + ImGui::PopID(); + return dirty; +} + +int GraphControler::ShowMultiplexed(const std::vector& inputs, NodeIndex currentMultiplexedOveride) const +{ + int ret = -1; + float displayWidth = ImGui::GetContentRegionAvail().x; + static const float iconWidth = 50.f; + unsigned int displayCount = std::max(int(floorf(displayWidth / iconWidth)), 1); + unsigned int lineCount = int(ceilf(float(inputs.size()) / float(displayCount))); + + // draw buttons + ImGui::BeginGroup(); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(1, 1)); + auto buttonsToDraw = inputs.size();; + int index = 0; + for (unsigned int line = 0; line < lineCount; line++) + { + for (unsigned int disp = 0; disp < displayCount; disp++) + { + if (!buttonsToDraw) + { + continue; + } + ImGui::PushID(index); + + bgfx::TextureHandle textureHandle; + ImRect uvs; + mEditingContext.GetThumb(inputs[index], textureHandle, uvs); + if (ImGui::ImageButton((ImTextureID)(int64_t)textureHandle.idx, ImVec2(iconWidth, iconWidth), uvs.Min, uvs.Max, -1, ImVec4(0, 0, 0, 1))) + { + ret = index; + } + + if (currentMultiplexedOveride == inputs[index]) + { + ImRect rc = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); + ImDrawList* drawList = ImGui::GetWindowDrawList(); + drawList->AddRect(rc.Min, rc.Max, 0xFF0000FF, 2.f, 15, 2.f); + } + + ImGui::PopID(); + if (disp != (displayCount - 1) && buttonsToDraw) + { + ImGui::SameLine(); + } + buttonsToDraw--; + index++; + } + } + ImGui::PopStyleVar(); + ImGui::EndGroup(); + return ret; +} + +void GraphControler::PinnedEdit() +{ + int dirtyNode = -1; + ParameterBlock dirtyParameterBlock(-1); + ImGui::BeginChild(655); + auto& pins = mModel.GetParameterPins(); + for (NodeIndex nodeIndex = 0; nodeIndex < mNodes.size(); nodeIndex++) + { + const auto pin = pins[nodeIndex]; + if (!pin) + { + continue; + } + + const uint32_t parameterPinMask = pin & 0xFFFF; + const size_t nodeType = mModel.GetNodeType(nodeIndex); + const MetaNode& metaNode = gMetaNodes[nodeType]; + + for (uint32_t parameterIndex = 0; parameterIndex < metaNode.mParams.size(); parameterIndex ++) + { + if (!(parameterPinMask & (1 << parameterIndex))) + { + continue; + } + + ImGui::PushID(171717 + parameterIndex); + const MetaParameter& metaParam = metaNode.mParams[parameterIndex]; + auto parameters = mModel.GetParameterBlock(nodeIndex); + if (EditSingleParameter(nodeIndex, parameterIndex, parameters.Data(parameterIndex), metaParam)) + { + dirtyNode = nodeIndex; + dirtyParameterBlock = parameters; + } + ImGui::PopID(); + } + } + ImGui::EndChild(); + if (dirtyNode != -1) + { + mModel.BeginTransaction(true); + mModel.SetParameterBlock(dirtyNode, dirtyParameterBlock); + mModel.EndTransaction(); + } +} + +bool GraphControler::EditNodeParameters(ParameterBlock& parameterBlock) +{ + NodeIndex nodeIndex = mSelectedNodeIndex; + + const MetaNode* metaNodes = gMetaNodes.data(); + bool dirty = false; + bool forceEval = false; + bool samplerDirty = false; + const auto nodeType = mModel.GetNodeType(nodeIndex); + const MetaNode& currentMeta = metaNodes[nodeType]; + ImGui::BeginChild(655); + // edit samplers + auto samplers = mModel.GetSamplers(nodeIndex); + if (samplers.size() && ImGui::CollapsingHeader("Samplers", 0)) + { + for (size_t i = 0; i < samplers.size(); i++) + { + InputSampler& inputSampler = samplers[i]; + static const char* wrapModes = {"REPEAT\0EDGE\0BORDER\0MIRROR"}; + static const char* filterModes = {"LINEAR\0NEAREST"}; + ImGui::PushItemWidth(80); + ImGui::PushID(int(99 + i)); + if (!PinnedIOUI(nodeIndex, SlotIndex(int(i)), false)) + { + ImGui::SameLine(); + } + ImGui::Text("Sampler %zu", i); + samplerDirty |= ImGui::Combo("U", (int*)&inputSampler.mWrapU, wrapModes); + ImGui::SameLine(); + samplerDirty |= ImGui::Combo("V", (int*)&inputSampler.mWrapV, wrapModes); + ImGui::SameLine(); + ImGui::PushItemWidth(80); + samplerDirty |= ImGui::Combo("Min", (int*)&inputSampler.mFilterMin, filterModes); + ImGui::SameLine(); + samplerDirty |= ImGui::Combo("Mag", (int*)&inputSampler.mFilterMag, filterModes); + ImGui::PopItemWidth(); + ImGui::PopID(); + ImGui::PopItemWidth(); + } + if (samplerDirty) + { + mModel.BeginTransaction(true); + mModel.SetSamplers(nodeIndex, samplers); + mModel.EndTransaction(); + mEditingContext.SetTargetDirty(nodeIndex, Dirty::Sampler); + } + } + if (!ImGui::CollapsingHeader(currentMeta.mName.c_str(), 0, ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::EndChild(); + return false; + } + + // edit parameters + for (size_t i = 0;i< currentMeta.mParams.size(); i++) + { + ImGui::PushID(667889 + i); + + dirty |= EditSingleParameter(nodeIndex, i, parameterBlock.Data(i), currentMeta.mParams[i]); + + ImGui::PopID(); + } + + // check for every possible inputs. only the first will be used for multiplexed inputs + for (unsigned int slotIndex = 0; slotIndex < 8; slotIndex++) + { + const std::vector& inputs = mEvaluationStages.mMultiplex[nodeIndex].mMultiplexPerInputs[slotIndex]; + NodeIndex currentMultiplexedOveride = mModel.GetMultiplexed(nodeIndex, slotIndex); // + + int selectedMultiplexIndex = ShowMultiplexed(inputs, currentMultiplexedOveride); + if (selectedMultiplexIndex != -1 && inputs[selectedMultiplexIndex] != currentMultiplexedOveride) + { + mModel.BeginTransaction(true); + mModel.SetMultiplexed(nodeIndex, slotIndex, int(inputs[selectedMultiplexIndex])); + mModel.EndTransaction(); + } + } + + ImGui::EndChild(); + return dirty; +} + +bool GraphControler::PinnedParameterUI(NodeIndex nodeIndex, size_t parameterIndex) +{ + bool pinned = mModel.IsParameterPinned(nodeIndex, parameterIndex); + ImGui::PushID(int(nodeIndex * 4096 + parameterIndex * 17)); + ImGui::PushStyleColor(ImGuiCol_Text, pinned ? ImVec4(1, 1, 1, 1) : ImVec4(1, 1, 1, 0.4)); + if (ImGui::Button(ICON_FA_THUMBTACK)) + { + mModel.BeginTransaction(true); + mModel.SetParameterPin(nodeIndex, parameterIndex, !pinned); + mModel.EndTransaction(); + } + ImGui::PopStyleColor(); + ImGui::PopID(); + return pinned; +} + +bool GraphControler::PinnedIOUI(NodeIndex nodeIndex, SlotIndex slotIndex, bool forOutput) +{ + if (mModel.IsIOUsed(nodeIndex, int(slotIndex), forOutput)) + { + return true; + } + ImGui::PushID(int(nodeIndex * 256 + slotIndex * 2 + (forOutput ? 1 : 0))); + bool pinned = mModel.IsIOPinned(nodeIndex, slotIndex, forOutput); + + ImGui::PushStyleColor(ImGuiCol_Text, pinned ? ImVec4(1, 1, 1, 1) : ImVec4(1, 1, 1, 0.4)); + if (ImGui::Button(ICON_FA_THUMBTACK)) + { + mModel.BeginTransaction(true); + mModel.SetIOPin(nodeIndex, slotIndex, forOutput, !pinned); + mModel.EndTransaction(); + } + ImGui::PopStyleColor(); + ImGui::PopID(); + return false; +} + +void GraphControler::NodeEdit() +{ + ApplyDirtyList(); + + ImGuiIO& io = ImGui::GetIO(); + + if (!mSelectedNodeIndex.IsValid()) + { + auto& io = mModel.GetIOPins(); + for (size_t nodeIndex = 0; nodeIndex < io.size(); nodeIndex++) + { + if ((io[nodeIndex] & 1) == 0) + { + continue; + } + ImGui::PushID(int(1717171 + nodeIndex)); + uint32_t parameterPair = (uint32_t(nodeIndex) << 16) + 0xDEAD; + if (!PinnedIOUI(nodeIndex, 0, true)) + { + ImGui::SameLine(); + } + ParameterBlock parameterBlock = mModel.GetParameterBlock(nodeIndex); + Imogen::RenderPreviewNode(int(nodeIndex), *this, parameterBlock); + ImGui::PopID(); + } + PinnedEdit(); + } + else + { + ParameterBlock parameterBlock = mModel.GetParameterBlock(mSelectedNodeIndex); + ImGui::PushID(1717171); + ImGui::BeginGroup(); + PinnedIOUI(mSelectedNodeIndex, 0, true); + bgfx::TextureHandle maxiMini = gImageCache.GetTexture("Stock/MaxiMini.png"); + bool selectedNodeAsBackground = mBackgroundNode == mSelectedNodeIndex; + float ofs = selectedNodeAsBackground ? 0.5f : 0.f; + /*if (ImGui::ImageButton( + (ImTextureID)(uint64_t)maxiMini.idx, ImVec2(12, 13), ImVec2(0.f + ofs, 1.f), ImVec2(0.5f + ofs, 0.f))) + { + if (!selectedNodeAsBackground) + { + mBackgroundNode = mSelectedNodeIndex; + } + else + { + mBackgroundNode.SetInvalid(); + } + } + */ + ImGui::EndGroup(); + ImGui::SameLine(); + bool dirty = Imogen::RenderPreviewNode(mSelectedNodeIndex, *this, parameterBlock); + ImGui::PopID(); + + dirty |= EditNodeParameters(parameterBlock); + + if (dirty) + { + mModel.BeginTransaction(true); + mModel.SetParameterBlock(mSelectedNodeIndex, parameterBlock); + mModel.EndTransaction(); + } + } +} + +void GraphControler::ApplyDirtyList() +{ + // apply dirty list + const auto& dirtyList = mModel.GetDirtyList(); + bool evaluationOrderChanged = false; + bool graphArrayChanged = false; + + std::vector deletionInEvaluation; + + for (const auto& dirtyItem : dirtyList) + { + NodeIndex nodeIndex = dirtyItem.mNodeIndex; + switch(dirtyItem.mFlags) + { + case Dirty::Input: + evaluationOrderChanged = true; + graphArrayChanged = true; + mEditingContext.SetTargetDirty(nodeIndex, Dirty::Input); + break; + case Dirty::Parameter: + mEvaluationStages.SetParameterBlock(nodeIndex, mModel.GetParameterBlock(nodeIndex)); + mEditingContext.SetTargetDirty(nodeIndex, Dirty::Parameter); + break; + case Dirty::VisualGraph: + graphArrayChanged = true; + break; + case Dirty::Mouse: + break; + case Dirty::Camera: + break; + case Dirty::Time: + break; + case Dirty::RugChanged: + graphArrayChanged = true; + break; + case Dirty::Sampler: + mEvaluationStages.SetSamplers(nodeIndex, mModel.GetSamplers(nodeIndex)); + mEditingContext.SetTargetDirty(nodeIndex, Dirty::Sampler); + break; + case Dirty::AddedNode: + { + int startFrame, endFrame; + mModel.GetStartEndFrame(nodeIndex, startFrame, endFrame); + mEvaluationStages.AddEvaluation(nodeIndex, mModel.GetNodeType(nodeIndex)); + mEditingContext.AddEvaluation(nodeIndex); + evaluationOrderChanged = true; + graphArrayChanged = true; + // params + mEvaluationStages.SetParameterBlock(nodeIndex, mModel.GetParameterBlock(nodeIndex)); + // samplers + mEvaluationStages.SetSamplers(nodeIndex, mModel.GetSamplers(nodeIndex)); + // time + mEvaluationStages.SetStartEndFrame(nodeIndex, startFrame, endFrame); + //dirty + mEditingContext.SetTargetDirty(nodeIndex, Dirty::Parameter | Dirty::Sampler); + ExtractedViewNodeInserted(nodeIndex); + UICallbackNodeInserted(nodeIndex); + } + break; + case Dirty::DeletedNode: + mEditingContext.SetTargetDirty(nodeIndex, Dirty::Input, false); + deletionInEvaluation.push_back(nodeIndex); + evaluationOrderChanged = true; + graphArrayChanged = true; + ExtractedViewNodeDeleted(nodeIndex); + UICallbackNodeDeleted(nodeIndex); + if (mSelectedNodeIndex.IsValid()) + { + if (mSelectedNodeIndex == nodeIndex) + { + mSelectedNodeIndex = InvalidNodeIndex; + } + else if (mSelectedNodeIndex > nodeIndex) + { + mSelectedNodeIndex --; + } + } + if (mBackgroundNode.IsValid()) + { + if (mBackgroundNode == nodeIndex) + { + mBackgroundNode = InvalidNodeIndex; + } + else if (mBackgroundNode > nodeIndex) + { + mBackgroundNode --; + } + } + break; + case Dirty::StartEndTime: + { + int times[2]; + mModel.GetStartEndFrame(nodeIndex, times[0], times[1]); + mEvaluationStages.SetStartEndFrame(nodeIndex, times[0], times[1]); + } + break; + } + } + + for (auto nodeIndex : deletionInEvaluation) + { + mEvaluationStages.DelEvaluation(nodeIndex); + mEditingContext.DelEvaluation(nodeIndex); + } + + if (evaluationOrderChanged) + { + mModel.GetInputs(mEvaluationStages.mInputs, mEvaluationStages.mDirectInputs); + mEvaluationStages.ComputeEvaluationOrder(); + } + + // second pass for multiplex : get nodes and children + std::set multiplexDrityList; + for (const auto& dirtyItem : dirtyList) + { + NodeIndex nodeIndex = dirtyItem.mNodeIndex; + switch (dirtyItem.mFlags) + { + case Dirty::Input: + { + auto evaluationOrderList = mEvaluationStages.GetForwardEvaluationOrder(); + multiplexDrityList.insert(nodeIndex); + for (size_t i = 0; i < evaluationOrderList.size(); i++) + { + size_t currentNodeIndex = evaluationOrderList[i]; + if (currentNodeIndex != nodeIndex) + { + continue; + } + for (i++; i < evaluationOrderList.size(); i++) + { + currentNodeIndex = evaluationOrderList[i]; + multiplexDrityList.insert(currentNodeIndex); + } + } + } + break; + default: + break; + } + } + + // update multiplex list for all subsequent nodes + for (auto nodeIndex : multiplexDrityList) + { + if (std::find(deletionInEvaluation.begin(), deletionInEvaluation.end(), nodeIndex) == deletionInEvaluation.end()) + { + for (int i = 0; i < 8; i++) + { + auto& multiplexList = mEvaluationStages.mMultiplex[nodeIndex].mMultiplexPerInputs[i]; + multiplexList.clear(); + mModel.GetMultiplexedInputs(mEvaluationStages.mDirectInputs, nodeIndex, i, multiplexList); + } + } + } + + if (graphArrayChanged) + { + ComputeGraphArrays(); + } + + mModel.ClearDirtyList(); +} + +void GraphControler::SetKeyboardMouse(NodeIndex nodeIndex, const UIInput& input, bool bValidInput) +{ + if (!nodeIndex.IsValid()) + { + return; + } + + if (!input.mLButDown) + { + mbMouseDragging = false; + } + + if (!input.mLButDown && !input.mRButDown && mModel.InTransaction() && mbUsingMouse) + { + mModel.EndTransaction(); + mbUsingMouse = false; + } + + size_t res = 0; + const MetaNode& metaNode = gMetaNodes[mModel.GetNodeType(nodeIndex)]; + + ParameterBlock parameterBlock = mModel.GetParameterBlock(nodeIndex); + bool parametersDirty = false; + + Camera* camera = parameterBlock.GetCamera(); + if (camera) + { + if (fabsf(input.mWheel)>0.f) + { + camera->mPosition += camera->mDirection * input.mWheel; + parametersDirty = true; + } + Vec4 right = Cross(camera->mUp, camera->mDirection); + right.y = 0.f; // keep head up + right.Normalize(); + auto& io = ImGui::GetIO(); + if (io.KeyAlt) + { + if (io.MouseDown[2]) + { + camera->mPosition += (right * io.MouseDelta.x + camera->mUp * io.MouseDelta.y) * 0.01f; + parametersDirty = true; + } + if (io.MouseDown[1]) + { + camera->mPosition += (camera->mDirection * io.MouseDelta.y) * 0.01f; + parametersDirty = true; + } + if (io.MouseDown[0]) + { + Mat4x4 tr, rtUp, rtRight, trp; + tr.Translation(-(camera->mPosition)); + rtRight.RotationAxis(right, io.MouseDelta.y * 0.01f); + rtUp.RotationAxis(camera->mUp, -io.MouseDelta.x * 0.01f); + trp.Translation((camera->mPosition)); + Mat4x4 res = tr * rtRight * rtUp * trp; + camera->mPosition.TransformPoint(res); + camera->mDirection.TransformVector(res); + camera->mUp.Cross(camera->mDirection, right); + camera->mUp.Normalize(); + parametersDirty = true; + } + } + } + + // + if (input.mLButDown) + { + for (size_t i = 0; i < metaNode.mParams.size(); i++) + { + const auto& param = metaNode.mParams[i]; + float* paramFlt = (float*)parameterBlock.Data(i); + if (param.mbQuadSelect && param.mType == Con_Float4) + { + parametersDirty = true; + if (!mbMouseDragging) + { + paramFlt[2] = paramFlt[0] = input.mRx; + paramFlt[3] = paramFlt[1] = 1.f - input.mRy; + mbMouseDragging = true; + } + else + { + paramFlt[2] = input.mRx; + paramFlt[3] = 1.f - input.mRy; + } + continue; + } + + if (param.mRangeMinX != 0.f || param.mRangeMaxX != 0.f) + { + parametersDirty = true; + if (param.mbRelative) + { + paramFlt[0] += (param.mRangeMaxX - param.mRangeMinX) * input.mDx; + if (param.mbLoop) + paramFlt[0] = fmodf(paramFlt[0], fabsf(param.mRangeMaxX - param.mRangeMinX)) + + Min(param.mRangeMinX, param.mRangeMaxX); + } + else + { + paramFlt[0] = ImLerp(param.mRangeMinX, param.mRangeMaxX, input.mRx); + } + } + if (param.mRangeMinY != 0.f || param.mRangeMaxY != 0.f) + { + parametersDirty = true; + if (param.mbRelative) + { + paramFlt[1] += (param.mRangeMaxY - param.mRangeMinY) * input.mDy; + if (param.mbLoop) + paramFlt[1] = fmodf(paramFlt[1], fabsf(param.mRangeMaxY - param.mRangeMinY)) + + Min(param.mRangeMinY, param.mRangeMaxY); + } + else + { + paramFlt[1] = ImLerp(param.mRangeMinY, param.mRangeMaxY, input.mRx); + } + } + } + } + if (metaNode.mbHasUI || parametersDirty) + { + mEditingContext.SetKeyboardMouse(nodeIndex, input); + + if ((input.mLButDown || input.mRButDown) && !mModel.InTransaction() && parametersDirty && bValidInput) + { + mModel.BeginTransaction(true); + mbUsingMouse = true; + } + if (parametersDirty && mModel.InTransaction() && bValidInput) + { + mModel.SetParameterBlock(nodeIndex, parameterBlock); + } + mEditingContext.SetTargetDirty(nodeIndex, Dirty::Mouse); + } +} + +void GraphControler::ContextMenu(ImVec2 rightclickPos, ImVec2 worldMousePos, int nodeHovered) +{ + ImGuiIO& io = ImGui::GetIO(); + size_t metaNodeCount = gMetaNodes.size(); + const MetaNode* metaNodes = gMetaNodes.data(); + const auto& nodes = mModel.GetNodes(); + + bool copySelection = false; + bool deleteSelection = false; + bool pasteSelection = false; + + // Draw context menu + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); + if (ImGui::BeginPopup("context_menu")) + { + auto* node = nodeHovered != -1 ? &nodes[nodeHovered] : NULL; + if (node) + { + ImGui::Text("%s", metaNodes[node->mNodeType].mName.c_str()); + ImGui::Separator(); + + if (ImGui::MenuItem("Extract view", NULL, false)) + { + AddExtractedView(nodeHovered); + } + } + else + { + static char inputText[64] = { 0 }; + + auto AddNode = [&](int nodeType) { + mModel.BeginTransaction(true); + mModel.AddNode(nodeType, rightclickPos); + mModel.EndTransaction(); + inputText[0] = 0; + }; + + + if (ImGui::IsWindowAppearing()) + { + ImGui::SetKeyboardFocusHere(); + } + ImGui::InputText("", inputText, sizeof(inputText)); + { + if (strlen(inputText)) + { + for (int i = 0; i < metaNodeCount; i++) + { + const char* nodeName = metaNodes[i].mName.c_str(); + bool displayNode = + !strlen(inputText) || + ImStristr(nodeName, nodeName + strlen(nodeName), inputText, inputText + strlen(inputText)); + if (displayNode && ImGui::MenuItem(nodeName, NULL, false)) + { + AddNode(i); + } + } + } + else + { + for (int i = 0; i < metaNodeCount; i++) + { + const char* nodeName = metaNodes[i].mName.c_str(); + if (metaNodes[i].mCategory == -1 && ImGui::MenuItem(nodeName, NULL, false)) + { + AddNode(i); + } + } + + const auto& categories = MetaNode::mCategories; + for (unsigned int iCateg = 0; iCateg < categories.size(); iCateg++) + { + if (ImGui::BeginMenu(categories[iCateg].c_str())) + { + for (int i = 0; i < metaNodeCount; i++) + { + const char* nodeName = metaNodes[i].mName.c_str(); + if (metaNodes[i].mCategory == iCateg && ImGui::MenuItem(nodeName, NULL, false)) + { + AddNode(i); + } + } + ImGui::EndMenu(); + } + } + } + } + } + + ImGui::Separator(); + if (ImGui::MenuItem("Add rug", NULL, false)) + { + GraphModel::Rug rug = { + rightclickPos, ImVec2(400, 200), 0xFFA0A0A0, "Description\nEdit me with a double click."}; + mModel.BeginTransaction(true); + mModel.AddRug(rug); + mModel.EndTransaction(); + } + ImGui::Separator(); + if (ImGui::MenuItem("Delete", "Del", false)) + { + deleteSelection = true; + } + if (ImGui::MenuItem("Copy", "CTRL+C")) + { + copySelection = true; + } + if (ImGui::MenuItem("Paste", "CTRL+V", false, !mModel.IsClipboardEmpty())) + { + pasteSelection = true; + } + + ImGui::EndPopup(); + } + ImGui::PopStyleVar(); + + if (copySelection || (ImGui::IsWindowFocused() && io.KeyCtrl && ImGui::IsKeyPressedMap(ImGuiKey_C))) + { + mModel.CopySelectedNodes(); + } + + if (deleteSelection || (ImGui::IsWindowFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Delete))) + { + mModel.CutSelectedNodes(); + } + + if (pasteSelection || (ImGui::IsWindowFocused() && io.KeyCtrl && ImGui::IsKeyPressedMap(ImGuiKey_V))) + { + mModel.PasteNodes(worldMousePos); + } +} + +bool GraphControler::NodeIs2D(NodeIndex nodeIndex) const +{ + auto target = mEditingContext.GetRenderTarget(nodeIndex); + if (target) + { + return !target->mImage.mIsCubemap; + } + return false; +} + +bool GraphControler::NodeIsCompute(NodeIndex nodeIndex) const +{ + return (gEvaluators.GetMask(mModel.GetNodeType(nodeIndex)) & EvaluationGLSLCompute) != 0; +} + +bool GraphControler::NodeIsCubemap(NodeIndex nodeIndex) const +{ + auto target = mEditingContext.GetRenderTarget(nodeIndex); + if (target) + { + return target->mImage.mIsCubemap; + } + return false; +} + +ImVec2 GraphControler::GetEvaluationSize(NodeIndex nodeIndex) const +{ + int imageWidth(1), imageHeight(1); + EvaluationAPI::GetEvaluationSize(&mEditingContext, int(nodeIndex), &imageWidth, &imageHeight); + return ImVec2(float(imageWidth), float(imageHeight)); +} + +void GraphControler::DrawNodeImage(ImDrawList* drawList, + const ImRect& rc, + const ImVec2 marge, + const NodeIndex nodeIndex) +{ + const auto& nodes = mModel.GetNodes(); + auto& meta = gMetaNodes[nodes[nodeIndex].mNodeType]; + if (!meta.mbThumbnail) + { + return; + } + + bool nodeIsCompute = NodeIsCompute(nodeIndex); + if (nodeIsCompute) + { + return; + } + if (NodeIsProcesing(nodeIndex) == 1) + { + AddUICustomDraw(drawList, rc, DrawUICallbacks::DrawUIProgress, nodeIndex, &mEditingContext); + } + else + { + bgfx::TextureHandle textureHandle{bgfx::kInvalidHandle}; + ImRect uvs; + mEditingContext.GetThumb(nodeIndex, textureHandle, uvs); + if (textureHandle.idx != bgfx::kInvalidHandle) + { + drawList->AddRectFilled(rc.Min, rc.Max, 0xFF000000); + drawList->AddImage((ImTextureID)(int64_t)textureHandle.idx, + rc.Min + marge, + rc.Max - marge, + uvs.Min, + uvs.Max); + } + } +} + +bool GraphControler::RenderBackground() +{ + /*if (mBackgroundNode.IsValid()) + { + Imogen::RenderPreviewNode(mBackgroundNode, *this, true); + return true; + }*/ + return false; +} + +void GraphControler::ComputeGraphArrays() +{ + const auto& nodes = mModel.GetNodes(); + const auto& rugs = mModel.GetRugs(); + const auto& links = mModel.GetLinks(); + + mNodes.resize(nodes.size()); + mRugs.resize(rugs.size()); + mLinks.resize(links.size()); + + for (auto i = 0; i < rugs.size(); i++) + { + const auto& r = rugs[i]; + mRugs[i] = {ImRect(r.mPos, r.mPos + r.mSize), r.mText.c_str(), r.mColor}; + } + + for (auto i = 0; i < links.size(); i++) + { + const auto& l = links[i]; + mLinks[i] = {l.mInputNodeIndex, l.mInputSlotIndex, l.mOutputNodeIndex, l.mOutputSlotIndex}; + } + + for (auto i = 0; i < nodes.size(); i++) + { + auto& n = nodes[i]; + auto& meta = gMetaNodes[n.mNodeType]; + + std::vector inp(meta.mInputs.size(), nullptr); + std::vector outp(meta.mOutputs.size(), nullptr); + for (auto in = 0; in < meta.mInputs.size(); in++) + { + inp[in] = meta.mInputs[in].mName.c_str(); + } + for (auto ou = 0; ou < meta.mOutputs.size(); ou++) + { + outp[ou] = meta.mOutputs[ou].mName.c_str(); + } + + mNodes[i] = {meta.mName.c_str() + , ImRect(n.mPos, n.mPos + ImVec2(float(meta.mWidth), float(meta.mHeight))) + , meta.mHeaderColor + , meta.mbExperimental ? IM_COL32(80, 50, 20, 255) : IM_COL32(60, 60, 60, 255) + , inp + , outp + , n.mbSelected}; + } +} + +bgfx::TextureHandle GraphControler::GetBitmapInfo(NodeIndex nodeIndex) const +{ + bgfx::TextureHandle stage2D = gImageCache.GetTexture("Stock/Stage2D.png"); + bgfx::TextureHandle stagecubemap = gImageCache.GetTexture("Stock/StageCubemap.png"); + bgfx::TextureHandle stageCompute = gImageCache.GetTexture("Stock/StageCompute.png"); + + if (NodeIsCompute(nodeIndex)) + { + return stageCompute; + } + else if (NodeIs2D(nodeIndex)) + { + return stage2D; + } + else if (NodeIsCubemap(nodeIndex)) + { + return stagecubemap; + } + return {0}; +} + diff --git a/src/GraphControler.h b/src/GraphControler.h new file mode 100644 index 00000000..839c02e3 --- /dev/null +++ b/src/GraphControler.h @@ -0,0 +1,104 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +#pragma once + +#include "GraphEditor.h" +#include "EvaluationStages.h" +#include "EvaluationContext.h" +#include "GraphModel.h" + +struct GraphControler : public GraphEditorDelegate +{ + GraphControler(); + + void Clear(); + + void SetKeyboardMouse(NodeIndex nodeIndex, const UIInput& input, bool bValidInput); + + // accessors + int NodeIsProcesing(NodeIndex nodeIndex) const override { return mEditingContext.StageIsProcessing(nodeIndex); } + float NodeProgress(NodeIndex nodeIndex) const override { return mEditingContext.StageGetProgress(nodeIndex); } + bool NodeIsCubemap(NodeIndex nodeIndex) const override; + bool NodeIs2D(NodeIndex nodeIndex) const override; + bool NodeIsCompute(NodeIndex nodeIndex) const override; + ImVec2 GetEvaluationSize(NodeIndex nodeIndex) const override; + bool RecurseIsLinked(NodeIndex from, NodeIndex to) const override { return mModel.RecurseIsLinked(from, to); } + bool IsIOPinned(NodeIndex nodeIndex, size_t io, bool forOutput) const override { return mModel.IsIOPinned(nodeIndex, io, forOutput); } + bgfx::TextureHandle GetBitmapInfo(NodeIndex nodeIndex) const override; + + // operations + bool InTransaction() override { return mModel.InTransaction(); } + void BeginTransaction(bool undoable) override { mModel.BeginTransaction(undoable); } + void EndTransaction() override { mModel.EndTransaction(); } + + void DelRug(size_t rugIndex) override { mModel.DelRug(rugIndex); } + void SelectNode(NodeIndex nodeIndex, bool selected) override { mModel.SelectNode(nodeIndex, selected); } + void MoveSelectedNodes(const ImVec2 delta) override { mModel.MoveSelectedNodes(delta); } + + void AddLink(NodeIndex inputNodeIndex, SlotIndex inputSlotIndex, NodeIndex outputNodeIndex, SlotIndex outputSlotIndex) override { mModel.AddLink(inputNodeIndex, inputSlotIndex, outputNodeIndex, outputSlotIndex); } + void DelLink(size_t linkIndex) override { mModel.DelLink(linkIndex); } + + void SetRug(size_t rugIndex, const ImRect& rect, const char *szText, uint32_t color) override { mModel.SetRug(rugIndex, GraphModel::Rug{rect.Min, rect.GetSize(), color, std::string(szText)}); } + + // accessors + const std::vector& GetNodes() const override { return mNodes; } + const std::vector& GetRugs() const override { return mRugs; } + const std::vector& GetLinks() const override { return mLinks; } + + void SetMaterialUniqueId(RuntimeId runtimeId); + + // UI + void NodeEdit(); + virtual void DrawNodeImage(ImDrawList* drawList, const ImRect& rc, const ImVec2 marge, NodeIndex nodeIndex) override; + virtual bool RenderBackground() override; + virtual void ContextMenu(ImVec2 rightclickPos, ImVec2 worldMousePos, int nodeHovered) override; + + EvaluationStages mEvaluationStages; + EvaluationContext mEditingContext; + NodeIndex mBackgroundNode{InvalidNodeIndex}; + + void ApplyDirtyList(); + GraphModel mModel; + +protected: + bool mbMouseDragging; + bool mbUsingMouse; + + std::vector mNodes; + std::vector mRugs; + std::vector mLinks; + + bool EditSingleParameter(NodeIndex nodeIndex, + unsigned int parameterIndex, + void* paramBuffer, + const MetaParameter& param); + void PinnedEdit(); + bool EditNodeParameters(ParameterBlock& parameterBlock); + bool PinnedParameterUI(NodeIndex nodeIndex, size_t parameterIndex); + // return true if io is used and UI is not displayed + bool PinnedIOUI(NodeIndex nodeIndex, SlotIndex slotIndex, bool forOutput); + int ShowMultiplexed(const std::vector& inputs, NodeIndex currentMultiplexedOveride) const; + void ComputeGraphArrays(); +}; diff --git a/src/GraphEditor.cpp b/src/GraphEditor.cpp new file mode 100644 index 00000000..2214e850 --- /dev/null +++ b/src/GraphEditor.cpp @@ -0,0 +1,1115 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "Platform.h" +#include "imgui.h" +#include "imgui_internal.h" +#include "imgui_stdlib.h" +#include "imgui_markdown/imgui_markdown.h" +#include +#include +#include +#include +#include "GraphEditor.h" + +extern ImGui::MarkdownConfig mdConfig; + +static inline float Distance(ImVec2& a, ImVec2& b) +{ + return sqrtf((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); +} + +static inline float sign(float v) +{ + return (v >= 0.f) ? 1.f : -1.f; +} + +ImVec2 GetInputSlotPos(const GraphEditorDelegate::Node& node, int slot_no, float factor) +{ + ImVec2 Size = node.mRect.GetSize() * factor; + size_t InputsCount = node.mInputs.size(); + return ImVec2(node.mRect.Min.x * factor, + node.mRect.Min.y * factor + Size.y * ((float)slot_no + 1) / ((float)InputsCount + 1) + 8.f); +} +ImVec2 GetOutputSlotPos(const GraphEditorDelegate::Node& node, int slot_no, float factor) +{ + ImVec2 Size = node.mRect.GetSize() * factor; + size_t OutputsCount = node.mOutputs.size(); + return ImVec2(node.mRect.Min.x * factor + Size.x, + node.mRect.Min.y * factor + Size.y * ((float)slot_no + 1) / ((float)OutputsCount + 1) + 8.f); +} +ImRect GetNodeRect(const GraphEditorDelegate::Node& node, float factor) +{ + ImVec2 Size = node.mRect.GetSize() * factor; + return ImRect(node.mRect.Min * factor, node.mRect.Min * factor + Size); +} + +const float NODE_SLOT_RADIUS = 8.0f; +const ImVec2 NODE_WINDOW_PADDING(8.0f, 8.0f); + +static int editRug = -1; + +static ImVec2 editingNodeSource; +bool editingInput = false; +static ImVec2 scrolling = ImVec2(0.0f, 0.0f); +float factor = 1.0f; +float factorTarget = 1.0f; +ImVec2 captureOffset; + +enum NodeOperation +{ + NO_None, + NO_EditingLink, + NO_QuadSelecting, + NO_MovingNodes, + NO_EditInput, + NO_MovingRug, + NO_SizingRug, + NO_PanView, +}; +NodeOperation nodeOperation = NO_None; + +void HandleZoomScroll(ImRect regionRect) +{ + ImGuiIO& io = ImGui::GetIO(); + + if (regionRect.Contains(io.MousePos)) + { + if (io.MouseWheel < -FLT_EPSILON) + factorTarget *= 0.9f; + + if (io.MouseWheel > FLT_EPSILON) + factorTarget *= 1.1f; + } + + ImVec2 mouseWPosPre = (io.MousePos - ImGui::GetCursorScreenPos()) / factor; + factorTarget = ImClamp(factorTarget, 0.2f, 3.f); + factor = ImLerp(factor, factorTarget, 0.15f); + ImVec2 mouseWPosPost = (io.MousePos - ImGui::GetCursorScreenPos()) / factor; + if (ImGui::IsMousePosValid()) + { + scrolling += mouseWPosPost - mouseWPosPre; + } +} + +void GraphEditorClear() +{ + editRug = -1; + nodeOperation = NO_None; + factor = 1.0f; + factorTarget = 1.0f; +} + +int DisplayRugs(GraphEditorDelegate* delegate, int editRug, ImDrawList* drawList, ImVec2 offset, float factor) +{ + ImGuiIO& io = ImGui::GetIO(); + int ret = editRug; + + const auto& nodes = delegate->GetNodes(); + const auto& rugs = delegate->GetRugs(); + + // mouse pointer over any node? + bool overAnyNode = false; + for (auto& node : nodes) + { + ImVec2 node_rect_min = offset + node.mRect.Min * factor; + ImVec2 node_rect_max = node_rect_min + node.mRect.GetSize() * factor; + if (ImRect(node_rect_min, node_rect_max).Contains(io.MousePos)) + { + overAnyNode = true; + break; + } + } + + for (unsigned int rugIndex = 0; rugIndex < rugs.size(); rugIndex++) + { + auto& rug = rugs[rugIndex]; + if (rugIndex == editRug) + continue; + ImGui::PushID(900 + rugIndex); + ImVec2 commentSize = rug.mRect.GetSize() * factor; + + ImVec2 node_rect_min = offset + rug.mRect.Min * factor; + + ImGui::SetCursorScreenPos(node_rect_min + NODE_WINDOW_PADDING); + + ImVec2 node_rect_max = node_rect_min + commentSize; + + ImRect rugRect(node_rect_min, node_rect_max); + if (rugRect.Contains(io.MousePos) && !overAnyNode) + { + if (io.MouseDoubleClicked[0]) + { + ret = rugIndex; + } + else if (io.KeyShift && ImGui::IsMouseClicked(0)) + { + for (auto i = 0; i < nodes.size(); i++) + { + auto& node = nodes[i]; + ImVec2 node_rect_min = offset + node.mRect.Min * factor; + ImVec2 node_rect_max = node_rect_min + node.mRect.GetSize() * factor; + if (rugRect.Overlaps(ImRect(node_rect_min, node_rect_max))) + { + delegate->SelectNode(i, true); + } + } + } + } + // drawList->AddText(io.FontDefault, 13 * ImLerp(1.f, factor, 0.5f), node_rect_min + ImVec2(5, 5), (rug.mColor & + // 0xFFFFFF) + 0xFF404040, rug.mText.c_str()); + ImGui::SetCursorScreenPos(node_rect_min + NODE_WINDOW_PADDING); + ImGui::PushStyleColor(ImGuiCol_FrameBg, 0x0); + ImGui::PushStyleColor(ImGuiCol_Border, 0x0); + ImGui::BeginChildFrame( + 88 + rugIndex, commentSize - NODE_WINDOW_PADDING * 2, ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav); + + ImGui::Markdown(rug.mText, strlen(rug.mText), mdConfig); + drawList->AddRectFilled(node_rect_min, node_rect_max, (rug.mColor & 0xFFFFFF) + 0x60000000, 10.0f, 15); + drawList->AddRect(node_rect_min, node_rect_max, (rug.mColor & 0xFFFFFF) + 0x90000000, 10.0f, 15, 2.f); + ImGui::EndChildFrame(); + ImGui::PopStyleColor(2); + ImGui::PopID(); + } + return ret; +} + +bool EditRug(GraphEditorDelegate *delegate, int rugIndex, ImDrawList* drawList, ImVec2 offset, float factor) +{ + ImGuiIO& io = ImGui::GetIO(); + const auto& rugs = delegate->GetRugs(); + ImVec2 commentSize = rugs[rugIndex].mRect.GetSize() * factor; + static int movingSizingRug = -1; + GraphEditorDelegate::Rug rug = rugs[rugIndex]; + static GraphEditorDelegate::Rug editingRug; + static GraphEditorDelegate::Rug editingRugSource; + + bool dirtyRug = false; + ImVec2 node_rect_min = offset + rug.mRect.Min * factor; + ImVec2 node_rect_max = node_rect_min + commentSize; + ImRect rugRect(node_rect_min, node_rect_max); + ImRect insideSizingRect(node_rect_min + commentSize - ImVec2(30, 30), node_rect_min + commentSize); + ImGui::SetCursorScreenPos(node_rect_min + NODE_WINDOW_PADDING); + + + drawList->AddRectFilled(node_rect_min, node_rect_max, (rug.mColor & 0xFFFFFF) + 0xE0000000, 10.0f, 15); + drawList->AddRect(node_rect_min, node_rect_max, (rug.mColor & 0xFFFFFF) + 0xFF000000, 10.0f, 15, 2.f); + drawList->AddTriangleFilled(node_rect_min + commentSize - ImVec2(25, 8), + node_rect_min + commentSize - ImVec2(8, 25), + node_rect_min + commentSize - ImVec2(8, 8), + (rug.mColor & 0xFFFFFF) + 0x90000000); + + ImGui::SetCursorScreenPos(node_rect_min + ImVec2(5, 5)); + ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(0, 0, 0, 0)); + ImGui::PushStyleColor(ImGuiCol_Border, IM_COL32(0, 0, 0, 0)); + std::string str = rug.mText; + dirtyRug |= ImGui::InputTextMultiline("", &str, (node_rect_max - node_rect_min) - ImVec2(30, 30)); + ImGui::PopStyleColor(2); + + ImGui::SetCursorScreenPos(node_rect_min + ImVec2(10, commentSize.y - 30)); + for (int i = 0; i < 7; i++) + { + if (i > 0) + ImGui::SameLine(); + ImGui::PushID(i); + ImColor buttonColor = ImColor::HSV(i / 7.0f, 0.6f, 0.6f); + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); + if (ImGui::Button(" ")) + { + rug.mColor = buttonColor; + dirtyRug = true; + } + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + ImGui::SameLine(0, 50); + + if (ImGui::Button("Delete")) + { + delegate->BeginTransaction(true); + delegate->DelRug(rugIndex); + delegate->EndTransaction(); + return true; + } + + bool createUndo = false; + bool commitUndo = false; + + if (insideSizingRect.Contains(io.MousePos)) + { + if (nodeOperation == NO_None && ImGui::IsMouseDragging(0, 1)) + { + movingSizingRug = rugIndex; + createUndo = true; + nodeOperation = NO_SizingRug; + editingRugSource = editingRug = rug; + } + } + + if (rugRect.Contains(io.MousePos) && !insideSizingRect.Contains(io.MousePos)) + { + if (nodeOperation == NO_None && ImGui::IsMouseDragging(0, 1)) + { + movingSizingRug = rugIndex; + createUndo = true; + nodeOperation = NO_MovingRug; + editingRugSource = editingRug = rug; + } + } + + if (movingSizingRug != -1 && !io.MouseDown[0]) + { + commitUndo = true; + nodeOperation = NO_None; + } + + // undo/redo for sizing/moving + if (commitUndo) + { + // set back value + delegate->BeginTransaction(false); + delegate->SetRug(movingSizingRug, editingRugSource.mRect, editingRugSource.mText, editingRugSource.mColor); + delegate->EndTransaction(); + + // add undo + delegate->BeginTransaction(true); + delegate->SetRug(movingSizingRug, editingRug.mRect, editingRug.mText, editingRug.mColor); + delegate->EndTransaction(); + movingSizingRug = -1; + } + + if (dirtyRug) + { + delegate->BeginTransaction(true); + delegate->SetRug(rugIndex, rug.mRect, str.c_str(), rug.mColor); + delegate->EndTransaction(); + } + + if (movingSizingRug != -1 && ImGui::IsMouseDragging(0)) + { + if (nodeOperation == NO_MovingRug) + { + editingRug.mRect.Min += io.MouseDelta * factor; + } + editingRug.mRect.Max += io.MouseDelta * factor; + + delegate->BeginTransaction(false); + delegate->SetRug(movingSizingRug, editingRug.mRect, editingRug.mText, editingRug.mColor); + delegate->EndTransaction(); + } + + if ((io.MouseClicked[0] || io.MouseClicked[1]) && !rugRect.Contains(io.MousePos)) + return true; + return false; +} + +void GraphEditorUpdateScrolling(GraphEditorDelegate *delegate) +{ + const auto& nodes = delegate->GetNodes(); + const auto& rugs = delegate->GetRugs(); + + if (nodes.empty() && rugs.empty()) + return; + + if (!nodes.empty()) + { + scrolling = nodes[0].mRect.Min; + } + else if (!rugs.empty()) + { + scrolling = rugs[0].mRect.Min; + } + else + { + scrolling = ImVec2(0, 0); + } + for (auto& node : nodes) + { + scrolling.x = std::min(scrolling.x, node.mRect.Min.x); + scrolling.y = std::min(scrolling.y, node.mRect.Min.y); + } + for (auto& rug : rugs) + { + scrolling.x = std::min(scrolling.x, rug.mRect.Min.x); + scrolling.y = std::min(scrolling.y, rug.mRect.Min.y); + } + + scrolling = ImVec2(40, 40) - scrolling; +} + +static void DisplayLinks(GraphEditorDelegate* delegate, + ImDrawList* drawList, + const ImVec2 offset, + const float factor, + const ImRect regionRect, + int hoveredNode) +{ + const auto& links = delegate->GetLinks(); + const auto& nodes = delegate->GetNodes(); + for (int link_idx = 0; link_idx < links.size(); link_idx++) + { + const auto* link = &links[link_idx]; + const auto* node_inp = &nodes[link->mInputNodeIndex]; + const auto* node_out = &nodes[link->mOutputNodeIndex]; + ImVec2 p1 = offset + GetOutputSlotPos(*node_inp, link->mInputSlotIndex, factor); + ImVec2 p2 = offset + GetInputSlotPos(*node_out, link->mOutputSlotIndex, factor); + + // con. view clipping + if ((p1.y < 0.f && p2.y < 0.f) || (p1.y > regionRect.Max.y && p2.y > regionRect.Max.y) || + (p1.x < 0.f && p2.x < 0.f) || (p1.x > regionRect.Max.x && p2.x > regionRect.Max.x)) + continue; + + bool highlightCons = hoveredNode == link->mInputNodeIndex || hoveredNode == link->mOutputNodeIndex; + uint32_t col = node_inp->mHeaderColor | (highlightCons ? 0xF0F0F0 : 0); + ; + // curves + // drawList->AddBezierCurve(p1, p1 + ImVec2(+50, 0) * factor, p2 + ImVec2(-50, 0) * factor, p2, 0xFF000000, 4.f + // * factor); drawList->AddBezierCurve(p1, p1 + ImVec2(+50, 0) * factor, p2 + ImVec2(-50, 0) * factor, p2, + // col, 3.0f * factor); + + // -/- + /* + ImVec2 p10 = p1 + ImVec2(20.f * factor, 0.f); + ImVec2 p20 = p2 - ImVec2(20.f * factor, 0.f); + + ImVec2 dif = p20 - p10; + ImVec2 p1a, p1b; + if (fabsf(dif.x) > fabsf(dif.y)) + { + p1a = p10 + ImVec2(fabsf(fabsf(dif.x) - fabsf(dif.y)) * 0.5 * sign(dif.x), 0.f); + p1b = p1a + ImVec2(fabsf(dif.y) * sign(dif.x) , dif.y); + } + else + { + p1a = p10 + ImVec2(0.f, fabsf(fabsf(dif.y) - fabsf(dif.x)) * 0.5 * sign(dif.y)); + p1b = p1a + ImVec2(dif.x, fabsf(dif.x) * sign(dif.y)); + } + drawList->AddLine(p1, p10, col, 3.f * factor); + drawList->AddLine(p10, p1a, col, 3.f * factor); + drawList->AddLine(p1a, p1b, col, 3.f * factor); + drawList->AddLine(p1b, p20, col, 3.f * factor); + drawList->AddLine(p20, p2, col, 3.f * factor); + */ + std::array pts; + int ptCount = 0; + ImVec2 dif = p2 - p1; + + ImVec2 p1a, p1b; + const float limitx = 12.f * factor; + if (dif.x < limitx) + { + ImVec2 p10 = p1 + ImVec2(limitx, 0.f); + ImVec2 p20 = p2 - ImVec2(limitx, 0.f); + + dif = p20 - p10; + p1a = p10 + ImVec2(0.f, dif.y * 0.5f); + p1b = p1a + ImVec2(dif.x, 0.f); + + pts = {p1, p10, p1a, p1b, p20, p2}; + ptCount = 6; + } + else + { + if (fabsf(dif.y) < 1.f) + { + pts = {p1, (p1 + p2) * 0.5f, p2}; + ptCount = 3; + } + else + { + if (fabsf(dif.y) < 10.f) + { + if (fabsf(dif.x) > fabsf(dif.y)) + { + p1a = p1 + ImVec2(fabsf(fabsf(dif.x) - fabsf(dif.y)) * 0.5f * sign(dif.x), 0.f); + p1b = p1a + ImVec2(fabsf(dif.y) * sign(dif.x), dif.y); + } + else + { + p1a = p1 + ImVec2(0.f, fabsf(fabsf(dif.y) - fabsf(dif.x)) * 0.5f * sign(dif.y)); + p1b = p1a + ImVec2(dif.x, fabsf(dif.x) * sign(dif.y)); + } + } + else + { + if (fabsf(dif.x) > fabsf(dif.y)) + { + float d = fabsf(dif.y) * sign(dif.x) * 0.5f; + p1a = p1 + ImVec2(d, dif.y * 0.5f); + p1b = p1a + ImVec2(fabsf(fabsf(dif.x) - fabsf(d) * 2.f) * sign(dif.x), 0.f); + } + else + { + float d = fabsf(dif.x) * sign(dif.y) * 0.5f; + p1a = p1 + ImVec2(dif.x * 0.5f, d); + p1b = p1a + ImVec2(0.f, fabsf(fabsf(dif.y) - fabsf(d) * 2.f) * sign(dif.y)); + } + } + pts = {p1, p1a, p1b, p2}; + ptCount = 4; + } + } + float highLightFactor = factor * (highlightCons ? 2.0f : 1.f); + for (int pass = 0; pass < 2; pass++) + { + drawList->AddPolyline( + pts.data(), ptCount, pass ? col : 0xFF000000, false, (pass ? 5.f : 7.5f) * highLightFactor); + } + } +} + +static void HandleQuadSelection( + GraphEditorDelegate* delegate, ImDrawList* drawList, const ImVec2 offset, const float factor, ImRect contentRect) +{ + ImGuiIO& io = ImGui::GetIO(); + static ImVec2 quadSelectPos; + auto& nodes = delegate->GetNodes(); + + ImRect editingRugRect(ImVec2(FLT_MAX, FLT_MAX), ImVec2(FLT_MAX, FLT_MAX)); + if (editRug != -1) + { + const auto& rug = delegate->GetRugs()[editRug]; + ImVec2 commentSize = rug.mRect.GetSize() * factor; + ImVec2 node_rect_min = (offset + rug.mRect.Min) * factor; + ImVec2 node_rect_max = node_rect_min + commentSize; + editingRugRect = ImRect(node_rect_min, node_rect_max); + } + + if (nodeOperation == NO_QuadSelecting && ImGui::IsWindowFocused()) + { + const ImVec2 bmin = ImMin(quadSelectPos, io.MousePos); + const ImVec2 bmax = ImMax(quadSelectPos, io.MousePos); + drawList->AddRectFilled(bmin, bmax, 0x40FF2020, 1.f); + drawList->AddRect(bmin, bmax, 0xFFFF2020, 1.f); + if (!io.MouseDown[0]) + { + if (!io.KeyCtrl && !io.KeyShift) + { + for (int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) + { + delegate->SelectNode(nodeIndex, false); + } + } + + nodeOperation = NO_None; + ImRect selectionRect(bmin, bmax); + for (int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) + { + const auto* node = &nodes[nodeIndex]; + ImVec2 node_rect_min = offset + node->mRect.Min * factor; + ImVec2 node_rect_max = node_rect_min + node->mRect.GetSize() * factor; + if (selectionRect.Overlaps(ImRect(node_rect_min, node_rect_max))) + { + if (io.KeyCtrl) + { + delegate->SelectNode(nodeIndex, false); + } + else + { + delegate->SelectNode(nodeIndex, true); + } + } + else + { + if (!io.KeyShift) + { + delegate->SelectNode(nodeIndex, false); + } + } + } + } + } + else if (nodeOperation == NO_None && io.MouseDown[0] && ImGui::IsWindowFocused() && + contentRect.Contains(io.MousePos) && !editingRugRect.Contains(io.MousePos)) + { + nodeOperation = NO_QuadSelecting; + quadSelectPos = io.MousePos; + } +} + + +bool HandleConnections(ImDrawList* drawList, + int nodeIndex, + const ImVec2 offset, + const float factor, + GraphEditorDelegate* delegate, + bool bDrawOnly) +{ + static int editingNodeIndex; + static int editingSlotIndex; + const auto& links = delegate->GetLinks(); + const auto& nodes = delegate->GetNodes(); + + ImGuiIO& io = ImGui::GetIO(); + const GraphEditorDelegate::Node* node = &nodes[nodeIndex]; + + size_t InputsCount = node->mInputs.size(); + size_t OutputsCount = node->mOutputs.size(); + + // draw/use inputs/outputs + bool hoverSlot = false; + for (int i = 0; i < 2; i++) + { + float closestDistance = FLT_MAX; + int closestConn = -1; + ImVec2 closestTextPos; + ImVec2 closestPos; + const size_t slotCount[2] = {InputsCount, OutputsCount}; + + for (int slot_idx = 0; slot_idx < slotCount[i]; slot_idx++) + { + const char* con = i ? node->mOutputs[slot_idx] : node->mInputs[slot_idx]; + const char* conText = con ? con : ""; + + ImVec2 p = + offset + (i ? GetOutputSlotPos(*node, slot_idx, factor) : GetInputSlotPos(*node, slot_idx, factor)); + float distance = Distance(p, io.MousePos); + bool overCon = (nodeOperation == NO_None || nodeOperation == NO_EditingLink) && + (distance < NODE_SLOT_RADIUS * 2.f) && (distance < closestDistance); + + + ImVec2 textSize; + textSize = ImGui::CalcTextSize(conText); + ImVec2 textPos = + p + ImVec2(-NODE_SLOT_RADIUS * (i ? -1.f : 1.f) * (overCon ? 3.f : 2.f) - (i ? 0 : textSize.x), + -textSize.y / 2); + + ImRect nodeRect = GetNodeRect(*node, factor); + if (overCon || (nodeRect.Contains(io.MousePos - offset) && closestConn == -1 && + (editingInput == (i != 0)) && nodeOperation == NO_EditingLink)) + { + closestDistance = distance; + closestConn = slot_idx; + closestTextPos = textPos; + closestPos = p; + } + + drawList->AddCircleFilled(p, NODE_SLOT_RADIUS * 1.2f, IM_COL32(0, 0, 0, 200)); + drawList->AddCircleFilled(p, NODE_SLOT_RADIUS * 0.75f * 1.2f, IM_COL32(160, 160, 160, 200)); + drawList->AddText(io.FontDefault, 14, textPos + ImVec2(2, 2), IM_COL32(0, 0, 0, 255), conText); + drawList->AddText(io.FontDefault, 14, textPos, IM_COL32(150, 150, 150, 255), conText); + } + + if (closestConn != -1) + { + const char* con = i ? node->mOutputs[closestConn] : node->mInputs[closestConn]; + const char* conText = con ? con : ""; + hoverSlot = true; + drawList->AddCircleFilled(closestPos, NODE_SLOT_RADIUS * 2.f, IM_COL32(0, 0, 0, 200)); + drawList->AddCircleFilled(closestPos, NODE_SLOT_RADIUS * 1.5f, IM_COL32(200, 200, 200, 200)); + drawList->AddText(io.FontDefault, 16, closestTextPos + ImVec2(1, 1), IM_COL32(0, 0, 0, 255), conText); + drawList->AddText(io.FontDefault, 16, closestTextPos, IM_COL32(250, 250, 250, 255), conText); + bool inputToOutput = (!editingInput && !i) || (editingInput && i); + if (nodeOperation == NO_EditingLink && !io.MouseDown[0] && !bDrawOnly) + { + if (inputToOutput) + { + // check loopback + GraphEditorDelegate::Link nl; + if (editingInput) + nl = GraphEditorDelegate::Link{nodeIndex, closestConn, editingNodeIndex, editingSlotIndex}; + else + nl = GraphEditorDelegate::Link{editingNodeIndex, editingSlotIndex, nodeIndex, closestConn}; + + if (delegate->RecurseIsLinked(nl.mOutputNodeIndex, nl.mInputNodeIndex)) + { + break; + } + bool alreadyExisting = false; + for (int linkIndex = 0; linkIndex < links.size(); linkIndex++) + { + if (!memcmp(&links[linkIndex], &nl, sizeof(GraphEditorDelegate::Link))) + { + alreadyExisting = true; + break; + } + } + + // check already connected output + for (int linkIndex = 0; linkIndex < links.size(); linkIndex++) + { + auto& link = links[linkIndex]; + if (link.mOutputNodeIndex == nl.mOutputNodeIndex && link.mOutputSlotIndex == nl.mOutputSlotIndex) + { + if (!delegate->InTransaction()) + delegate->BeginTransaction(true); + delegate->DelLink(linkIndex); + + break; + } + } + + if (!alreadyExisting) + { + if (!delegate->InTransaction()) + delegate->BeginTransaction(true); + delegate->AddLink(nl.mInputNodeIndex, nl.mInputSlotIndex, nl.mOutputNodeIndex, nl.mOutputSlotIndex); + } + } + } + // when ImGui::IsWindowHovered() && !ImGui::IsAnyItemActive() is uncommented, one can't click the node + // input/output when mouse is over the node itself. + if (nodeOperation == NO_None && + /*ImGui::IsWindowHovered() && !ImGui::IsAnyItemActive() &&*/ io.MouseClicked[0] && !bDrawOnly) + { + nodeOperation = NO_EditingLink; + editingInput = i == 0; + editingNodeSource = closestPos; + editingNodeIndex = nodeIndex; + editingSlotIndex = closestConn; + if (editingInput) + { + // remove existing link + for (int linkIndex = 0; linkIndex < links.size(); linkIndex++) + { + auto& link = links[linkIndex]; + if (link.mOutputNodeIndex == nodeIndex && link.mOutputSlotIndex == closestConn) + { + if (!delegate->InTransaction()) + delegate->BeginTransaction(true); + delegate->DelLink(linkIndex); + break; + } + } + } + } + } + } + if (nodeOperation == NO_EditingLink && delegate->InTransaction()) + { + delegate->EndTransaction(); + } + return hoverSlot; +} + +static void DrawGrid(ImDrawList* drawList, ImVec2 windowPos, const ImVec2 canvasSize, const float factor) +{ + ImU32 GRID_COLOR = IM_COL32(100, 100, 100, 40); + float GRID_SZ = 64.0f * factor; + for (float x = fmodf(scrolling.x * factor, GRID_SZ); x < canvasSize.x; x += GRID_SZ) + drawList->AddLine(ImVec2(x, 0.0f) + windowPos, ImVec2(x, canvasSize.y) + windowPos, GRID_COLOR); + for (float y = fmodf(scrolling.y * factor, GRID_SZ); y < canvasSize.y; y += GRID_SZ) + drawList->AddLine(ImVec2(0.0f, y) + windowPos, ImVec2(canvasSize.x, y) + windowPos, GRID_COLOR); +} + +// return true if node is hovered +static bool DrawNode(ImDrawList* drawList, + int nodeIndex, + const ImVec2 offset, + const float factor, + GraphEditorDelegate* delegate, + bool overInput) +{ + ImGuiIO& io = ImGui::GetIO(); + const auto& nodes = delegate->GetNodes(); + const auto* node = &nodes[nodeIndex]; + + const ImVec2 node_rect_min = offset + node->mRect.Min * factor; + + const bool old_any_active = ImGui::IsAnyItemActive(); + ImGui::SetCursorScreenPos(node_rect_min + NODE_WINDOW_PADDING); + const ImVec2 nodeSize = node->mRect.GetSize() * factor; + + // test nested IO + drawList->ChannelsSetCurrent(1); // Background + const size_t InputsCount = node->mInputs.size(); + const size_t OutputsCount = node->mOutputs.size(); + + for (int i = 0; i < 2; i++) + { + const size_t slotCount[2] = {InputsCount, OutputsCount}; + + for (int slot_idx = 0; slot_idx < slotCount[i]; slot_idx++) + { + const char* con = i ? node->mOutputs[slot_idx] : node->mInputs[slot_idx]; + if (!delegate->IsIOPinned(nodeIndex, slot_idx, i == 1)) + { + continue; + } + ImVec2 p = + offset + (i ? GetOutputSlotPos(*node, slot_idx, factor) : GetInputSlotPos(*node, slot_idx, factor)); + const float arc = 28.f * (float(i) * 0.3f + 1.0f) * (i ? 1.f : -1.f); + const float ofs = 0.f; + + ImVec2 pts[3] = {p + ImVec2(arc + ofs, 0.f), p + ImVec2(0.f + ofs, -arc), p + ImVec2(0.f + ofs, arc)}; + drawList->AddTriangleFilled(pts[0], pts[1], pts[2], i ? 0xFFAA5030 : 0xFF30AA50); + drawList->AddTriangle(pts[0], pts[1], pts[2], 0xFF000000, 2.f); + } + } + + ImGui::SetCursorScreenPos(node_rect_min); + ImGui::InvisibleButton("node", nodeSize); + // must be called right after creating the control we want to be able to move + bool node_moving_active = ImGui::IsItemActive(); + + // Save the size of what we have emitted and whether any of the widgets are being used + bool node_widgets_active = (!old_any_active && ImGui::IsAnyItemActive()); + ImVec2 node_rect_max = node_rect_min + nodeSize; + + bool nodeHovered = false; + if (ImGui::IsItemHovered() && nodeOperation == NO_None && !overInput) + { + nodeHovered = true; + } + + if (ImGui::IsWindowFocused()) + { + if (node_widgets_active || node_moving_active) + { + if (!node->mbSelected) + { + if (!io.KeyShift) + { + for (auto i = 0; i < nodes.size(); i++) + { + delegate->SelectNode(i, false); + } + } + delegate->SelectNode(nodeIndex, true); + } + } + } + if (node_moving_active && io.MouseDown[0] && nodeHovered) + { + if (nodeOperation != NO_MovingNodes) + { + nodeOperation = NO_MovingNodes; + } + } + + bool currentSelectedNode = node->mbSelected; + + + ImU32 node_bg_color = node->mBackgroundColor + (nodeHovered?0x191919:0); + + drawList->AddRect(node_rect_min, + node_rect_max, + currentSelectedNode ? IM_COL32(255, 130, 30, 255) : IM_COL32(100, 100, 100, 0), + 2.0f, + 15, + currentSelectedNode ? 6.f : 2.f); + + ImVec2 imgPos = node_rect_min + ImVec2(14, 25); + ImVec2 imgSize = node_rect_max + ImVec2(-5, -5) - imgPos; + float imgSizeComp = std::min(imgSize.x, imgSize.y); + + drawList->AddRectFilled(node_rect_min, node_rect_max, node_bg_color, 2.0f); + float progress = delegate->NodeProgress(nodeIndex); + if (progress > FLT_EPSILON && progress < 1.f - FLT_EPSILON) + { + ImVec2 progressLineA = node_rect_max - ImVec2(nodeSize.x - 2.f, 3.f); + ImVec2 progressLineB = progressLineA + ImVec2(nodeSize.x * factor - 4.f, 0.f); + drawList->AddLine(progressLineA, progressLineB, 0xFF400000, 3.f); + drawList->AddLine(progressLineA, ImLerp(progressLineA, progressLineB, progress), 0xFFFF0000, 3.f); + } + ImVec2 imgPosMax = imgPos + ImVec2(imgSizeComp, imgSizeComp); + + ImVec2 imageSize = delegate->GetEvaluationSize(nodeIndex); + float imageRatio = 1.f; + if (imageSize.x > 0.f && imageSize.y > 0.f) + { + imageRatio = imageSize.y / imageSize.x; + } + ImVec2 quadSize = imgPosMax - imgPos; + ImVec2 marge(0.f, 0.f); + if (imageRatio > 1.f) + { + marge.x = (quadSize.x - quadSize.y / imageRatio) * 0.5f; + } + else + { + marge.y = (quadSize.y - quadSize.y * imageRatio) * 0.5f; + } + + delegate->DrawNodeImage(drawList, ImRect(imgPos, imgPosMax), marge, nodeIndex); + + drawList->AddRectFilled(node_rect_min, + ImVec2(node_rect_max.x, node_rect_min.y + 20), + node->mHeaderColor, + 2.0f); + drawList->PushClipRect(node_rect_min, ImVec2(node_rect_max.x, node_rect_min.y + 20), true); + drawList->AddText(node_rect_min + ImVec2(2, 2), IM_COL32(0, 0, 0, 255), node->mName); + drawList->PopClipRect(); + + + const ImTextureID bmpInfo = (ImTextureID)(uint64_t)delegate->GetBitmapInfo(nodeIndex).idx; + if (bmpInfo) + { + ImVec2 bmpInfoPos(node_rect_max - ImVec2(26, 12)); + ImVec2 bmpInfoSize(20, 20); + if (delegate->NodeIsCompute(nodeIndex)) + { + drawList->AddImageQuad(bmpInfo, + bmpInfoPos, + bmpInfoPos + ImVec2(bmpInfoSize.x, 0.f), + bmpInfoPos + bmpInfoSize, + bmpInfoPos + ImVec2(0., bmpInfoSize.y)); + } + else if (delegate->NodeIs2D(nodeIndex)) + { + drawList->AddImageQuad(bmpInfo, + bmpInfoPos, + bmpInfoPos + ImVec2(bmpInfoSize.x, 0.f), + bmpInfoPos + bmpInfoSize, + bmpInfoPos + ImVec2(0., bmpInfoSize.y)); + } + else if (delegate->NodeIsCubemap(nodeIndex)) + { + drawList->AddImageQuad(bmpInfo, + bmpInfoPos + ImVec2(0., bmpInfoSize.y), + bmpInfoPos + bmpInfoSize, + bmpInfoPos + ImVec2(bmpInfoSize.x, 0.f), + bmpInfoPos); + } + } + return nodeHovered; +} + +void ComputeDelegateSelection(GraphEditorDelegate* delegate) +{ + const auto& nodes = delegate->GetNodes(); + // only one selection allowed for delegate + delegate->mSelectedNodeIndex = {InvalidNodeIndex}; + for (auto& node : nodes) + { + if (node.mbSelected) + { + if (!delegate->mSelectedNodeIndex.IsValid()) + { + delegate->mSelectedNodeIndex = int(&node - nodes.data()); + } + else + { + delegate->mSelectedNodeIndex.SetInvalid(); + return; + } + } + } +} + +void GraphEditor(GraphEditorDelegate* delegate, bool enabled) +{ + ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 0.f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.f); + + const ImVec2 windowPos = ImGui::GetCursorScreenPos(); + const ImVec2 canvasSize = ImGui::GetWindowSize(); + const ImVec2 scrollRegionLocalPos(0, 50); + const auto& nodes = delegate->GetNodes(); + + bool openContextMenu = false; + + static ImVec2 scenePos; + + ImRect regionRect(windowPos, windowPos + canvasSize); + + HandleZoomScroll(regionRect); + ImVec2 offset = ImGui::GetCursorScreenPos() + scrolling * factor; + captureOffset = scrollRegionLocalPos + scrolling * factor + ImVec2(10.f, 0.f); + + { + ImGui::BeginChild("rugs_region", ImVec2(0, 0), true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove); + ImDrawList* drawList = ImGui::GetWindowDrawList(); + + editRug = DisplayRugs(delegate, editRug, drawList, offset, factor); + + ImGui::EndChild(); + } + + ImGui::SetCursorPos(windowPos); + ImGui::BeginGroup(); + + + ImGuiIO& io = ImGui::GetIO(); + + // Create our child canvas + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1, 1)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(30, 30, 30, 200)); + + ImGui::SetCursorPos(scrollRegionLocalPos); + ImGui::BeginChild("scrolling_region", + ImVec2(0, 0), + true, + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground); + ImGui::PushItemWidth(120.0f); + + ImDrawList* drawList = ImGui::GetWindowDrawList(); + + // Background or Display grid + if (!delegate->RenderBackground()) + { + DrawGrid(drawList, windowPos, canvasSize, factor); + } + + if (!enabled) + { + goto nodeGraphExit; + } + + static int hoveredNode = -1; + // Display links + drawList->ChannelsSplit(3); + drawList->ChannelsSetCurrent(1); // Background + DisplayLinks(delegate, drawList, offset, factor, regionRect, hoveredNode); + + // edit node link + if (nodeOperation == NO_EditingLink) + { + ImVec2 p1 = editingNodeSource; + ImVec2 p2 = io.MousePos; + drawList->AddLine(p1, p2, IM_COL32(200, 200, 200, 255), 3.0f); + } + + // Display nodes + drawList->PushClipRect(regionRect.Min, regionRect.Max, true); + hoveredNode = -1; + for (int i = 0; i < 2; i++) + { + for (int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) + { + const auto* node = &nodes[nodeIndex]; + if (node->mbSelected != (i != 0)) + { + continue; + } + + // node view clipping + ImRect nodeRect = GetNodeRect(*node, factor); + nodeRect.Min += offset; + nodeRect.Max += offset; + if (!regionRect.Overlaps(nodeRect)) + { + continue; + } + + ImGui::PushID(nodeIndex); + + // Display node contents first + // drawList->ChannelsSetCurrent(i+1); // channel 2 = Foreground channel 1 = background + + bool overInput = HandleConnections(drawList, nodeIndex, offset, factor, delegate, false); + + if (DrawNode(drawList, nodeIndex, offset, factor, delegate, overInput)) + hoveredNode = nodeIndex; + + HandleConnections(drawList, nodeIndex, offset, factor, delegate, true); + + ImGui::PopID(); + } + } + drawList->PopClipRect(); + + if (nodeOperation == NO_MovingNodes) + { + if (ImGui::IsMouseDragging(0, 1)) + { + ImVec2 delta = io.MouseDelta / factor; + if (fabsf(delta.x) >= 1.f || fabsf(delta.y) >= 1.f) + { + if (!delegate->InTransaction()) + { + delegate->BeginTransaction(true); + } + delegate->MoveSelectedNodes(delta); + } + } + } + + // rugs + drawList->ChannelsSetCurrent(0); + + // quad selection + HandleQuadSelection(delegate, drawList, offset, factor, regionRect); + + drawList->ChannelsMerge(); + + if (editRug != -1) + { + if (EditRug(delegate, editRug, drawList, offset, factor)) + { + editRug = -1; + } + } + + // releasing mouse button means it's done in any operation + if (nodeOperation == NO_PanView) + { + if (!io.MouseDown[2]) + { + nodeOperation = NO_None; + } + } + else if (nodeOperation != NO_None && !io.MouseDown[0]) + { + nodeOperation = NO_None; + if (delegate->InTransaction()) + { + delegate->EndTransaction(); + } + } + + // Open context menu + static int contextMenuHoverNode = -1; + if (nodeOperation == NO_None && regionRect.Contains(io.MousePos) && + (ImGui::IsMouseClicked(1) || (ImGui::IsWindowFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Tab)))) + { + openContextMenu = true; + contextMenuHoverNode = hoveredNode; + } + + if (openContextMenu) + { + scenePos = (ImGui::GetMousePosOnOpeningCurrentPopup() - offset) / factor; + ImGui::OpenPopup("context_menu"); + } + ; + + delegate->ContextMenu(scenePos, (io.MousePos - offset) / factor, contextMenuHoverNode); + + // Scrolling + if (ImGui::IsWindowHovered() && !ImGui::IsAnyItemActive() && io.MouseClicked[2] && nodeOperation == NO_None) + { + nodeOperation = NO_PanView; + } + if (nodeOperation == NO_PanView) + { + scrolling += io.MouseDelta / factor; + } + +nodeGraphExit:; + ImGui::PopItemWidth(); + ImGui::EndChild(); + ImGui::PopStyleColor(1); + ImGui::PopStyleVar(2); + + ComputeDelegateSelection(delegate); + + ImGui::EndGroup(); + ImGui::PopStyleVar(3); +} diff --git a/src/GraphEditor.h b/src/GraphEditor.h new file mode 100644 index 00000000..f5ab7529 --- /dev/null +++ b/src/GraphEditor.h @@ -0,0 +1,102 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +#pragma once + +#include +#include +#include +#include "imgui.h" +#include "imgui_internal.h" +#include "Types.h" + +struct GraphEditorDelegate +{ + NodeIndex mSelectedNodeIndex{ InvalidNodeIndex }; + + // getters + virtual ImVec2 GetEvaluationSize(NodeIndex nodeIndex) const = 0; + virtual int NodeIsProcesing(NodeIndex nodeIndex) const = 0; + virtual float NodeProgress(NodeIndex nodeIndex) const = 0; + virtual bool NodeIsCubemap(NodeIndex nodeIndex) const = 0; + virtual bool NodeIs2D(NodeIndex nodeIndex) const = 0; + virtual bool NodeIsCompute(NodeIndex nodeIndex) const = 0; + virtual bool IsIOPinned(NodeIndex nodeIndex, size_t io, bool forOutput) const = 0; + virtual bool RecurseIsLinked(NodeIndex from, NodeIndex to) const = 0; + virtual bgfx::TextureHandle GetBitmapInfo(NodeIndex nodeIndex) const = 0; + + virtual void DrawNodeImage(ImDrawList* drawList, const ImRect& rc, const ImVec2 marge, NodeIndex nodeIndex) = 0; + virtual void ContextMenu(ImVec2 rightclickPos, ImVec2 worldMousePos, int nodeHovered) = 0; + + // operations + virtual bool InTransaction() = 0; + virtual void BeginTransaction(bool undoable) = 0; + virtual void EndTransaction() = 0; + + virtual void DelRug(size_t rugIndex) = 0; + virtual void SelectNode(NodeIndex nodeIndex, bool selected) = 0; + virtual void MoveSelectedNodes(const ImVec2 delta) = 0; + + virtual void AddLink(NodeIndex inputNodeIndex, SlotIndex inputSlotIndex, NodeIndex outputNodeIndex, SlotIndex outputSlotIndex) = 0; + virtual void DelLink(size_t linkIndex) = 0; + + virtual void SetRug(size_t rugIndex, const ImRect& rect, const char *szText, uint32_t color) = 0; + + // return false if background must be rendered by node graph + virtual bool RenderBackground() = 0; + + struct Node + { + const char *mName; + ImRect mRect; + uint32_t mHeaderColor; + uint32_t mBackgroundColor; + std::vector mInputs; + std::vector mOutputs; + bool mbSelected; + }; + + struct Rug + { + ImRect mRect; + const char* mText; + uint32_t mColor; + }; + + struct Link + { + int mInputNodeIndex, mInputSlotIndex, mOutputNodeIndex, mOutputSlotIndex; + }; + + // node/links/rugs retrieval + virtual const std::vector& GetNodes() const = 0; + virtual const std::vector& GetRugs() const = 0; + virtual const std::vector& GetLinks() const = 0; +}; + +void GraphEditor(GraphEditorDelegate* delegate, bool enabled); +void GraphEditorClear(); + +void GraphEditorUpdateScrolling(GraphEditorDelegate* delegate); + diff --git a/src/GraphModel.cpp b/src/GraphModel.cpp new file mode 100644 index 00000000..d1c68981 --- /dev/null +++ b/src/GraphModel.cpp @@ -0,0 +1,1081 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include +#include +#include +#include +#include "GraphModel.h" +#include "UndoRedo.h" +#include "Cam.h" + +extern UndoRedoHandler gUndoRedoHandler; +size_t GetUndoRedoMemoryFootPrint() +{ + return gUndoRedoHandler.GetMemUsed(); +} + + +ImRect GraphModel::Node::GetDisplayRect() const +{ + int width = gMetaNodes[mNodeType].mWidth; + int height = gMetaNodes[mNodeType].mHeight; + return ImRect(mPos, mPos + ImVec2(float(width), float(height))); +} + +GraphModel::GraphModel() : mbTransaction(false), mUndoRedo(nullptr), mStartFrame(0), mEndFrame(1) +{ +} + +GraphModel::~GraphModel() +{ + assert(!mbTransaction); +} + +void GraphModel::Clear() +{ + assert(!mbTransaction); + + mNodes.clear(); + mLinks.clear(); + mRugs.clear(); + gUndoRedoHandler.Clear(); + mDirtyList.clear(); +} + +void GraphModel::BeginTransaction(bool undoable) +{ + assert(!mbTransaction); + + mbTransaction = true; + if (undoable) + { + mUndoRedo = new URDummy; + } +} + +bool GraphModel::InTransaction() const +{ + return mbTransaction; +} + +void GraphModel::EndTransaction() +{ + assert(mbTransaction); + mbTransaction = false; + if (mUndoRedo) + { + // undo/redo but nothing has been updated + assert(mUndoRedo->HasSubUndoRedo()); + } + delete mUndoRedo; + mUndoRedo = nullptr; +} + +void GraphModel::GetInputs(std::vector& multiplexedInPuts, std::vector& directInputs) const +{ + std::vector inputs; + inputs.resize(mNodes.size()); + + for(const auto& link: mLinks) + { + auto source = link.mInputNodeIndex; + assert(source < mNodes.size() && source > -1); + assert(link.mOutputSlotIndex < 8 && link.mOutputSlotIndex > -1); + inputs[link.mOutputNodeIndex].mInputs[link.mOutputSlotIndex] = source; + } + + directInputs = inputs; + + // overide + for (auto i = 0; i < mNodes.size(); i++) + { + const auto& multiplexInput = mNodes[i].mMultiplexInput; + for (auto j = 0; j < 8; j++) + { + auto m = multiplexInput.mInputs[j]; + if (m.IsValid()) + { + inputs[i].mInputs[j] = m; + } + } + } + multiplexedInPuts = inputs; +} + +const AnimationTracks& GraphModel::GetAnimationTracks() const +{ + if (mAnimationTracks) + { + return *mAnimationTracks; + } + static AnimationTracks emptyAnimationTracks; + return emptyAnimationTracks; +} + +void GraphModel::Undo() +{ + assert(!mbTransaction); + gUndoRedoHandler.Undo(); +} + +void GraphModel::Redo() +{ + assert(!mbTransaction); + gUndoRedoHandler.Redo(); +} + +void GraphModel::MoveSelectedNodes(const ImVec2 delta) +{ + assert(mbTransaction); + for (auto i = 0 ; i < mNodes.size(); i++) + { + auto& node = mNodes[i]; + if (!node.mbSelected) + { + continue; + } + auto ur = mUndoRedo + ? std::make_unique>(int(i), [this](int index) { return &mNodes[index]; }, [this](int index) {SetDirty(index, Dirty::VisualGraph);}) + : nullptr; + node.mPos += delta; + SetDirty(i, Dirty::VisualGraph); + } +} + +void GraphModel::SetNodePosition(NodeIndex nodeIndex, const ImVec2 position) +{ + assert(mbTransaction); + auto ur = mUndoRedo + ? std::make_unique>(int(nodeIndex), [this](int index) { return &mNodes[index]; }, [this](int index) {SetDirty(index, Dirty::VisualGraph); }) + : nullptr; + mNodes[nodeIndex].mPos = position; + SetDirty(nodeIndex, Dirty::VisualGraph); +} + +// called when a node is added by user, or with undo/redo +void GraphModel::AddNodeHelper(int nodeIndex) +{ + SetDirty(nodeIndex, Dirty::AddedNode); +} + +void GraphModel::RemoveAnimation(NodeIndex nodeIndex) +{ + if (mAnimationTracks->empty()) + { + return; + } + std::vector tracks; + for (int i = 0; i < int(mAnimationTracks->size()); i++) + { + const AnimTrack& animTrack = mAnimationTracks->at(i); + if (animTrack.mNodeIndex == nodeIndex) + { + tracks.push_back(i); + } + } + if (tracks.empty()) + { + return; + } + for (int i = 0; i < int(tracks.size()); i++) + { + int index = tracks[i] - i; + auto urAnimTrack = mUndoRedo ? std::make_unique>(index, [&] { return mAnimationTracks.get(); }):nullptr; + mAnimationTracks->erase(mAnimationTracks->begin() + index); + } +} + +size_t GraphModel::AddNode(size_t type, ImVec2 position) +{ + assert(mbTransaction); + + NodeIndex nodeIndex = mNodes.size(); + + auto delNode = [this](int index) { SetDirty(index, Dirty::DeletedNode); }; + auto addNode = [this](int index) { SetDirty(index, Dirty::AddedNode); }; + + auto urNode = mUndoRedo ? std::make_unique>(int(nodeIndex), [this]() { return &mNodes; }, delNode, addNode) : nullptr; + + mNodes.push_back(Node(int(type), position, mStartFrame, mEndFrame)); + mNodes[nodeIndex].mParameterBlock.InitDefault(); + mNodes.back().mSamplers.resize(gMetaNodes[type].mInputs.size()); + + addNode(int(nodeIndex)); + return nodeIndex; +} + +void GraphModel::AddLinkInternal(NodeIndex inputNodeIndex, SlotIndex inputSlotIndex, NodeIndex outputNodeIndex, SlotIndex outputSlotIndex) +{ + size_t linkIndex = mLinks.size(); + Link link; + link.mInputNodeIndex = inputNodeIndex; + link.mInputSlotIndex = inputSlotIndex; + link.mOutputNodeIndex = outputNodeIndex; + link.mOutputSlotIndex = outputSlotIndex; + mLinks.push_back(link); +} + +void GraphModel::AddLink(NodeIndex inputNodeIndex, SlotIndex inputSlotIndex, NodeIndex outputNodeIndex, SlotIndex outputSlotIndex) +{ + assert(mbTransaction); + + if (inputNodeIndex >= mNodes.size() || outputNodeIndex >= mNodes.size()) + { + // Log("Error : Link node index doesn't correspond to an existing node."); + return; + } + + auto inputChanged = [this, outputSlotIndex](int index) { SetDirty(mLinks[index].mOutputNodeIndex, Dirty::Input, outputSlotIndex); }; + size_t linkIndex = mLinks.size(); + + auto ur = mUndoRedo ? std::make_unique>(int(linkIndex), [&]() { return &mLinks; }, inputChanged, inputChanged) + : nullptr; + + SetIOPin(inputNodeIndex, inputSlotIndex, true, false); + SetIOPin(outputNodeIndex, outputSlotIndex, false, false); + + AddLinkInternal(inputNodeIndex, inputSlotIndex, outputNodeIndex, outputSlotIndex); + inputChanged(int(mLinks.size() - 1)); +} + +void GraphModel::DelLinkInternal(size_t linkIndex) +{ + mLinks.erase(mLinks.begin() + linkIndex); +} + +void GraphModel::DelLink(size_t linkIndex) +{ + assert(mbTransaction); + + auto inputChanged = [this](int index) { SetDirty(mLinks[index].mOutputNodeIndex, Dirty::Input, mLinks[index].mOutputSlotIndex); }; + auto ur = mUndoRedo ? std::make_unique>(int(linkIndex), [&]() { return &mLinks; }, inputChanged, inputChanged) + : nullptr; + + inputChanged(int(linkIndex)); + DelLinkInternal(linkIndex); +} + +void GraphModel::DelLink(NodeIndex inputNodeIndex, SlotIndex inputSlotIndex) +{ + assert(mbTransaction); + + for (size_t linkIndex = 0; linkIndex < mLinks.size(); linkIndex++) + { + const Link& link = mLinks[linkIndex]; + if (link.mOutputNodeIndex == inputNodeIndex && link.mOutputSlotIndex == inputSlotIndex) + { + auto inputChanged = [this, inputSlotIndex](int index) { SetDirty(mLinks[index].mOutputNodeIndex, Dirty::Input, inputSlotIndex); }; + auto ur = mUndoRedo ? std::make_unique>(int(linkIndex), [&]() { return &mLinks; }, inputChanged, inputChanged) + : nullptr; + + inputChanged(int(linkIndex)); + DelLinkInternal(linkIndex); + return; + } + } +} + +void GraphModel::AddRug(const Rug& rug) +{ + assert(mbTransaction); + + auto rugDirty = [&](int index) {SetDirty(-1, Dirty::RugChanged); }; + auto ur = mUndoRedo + ? std::make_unique>(int(mRugs.size()), [&]() { return &mRugs; }, rugDirty, rugDirty) + : nullptr; + + mRugs.push_back(rug); + rugDirty(-1); +} + +void GraphModel::DelRug(size_t rugIndex) +{ + assert(mbTransaction); + + auto rugDirty = [&](int index) {SetDirty(-1, Dirty::RugChanged); }; + auto ur = mUndoRedo ? std::make_unique>(int(rugIndex), [&]() { return &mRugs; }, rugDirty, rugDirty) + : nullptr; + + mRugs.erase(mRugs.begin() + rugIndex); + rugDirty(-1); +} + +void GraphModel::SetRug(size_t rugIndex, const Rug& rug) +{ + assert(mbTransaction); + + auto rugDirty = [&](int index) {SetDirty(-1, Dirty::RugChanged); }; + auto ur = mUndoRedo + ? std::make_unique>(int(rugIndex), [&](int index) { return &mRugs[index]; }, rugDirty) + : nullptr; + + mRugs[rugIndex] = rug; + rugDirty(-1); +} + +bool GraphModel::HasSelectedNodes() const +{ + bool hasSelectedNode = false; + for (int selection = int(mNodes.size()) - 1; selection >= 0; selection--) + { + if (mNodes[selection].mbSelected) + { + return true; + } + } + return false; +} + +void GraphModel::DeleteSelectedNodes() +{ + assert(HasSelectedNodes()); + + for (int selection = int(mNodes.size()) - 1; selection >= 0; selection--) + { + if (!mNodes[selection].mbSelected) + { + continue; + } + NodeIndex nodeIndex = selection; + DeleteNode(nodeIndex); + } +} + +void GraphModel::DeleteNode(NodeIndex nodeIndex) +{ + auto delNode = [this](int index) { SetDirty(index, Dirty::DeletedNode); }; + auto addNode = [this](int index) { SetDirty(index, Dirty::AddedNode); }; + + auto ur = mUndoRedo ? std::make_unique>(nodeIndex, + [this]() { return &mNodes; }, + delNode, addNode) : nullptr; + + for (size_t i = 0; i < mLinks.size();) + { + auto& link = mLinks[i]; + if (link.mInputNodeIndex == nodeIndex || link.mOutputNodeIndex == nodeIndex) + { + DelLink(i); + } + else + { + i++; + } + } + + mNodes.erase(mNodes.begin() + nodeIndex); + for (int id = 0; id < mLinks.size(); id++) + { + if (mLinks[id].mInputNodeIndex > nodeIndex) + { + auto ur = mUndoRedo ? std::make_unique>(id, + [this](int index) { return &mLinks[index]; }) : nullptr; + + mLinks[id].mInputNodeIndex--; + } + if (mLinks[id].mOutputNodeIndex > nodeIndex) + { + auto ur = mUndoRedo ? std::make_unique>(id, + [this](int index) { return &mLinks[index]; }) : nullptr; + + mLinks[id].mOutputNodeIndex--; + } + } + RemoveAnimation(nodeIndex); + SetDirty(nodeIndex, Dirty::DeletedNode); +} + +bool GraphModel::IsIOUsed(NodeIndex nodeIndex, int slotIndex, bool forOutput) const +{ + for (auto& link : mLinks) + { + if ((link.mInputNodeIndex == int(nodeIndex) && link.mInputSlotIndex == slotIndex && forOutput) || + (link.mOutputNodeIndex == int(nodeIndex) && link.mOutputSlotIndex == slotIndex && !forOutput)) + { + return true; + } + } + return false; +} + +void GraphModel::SelectNode(NodeIndex nodeIndex, bool selected) +{ + // assert(mbTransaction); + mNodes[nodeIndex].mbSelected = selected; + SetDirty(nodeIndex, Dirty::VisualGraph); +} + +void GraphModel::UnselectNodes() +{ + for (size_t i = 0; i < GetNodeCount(); i++) + { + mNodes[i].mbSelected = false; + SetDirty(i, Dirty::VisualGraph); + } +} + +ImVec2 GraphModel::GetNodePos(NodeIndex nodeIndex) const +{ + return mNodes[nodeIndex].mPos; +} + +void GraphModel::SetSamplers(NodeIndex nodeIndex, const std::vector& samplers) +{ + assert(mbTransaction); + + auto ur = mUndoRedo ? std::make_unique>( + int(nodeIndex), + [this](int index) { return &mNodes[index]; }, + [this](int index) { SetDirty(index, Dirty::Sampler); }) + : nullptr; + mNodes[nodeIndex].mSamplers = samplers; + SetDirty(nodeIndex, Dirty::Sampler); +} + +void GraphModel::SetSampler(NodeIndex nodeIndex, size_t input, const InputSampler& sampler) +{ + assert(mbTransaction); + if (input >= mNodes[nodeIndex].mSamplers.size()) + { + return ; + } + auto ur = mUndoRedo ? std::make_unique>( + int(nodeIndex), + [this](int index) { return &mNodes[index]; }, + [this](int index) { SetDirty(index, Dirty::Sampler); }) + : nullptr; + mNodes[nodeIndex].mSamplers[input] = sampler; + SetDirty(nodeIndex, Dirty::Sampler); +} + +bool GraphModel::NodeHasUI(NodeIndex nodeIndex) const +{ + return gMetaNodes[mNodes[nodeIndex].mNodeType].mbHasUI; +} + +void GraphModel::SetParameter(NodeIndex nodeIndex, const std::string& parameterName, const std::string& parameterValue) +{ + assert(mbTransaction); + if (!nodeIndex.IsValid() || nodeIndex >= mNodes.size()) + { + return; + } + uint32_t nodeType = uint32_t(mNodes[nodeIndex].mNodeType); + int parameterIndex = GetParameterIndex(nodeType, parameterName.c_str()); + if (parameterIndex == -1) + { + return; + } + ConTypes parameterType = GetParameterType(nodeType, parameterIndex); + //size_t paramOffset = GetParameterOffset(nodeType, parameterIndex); + ParseStringToParameter( + parameterValue, parameterType, mNodes[nodeIndex].mParameterBlock.Data(parameterIndex)); + SetDirty(nodeIndex, Dirty::Parameter); +} + +void GraphModel::SetCameraLookAt(NodeIndex nodeIndex, const Vec4& eye, const Vec4& target, const Vec4& up) +{ + assert(mbTransaction); + //uint32_t nodeType = uint32_t(mNodes[nodeIndex].mNodeType); + Camera* camera = mNodes[nodeIndex].mParameterBlock.GetCamera(); + if (!camera) + { + return; + } + camera->LookAt(eye, target, up); + SetDirty(nodeIndex, Dirty::Parameter); +} + +AnimTrack* GraphModel::GetAnimTrack(uint32_t nodeIndex, uint32_t parameterIndex) +{ + for (auto& animTrack : *mAnimationTracks) + { + if (animTrack.mNodeIndex == nodeIndex && animTrack.mParamIndex == parameterIndex) + { + return &animTrack; + } + } + return NULL; +} + +void GraphModel::MakeKey(int frame, uint32_t nodeIndex, uint32_t parameterIndex) +{ + assert(mbTransaction); + if (nodeIndex == -1) + { + return; + } + + AnimTrack* animTrack = GetAnimTrack(nodeIndex, parameterIndex); + if (!animTrack) + { + uint32_t parameterType = gMetaNodes[mNodes[nodeIndex].mNodeType].mParams[parameterIndex].mType; + AnimTrack newTrack; + newTrack.mNodeIndex = nodeIndex; + newTrack.mParamIndex = parameterIndex; + newTrack.mValueType = parameterType; + newTrack.mAnimation = AllocateAnimation(parameterType); + mAnimationTracks->push_back(newTrack); + animTrack = &mAnimationTracks->back(); + } + + auto ur = mUndoRedo ? std::make_unique>( + int(animTrack - mAnimationTracks->data()), + [&](int index) { return &mAnimationTracks->at(index); }) + : nullptr; + + //size_t parameterOffset = GetParameterOffset(uint32_t(mNodes[nodeIndex].mNodeType), parameterIndex); + animTrack->mAnimation->SetValue(frame, mNodes[nodeIndex].mParameterBlock.Data(parameterIndex)); +} + +void GraphModel::GetKeyedParameters(int frame, uint32_t nodeIndex, std::vector& keyed) const +{ +} + +void GraphModel::SetIOPin(NodeIndex nodeIndex, size_t io, bool forOutput, bool pinned) +{ + assert(mbTransaction); + auto ur = mUndoRedo ? std::make_unique>( + int(nodeIndex), + [&](int index) { return &mNodes[index]; }) + : nullptr; + + uint32_t mask = 0; + if (forOutput) + { + mask = (1 << io) & 0xFF; + // un set previous output + for (size_t i = 0; i < mNodes.size(); i++) + { + if (nodeIndex != NodeIndex(i)) + { + if (mNodes[i].mPinnedIO & mask) + { + auto ur2 = mUndoRedo ? std::make_unique>( + int(i), + [&](int index) { return &mNodes[index]; }) + : nullptr; + mNodes[i].mPinnedIO &= ~mask; + } + } + + } + } + else + { + mask = (1 << (8 + io)); + } + mNodes[nodeIndex].mPinnedIO &= ~mask; + mNodes[nodeIndex].mPinnedIO += pinned ? mask : 0; +} + +void GraphModel::SetAnimTrack(const AnimationTracks& animationTracks) +{ + //assert(mbTransaction); + if (mAnimationTracks) + { + *mAnimationTracks = animationTracks; + } + else + { + mAnimationTracks = std::make_shared(animationTracks); + } +} + +void GraphModel::SetMultiplexInputs(const std::vector& multiplexInputs) +{ + assert(multiplexInputs.size() == mNodes.size()); + for (auto i = 0; i < mNodes.size() ; i++) + { + mNodes[i].mMultiplexInput = multiplexInputs[i]; + } +} + +void GraphModel::SetParameterPin(NodeIndex nodeIndex, size_t parameterIndex, bool pinned) +{ + assert(mbTransaction); + auto ur = mUndoRedo ? std::make_unique>( + int(nodeIndex), + [&](int index) { return &mNodes[index]; }) + : nullptr; + + uint32_t mask = 1 << parameterIndex; + mNodes[nodeIndex].mPinnedParameters &= ~mask; + mNodes[nodeIndex].mPinnedParameters += pinned ? mask : 0; +} + +void GraphModel::SetParameterBlock(NodeIndex nodeIndex, const ParameterBlock& parameterBlock) +{ + assert(mbTransaction); + + auto dirtyParameters = [this](int index) { SetDirty(index, Dirty::Parameter); }; + auto ur = mUndoRedo ? std::make_unique>( + int(nodeIndex), + [this](int index) { return &mNodes[index]; }, + dirtyParameters) + : nullptr; + + mNodes[nodeIndex].mParameterBlock = parameterBlock; + dirtyParameters(int(nodeIndex)); +} + +void GraphModel::CopySelectedNodes() +{ + mNodesClipboard.clear(); + for (auto i = 0; i < mNodes.size(); i++) + { + if (!mNodes[i].mbSelected) + { + continue; + } + mNodesClipboard.push_back(mNodes[i]); + } +} + +void GraphModel::CutSelectedNodes() +{ + if (!HasSelectedNodes()) + { + return; + } + CopySelectedNodes(); + BeginTransaction(true); + DeleteSelectedNodes(); + EndTransaction(); +} + +bool GraphModel::IsClipboardEmpty() const +{ + return mNodesClipboard.empty(); +} + +void GraphModel::PasteNodes(ImVec2 viewOffsetPosition) +{ + if (IsClipboardEmpty()) + { + return; + } + BeginTransaction(true); + auto firstNodeIndex = mNodes.size(); + + ImVec2 min(FLT_MAX, FLT_MAX); + for (auto& clipboardNode : mNodesClipboard) + { + min.x = ImMin(clipboardNode.mPos.x, min.x); + min.y = ImMin(clipboardNode.mPos.y, min.y); + } + const ImVec2 offset = viewOffsetPosition - min; + for (auto& selnode : mNodes) + { + selnode.mbSelected = false; + } + + for (size_t i = 0; i < mNodesClipboard.size(); i++) + { + NodeIndex nodeIndex = mNodes.size(); + + auto delNode = [this](int index) { SetDirty(index, Dirty::DeletedNode); }; + auto addNode = [this](int index) { SetDirty(index, Dirty::AddedNode); }; + + auto urNode = mUndoRedo ? std::make_unique>(int(nodeIndex), [this]() { return &mNodes; }, delNode, addNode) : nullptr; + + mNodes.push_back(mNodesClipboard[i]); + mNodes.back().mPos += offset; + mNodes.back().mbSelected = true; + addNode(nodeIndex); + } + + EndTransaction(); +} + +const ParameterBlock& GraphModel::GetParameterBlock(NodeIndex nodeIndex) const +{ + return mNodes[nodeIndex].mParameterBlock; +} + +static ImRect DisplayRectMargin(ImRect rect) +{ + extern ImVec2 captureOffset; + // margins + static const float margin = 10.f; + rect.Min += captureOffset; + rect.Max += captureOffset; + rect.Min -= ImVec2(margin, margin); + rect.Max += ImVec2(margin, margin); + return rect; +} + +ImRect GraphModel::GetNodesDisplayRect() const +{ + ImRect rect; + if (mNodes.empty()) + { + return ImRect(ImVec2(0.f, 0.f), ImVec2(0.f, 0.f)); + } + rect = mNodes[0].GetDisplayRect(); + for (auto& node : mNodes) + { + rect.Add(node.GetDisplayRect()); + } + + return DisplayRectMargin(rect); +} + +ImRect GraphModel::GetFinalNodeDisplayRect(const std::vector& orderList) const +{ + auto& evaluationOrder = orderList; + ImRect rect(ImVec2(0.f, 0.f), ImVec2(0.f, 0.f)); + if (!evaluationOrder.empty() && !mNodes.empty()) + { + auto& node = mNodes[evaluationOrder.back()]; + rect = node.GetDisplayRect(); + } + return DisplayRectMargin(rect); +} + +void GraphModel::RecurseNodeGraphLayout(std::vector& positions, + std::map& stacks, + size_t currentIndex, + int currentLayer) +{ + const auto& nodes = mNodes; + const auto& links = mLinks; + + if (positions[currentIndex].mLayer == -1) + { + positions[currentIndex].mLayer = currentLayer; + int layer = positions[currentIndex].mLayer = currentLayer; + if (stacks.find(layer) != stacks.end()) + stacks[layer]++; + else + stacks[layer] = 0; + positions[currentIndex].mStackIndex = stacks[currentLayer]; + } + else + { + // already hooked node + if (currentLayer > positions[currentIndex].mLayer) + { + // remove stack at current pos + int currentStack = positions[currentIndex].mStackIndex; + for (auto& pos : positions) + { + if (pos.mLayer == positions[currentIndex].mLayer && pos.mStackIndex > currentStack) + { + pos.mStackIndex--; + stacks[pos.mLayer]--; + } + } + // apply new one + int layer = positions[currentIndex].mLayer = currentLayer; + if (stacks.find(layer) != stacks.end()) + stacks[layer]++; + else + stacks[layer] = 0; + positions[currentIndex].mStackIndex = stacks[currentLayer]; + } + } + + size_t InputsCount = gMetaNodes[nodes[currentIndex].mNodeType].mInputs.size(); + std::vector inputNodes(InputsCount, -1); + for (auto& link : links) + { + if (link.mOutputNodeIndex != currentIndex) + continue; + inputNodes[link.mOutputSlotIndex] = link.mInputNodeIndex; + } + for (auto inputNode : inputNodes) + { + if (inputNode == -1) + continue; + RecurseNodeGraphLayout(positions, stacks, inputNode, currentLayer + 1); + } +} + +void GraphModel::NodeGraphLayout(const std::vector& orderList) +{ + if (mNodes.empty()) + { + return; + } + // get stack/layer pos + std::vector nodePositions(mNodes.size(), { -1, -1, -1 }); + std::map stacks; + ImRect sourceRect, destRect; + BeginTransaction(true); + std::vector nodePos(mNodes.size()); + + // compute source bounds + for (unsigned int i = 0; i < mNodes.size(); i++) + { + const auto& node = mNodes[i]; + sourceRect.Add(ImRect(node.mPos, node.mPos + ImVec2(100, 100))); + } + + for (unsigned int i = 0; i < mNodes.size(); i++) + { + NodeIndex nodeIndex = orderList[mNodes.size() - i - 1]; + RecurseNodeGraphLayout(nodePositions, stacks, nodeIndex, 0); + } + + // set corresponding node index in nodePosition + for (unsigned int i = 0; i < mNodes.size(); i++) + { + int nodeIndex = int(orderList[i]); + auto& layout = nodePositions[nodeIndex]; + layout.mNodeIndex = nodeIndex; + } + + // sort nodePositions + std::sort(nodePositions.begin(), nodePositions.end()); + + // set x,y position from layer/stack + float currentStackHeight = 0.f; + int currentLayerIndex = -1; + for (unsigned int i = 0; i < nodePositions.size(); i++) + { + auto& layout = nodePositions[i]; + if (currentLayerIndex != layout.mLayer) + { + currentLayerIndex = layout.mLayer; + currentStackHeight = 0.f; + } + NodeIndex nodeIndex = layout.mNodeIndex; + const auto& node = mNodes[nodeIndex]; + float height = float(gMetaNodes[node.mNodeType].mHeight); + nodePos[nodeIndex] = ImVec2(-layout.mLayer * 180.f, currentStackHeight); + currentStackHeight += height + 40.f; + } + + // new bounds + for (unsigned int i = 0; i < mNodes.size(); i++) + { + ImVec2 newPos = nodePos[i]; + // todo: support height more closely with metanodes + destRect.Add(ImRect(newPos, newPos + ImVec2(100, 100))); + } + + // move all nodes + ImVec2 offset = sourceRect.GetCenter() - destRect.GetCenter(); + for (auto& pos : nodePos) + { + pos += offset; + } + for (auto i = 0; i < mNodes.size(); i++) + { + SetNodePosition(i, nodePos[i]); + } + + // finish undo + EndTransaction(); +} + +bool GraphModel::RecurseIsLinked(int from, int to) const +{ + if (from == to) + { + return true; + } + for (auto& link : mLinks) + { + if (link.mInputNodeIndex == from) + { + if (link.mOutputNodeIndex == to) + return true; + + if (RecurseIsLinked(link.mOutputNodeIndex, to)) + return true; + } + } + return false; +} + +void GraphModel::SetMultiplexed(NodeIndex nodeIndex, SlotIndex slotIndex, int multiplex) +{ + assert(mbTransaction); + auto ur = mUndoRedo + ? std::make_unique>(nodeIndex, [this](int index) { return &mNodes[index]; }, [this, slotIndex](int index) { SetDirty(index, Dirty::Input, slotIndex); }) + : nullptr; + + mNodes[nodeIndex].mMultiplexInput.mInputs[slotIndex] = multiplex; + SetDirty(nodeIndex, Dirty::Input, slotIndex); +} + +bool GraphModel::IsParameterPinned(NodeIndex nodeIndex, size_t parameterIndex) const +{ + uint32_t mask = 1 << parameterIndex; + return mNodes[nodeIndex].mPinnedParameters & mask; +} + +bool GraphModel::IsIOPinned(NodeIndex nodeIndex, size_t io, bool forOutput) const +{ + uint32_t mask = 0; + if (forOutput) + { + mask = (1 << io) & 0xFF; + } + else + { + mask = (1 << (8 + io)); + } + return mNodes[nodeIndex].mPinnedIO & mask; +} + +static bool NodeTypeHasMultiplexer(size_t nodeType) +{ + for (const auto& parameter : gMetaNodes[nodeType].mParams) + { + if (parameter.mType == Con_Multiplexer) + { + return true; + } + } + return false; +} + +void GraphModel::GetMultiplexedInputs(const std::vector& inputs, NodeIndex nodeIndex, std::set& list) const +{ + for (auto input : inputs[nodeIndex].mInputs) + { + if (!input.IsValid()) + { + continue; + } + if (!NodeTypeHasMultiplexer(mNodes[input].mNodeType)) + { + list.insert(input); + } + else + { + GetMultiplexedInputs(inputs, input, list); + } + } +} + +bool GraphModel::GetMultiplexedInputs(const std::vector& inputs, NodeIndex nodeIndex, SlotIndex slotIndex, std::vector& list) const +{ + NodeIndex input = inputs[nodeIndex].mInputs[slotIndex]; + if (!input.IsValid()) + { + return false; + } + if (NodeTypeHasMultiplexer(mNodes[input].mNodeType)) + { + std::set uniqueList; + GetMultiplexedInputs(inputs, input, uniqueList); + for (auto nodeIndex : uniqueList) + { + list.push_back(nodeIndex); + } + return true; + } + return false; +} + +void GraphModel::SetParameterPins(const std::vector& pins) +{ + for (auto i = 0; i < pins.size(); i++) + { + mNodes[i].mPinnedParameters = pins[i]; + } +} + +void GraphModel::SetIOPins(const std::vector& pins) +{ + for (auto i = 0; i < pins.size(); i++) + { + mNodes[i].mPinnedIO = pins[i]; + } +} + +const std::vector GraphModel::GetParameterPins() const +{ + std::vector ret; + ret.reserve(mNodes.size()); + for (auto& node : mNodes) + { + ret.push_back(node.mPinnedParameters); + } + return ret; +} + +const std::vector GraphModel::GetIOPins() const +{ + std::vector ret; + ret.reserve(mNodes.size()); + for (auto& node : mNodes) + { + ret.push_back(node.mPinnedIO); + } + return ret; +} + +const std::vector GraphModel::GetMultiplexInputs() const +{ + std::vector ret; + ret.reserve(mNodes.size()); + for (const auto& node : mNodes) + { + ret.push_back(node.mMultiplexInput); + } + return ret; +} + +void GraphModel::SetStartEndFrame(int startFrame, int endFrame) +{ + assert(mbTransaction); + + auto urStart = mUndoRedo ? std::make_unique>(mStartFrame): nullptr; + auto urEnd = mUndoRedo ? std::make_unique>(mEndFrame) : nullptr; + + mStartFrame = startFrame; + mEndFrame = endFrame; +} + +void GraphModel::SetStartEndFrame(NodeIndex nodeIndex, int startFrame, int endFrame) +{ + assert(mbTransaction); + auto ur = mUndoRedo + ? std::make_unique>(int(nodeIndex), [this](int index) { return &mNodes[index]; }, [this](int index) {SetDirty(index, Dirty::StartEndTime); }) + : nullptr; + + Node& node = mNodes[nodeIndex]; + node.mStartFrame = startFrame; + node.mEndFrame = endFrame; + SetDirty(nodeIndex, Dirty::StartEndTime); +} + +NodeIndex GraphModel::GetNodeIndex(RuntimeId runtimeUniqueId) const +{ + for (int nodeIndex = 0; nodeIndex < mNodes.size(); nodeIndex ++) + { + if (mNodes[nodeIndex].mRuntimeUniqueId == runtimeUniqueId) + { + return nodeIndex; + } + } + return InvalidNodeIndex; +} diff --git a/src/GraphModel.h b/src/GraphModel.h new file mode 100644 index 00000000..0b1eec17 --- /dev/null +++ b/src/GraphModel.h @@ -0,0 +1,238 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +#pragma once + +#include "imgui.h" +#include +#include +#include +#include +#include "Library.h" +#include "EvaluationStages.h" +#include "ParameterBlock.h" + +struct UndoRedo; + +class GraphModel +{ +public: + GraphModel(); + ~GraphModel(); + + struct Rug + { + ImVec2 mPos, mSize; + uint32_t mColor; + std::string mText; + }; + + struct Node + { + Node(int nodeType, ImVec2 position, int startFrame, int endFrame) : mNodeType(nodeType) + , mPos(position) + , mbSelected(false) + , mPinnedIO(0) + , mPinnedParameters(0) + , mStartFrame(startFrame) + , mEndFrame(endFrame) + , mParameterBlock(nodeType) + { + } + + Node() : mNodeType(-1), mbSelected(false), mPinnedIO(0), mPinnedParameters(0), mParameterBlock(-1) + { + } + + int mNodeType; + ImVec2 mPos; + uint32_t mPinnedIO; + uint32_t mPinnedParameters; + int mStartFrame, mEndFrame; + ParameterBlock mParameterBlock; + MultiplexInput mMultiplexInput; + InputSamplers mSamplers; + bool mbSelected; + RuntimeId mRuntimeUniqueId; + // Helpers + ImRect GetDisplayRect() const; + }; + + struct Link + { + int mInputNodeIndex, mInputSlotIndex, mOutputNodeIndex, mOutputSlotIndex; + bool operator==(const Link& other) const + { + return mInputNodeIndex == other.mInputNodeIndex && mInputSlotIndex == other.mInputSlotIndex && + mOutputNodeIndex == other.mOutputNodeIndex && mOutputSlotIndex == other.mOutputSlotIndex; + } + }; + + // Transaction + void Clear(); + void BeginTransaction(bool undoable); + bool InTransaction() const; + void EndTransaction(); + + // undo/redo + void Undo(); + void Redo(); + + // setters + size_t AddNode(size_t type, ImVec2 position); + void SelectNode(NodeIndex nodeIndex, bool selected); + void UnselectNodes(); + void MoveSelectedNodes(const ImVec2 delta); + void SetNodePosition(NodeIndex nodeIndex, const ImVec2 position); + void DeleteSelectedNodes(); + void DeleteNode(NodeIndex nodeIndex); + void AddLink(NodeIndex inputNodeIndex, SlotIndex inputSlotIndex, NodeIndex outputNodeIndex, SlotIndex outputSlotIndex); + void DelLink(NodeIndex inputNodeIndex, SlotIndex inputSlotIndex); + void DelLink(size_t linkIndex); + void AddRug(const Rug& rug); + void DelRug(size_t rugIndex); + void SetRug(size_t rugIndex, const Rug& rug); + void SetSamplers(NodeIndex nodeIndex, const InputSamplers& samplers); + void SetSampler(NodeIndex nodeIndex, size_t input, const InputSampler& sampler); + void SetParameter(NodeIndex nodeIndex, const std::string& parameterName, const std::string& parameterValue); + void SetParameterBlock(NodeIndex nodeIndex, const ParameterBlock& parameterBlock); + void MakeKey(int frame, uint32_t nodeIndex, uint32_t parameterIndex); + void SetIOPin(NodeIndex nodeIndex, size_t io, bool forOutput, bool pinned); + void SetParameterPin(NodeIndex nodeIndex, size_t parameterIndex, bool pinned); + void SetMultiplexed(NodeIndex nodeIndex, SlotIndex slotIndex, int multiplex); + void SetMultiplexInputs(const std::vector& multiplexInputs); + void SetParameterPins(const std::vector& pins); + void SetIOPins(const std::vector& pins); + void SetAnimTrack(const std::vector& animTrack); + void SetStartEndFrame(int startFrame, int endFrame); + void SetStartEndFrame(NodeIndex nodeIndex, int startFrame, int endFrame); + void SetCameraLookAt(NodeIndex nodeIndex, const Vec4& eye, const Vec4& target, const Vec4& up = Vec4(0.f, 1.f, 0.f, 0.f)); + // transaction is handled is the function + void NodeGraphLayout(const std::vector& orderList); + + // getters + size_t GetNodeCount() const { return mNodes.size(); } + int GetNodeType(NodeIndex nodeIndex) const { return mNodes[nodeIndex].mNodeType; } + bool NodeHasUI(NodeIndex nodeIndex) const; + const std::vector& GetRugs() const { return mRugs; } + const std::vector& GetNodes() const { return mNodes; } + const std::vector& GetLinks() const { return mLinks; } + ImVec2 GetNodePos(NodeIndex nodeIndex) const; + bool IsIOUsed(NodeIndex nodeIndex, int slotIndex, bool forOutput) const; + bool IsIOPinned(NodeIndex nodeIndex, size_t io, bool forOutput) const; + bool IsParameterPinned(NodeIndex nodeIndex, size_t parameterIndex) const; + const AnimationTracks& GetAnimationTracks() const; + std::shared_ptr GetSharedAnimationTracks() const { return mAnimationTracks; } + void GetKeyedParameters(int frame, uint32_t nodeIndex, std::vector& keyed) const; + const std::vector GetParameterPins() const; + const std::vector GetIOPins() const; + const std::vector GetMultiplexInputs() const; + const ParameterBlock& GetParameterBlock(NodeIndex nodeIndex) const; + const InputSamplers& GetSamplers(NodeIndex nodeIndex) const { return mNodes[nodeIndex].mSamplers; } + ImRect GetNodesDisplayRect() const; + ImRect GetFinalNodeDisplayRect(const std::vector& orderList) const; + bool RecurseIsLinked(int from, int to) const; + NodeIndex GetMultiplexed(NodeIndex nodeIndex, size_t slotIndex) const { return mNodes[nodeIndex].mMultiplexInput.mInputs[slotIndex]; } + bool GetMultiplexedInputs(const std::vector& inputs, NodeIndex nodeIndex, SlotIndex slotIndex, std::vector& list) const; + AnimTrack* GetAnimTrack(uint32_t nodeIndex, uint32_t parameterIndex); + void GetStartEndFrame(int& startFrame, int& endFrame) const { startFrame = mStartFrame; endFrame = mEndFrame; } + void GetStartEndFrame(NodeIndex nodeIndex, int& startFrame, int& endFrame) const { startFrame = mNodes[nodeIndex].mStartFrame; endFrame = mNodes[nodeIndex].mEndFrame; } + void GetInputs(std::vector& multiplexedInPuts, std::vector& directInputs) const; + NodeIndex GetNodeIndex(RuntimeId runtimeUniqueId) const; + + // dirty + const std::vector& GetDirtyList() const { return mDirtyList; } + void ClearDirtyList() { mDirtyList.clear(); } + + // clipboard + void CopySelectedNodes(); + void CutSelectedNodes(); + void PasteNodes(ImVec2 viewOffsetPosition); + bool IsClipboardEmpty() const; + + +private: + + // ser datas + int mStartFrame, mEndFrame; + std::vector mNodes; + std::vector mLinks; + std::vector mRugs; + std::shared_ptr mAnimationTracks; + + // non ser data / runtime datas + std::vector mNodesClipboard; + std::vector mDirtyList; + + // undo and transaction + bool mbTransaction; + UndoRedo* mUndoRedo; + + void SetDirty(NodeIndex nodeIndex, Dirty::Type flags, SlotIndex slotIndex = {InvalidSlotIndex}) + { + if (flags == Dirty::Input) + { + assert(slotIndex != -1); + } + mDirtyList.push_back({nodeIndex, slotIndex, flags}); + } + void AddNodeHelper(int nodeIndex); + + void DelLinkInternal(size_t linkIndex); + void AddLinkInternal(NodeIndex inputNodeIndex, SlotIndex inputSlotIndex, NodeIndex outputNodeIndex, SlotIndex outputSlotIndex); + void RemoveAnimation(NodeIndex nodeIndex); + + void GetMultiplexedInputs(const std::vector& inputs, NodeIndex nodeIndex, std::set& list) const; + + // layout + struct NodePosition + { + int mLayer; + int mStackIndex; + int mNodeIndex; // used for sorting + + bool operator <(const NodePosition& other) const + { + if (mLayer < other.mLayer) + { + return true; + } + if (mLayer > other.mLayer) + { + return false; + } + if (mStackIndex& positions, + std::map& stacks, + size_t currentIndex, + int currentLayer); + bool HasSelectedNodes() const; +}; \ No newline at end of file diff --git a/src/Imogen.cpp b/src/Imogen.cpp index 5861a3ab..a82c9b70 100644 --- a/src/Imogen.cpp +++ b/src/Imogen.cpp @@ -29,11 +29,9 @@ #include #include #include "EvaluationStages.h" -#include "NodeGraphControler.h" +#include "GraphControler.h" #include "Library.h" -#include "stb_image.h" #include "tinydir.h" -#include "stb_image.h" #include "imgui_stdlib.h" #include "ImSequencer.h" #include "Evaluators.h" @@ -41,9 +39,15 @@ #include "imgui_markdown/imgui_markdown.h" #include "imHotKey.h" #include "imgInspect.h" +#include "IconsFontAwesome5.h" +#include "Mem.h" +#include +#include +#include "Libraries.h" +#include "ImGuizmo.h" +#include "Cam.h" Imogen* Imogen::instance = nullptr; -unsigned char* stbi_write_png_to_mem(unsigned char* pixels, int stride_bytes, int x, int y, int n, int* out_len); extern TaskScheduler g_TS; @@ -75,10 +79,8 @@ inline ImGui::MarkdownImageData ImageCallback(ImGui::MarkdownLinkCallbackData da ((Imogen*)data_.userData)->DecodeThumbnailAsync(libraryMaterial); return {true, true, - (ImTextureID)(uint64_t)libraryMaterial->mThumbnailTextureId, - ImVec2(100, 100), - ImVec2(0.f, 1.f), - ImVec2(1.f, 0.f)}; + (ImTextureID)(uint64_t)libraryMaterial->mThumbnailTextureHandle.idx, + ImVec2(100, 100)}; } } else @@ -90,17 +92,15 @@ inline ImGui::MarkdownImageData ImageCallback(ImGui::MarkdownLinkCallbackData da sscanf(url.c_str() + sz + 1, "%d%%", &percent); url = url.substr(0, sz); } - unsigned int textureId = gImageCache.GetTexture(url); - if (textureId) + + bgfx::TextureHandle textureHandle = gImageCache.GetTexture(url); + if (textureHandle.idx) { - int w, h; - GetTextureDimension(textureId, &w, &h); + auto size = gImageCache.GetImageSize(url); return {true, false, - (ImTextureID)(uint64_t)textureId, - ImVec2(float(w * percent / 100), float(h * percent / 100)), - ImVec2(0.f, 1.f), - ImVec2(1.f, 0.f)}; + (ImTextureID)(uint64_t)textureHandle.idx, + ImVec2(float(size.first * percent / 100), float(size.second * percent / 100))}; } } @@ -114,17 +114,49 @@ struct ExtractedView size_t mNodeIndex; bool mFirstFrame; }; + std::vector mExtratedViews; void AddExtractedView(size_t nodeIndex) { mExtratedViews.push_back({nodeIndex, true}); } + void ClearExtractedViews() { mExtratedViews.clear(); } -void Imogen::RenderPreviewNode(int selNode, NodeGraphControler& nodeGraphControler, bool forceUI) +void ExtractedViewNodeDeleted(size_t nodeIndex) +{ + auto iter = mExtratedViews.begin(); + for (;iter != mExtratedViews.end(); ) + { + if (iter->mNodeIndex == nodeIndex) + { + iter = mExtratedViews.erase(iter); + continue; + } + if (iter->mNodeIndex > nodeIndex) + { + iter->mNodeIndex --; + } + ++iter; + } +} + +void ExtractedViewNodeInserted(size_t nodeIndex) +{ + for (auto& extract : mExtratedViews) + { + if (extract.mNodeIndex >= nodeIndex) + { + extract.mNodeIndex ++; + } + } +} + + +bool Imogen::RenderPreviewNode(NodeIndex selNode, GraphControler& nodeGraphControler, ParameterBlock& parameterBlock, bool forceUI) { ImGuiIO& io = ImGui::GetIO(); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); @@ -132,34 +164,41 @@ void Imogen::RenderPreviewNode(int selNode, NodeGraphControler& nodeGraphControl ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF000000); ImGui::PushStyleColor(ImGuiCol_Button, 0xFF000000); float w = ImGui::GetContentRegionAvail().x; + float h = w; int imageWidth(1), imageHeight(1); // make 2 evaluation for node to get the UI pass image size - if (selNode != -1 && nodeGraphControler.NodeHasUI(selNode)) + if (selNode.IsValid() && nodeGraphControler.mModel.NodeHasUI(selNode)) { - nodeGraphControler.mEditingContext.AllocRenderTargetsForEditingPreview(); + //nodeGraphControler.mEditingContext.AllocRenderTargetsForEditingPreview(); TODOEVA EvaluationInfo evaluationInfo; - evaluationInfo.forcedDirty = 1; + //evaluationInfo.forcedDirty = 1; evaluationInfo.uiPass = 1; - nodeGraphControler.mEditingContext.RunSingle(selNode, evaluationInfo); + //nodeGraphControler.mEditingContext.RunSingle(selNode, 1, evaluationInfo); } EvaluationAPI::GetEvaluationSize(&nodeGraphControler.mEditingContext, selNode, &imageWidth, &imageHeight); - if (selNode != -1 && nodeGraphControler.NodeHasUI(selNode)) + if (selNode.IsValid() && nodeGraphControler.mModel.NodeHasUI(selNode)) { EvaluationInfo evaluationInfo; - evaluationInfo.forcedDirty = 1; + //evaluationInfo.forcedDirty = 1; evaluationInfo.uiPass = 0; - nodeGraphControler.mEditingContext.RunSingle(selNode, evaluationInfo); + //nodeGraphControler.mEditingContext.RunSingle(selNode, 1, evaluationInfo); } ImTextureID displayedTexture = 0; ImRect rc; ImVec2 displayedTextureSize; ImVec2 mouseUVCoord(-FLT_MAX, -FLT_MAX); + const ImVec2 p = ImGui::GetCursorPos() + ImGui::GetWindowPos(); + Vec4 uva(0, 0), uvb(1, 1); if (imageWidth && imageHeight) { - float ratio = float(imageHeight) / float(imageWidth); - float h = w * ratio; - ImVec2 p = ImGui::GetCursorPos() + ImGui::GetWindowPos(); + const float ratio = float(imageHeight) / float(imageWidth); + h = w * ratio; + + if (nodeGraphControler.mModel.NodeHasUI(selNode)) + { + h = w; + } if (forceUI) { @@ -174,30 +213,34 @@ void Imogen::RenderPreviewNode(int selNode, NodeGraphControler& nodeGraphControl } else { - if (selNode != -1 && nodeGraphControler.NodeIsCubemap(selNode)) + if (selNode.IsValid() && nodeGraphControler.NodeIsCubemap(selNode)) { ImGui::InvisibleButton("ImTheInvisibleMan", ImVec2(w, h)); } else { displayedTexture = (ImTextureID)(int64_t)( - (selNode != -1) ? nodeGraphControler.mEditingContext.GetEvaluationTexture(selNode) : 0); + (selNode.IsValid()) ? nodeGraphControler.mEditingContext.GetEvaluationTexture(selNode).idx : 0); if (displayedTexture) { auto tgt = nodeGraphControler.mEditingContext.GetRenderTarget(selNode); - displayedTextureSize = ImVec2(float(tgt->mImage->mWidth), float(tgt->mImage->mHeight)); + if (tgt) + { + displayedTextureSize = ImVec2(float(tgt->mImage.mWidth), float(tgt->mImage.mHeight)); + } } ImVec2 mouseUVPos = (io.MousePos - p) / ImVec2(w, h); mouseUVPos.y = 1.f - mouseUVPos.y; Vec4 mouseUVPosv(mouseUVPos.x, mouseUVPos.y); mouseUVCoord = ImVec2(mouseUVPosv.x, mouseUVPosv.y); - Vec4 uva(0, 0), uvb(1, 1); + + auto nodeType = nodeGraphControler.mModel.GetNodeType(selNode); Mat4x4* viewMatrix = nodeGraphControler.mEvaluationStages.GetParameterViewMatrix(selNode); - Camera* nodeCamera = nodeGraphControler.mEvaluationStages.GetCameraParameter(selNode); + const Camera* nodeCamera = nodeGraphControler.mModel.GetParameterBlock(selNode).GetCamera(); if (viewMatrix && !nodeCamera) { - Mat4x4& res = *viewMatrix; + Mat4x4 res = *viewMatrix; Mat4x4 tr, trp, sc; static float scale = 1.f; scale = ImLerp(scale, 1.f, 0.15f); @@ -208,7 +251,7 @@ void Imogen::RenderPreviewNode(int selNode, NodeGraphControler& nodeGraphControl ImVec2 pix2uv = ImVec2(1.f, 1.f) / ImVec2(w, h); Vec4 localTranslate; - localTranslate = Vec4(-io.MouseDelta.x * pix2uv.x, io.MouseDelta.y * pix2uv.y) * + localTranslate = Vec4(-io.MouseDelta.x * pix2uv.x, -io.MouseDelta.y * pix2uv.y) * ((io.KeyAlt && io.MouseDown[2]) ? 1.f : 0.f) * res[0]; Mat4x4 localTranslateMat; localTranslateMat.Translation(localTranslate); @@ -229,19 +272,15 @@ void Imogen::RenderPreviewNode(int selNode, NodeGraphControler& nodeGraphControl uva.TransformPoint(res); uvb.TransformPoint(res); + *viewMatrix = res; } - - ImGui::ImageButton(displayedTexture, ImVec2(w, h), ImVec2(uva.x, uvb.y), ImVec2(uvb.x, uva.y)); + + ImGui::ImageButton(displayedTexture, ImVec2(w, h), ImVec2(uva.x, uva.y), ImVec2(uvb.x, uvb.y)); } rc = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); ImDrawList* draw_list = ImGui::GetWindowDrawList(); - if (selNode != -1 && nodeGraphControler.NodeIsCubemap(selNode)) - { - AddUICustomDraw( - draw_list, rc, DrawUICallbacks::DrawUICubemap, selNode, &nodeGraphControler.mEditingContext); - } - else if (selNode != -1 && nodeGraphControler.NodeHasUI(selNode)) + if (selNode.IsValid() && nodeGraphControler.mModel.NodeHasUI(selNode)) { AddUICustomDraw( draw_list, rc, DrawUICallbacks::DrawUISingle, selNode, &nodeGraphControler.mEditingContext); @@ -266,23 +305,29 @@ void Imogen::RenderPreviewNode(int selNode, NodeGraphControler& nodeGraphControl int width = pickerImage.mWidth; int height = pickerImage.mHeight; - ImageInspect::inspect(width, height, pickerImage.GetBits(), mouseUVCoord, displayedTextureSize); + + ImVec2 mousePos = (io.MousePos - p) / ImVec2(w, h); + ImVec2 mousePosTr; + mousePosTr.x = ImLerp(uva.x, uvb.x, mousePos.x); + mousePosTr.y = 1.f - ImLerp(uva.y, uvb.y, mousePos.y); + ImageInspect::inspect(width, height, pickerImage.GetBits(), mousePosTr, displayedTextureSize, true); } else if (ImGui::IsWindowFocused()) { Image::Free(&pickerImage); ImVec2 ratio((io.MousePos.x - rc.Min.x) / rc.GetSize().x, (io.MousePos.y - rc.Min.y) / rc.GetSize().y); ImVec2 deltaRatio((io.MouseDelta.x) / rc.GetSize().x, (io.MouseDelta.y) / rc.GetSize().y); - nodeGraphControler.SetKeyboardMouse(ratio.x, - ratio.y, - deltaRatio.x, - deltaRatio.y, - io.MouseDown[0], - io.MouseDown[1], - io.MouseWheel, - io.KeyCtrl, - io.KeyAlt, - io.KeyShift); + UIInput input = {ratio.x, + ratio.y, + deltaRatio.x, + deltaRatio.y, + io.MouseWheel, + io.MouseDown[0], + io.MouseDown[1], + io.KeyCtrl, + io.KeyAlt, + io.KeyShift}; + nodeGraphControler.SetKeyboardMouse(selNode, input, true); } lastSentExit = -1; } @@ -291,10 +336,39 @@ void Imogen::RenderPreviewNode(int selNode, NodeGraphControler& nodeGraphControl if (lastSentExit != selNode) { lastSentExit = selNode; - nodeGraphControler.SetKeyboardMouse( - -9999.f, -9999.f, -9999.f, -9999.f, false, false, 0.f, false, false, false); + UIInput input = { + -9999.f, + -9999.f, + -9999.f, + -9999.f, + 0, + false, + false, + false, + false, + false + }; + nodeGraphControler.SetKeyboardMouse(selNode, input, false); + } + } + + // imView + Camera *camera = parameterBlock.GetCamera(); + if (camera) + { + Mat4x4 view, viewInverse; + camera->ComputeViewMatrix(view.m16, viewInverse.m16); + static const float viewManipulatorSize = 80.f; + if (w > viewManipulatorSize * 1.5f) + { + if (ImGuizmo::ViewManipulate(view.m16, camera->mLens.y, p + ImVec2(w - viewManipulatorSize - 4, 4), ImVec2(viewManipulatorSize, viewManipulatorSize), 0x40404040)) + { + camera->SetViewMatrix(view); + return true; + } } } + return false; } template @@ -332,7 +406,7 @@ struct SortedResource struct PinnedTaskUploadImage : PinnedTask { - PinnedTaskUploadImage(Image* image, ASyncId identifier, bool isThumbnail, NodeGraphControler* controler) + PinnedTaskUploadImage(Image* image, ASyncId identifier, bool isThumbnail, GraphControler* controler) : PinnedTask(0) // set pinned thread to 0 , mImage(image) , mIdentifier(identifier) @@ -343,63 +417,79 @@ struct PinnedTaskUploadImage : PinnedTask virtual void Execute() { - unsigned int textureId = Image::Upload(mImage, 0); + bgfx::TextureHandle textureHandle = Image::Upload(mImage, {0}); if (mbIsThumbnail) { Material* material = library.Get(mIdentifier); if (material) - material->mThumbnailTextureId = textureId; + { + material->mThumbnailTextureHandle = textureHandle; + } } else { - auto* node = mControler->Get(mIdentifier); - size_t nodeIndex = node - mControler->mEvaluationStages.mStages.data(); - if (node) + auto nodeIndex = mControler->mModel.GetNodeIndex(mIdentifier.second); + if (nodeIndex.IsValid()) { - EvaluationAPI::SetEvaluationImage(&mControler->mEditingContext, int(nodeIndex), mImage); - mControler->mEvaluationStages.SetEvaluationParameters(nodeIndex, node->mParameters); + EvaluationAPI::SetEvaluationImage(&mControler->mEditingContext, nodeIndex, mImage); + mControler->mEditingContext.GenerateThumbnail(nodeIndex); mControler->mEditingContext.StageSetProcessing(nodeIndex, false); } Image::Free(mImage); } } Image* mImage; - NodeGraphControler* mControler; + GraphControler* mControler; ASyncId mIdentifier; bool mbIsThumbnail; }; struct DecodeThumbnailTaskSet : TaskSet { - DecodeThumbnailTaskSet(std::vector* src, ASyncId identifier, NodeGraphControler* nodeGraphControler) + DecodeThumbnailTaskSet(std::vector* src, ASyncId identifier, GraphControler* nodeGraphControler) : TaskSet(), mIdentifier(identifier), mSrc(src), mNodeGraphControler(nodeGraphControler) { } virtual void ExecuteRange(TaskSetPartition range, uint32_t threadnum) { Image image; - int components; - unsigned char* data = - stbi_load_from_memory(mSrc->data(), int(mSrc->size()), &image.mWidth, &image.mHeight, &components, 0); - if (data) - { - image.SetBits(data, image.mWidth * image.mHeight * components); - image.mNumFaces = 1; - image.mNumMips = 1; - image.mFormat = (components == 4) ? TextureFormat::RGBA8 : TextureFormat::RGB8; + if (!mSrc->empty() && Image::ReadMem(mSrc->data(), mSrc->size(), &image) == EVAL_OK) + { PinnedTaskUploadImage uploadTexTask(&image, mIdentifier, true, mNodeGraphControler); g_TS.AddPinnedTask(&uploadTexTask); g_TS.WaitforTask(&uploadTexTask); - stbi_image_free(data); Image::Free(&image); } delete this; } ASyncId mIdentifier; std::vector* mSrc; - NodeGraphControler* mNodeGraphControler; + GraphControler* mNodeGraphControler; }; +struct stbi_context +{ + stbi_context() : mDest(0), mOffset(0) + {} + ~stbi_context() { free(mDest); } + unsigned char *mDest; + size_t mOffset; + size_t mAllocated; +}; +static void stbi_write_func_mem(void *context, void *data, int size) +{ + stbi_context* ctx = (stbi_context*)context; + if (ctx->mOffset + size > ctx->mAllocated) + { + ctx->mAllocated = ctx->mOffset + size + 10240; + ctx->mDest = (unsigned char*)realloc(ctx->mDest, ctx->mAllocated); + } + + memcpy(&ctx->mDest[ctx->mOffset], data, size); + ctx->mOffset += size; +} +bx::AllocatorI* getDefaultAllocator(); + struct EncodeImageTaskSet : TaskSet { EncodeImageTaskSet(Image image, ASyncId materialIdentifier, ASyncId nodeIdentifier) @@ -408,25 +498,13 @@ struct EncodeImageTaskSet : TaskSet } virtual void ExecuteRange(TaskSetPartition range, uint32_t threadnum) { - int outlen; - int components = 4; - unsigned char* bits = stbi_write_png_to_mem((unsigned char*)mImage.GetBits(), - mImage.mWidth * components, - mImage.mWidth, - mImage.mHeight, - components, - &outlen); - if (bits) - { - Material* material = library.Get(mMaterialIdentifier); - if (material) + Material* material = library.Get(mMaterialIdentifier); + if (material) + { + MaterialNode* node = material->Get(mNodeIdentifier); + if (node) { - MaterialNode* node = material->Get(mNodeIdentifier); - if (node) - { - node->mImage.resize(outlen); - memcpy(node->mImage.data(), bits, outlen); - } + Image::EncodePng(&mImage, node->mImage); } } delete this; @@ -438,40 +516,33 @@ struct EncodeImageTaskSet : TaskSet struct DecodeImageTaskSet : TaskSet { - DecodeImageTaskSet(std::vector* src, ASyncId identifier, NodeGraphControler* nodeGraphControler) + DecodeImageTaskSet(std::vector* src, ASyncId identifier, GraphControler* nodeGraphControler) : TaskSet(), mIdentifier(identifier), mSrc(src), mNodeGraphControler(nodeGraphControler) { } virtual void ExecuteRange(TaskSetPartition range, uint32_t threadnum) { Image image; - int components; - unsigned char* data = - stbi_load_from_memory(mSrc->data(), int(mSrc->size()), &image.mWidth, &image.mHeight, &components, 0); - if (data) - { - image.SetBits(data, image.mWidth * image.mHeight * components); - image.mNumFaces = 1; - image.mNumMips = 1; - image.mFormat = (components == 3) ? TextureFormat::RGB8 : TextureFormat::RGBA8; + if (!mSrc->empty() && Image::ReadMem(mSrc->data(), mSrc->size(), &image) == EVAL_OK) + { PinnedTaskUploadImage uploadTexTask(&image, mIdentifier, false, mNodeGraphControler); g_TS.AddPinnedTask(&uploadTexTask); g_TS.WaitforTask(&uploadTexTask); - stbi_image_free(data); + Image::Free(&image); } delete this; } ASyncId mIdentifier; std::vector* mSrc; - NodeGraphControler* mNodeGraphControler; + GraphControler* mNodeGraphControler; }; void Imogen::DecodeThumbnailAsync(Material* material) { - static unsigned int defaultTextureId = gImageCache.GetTexture("Stock/thumbnail-icon.png"); - if (!material->mThumbnailTextureId) + static bgfx::TextureHandle defaultTextureHandle = gImageCache.GetTexture("Stock/thumbnail-icon.png"); + if (material->mThumbnailTextureHandle.idx == bgfx::kInvalidHandle) { - material->mThumbnailTextureId = defaultTextureId; + material->mThumbnailTextureHandle = defaultTextureHandle; g_TS.AddTaskSetToPipe( new DecodeThumbnailTaskSet(&material->mThumbnail, std::make_pair(material - library.mMaterials.data(), material->mRuntimeUniqueId), @@ -550,7 +621,7 @@ bool TVRes(std::vector& res, const char* szName, int& selection, int inde break; case 1: ImGui::Image( - (ImTextureID)(int64_t)(resource.mThumbnailTextureId), ImVec2(64, 64), ImVec2(0, 1), ImVec2(1, 0)); + (ImTextureID)(int64_t)(resource.mThumbnailTextureHandle.idx), ImVec2(64, 64)); clicked = ImGui::IsItemClicked(); ImGui::SameLine(); ImGui::TreeNodeEx(GetName(resource.mName).c_str(), node_flags); @@ -558,12 +629,12 @@ bool TVRes(std::vector& res, const char* szName, int& selection, int inde break; case 2: ImGui::Image( - (ImTextureID)(int64_t)(resource.mThumbnailTextureId), ImVec2(64, 64), ImVec2(0, 1), ImVec2(1, 0)); + (ImTextureID)(int64_t)(resource.mThumbnailTextureHandle.idx), ImVec2(64, 64)); clicked = ImGui::IsItemClicked(); break; case 3: ImGui::Image( - (ImTextureID)(int64_t)(resource.mThumbnailTextureId), ImVec2(128, 128), ImVec2(0, 1), ImVec2(1, 0)); + (ImTextureID)(int64_t)(resource.mThumbnailTextureHandle.idx), ImVec2(128, 128)); clicked = ImGui::IsItemClicked(); break; } @@ -583,19 +654,20 @@ bool TVRes(std::vector& res, const char* szName, int& selection, int inde return ret; } -void ValidateMaterial(Library& library, NodeGraphControler& nodeGraphControler, int materialIndex) +void CommitGraph(Library& library, GraphControler& nodeGraphControler, int materialIndex) { if (materialIndex == -1) return; Material& material = library.mMaterials[materialIndex]; - material.mMaterialNodes.resize(nodeGraphControler.mEvaluationStages.mStages.size()); + const auto& model = nodeGraphControler.mModel; + auto nodeCount = model.GetNodeCount(); + material.mMaterialNodes.resize(nodeCount); - for (size_t i = 0; i < nodeGraphControler.mEvaluationStages.mStages.size(); i++) + for (size_t i = 0; i < nodeCount; i++) { - auto srcNode = nodeGraphControler.mEvaluationStages.mStages[i]; + auto nodeType = model.GetNodeType(i); MaterialNode& dstNode = material.mMaterialNodes[i]; - MetaNode& metaNode = gMetaNodes[srcNode.mType]; - dstNode.mRuntimeUniqueId = GetRuntimeId(); + MetaNode& metaNode = gMetaNodes[nodeType]; if (metaNode.mbSaveTexture) { Image image; @@ -607,27 +679,29 @@ void ValidateMaterial(Library& library, NodeGraphControler& nodeGraphControler, } } - dstNode.mType = uint32_t(srcNode.mType); + dstNode.mNodeType = uint32_t(nodeType); dstNode.mTypeName = metaNode.mName; - dstNode.mParameters = srcNode.mParameters; - dstNode.mInputSamplers = srcNode.mInputSamplers; - ImVec2 nodePos = NodeGraphGetNodePos(i); + dstNode.mParameters = model.GetParameterBlock(i); + dstNode.mInputSamplers = model.GetSamplers(i); + ImVec2 nodePos = model.GetNodePos(i); dstNode.mPosX = int32_t(nodePos.x); dstNode.mPosY = int32_t(nodePos.y); - dstNode.mFrameStart = srcNode.mStartFrame; - dstNode.mFrameEnd = srcNode.mEndFrame; + int times[2]; + model.GetStartEndFrame(i, times[0], times[1]); + dstNode.mFrameStart = uint32_t(times[0]); // todo serialize time as signed values + dstNode.mFrameEnd = uint32_t(times[1]); } - auto links = NodeGraphGetLinks(); + auto links = model.GetLinks(); material.mMaterialConnections.resize(links.size()); for (size_t i = 0; i < links.size(); i++) { MaterialConnection& materialConnection = material.mMaterialConnections[i]; - materialConnection.mInputNode = links[i].InputIdx; - materialConnection.mInputSlot = links[i].InputSlot; - materialConnection.mOutputNode = links[i].OutputIdx; - materialConnection.mOutputSlot = links[i].OutputSlot; + materialConnection.mInputNodeIndex = links[i].mInputNodeIndex; + materialConnection.mInputSlotIndex = links[i].mInputSlotIndex; + materialConnection.mOutputNodeIndex = links[i].mOutputNodeIndex; + materialConnection.mOutputSlotIndex = links[i].mOutputSlotIndex; } - auto rugs = NodeGraphRugs(); + auto rugs = model.GetRugs(); material.mMaterialRugs.resize(rugs.size()); for (size_t i = 0; i < rugs.size(); i++) { @@ -639,12 +713,11 @@ void ValidateMaterial(Library& library, NodeGraphControler& nodeGraphControler, rug.mColor = rugs[i].mColor; rug.mComment = rugs[i].mText; } - material.mAnimTrack = nodeGraphControler.GetAnimTrack(); - material.mFrameMin = nodeGraphControler.mEvaluationStages.mFrameMin; - material.mFrameMax = nodeGraphControler.mEvaluationStages.mFrameMax; - material.mPinnedParameters = nodeGraphControler.mEvaluationStages.mPinnedParameters; - material.mPinnedIO = nodeGraphControler.mEvaluationStages.mPinnedIO; - + material.mAnimTrack = model.GetAnimationTracks(); + model.GetStartEndFrame(material.mFrameMin, material.mFrameMax); + material.mPinnedParameters = model.GetParameterPins(); + material.mPinnedIO = model.GetIOPins(); + material.mMultiplexInputs = model.GetMultiplexInputs(); material.mBackgroundNode = *(uint32_t*)(&nodeGraphControler.mBackgroundNode); } @@ -655,7 +728,20 @@ int Imogen::AddNode(const std::string& nodeType) { return -1; } - return int(NodeGraphAddNode(mNodeGraphControler, type, nullptr, 0, 0, 0, 1)); + auto& model = mNodeGraphControler->mModel; + model.BeginTransaction(false); + auto nodeIndex = model.AddNode(type, ImVec2(0, 0)); + model.SetStartEndFrame(nodeIndex, 0, 1); + model.EndTransaction(); + return int(nodeIndex); +} + +void Imogen::DelNode(int nodeIndex) +{ + auto& model = mNodeGraphControler->mModel; + mNodeGraphControler->mModel.BeginTransaction(false); + model.DeleteNode(nodeIndex); + mNodeGraphControler->mModel.EndTransaction(); } void Imogen::UpdateNewlySelectedGraph() @@ -664,83 +750,104 @@ void Imogen::UpdateNewlySelectedGraph() if (mSelectedMaterial != -1) { ClearAll(); - + auto& model = mNodeGraphControler->mModel; + model.BeginTransaction(false); Material& material = library.mMaterials[mSelectedMaterial]; - for (size_t i = 0; i < material.mMaterialNodes.size(); i++) + auto nodeCount = material.mMaterialNodes.size(); + std::vector* >> nodeImages; + for (size_t i = 0; i < nodeCount; i++) { MaterialNode& node = material.mMaterialNodes[i]; - if (node.mType == 0xFFFFFFFF) + if (node.mNodeType == 0xFFFFFFFF) continue; - NodeGraphAddNode(mNodeGraphControler, - node.mType, - &node.mParameters, - node.mPosX, - node.mPosY, - node.mFrameStart, - node.mFrameEnd); - auto& lastNode = mNodeGraphControler->mEvaluationStages.mStages.back(); + + auto nodeIndex = model.AddNode(node.mNodeType, ImVec2(float(node.mPosX), float(node.mPosY))); + model.SetParameterBlock(nodeIndex, ParameterBlock(node.mNodeType, node.mParameters)); + model.SetStartEndFrame(nodeIndex, node.mFrameStart, node.mFrameEnd); + model.SetSamplers(nodeIndex, node.mInputSamplers); if (!node.mImage.empty()) { - mNodeGraphControler->mEditingContext.StageSetProcessing(i, true); - g_TS.AddTaskSetToPipe(new DecodeImageTaskSet( - &node.mImage, std::make_pair(i, lastNode.mRuntimeUniqueId), mNodeGraphControler)); + nodeImages.push_back({i, &node.mImage }); } - lastNode.mInputSamplers = node.mInputSamplers; - mNodeGraphControler->mEvaluationStages.SetEvaluationSampler(i, node.mInputSamplers); } for (size_t i = 0; i < material.mMaterialConnections.size(); i++) { MaterialConnection& materialConnection = material.mMaterialConnections[i]; - NodeGraphAddLink(mNodeGraphControler, - materialConnection.mInputNode, - materialConnection.mInputSlot, - materialConnection.mOutputNode, - materialConnection.mOutputSlot); + model.AddLink(uint16_t(materialConnection.mInputNodeIndex), + materialConnection.mInputSlotIndex, + uint16_t(materialConnection.mOutputNodeIndex), + materialConnection.mOutputSlotIndex); } for (size_t i = 0; i < material.mMaterialRugs.size(); i++) { MaterialNodeRug& rug = material.mMaterialRugs[i]; - NodeGraphAddRug(rug.mPosX, rug.mPosY, rug.mSizeX, rug.mSizeY, rug.mColor, rug.mComment); + model.AddRug({ImVec2(float(rug.mPosX), float(rug.mPosY)), + ImVec2(float(rug.mSizeX), float(rug.mSizeY)), + rug.mColor, + rug.mComment}); + } + material.mPinnedParameters.resize(model.GetNodeCount()); + material.mPinnedIO.resize(model.GetNodeCount()); + material.mMultiplexInputs.resize(model.GetNodeCount()); + + + model.SetStartEndFrame(material.mFrameMin, material.mFrameMax); + model.SetAnimTrack(material.mAnimTrack); + model.SetParameterPins(material.mPinnedParameters); + model.SetIOPins(material.mPinnedIO); + model.SetMultiplexInputs(material.mMultiplexInputs); + model.EndTransaction(); + mNodeGraphControler->ApplyDirtyList(); + // upload custom images to nodes + for (auto nodeImage : nodeImages) + { + auto nodeIndex = nodeImage.first; + const auto imageArray = nodeImage.second; + //auto& lastNode = mNodeGraphControler->mEvaluationStages.mStages[nodeIndex]; + mNodeGraphControler->mEditingContext.StageSetProcessing(nodeIndex, true); + g_TS.AddTaskSetToPipe(new DecodeImageTaskSet( + imageArray, std::make_pair(nodeIndex, model.GetNodes()[nodeIndex].mRuntimeUniqueId), mNodeGraphControler)); } - NodeGraphUpdateEvaluationOrder(mNodeGraphControler); - NodeGraphUpdateScrolling(); + + + + GraphEditorUpdateScrolling(mNodeGraphControler); + mCurrentTime = 0; mbIsPlaying = false; mNodeGraphControler->mEditingContext.SetCurrentTime(mCurrentTime); - mNodeGraphControler->mEvaluationStages.SetAnimTrack(material.mAnimTrack); - mNodeGraphControler->mEvaluationStages.mFrameMin = material.mFrameMin; - mNodeGraphControler->mEvaluationStages.mFrameMax = material.mFrameMax; - mNodeGraphControler->mEvaluationStages.mPinnedParameters = material.mPinnedParameters; - mNodeGraphControler->mEvaluationStages.mPinnedIO = material.mPinnedIO; - mNodeGraphControler->mEvaluationStages.mPinnedIO.resize(material.mMaterialNodes.size(), 0); - mNodeGraphControler->mBackgroundNode = *(int*)(&material.mBackgroundNode); + + //mNodeGraphControler->mBackgroundNode = *(int*)(&material.mBackgroundNode); TODO + mNodeGraphControler->mEditingContext.SetMaterialUniqueId(material.mRuntimeUniqueId); + mNodeGraphControler->mEvaluationStages.SetMaterialUniqueId(material.mRuntimeUniqueId); + mNodeGraphControler->mEvaluationStages.mAnimationTracks = model.GetSharedAnimationTracks(); mNodeGraphControler->mEvaluationStages.SetTime(&mNodeGraphControler->mEditingContext, mCurrentTime, true); mNodeGraphControler->mEvaluationStages.ApplyAnimation(&mNodeGraphControler->mEditingContext, mCurrentTime); - mNodeGraphControler->mEditingContext.SetMaterialUniqueId(material.mRuntimeUniqueId); - mNodeGraphControler->mEditingContext.RunAll(); } } -void Imogen::NewMaterial(const std::string& materialName) +Material& Imogen::NewMaterial(const std::string& materialName) { int previousSelection = mSelectedMaterial; library.mMaterials.push_back(Material()); Material& back = library.mMaterials.back(); back.mName = materialName; - back.mThumbnailTextureId = 0; - back.mRuntimeUniqueId = GetRuntimeId(); + back.mThumbnailTextureHandle = {bgfx::kInvalidHandle}; + back.mBackgroundNode = -1; if (previousSelection != -1) { - ValidateMaterial(library, *mNodeGraphControler, previousSelection); + CommitGraph(library, *mNodeGraphControler, previousSelection); } mSelectedMaterial = int(library.mMaterials.size()) - 1; ClearAll(); + mNodeGraphControler->SetMaterialUniqueId(back.mRuntimeUniqueId); + return library.mMaterials.back(); } void Imogen::ImportMaterial() { - #ifdef NFD_OpenDialog +#if defined(_NFD_H) nfdchar_t* outPath = NULL; nfdresult_t result = NFD_OpenDialog("imogen", NULL, &outPath); @@ -755,13 +862,15 @@ void Imogen::ImportMaterial() } free(outPath); } - #endif +#endif } void Imogen::LibraryEdit(Library& library) { int previousSelection = mSelectedMaterial; - if (Button("MaterialNew", "New Material", ImVec2(0, 0))) + if (Button("MaterialNew", + ICON_FA_PLUS " New Material", + ImVec2(0, 0))) { NewMaterial(); } @@ -772,14 +881,14 @@ void Imogen::LibraryEdit(Library& library) } ImGui::SameLine(); - unsigned int libraryViewTextureId = gImageCache.GetTexture("Stock/library-view.png"); + bgfx::TextureHandle libraryViewTextureHandle = gImageCache.GetTexture("Stock/library-view.png"); static const ImVec2 iconSize(16.f, 16.f); for (int i = 0; i < 4; i++) { if (i) ImGui::SameLine(); ImGui::PushID(99 + i); - if (ImGui::ImageButton((ImTextureID)(int64_t)libraryViewTextureId, + if (ImGui::ImageButton((ImTextureID)(int64_t)libraryViewTextureHandle.idx, iconSize, ImVec2(float(i) * 0.25f, 0.f), ImVec2(float(i + 1) * 0.25f, 1.f), @@ -793,11 +902,11 @@ void Imogen::LibraryEdit(Library& library) ImGui::BeginChild("TV"); if (TVRes(library.mMaterials, "Graphs", mSelectedMaterial, 0, mLibraryViewMode, this)) { - mNodeGraphControler->mSelectedNodeIndex = -1; + mNodeGraphControler->mSelectedNodeIndex.SetInvalid(); // save previous if (previousSelection != -1) { - ValidateMaterial(library, *mNodeGraphControler, previousSelection); + CommitGraph(library, *mNodeGraphControler, previousSelection); } UpdateNewlySelectedGraph(); } @@ -818,7 +927,7 @@ void Imogen::SetExistingMaterialActive(int materialIndex) { if (materialIndex != mSelectedMaterial && mSelectedMaterial != -1) { - ValidateMaterial(library, *mNodeGraphControler, mSelectedMaterial); + CommitGraph(library, *mNodeGraphControler, mSelectedMaterial); } mSelectedMaterial = materialIndex; UpdateNewlySelectedGraph(); @@ -826,14 +935,14 @@ void Imogen::SetExistingMaterialActive(int materialIndex) struct AnimCurveEdit : public ImCurveEdit::Delegate { - AnimCurveEdit(NodeGraphControler& NodeGraphControler, + AnimCurveEdit(GraphControler& GraphControler, ImVec2& min, ImVec2& max, - std::vector& animTrack, + AnimationTracks& animTrack, std::vector& visible, int nodeIndex, int currentTime) - : mNodeGraphControler(NodeGraphControler) + : mNodeGraphControler(GraphControler) , mMin(min) , mMax(max) , mAnimTrack(animTrack) @@ -841,7 +950,8 @@ struct AnimCurveEdit : public ImCurveEdit::Delegate , mNodeIndex(nodeIndex) , mCurrentTime(currentTime) { - size_t type = mNodeGraphControler.mEvaluationStages.mStages[nodeIndex].mType; + const auto& model = mNodeGraphControler.mModel; + size_t type = model.GetNodeType(nodeIndex); const MetaNode& metaNode = gMetaNodes[type]; std::vector parameterAddressed(metaNode.mParams.size(), false); @@ -849,7 +959,9 @@ struct AnimCurveEdit : public ImCurveEdit::Delegate const std::string& parameterName = metaNode.mParams[parameterIndex].mName; CurveType curveType = GetCurveTypeForParameterType(type); if (curveType == CurveNone) + { return; + } size_t curveCountPerParameter = GetCurveCountPerParameterType(type); parameterAddressed[parameterIndex] = true; for (size_t curveIndex = 0; curveIndex < curveCountPerParameter; curveIndex++) @@ -858,11 +970,13 @@ struct AnimCurveEdit : public ImCurveEdit::Delegate if (!animation || animation->mFrames.empty()) { curvePts.resize(2); - auto& node = mNodeGraphControler.mEvaluationStages.mStages[mNodeIndex]; - float value = mNodeGraphControler.mEvaluationStages.GetParameterComponentValue( - nodeIndex, parameterIndex, int(curveIndex)); - curvePts[0] = ImVec2(float(node.mStartFrame) + 0.5f, value); - curvePts[1] = ImVec2(float(node.mEndFrame) + 0.5f, value); + + int times[2]; + model.GetStartEndFrame(mNodeIndex, times[0], times[1]); + const auto& parameters = model.GetParameterBlock(nodeIndex); + float value = parameters.GetParameterComponentValue(parameterIndex, int(curveIndex)); + curvePts[0] = ImVec2(float(times[0]) + 0.5f, value); + curvePts[1] = ImVec2(float(times[1]) + 0.5f, value); } else { @@ -884,29 +998,33 @@ struct AnimCurveEdit : public ImCurveEdit::Delegate } }; - for (auto& track : mAnimTrack) + for (auto& track : animTrack) { if (track.mNodeIndex != nodeIndex) + { continue; + } curveForParameter(track.mParamIndex, ConTypes(track.mValueType), track.mAnimation); } // non keyed parameters for (size_t param = 0; param < metaNode.mParams.size(); param++) { if (parameterAddressed[param]) + { continue; + } curveForParameter(int(param), metaNode.mParams[param].mType, nullptr); } } void BakeValuesToAnimationTrack() { - size_t type = mNodeGraphControler.mEvaluationStages.mStages[mNodeIndex].mType; + size_t type = mNodeGraphControler.mModel.GetNodeType(mNodeIndex); const MetaNode& metaNode = gMetaNodes[type]; for (size_t curve = 0; curve < mPts.size();) { - AnimTrack& animTrack = *mNodeGraphControler.GetAnimTrack(mNodeIndex, mParameterIndex[curve]); + AnimTrack& animTrack = *mNodeGraphControler.mModel.GetAnimTrack(mNodeIndex, mParameterIndex[curve]); animTrack.mNodeIndex = mNodeIndex; animTrack.mParamIndex = mParameterIndex[curve]; animTrack.mValueType = mValueType[curve]; @@ -918,7 +1036,9 @@ struct AnimCurveEdit : public ImCurveEdit::Delegate keyCount--; } if (!keyCount) + { continue; + } auto anim = animTrack.mAnimation; anim->mFrames.resize(keyCount); anim->Allocate(keyCount); @@ -943,8 +1063,7 @@ struct AnimCurveEdit : public ImCurveEdit::Delegate curve++; } while (curve < mPts.size() && animTrack.mParamIndex == mParameterIndex[curve]); } - mNodeGraphControler.mEvaluationStages.ApplyAnimationForNode( - &mNodeGraphControler.mEditingContext, mNodeIndex, mCurrentTime); + mNodeGraphControler.mEvaluationStages.ApplyAnimationForNode(&mNodeGraphControler.mEditingContext, mNodeIndex, mCurrentTime); } virtual ImCurveEdit::CurveType GetCurveType(size_t curveIndex) const @@ -1051,23 +1170,17 @@ struct AnimCurveEdit : public ImCurveEdit::Delegate BakeValuesToAnimationTrack(); } - static std::vector undoRedoEditCurves; virtual void BeginEdit(int /*index*/) { - assert(gUndoRedoHandler.mCurrent == nullptr); - URDummy urDummy; - for (size_t curve = 0; curve < mParameterIndex.size(); curve++) { uint32_t parameterIndex = mParameterIndex[curve]; bool parameterFound = false; int index = 0; - for (auto& track : mNodeGraphControler.mEvaluationStages.mAnimTrack) + for (auto& track : mNodeGraphControler.mModel.GetAnimationTracks()) { if (track.mNodeIndex == mNodeGraphControler.mSelectedNodeIndex && track.mParamIndex == parameterIndex) { - undoRedoEditCurves.push_back(new URChange( - index, [&](int index) { return &mNodeGraphControler.mEvaluationStages.mAnimTrack[index]; })); parameterFound = true; break; } @@ -1075,8 +1188,6 @@ struct AnimCurveEdit : public ImCurveEdit::Delegate } if (!parameterFound) { - undoRedoEditCurves.push_back( - new URAdd(index, [&]() { return &mNodeGraphControler.mEvaluationStages.mAnimTrack; })); AnimTrack animTrack; animTrack.mNodeIndex = mNodeIndex; animTrack.mParamIndex = mParameterIndex[curve]; @@ -1089,9 +1200,6 @@ struct AnimCurveEdit : public ImCurveEdit::Delegate virtual void EndEdit() { - for (auto ur : undoRedoEditCurves) - delete ur; - undoRedoEditCurves.clear(); } void MakeCurvesVisible() @@ -1140,7 +1248,7 @@ struct AnimCurveEdit : public ImCurveEdit::Delegate ImVec2 &mMin, &mMax; int mNodeIndex; int mCurrentTime; - NodeGraphControler& mNodeGraphControler; + GraphControler& mNodeGraphControler; private: void SortValues(size_t curveIndex) @@ -1152,12 +1260,10 @@ struct AnimCurveEdit : public ImCurveEdit::Delegate } }; -std::vector AnimCurveEdit::undoRedoEditCurves; - struct MySequence : public ImSequencer::SequenceInterface { - MySequence(NodeGraphControler& NodeGraphControler) - : mNodeGraphControler(NodeGraphControler), setKeyFrameOrValue(FLT_MAX, FLT_MAX), undoRedoChange(nullptr) + MySequence(GraphControler& GraphControler) + : mNodeGraphControler(GraphControler), setKeyFrameOrValue(FLT_MAX, FLT_MAX) { } @@ -1175,64 +1281,103 @@ struct MySequence : public ImSequencer::SequenceInterface { mCurrentTime = currentTime; } + virtual int GetFrameMin() const { - return mNodeGraphControler.mEvaluationStages.mFrameMin; + int startFrame, endFrame; + mNodeGraphControler.mModel.GetStartEndFrame(startFrame, endFrame); + return startFrame; } virtual int GetFrameMax() const { - return mNodeGraphControler.mEvaluationStages.mFrameMax; + int startFrame, endFrame; + mNodeGraphControler.mModel.GetStartEndFrame(startFrame, endFrame); + return endFrame; } virtual void BeginEdit(int index) { - assert(undoRedoChange == nullptr); - undoRedoChange = new URChange( - index, [&](int index) { return &mNodeGraphControler.mEvaluationStages.mStages[index]; }); + mCurrentIndex = index; + mNodeGraphControler.mModel.GetStartEndFrame(index, mCurrentStart, mCurrentEnd); } + virtual void EndEdit() { - delete undoRedoChange; - undoRedoChange = NULL; - mNodeGraphControler.mEvaluationStages.SetTime(&mNodeGraphControler.mEditingContext, mCurrentTime, false); + mNodeGraphControler.mModel.BeginTransaction(true); + mNodeGraphControler.mModel.SetStartEndFrame(mCurrentIndex, mCurrentStart, mCurrentEnd); + mNodeGraphControler.mModel.EndTransaction(); + mCurrentIndex = -1; } virtual int GetItemCount() const { - return (int)mNodeGraphControler.mEvaluationStages.GetStagesCount(); + return (int)mNodeGraphControler.mModel.GetNodeCount(); } virtual int GetItemTypeCount() const { return 0; } + virtual const char* GetItemTypeName(int typeIndex) const { return NULL; } + virtual const char* GetItemLabel(int index) const { - size_t nodeType = mNodeGraphControler.mEvaluationStages.GetStageType(index); + size_t nodeType = mNodeGraphControler.mModel.GetNodeType(index); return gMetaNodes[nodeType].mName.c_str(); } virtual void Get(int index, int** start, int** end, int* type, unsigned int* color) { - size_t nodeType = mNodeGraphControler.mEvaluationStages.GetStageType(index); - + const auto& model = mNodeGraphControler.mModel; + size_t nodeType = model.GetNodeType(index); + + if (index == mCurrentIndex) + { + mCurrentDisplayStart = mCurrentStart; + mCurrentDisplayEnd = mCurrentEnd; + if (start) + { + *start = &mCurrentStart; + } + if (end) + { + *end = &mCurrentEnd; + } + } + else + { + model.GetStartEndFrame(index, mCurrentDisplayStart, mCurrentDisplayEnd); + if (start) + { + *start = &mCurrentDisplayStart; + } + if (end) + { + *end = &mCurrentDisplayEnd; + } + } if (color) + { *color = gMetaNodes[nodeType].mHeaderColor; - if (start) - *start = &mNodeGraphControler.mEvaluationStages.mStages[index].mStartFrame; - if (end) - *end = &mNodeGraphControler.mEvaluationStages.mStages[index].mEndFrame; + } if (type) + { *type = int(nodeType); + } } - virtual void Add(int type){}; + + virtual void Add(int type) + { + } + virtual void Del(int index) { } + virtual void Duplicate(int index) { } @@ -1243,6 +1388,7 @@ struct MySequence : public ImSequencer::SequenceInterface return false; return mbExpansions[index] ? 300 : 0; } + virtual void DoubleClick(int index) { if (index >= mbExpansions.size()) @@ -1252,7 +1398,6 @@ struct MySequence : public ImSequencer::SequenceInterface mbExpansions[index] = false; return; } - //for (auto& item : mbExpansions) for (auto i = 0;i&>(mNodeGraphControler.mModel.GetAnimationTracks()), mbVisible, index, mCurrentTime); @@ -1322,7 +1470,7 @@ struct MySequence : public ImSequencer::SequenceInterface ImVec2 keyValue = curveEdit.mPts[selPoint.curveIndex][keyIndex]; uint32_t parameterIndex = curveEdit.mParameterIndex[selPoint.curveIndex]; AnimTrack* animTrack = - mNodeGraphControler.GetAnimTrack(mNodeGraphControler.mSelectedNodeIndex, parameterIndex); + mNodeGraphControler.mModel.GetAnimTrack(mNodeGraphControler.mSelectedNodeIndex, parameterIndex); // UndoRedo *undoRedo = nullptr; // undoRedo = new URChange(int(animTrack - gNodeDelegate.GetAnimTrack().data()), [](int // index) { return &gNodeDelegate.mAnimTrack[index]; }); @@ -1351,7 +1499,10 @@ struct MySequence : public ImSequencer::SequenceInterface mCurveMax = curveMax.y; } - NodeGraphControler& mNodeGraphControler; + int mCurrentStart, mCurrentEnd; + int mCurrentIndex{-1}; + int mCurrentDisplayStart, mCurrentDisplayEnd; + GraphControler& mNodeGraphControler; std::vector mbExpansions; std::vector mbVisible; ImVector mSelectedCurvePoints; @@ -1360,22 +1511,16 @@ struct MySequence : public ImSequencer::SequenceInterface ImVec2 getKeyFrameOrValue; float mCurveMin, mCurveMax; int mCurrentTime; - URChange* undoRedoChange; }; std::vector mHotkeys; -void Imogen::Init() +void Imogen::Init(bool bDebugWindow) { + mbDebugWindow = bDebugWindow; SetStyle(); ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable; - DiscoverNodes("glsl", "Nodes/GLSL/", EVALUATOR_GLSL, mEvaluatorFiles); - //DiscoverNodes("c", "Nodes/C/", EVALUATOR_C, mEvaluatorFiles); - //DiscoverNodes("py", "Nodes/Python/", EVALUATOR_PYTHON, mEvaluatorFiles); - //DiscoverNodes("glsl", "Nodes/GLSLCompute/", EVALUATOR_GLSLCOMPUTE, mEvaluatorFiles); - //DiscoverNodes("glslc", "Nodes/GLSLCompute/", EVALUATOR_GLSLCOMPUTE, mEvaluatorFiles); - struct HotKeyFunction { const char* name; @@ -1383,11 +1528,15 @@ void Imogen::Init() std::function function; }; static const std::vector hotKeyFunctions = { - {"Layout", "Reorder nodes in a simpler layout", []() { NodeGraphLayout(); }}, + {"Layout", "Reorder nodes in a simpler layout", [&]() { GetNodeGraphControler()->mModel.NodeGraphLayout(GetNodeGraphControler()->mEvaluationStages.GetForwardEvaluationOrder()); }}, {"PlayPause", "Play or Stop current animation", [&]() { PlayPause(); }}, {"AnimationFirstFrame", "Set current time to the first frame of animation", - [&]() { mCurrentTime = mNodeGraphControler->mEvaluationStages.mFrameMin; }}, + [&]() { + int startFrame, endFrame; + GetNodeGraphControler()->mModel.GetStartEndFrame(startFrame, endFrame); + mCurrentTime = startFrame; + }}, {"AnimationNextFrame", "Move to the next animation frame", [&]() { mCurrentTime++; }}, {"AnimationPreviousFrame", "Move to previous animation frame", [&]() { mCurrentTime--; }}, {"MaterialExport", "Export current material to a file", [&]() { ExportMaterial(); }}, @@ -1398,24 +1547,25 @@ void Imogen::Init() {"ToggleSequencer", "Show or hide Sequencer window", [&]() { mbShowTimeline = !mbShowTimeline; }}, {"ToggleParameters", "Show or hide Parameters window", [&]() { mbShowParameters = !mbShowParameters; }}, {"MaterialNew", "Create a new graph", [&]() { NewMaterial(); }}, - {"ReloadShaders", + /*{"ReloadShaders", "Reload them", [&]() { gEvaluators.SetEvaluators(mEvaluatorFiles); mNodeGraphControler->mEditingContext.RunAll(); - }}, + }},*/ {"DeleteSelectedNodes", "Delete selected nodes in the current graph", []() {}}, {"AnimationSetKey", "Make a new animation key with the current parameters values at the current time", - [&]() { mNodeGraphControler->MakeKey(mCurrentTime, uint32_t(mNodeGraphControler->mSelectedNodeIndex), 0); }}, + [&]() { mNodeGraphControler->mModel.MakeKey(mCurrentTime, uint32_t(mNodeGraphControler->mSelectedNodeIndex), 0); }}, {"HotKeyEditor", "Open the Hotkey editor window", [&]() { ImGui::OpenPopup("HotKeys Editor"); }}, {"NewNodePopup", "Open the new node menu", []() {}}, - {"Undo", "Undo the last operation", []() { gUndoRedoHandler.Undo(); }}, - {"Redo", "Redo the last undo", []() { gUndoRedoHandler.Redo(); }}, + {"Undo", "Undo the last operation", []() { Imogen::instance->GetNodeGraphControler()->mModel.Undo(); }}, + {"Redo", "Redo the last undo", []() { Imogen::instance->GetNodeGraphControler()->mModel.Redo(); }}, {"Copy", "Copy the selected nodes", []() {}}, {"Cut", "Cut the selected nodes", []() {}}, {"Paste", "Paste previously copy/cut nodes", []() {}}, {"BuildMaterial", "Build current material", [&]() { BuildCurrentMaterial(mBuilder); }}, + {"CloseLibrary", "Close current library", [&]() { CloseLibrary(); }}, {"MouseState", "Show Mouse State as a tooltip", [&]() { mbShowMouseState = !mbShowMouseState; }}}; mHotkeys.reserve(hotKeyFunctions.size()); @@ -1429,6 +1579,7 @@ void Imogen::Init() void Imogen::Finish() { + mNodeGraphControler->Clear(); } const char* GetShortCutLib(const char* functionName) @@ -1463,7 +1614,7 @@ void Imogen::RunDeferedCommands() return; std::string tmpCommand = mRunCommand; mRunCommand = ""; - #if USE_PYTHON +#if USE_PYTHON try { pybind11::exec(tmpCommand); @@ -1471,8 +1622,21 @@ void Imogen::RunDeferedCommands() catch (pybind11::error_already_set& ex) { Log(ex.what()); + exit(1); + } + if (mbQuitAfterRunCommand) + { + extern bool done; + done = true; } - #endif +#endif +} + +void Imogen::CloseLibrary() +{ + mRecentLibraries.SetMostRecentLibraryIndex(-1); + SaveLib(&library, library.mFilename); + mSelectedMaterial = -1; } void Imogen::ShowAppMainMenuBar() @@ -1490,6 +1654,13 @@ void Imogen::ShowAppMainMenuBar() mMainMenuPos = -440; return; } + if (ImGui::CollapsingHeader("Library", ImGuiTreeNodeFlags_DefaultOpen)) + { + if (Button("CloseLibrary", "Close Library", buttonSize)) + { + CloseLibrary(); + } + } if (ImGui::CollapsingHeader("Plugins", ImGuiTreeNodeFlags_DefaultOpen)) { @@ -1511,7 +1682,7 @@ void Imogen::ShowAppMainMenuBar() { if (Button("Layout", "Layout", buttonSize)) { - NodeGraphLayout(); + GetNodeGraphControler()->mModel.NodeGraphLayout(GetNodeGraphControler()->mEvaluationStages.GetForwardEvaluationOrder()); } if (Button("MaterialExport", "Export Material", buttonSize)) { @@ -1571,9 +1742,9 @@ int Imogen::GetFunctionByName(const char* functionName) const return -1; } -bool Imogen::ImageButton(const char* functionName, unsigned int icon, ImVec2 size) +bool Imogen::ImageButton(const char* functionName, bgfx::TextureHandle icon, ImVec2 size) { - bool res = ImGui::ImageButton((ImTextureID)(int64_t)icon, size, ImVec2(0, 1), ImVec2(1, 0)); + bool res = ImGui::ImageButton((ImTextureID)(int64_t)icon.idx, size); if (ImGui::IsItemHovered()) { int functionIndex = GetFunctionByName(functionName); @@ -1609,6 +1780,259 @@ bool Imogen::Button(const char* functionName, const char* label, ImVec2 size) return res; } +int Imogen::NewLibrary(const std::string& directory, const std::string& name, bool addDefaultMaterial) +{ + int ret; +#ifdef __EMSCRIPTEN__ + ret = int(mRecentLibraries.AddRecent("/offline/", name)); +#else + ret = int(mRecentLibraries.AddRecent(directory, name)); +#endif + // create lib + Library newLib; + if (addDefaultMaterial) + { + MaterialNode defNode; + defNode.mPosX = 40; + defNode.mPosY = 40; + defNode.mTypeName = "Color"; + auto nodeType = GetMetaNodeIndex(defNode.mTypeName.c_str()); + defNode.mNodeType = uint32_t(nodeType); + defNode.mParameters.resize(ComputeNodeParametersSize(nodeType), 0); + defNode.mParameters = ParameterBlock(nodeType).InitDefault(); + + MaterialNodeRug defRug; + defRug.mPosX = 0; + defRug.mPosY = 0; + defRug.mColor = 0xFF7799CC; + defRug.mComment = "Imogen default material"; + defRug.mSizeX = 400; + defRug.mSizeY = 300; + + Material defMat; + defMat.mName = ".default"; + defMat.mMaterialRugs.push_back(defRug); + defMat.mMaterialNodes.push_back(defNode); + defMat.mBackgroundNode = -1; + + newLib.mMaterials.push_back(defMat); + } + SaveLib(&newLib, mRecentLibraries.GetRecentLibraries()[ret].ComputeFullPath().c_str()); + return ret; +} + +void Imogen::OpenLibrary(int libraryIndex, bool saveCurrent) +{ + if (saveCurrent) + { + SaveLib(&library, library.mFilename); + } + std::string selectedLibraryFilePath = mRecentLibraries.GetRecentLibraries()[libraryIndex].ComputeFullPath(); + LoadLib(&library, selectedLibraryFilePath); + mNodeGraphControler->Clear(); + SetExistingMaterialActive(".default"); + mRecentLibraries.SetMostRecentLibraryIndex(libraryIndex); +} + +// return -1 if nothing happens, index of recent library if one is chosen +int Imogen::EditRecentLibraries(RecentLibraries& recentLibraries) +{ + ImGuiIO& io = ImGui::GetIO(); + int ret = -1; + static std::string tempName; + static std::string tempDir; + static std::string tempCompletePath; + static bool addDefMat = false; + + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowSize(io.DisplaySize); + + ImGui::Begin("RecentLibrary", 0, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar); + + // CREATE NEW LIBRARY + ImGui::PushFont(bigAF); + ImGui::Text(ICON_FA_FILE " Create New Library"); + ImGui::PopFont(); + + ImGui::Indent(); + + ImGui::PushFont(mediumAF); + ImGui::Text(ICON_FA_PENCIL_ALT " Name"); + ImGui::PopFont(); + ImGui::PushID(1106); + ImGui::InputText("", &tempName); + ImVec2 editSize = ImGui::GetItemRectSize(); + if (recentLibraries.IsNamedUsed(tempName)) + { + ImGui::SameLine(); + ImGui::Text(ICON_FA_EXCLAMATION_TRIANGLE" Name used"); + } + ImGui::PopID(); + +#ifndef __EMSCRIPTEN__ + ImGui::PushFont(mediumAF); + ImGui::Text(ICON_FA_FOLDER_OPEN " Directory"); + ImGui::PopFont(); + ImGui::PushID(1107); + ImGui::InputText("", &tempDir); + ImGui::PopID(); + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_FOLDER " Browse ...")) + { + nfdchar_t* outPath = NULL; + nfdresult_t result = NFD_PickFolder(NULL, &outPath); + if (result == NFD_OKAY) + { + tempDir = outPath; + tempDir = ReplaceAll(tempDir, "\\", "/"); + if (tempDir[tempDir.size() - 1] != '/') + { + tempDir += "/"; + } + free(outPath); + } + } + + ImGui::PushFont(mediumAF); + ImGui::Text(ICON_FA_ANGLE_DOUBLE_RIGHT" Full path"); + ImGui::PopFont(); + ImGui::Indent(); + std::string completePath; + if (tempDir.length() && tempName.length()) + { + completePath = tempDir + tempName + ".imogen"; + } + ImGui::Text(completePath.c_str()); + ImGui::Unindent(); +#endif // __EMSCRIPTEN__ + + ImGui::PushFont(mediumAF); + ImGui::Text(ICON_FA_COG" Options"); + ImGui::PopFont(); + ImGui::Indent(); + ImGui::Checkbox("Add default material", &addDefMat); + ImGui::Unindent(); + + bool createLibValid = recentLibraries.IsValidForCreatingRecent(tempDir, tempName); + if (!createLibValid) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + ImGui::PushFont(bigAF); + if (ImGui::Button(ICON_FA_PLUS " Create Library", ImVec2(editSize.x, 40.f))) + { + ret = NewLibrary(tempDir, tempName, addDefMat); + tempDir = tempName = ""; + } + ImGui::PopFont(); + + if (!createLibValid) + { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } + + ImGui::Unindent(); + + ImGui::InvisibleButton("", ImVec2(1, 30.f)); + +#ifdef __EMSCRIPTEN__ + ImGui::PushFont(mediumAF); + ImGui::Text(ICON_FA_EXCLAMATION_TRIANGLE" Web edition will not allow to save modification to default library."); + ImGui::Text(" In order to save changes, user will have to create a library that will be"); + ImGui::Text(" saved using local storage. Datas will stay local to this machine."); + ImGui::Text(ICON_FA_EXCLAMATION_TRIANGLE" The changes you've made to your library won't be save until library is closed."); + ImGui::PopFont(); +#endif + +#ifndef __EMSCRIPTEN__ + + // ADD EXISTING + ImGui::PushFont(bigAF); + ImGui::Text(ICON_FA_FILE_MEDICAL " Add Existing Library"); + ImGui::PopFont(); + + ImGui::Indent(); + ImGui::PushID(1108); + ImGui::InputText("", &tempCompletePath); + ImGui::PopID(); + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_FILE " Browse ...")) + { + nfdchar_t* outPath = NULL; + nfdresult_t result = NFD_OpenDialog("imogen", NULL, &outPath); + if (result == NFD_OKAY) + { + tempCompletePath = outPath; + free(outPath); + } + } + bool addLibraryValid = recentLibraries.IsValidForAddingRecent(tempCompletePath); + if (!addLibraryValid) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + ImGui::PushFont(bigAF); + if (ImGui::Button(ICON_FA_PLUS " Add Library", ImVec2(editSize.x, 40.f))) + { + recentLibraries.AddRecent(tempCompletePath); + tempCompletePath.clear(); + } + + if (!addLibraryValid) + { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } + ImGui::PopFont(); + ImGui::Unindent(); +#endif // __EMSCRIPTEN__ + float d = std::max(ImGui::GetContentRegionAvail().y - 240.f, 30.f); + if (d > 0.f) + { + ImGui::InvisibleButton("", ImVec2(1, d)); + } + + // BROWSE RECENT + ImGui::PushFont(bigAF); + ImGui::Text(ICON_FA_COPY " Open Recently Used Library"); + ImGui::PopFont(); + const auto& libs = recentLibraries.GetRecentLibraries(); + ImGui::BeginChild(147, ImVec2(0, 200), false, ImGuiWindowFlags_HorizontalScrollbar); + for (size_t i = 0; i < libs.size(); i++) + { + if (i) + { + ImGui::SameLine(); + } + ImGui::PushID(200 + int(i)); + ImGui::BeginGroup(); + if (ImGui::Button("...", ImVec2(160, 160))) + { + ret = int(i); + } + if (ImGui::IsItemHovered()) + { + ImGui::SetTooltip(libs[i].ComputeFullPath().c_str()); + } + ImGui::Text("%s", libs[i].mName.c_str()); + ImGui::EndGroup(); + ImGui::PopID(); + } + ImGui::EndChild(); + + ImGui::End(); + + if (ret != -1) + { + recentLibraries.SetMostRecentLibraryIndex(ret); + } + + return ret; +} + void Imogen::ShowTitleBar(Builder* builder) { ImGuiIO& io = ImGui::GetIO(); @@ -1656,7 +2080,7 @@ void Imogen::ShowTitleBar(Builder* builder) ImGui::SameLine(); // imogen info strings ImGui::BeginChildFrame(152, ImVec2(io.DisplaySize.x - butSize.x * 4.f - 300, 32.f)); - ImGui::Text("Imogen 0.13"); + ImGui::Text(IMOGENTITLE); if (mSelectedMaterial != -1) { Material& material = library.mMaterials[mSelectedMaterial]; @@ -1666,7 +2090,7 @@ void Imogen::ShowTitleBar(Builder* builder) ImGui::SameLine(); // exporting frame / build - unsigned int buildIcon = gImageCache.GetTexture("Stock/Build.png"); + bgfx::TextureHandle buildIcon = gImageCache.GetTexture("Stock/Build.png"); if (ImageButton("BuildMaterial", buildIcon, ImVec2(30, 30))) { BuildCurrentMaterial(builder); @@ -1688,7 +2112,7 @@ void Imogen::ShowTitleBar(Builder* builder) ImGui::BeginTooltip(); for (auto& bi : buildInfos) { - ImGui::Text(bi.mName.c_str()); + ImGui::Text("%s", bi.mName.c_str()); } ImGui::EndTooltip(); } @@ -1747,34 +2171,43 @@ void Imogen::PlayPause() { if (!mbIsPlaying) { - mCurrentTime = mNodeGraphControler->mEvaluationStages.mFrameMin; + int startFrame, endFrame; + auto& model = mNodeGraphControler->mModel; + model.GetStartEndFrame(startFrame, endFrame); + mCurrentTime = startFrame; } mbIsPlaying = !mbIsPlaying; } void Imogen::ShowTimeLine() { - int selectedEntry = mNodeGraphControler->mSelectedNodeIndex; + NodeIndex selectedEntry = mNodeGraphControler->mSelectedNodeIndex; static int firstFrame = 0; mSequence->SetCurrentTime(mCurrentTime); + int startFrame, endFrame; + auto& model = mNodeGraphControler->mModel; + model.GetStartEndFrame(startFrame, endFrame); + ImGui::PushItemWidth(80); ImGui::PushID(200); - ImGui::InputInt("", &mNodeGraphControler->mEvaluationStages.mFrameMin, 0, 0); + bool dirtyFrame = ImGui::InputInt("", &startFrame, 0, 0); ImGui::PopID(); + ImGui::SameLine(); - if (Button("AnimationFirstFrame", "|<", ImVec2(0, 0))) + if (Button("AnimationFirstFrame", ICON_FA_STEP_BACKWARD, ImVec2(0, 0))) { - mCurrentTime = mNodeGraphControler->mEvaluationStages.mFrameMin; + mCurrentTime = startFrame; } + ImGui::SameLine(); - if (Button("AnimationPreviousFrame", "<", ImVec2(0, 0))) + if (Button("AnimationPreviousFrame", ICON_FA_CARET_LEFT, ImVec2(0, 0))) { mCurrentTime--; } - ImGui::SameLine(); + ImGui::SameLine(); ImGui::PushID(201); if (ImGui::InputInt("", &mCurrentTime, 0, 0, 0)) { @@ -1782,51 +2215,57 @@ void Imogen::ShowTimeLine() ImGui::PopID(); ImGui::SameLine(); - if (Button("AnimationNextFrame", ">", ImVec2(0, 0))) + if (Button("AnimationNextFrame", ICON_FA_CARET_RIGHT, ImVec2(0, 0))) { mCurrentTime++; } + ImGui::SameLine(); - if (ImGui::Button(">|")) + if (ImGui::Button(ICON_FA_STEP_FORWARD, ImVec2(0, 0))) { - mCurrentTime = mNodeGraphControler->mEvaluationStages.mFrameMax; + mCurrentTime = endFrame; } - ImGui::SameLine(); - if (Button("PlayPause", mbIsPlaying ? "Stop" : "Play", ImVec2(0, 0))) + ImGui::SameLine(); + if (Button("PlayPause", mbIsPlaying ? ICON_FA_PAUSE_CIRCLE : ICON_FA_PLAY_CIRCLE, ImVec2(0, 0))) { PlayPause(); } - unsigned int playNoLoopTextureId = gImageCache.GetTexture("Stock/PlayNoLoop.png"); - unsigned int playLoopTextureId = gImageCache.GetTexture("Stock/PlayLoop.png"); - ImGui::SameLine(); - if (ImGui::ImageButton((ImTextureID)(uint64_t)(mbPlayLoop ? playLoopTextureId : playNoLoopTextureId), - ImVec2(16.f, 16.f))) + if (ImGui::Button(mbPlayLoop ? ICON_FA_HISTORY : ICON_FA_ANGLE_DOUBLE_RIGHT, ImVec2(24, 20))) { mbPlayLoop = !mbPlayLoop; } ImGui::SameLine(); ImGui::PushID(202); - ImGui::InputInt("", &mNodeGraphControler->mEvaluationStages.mFrameMax, 0, 0); + dirtyFrame |= ImGui::InputInt("", &endFrame, 0, 0); + + if (dirtyFrame) + { + model.BeginTransaction(true); + model.SetStartEndFrame(startFrame, endFrame); + model.EndTransaction(); + } ImGui::PopID(); - ImGui::SameLine(); + ImGui::SameLine(0, 40.f); - if (Button("AnimationSetKey", "Make Key", ImVec2(0, 0)) && selectedEntry != -1) + if (Button("AnimationSetKey", ICON_FA_KEY, ImVec2(0, 0)) && selectedEntry.IsValid()) { - mNodeGraphControler->MakeKey(mCurrentTime, uint32_t(selectedEntry), 0); + model.BeginTransaction(true); + model.MakeKey(mCurrentTime, uint32_t(selectedEntry), 0); + model.EndTransaction(); } ImGui::SameLine(0, 50.f); - int setf = (mSequence->getKeyFrameOrValue.x < FLT_MAX) ? int(mSequence->getKeyFrameOrValue.x) : 0; ImGui::PushID(203); if (ImGui::InputInt("", &setf, 0, 0)) { mSequence->setKeyFrameOrValue.x = float(setf); } + ImGui::SameLine(); float setv = (mSequence->getKeyFrameOrValue.y < FLT_MAX) ? mSequence->getKeyFrameOrValue.y : 0.f; if (ImGui::InputFloat("Key", &setv)) @@ -1834,42 +2273,75 @@ void Imogen::ShowTimeLine() mSequence->setKeyFrameOrValue.y = setv; } ImGui::PopID(); + ImGui::SameLine(); int timeMask[2] = {0, 0}; - if (selectedEntry != -1) + if (selectedEntry.IsValid()) { - timeMask[0] = mNodeGraphControler->mEvaluationStages.mStages[selectedEntry].mStartFrame; - timeMask[1] = mNodeGraphControler->mEvaluationStages.mStages[selectedEntry].mEndFrame; + model.GetStartEndFrame(selectedEntry, timeMask[0], timeMask[1]); } ImGui::PushItemWidth(120); - if (ImGui::InputInt2("Time Mask", timeMask) && selectedEntry != -1) + if (ImGui::InputInt2("Time Mask", timeMask) && selectedEntry.IsValid()) { - URChange undoRedoChange( - selectedEntry, [&](int index) { return &mNodeGraphControler->mEvaluationStages.mStages[index]; }); timeMask[1] = ImMax(timeMask[1], timeMask[0]); timeMask[0] = ImMin(timeMask[1], timeMask[0]); - mNodeGraphControler->SetTimeSlot(selectedEntry, timeMask[0], timeMask[1]); + model.BeginTransaction(true); + model.SetStartEndFrame(selectedEntry, timeMask[0], timeMask[1]); + model.EndTransaction(); } ImGui::PopItemWidth(); ImGui::PopItemWidth(); + int tempSelectedEntry = selectedEntry.IsValid() ? selectedEntry.operator int() : -1; Sequencer(mSequence, &mCurrentTime, NULL, - &selectedEntry, + &tempSelectedEntry, &firstFrame, ImSequencer::SEQUENCER_EDIT_STARTEND | ImSequencer::SEQUENCER_CHANGE_FRAME); - if (selectedEntry != -1) + + if (tempSelectedEntry != -1) + { + selectedEntry = tempSelectedEntry; + } + else + { + selectedEntry.SetInvalid(); + } + + if (selectedEntry.IsValid() && !(selectedEntry == mNodeGraphControler->mSelectedNodeIndex)) { + auto& model = mNodeGraphControler->mModel; + /*if (mNodeGraphControler->mSelectedNodeIndex.IsValid()) + { + model.SelectNode(mNodeGraphControler->mSelectedNodeIndex, false); + } + */ + model.UnselectNodes(); mNodeGraphControler->mSelectedNodeIndex = selectedEntry; - NodeGraphSelectNode(selectedEntry); - auto& imoNode = mNodeGraphControler->mEvaluationStages.mStages[selectedEntry]; - mNodeGraphControler->mEvaluationStages.SetStageLocalTime( - &mNodeGraphControler->mEditingContext, - selectedEntry, - ImClamp(mCurrentTime - imoNode.mStartFrame, 0, imoNode.mEndFrame - imoNode.mStartFrame), - true); - } + + if (mNodeGraphControler->mSelectedNodeIndex.IsValid()) + { + model.SelectNode(mNodeGraphControler->mSelectedNodeIndex, true); + } +#if 0 + if (selectedEntry.IsValid()) + { + model.SelectNode(selectedEntry, true); + int times[2]; + model.GetStartEndFrame(selectedEntry, times[0], times[1]); + /*mNodeGraphControler->mModel.mEvaluationStages.SetStageLocalTime( todo + &mNodeGraphControler->mEditingContext, + selectedEntry, + ImClamp(mCurrentTime - times[0], 0, times[1] - times[0]), + true);*/ + } +#endif + } + else + { + mNodeGraphControler->mSelectedNodeIndex.SetInvalid(); + } } void Imogen::DeleteCurrentMaterial() @@ -1901,12 +2373,12 @@ void Imogen::ShowNodeGraph() } ImGui::PopItemWidth(); } - NodeGraph(mNodeGraphControler, mSelectedMaterial != -1); + GraphEditor(mNodeGraphControler, mSelectedMaterial != -1); } void Imogen::ExportMaterial() { - #ifdef NFD_SaveDialog +#if defined(_NFD_H) nfdchar_t* outPath = NULL; nfdresult_t result = NFD_SaveDialog("imogen", NULL, &outPath); @@ -1919,14 +2391,195 @@ void Imogen::ExportMaterial() Log("Graph %s saved at path %s\n", material.mName.c_str(), outPath); free(outPath); } - #endif +#endif +} + +float MemoryGetter(void *data, int idx) +{ + MemoryProfileHistory_t::MemHistory* hist = (MemoryProfileHistory_t::MemHistory*)data; + return (float)hist->mValues[idx]; } +size_t GetUndoRedoMemoryFootPrint(); +void Imogen::ShowDebugWindow() +{ + ImGui::Begin("Debug"); + if (ImGui::CollapsingHeader("Thumbnails Atlas")) + { + auto atlases = this->GetNodeGraphControler()->mEditingContext.GetThumbnails().GetAtlasTextures(); + for (auto& atlas : atlases) + { + ImGui::Text("Atlas %d", int(&atlas - atlases.data())); + ImGui::Image((ImTextureID)(int64_t)atlas.idx, ImVec2(1024, 1024)); + } + } + if (ImGui::CollapsingHeader("bgfx")) + { + const bgfx::Stats* stats = bgfx::getStats(); + ImGui::Text("%d draw calls submitted", stats->numDraw); + ImGui::Text("%d compute calls submitted", stats->numCompute); + ImGui::Text("%d blit calls submitted", stats->numBlit); + ImGui::Text("%d GPU driver latency", stats->maxGpuLatency); + ImGui::Text("%d dynamic index buffers", stats->numDynamicIndexBuffers); + ImGui::Text("%d dynamic vertex buffers", stats->numDynamicVertexBuffers); + ImGui::Text("%d frame buffers", stats->numFrameBuffers); + ImGui::Text("%d index buffers", stats->numIndexBuffers); + ImGui::Text("%d programs", stats->numPrograms); + ImGui::Text("%d shaders", stats->numShaders); + ImGui::Text("%d textures", stats->numTextures); + ImGui::Text("%d uniforms", stats->numUniforms); + ImGui::Text("%d vertex buffers", stats->numVertexBuffers); + ImGui::Text("%d vertex layouts", stats->numVertexDecls); + ImGui::Text("%d Mb texture memory used", int(stats->textureMemoryUsed / (1 << 20))); + ImGui::Text("%d Mb target memory used", int(stats->rtMemoryUsed / (1 << 20))); + ImGui::Text("%d Mb available GPU memory", int(stats->gpuMemoryMax / (1 << 20))); + ImGui::Text("%d Mb GPU memory used", int(stats->gpuMemoryUsed / (1 << 20))); + } + if (ImGui::CollapsingHeader("Memory")) + { + ImGui::Text("Undo/Redo footprint %d bytes", int(GetUndoRedoMemoryFootPrint())); + ImGui::PushStyleColor(ImGuiCol_PlotLines, ImVec4(1.f, 0.5f, 0.1f, 1.f)); + static const char *moduleLabels[MODULE_COUNT] = { + "IMGUI", + "Default", + "VRAM Textures", + "Images" + }; + static const char *labels[] = { "Active Allocated", "Active Allocation Count", "Total Allocated", "Total Freed" }; // , "Allocation Count", "Deallocation Count" + + for (size_t imodule = 0; imodule < MODULE_COUNT; imodule++) + { + ImGui::Indent(); + + auto& nd = gMemoryHistory.mMemory[imodule]; + MemoryProfileHistory_t::MemHistory* histories[] = { + &nd.mActiveAllocated, + &nd.mActiveAllocationCount, + &nd.mTotalAllocated, + &nd.mTotalFreed }; + static const bool displayMax[] = { false, false, true, true}; + static const bool isByteQuantity[] = { true, false, true, true }; + size_t countInfos[] = {0, 0, nd.mAllocationCount.getValue() , nd.mDeallocationCount.getValue() }; + static const char* countInfoTexts[] = {"", "", "Allocations", "Deallocations"}; + if (ImGui::CollapsingHeader(moduleLabels[imodule])) + { + for (size_t iHist = 0; iHist < sizeof(histories) / sizeof(MemoryProfileHistory_t::MemHistory*); iHist++) + { + const auto& hist = *histories[iHist]; -ImRect GetNodesDisplayRect(); -ImRect GetFinalNodeDisplayRect(); + ImGui::PlotLines("", MemoryGetter, (void*)&hist, 64, int(hist.mOffset), labels[iHist], 0.f, (float)hist.getMax(), ImVec2(0, 100)); + ImGui::SameLine(); + ImGui::BeginGroup(); + if (isByteQuantity[iHist]) + { + size_t mx = std::max(hist.getValue(), hist.getMax()); + const char *unit = "bytes"; + size_t dv = 1; + if (mx > 1024 * 10) + { + dv = 1024; + unit = "Kb"; + if (mx > 1024 * 1024 * 10) + { + dv = 1024 * 1024; + unit = "Mb"; + } + } + if (dv > 1) + { + ImGui::Text("%.2f %s", float(hist.getValue()) / float(dv), unit); + if (displayMax[iHist]) + { + ImGui::Text("Max %.2f %s", float(hist.getMax()) / float(dv), unit); + } + } + else + { + ImGui::Text("%d %s", hist.getValue(), unit); + if (displayMax[iHist]) + { + ImGui::Text("Max %d %s", hist.getMax(), unit); + } + } + } + else + { + ImGui::Text("%d", hist.getValue()); + if (displayMax[iHist]) + { + ImGui::Text("Max %d", hist.getMax()); + } + } + + if (countInfos[iHist]) + { + ImGui::Text("%d %s", int(countInfos[iHist]), countInfoTexts[iHist]); + } + + ImGui::EndGroup(); + } + } + ImGui::Unindent(); + } + ImGui::PopStyleColor(); + } + ImGui::End(); +} + +ImRect GetNodesDisplayRect(GraphModel* model); +ImRect GetFinalNodeDisplayRect(GraphModel* model); std::map interfacesRect; + +void Imogen::ShowExtractedViews() +{ + int index = 0; + int removeExtractedView = -1; + for (auto& extraction : mExtratedViews) + { + char tmps[512]; + sprintf( + tmps, + "%s_View_%03d", + gMetaNodes[mNodeGraphControler->mModel.GetNodeType(extraction.mNodeIndex)].mName.c_str(), + index); + bool open = true; + if (extraction.mFirstFrame) + { + extraction.mFirstFrame = false; + ImGui::SetNextWindowSize(ImVec2(256, 256)); + } + if (ImGui::Begin(tmps, &open)) + { + ParameterBlock parameterBlock = mNodeGraphControler->mModel.GetParameterBlock(extraction.mNodeIndex); + RenderPreviewNode(extraction.mNodeIndex, *mNodeGraphControler, parameterBlock, true); + } + ImGui::End(); + if (!open) + { + removeExtractedView = index; + } + index++; + } + if (removeExtractedView != -1) + { + mExtratedViews.erase(mExtratedViews.begin() + removeExtractedView); + } +} + void Imogen::Show(Builder* builder, Library& library, bool capturing) { + if (mRecentLibraries.GetMostRecentLibraryIndex() == -1) + { + if (EditRecentLibraries(mRecentLibraries) != -1) + { + std::string selectedLibraryFilePath = mRecentLibraries.GetMostRecentLibraryPath(); + if (library.mFilename != selectedLibraryFilePath) + { + OpenLibrary(mRecentLibraries.GetMostRecentLibraryIndex(), true); + } + } + return; + } + int currentTime = mCurrentTime; ImGuiIO& io = ImGui::GetIO(); mBuilder = builder; @@ -1938,6 +2591,9 @@ void Imogen::Show(Builder* builder, Library& library, bool capturing) ImGui::SetNextWindowSize(io.DisplaySize - deltaHeight); ImVec2 nodesWindowPos; + // be sure that everything is in sync before rendering them + mNodeGraphControler->ApplyDirtyList(); + if (ImGui::Begin("Imogen", 0, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | @@ -1949,6 +2605,11 @@ void Imogen::Show(Builder* builder, Library& library, bool capturing) ImGuiID dockspace_id = ImGui::GetID("MyDockspace"); ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), opt_flags); + + // view extraction, just aftper applydirtylist and before node editing in case a node + // has been deleted and the extracted views are not aware of + ShowExtractedViews(); + if (mbShowNodes) { if (ImGui::Begin("Nodes", &mbShowNodes)) @@ -2001,47 +2662,24 @@ void Imogen::Show(Builder* builder, Library& library, bool capturing) ImGui::End(); } - // view extraction - int index = 0; - int removeExtractedView = -1; - for (auto& extraction : mExtratedViews) - { - char tmps[512]; - sprintf( - tmps, - "%s_View_%03d", - gMetaNodes[mNodeGraphControler->mEvaluationStages.mStages[extraction.mNodeIndex].mType].mName.c_str(), - index); - bool open = true; - if (extraction.mFirstFrame) - { - extraction.mFirstFrame = false; - ImGui::SetNextWindowSize(ImVec2(256, 256)); - } - if (ImGui::Begin(tmps, &open)) - { - RenderPreviewNode(int(extraction.mNodeIndex), *mNodeGraphControler, true); - } - ImGui::End(); - if (!open) - { - removeExtractedView = index; - } - index++; - } - if (removeExtractedView != -1) - mExtratedViews.erase(mExtratedViews.begin() + removeExtractedView); - ImGui::End(); } - ImHotKey::Edit(mHotkeys.data(), mHotkeys.size(), "HotKeys Editor"); - Playback(currentTime != mCurrentTime); + if (mbDebugWindow) + { + ShowDebugWindow(); + } - ImRect rc = GetNodesDisplayRect(); + // getting node graph AABB here as everything is in sync. Might not be the case after the UI tick as things + // can change and not be updated via the dirtylist (nodegraph evaluation list with fewer or more elements than nodes in model) + ImRect rc = mNodeGraphControler->mModel.GetNodesDisplayRect(); interfacesRect["Graph"] = ImRect(nodesWindowPos + rc.Min, nodesWindowPos + rc.Max); - rc = GetFinalNodeDisplayRect(); + rc = mNodeGraphControler->mModel.GetFinalNodeDisplayRect(mNodeGraphControler->mEvaluationStages.GetForwardEvaluationOrder()); interfacesRect["FinalNode"] = ImRect(nodesWindowPos + rc.Min, nodesWindowPos + rc.Max); + + ImHotKey::Edit(mHotkeys.data(), mHotkeys.size(), "HotKeys Editor"); + + Playback(currentTime != mCurrentTime); } void Imogen::Playback(bool timeHasChanged) @@ -2049,11 +2687,13 @@ void Imogen::Playback(bool timeHasChanged) if (mbIsPlaying) { mCurrentTime++; - if (mCurrentTime >= mNodeGraphControler->mEvaluationStages.mFrameMax) + int startFrame, endFrame; + mNodeGraphControler->mModel.GetStartEndFrame(startFrame, endFrame); + if (mCurrentTime >= endFrame) { if (mbPlayLoop) { - mCurrentTime = mNodeGraphControler->mEvaluationStages.mFrameMin; + mCurrentTime = startFrame; } else { @@ -2071,11 +2711,11 @@ void Imogen::Playback(bool timeHasChanged) } } -void Imogen::ValidateCurrentMaterial(Library& library) +void Imogen::CommitCurrentGraph(Library& library) { - ValidateMaterial(library, *mNodeGraphControler, mSelectedMaterial); + CommitGraph(library, *mNodeGraphControler, mSelectedMaterial); } - +/* void Imogen::DiscoverNodes(const char* extension, const char* directory, EVALUATOR_TYPE evaluatorType, @@ -2099,7 +2739,7 @@ void Imogen::DiscoverNodes(const char* extension, tinydir_close(&dir); } - +*/ struct readHelper { Imogen* imogen; @@ -2152,9 +2792,9 @@ void Imogen::ReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* en } else if (sscanf(line_start, "ShowMouseState=%d", &active) == 1) { - userdata->imogen->mbShowMouseState = active; - } - else + userdata->imogen->mbShowMouseState = active; + } + else { for (auto& hotkey : mHotkeys) { @@ -2187,7 +2827,7 @@ void Imogen::WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTex } } -Imogen::Imogen(NodeGraphControler* nodeGraphControler) : mNodeGraphControler(nodeGraphControler) +Imogen::Imogen(GraphControler* nodeGraphControler, RecentLibraries& recentLibraries) : mNodeGraphControler(nodeGraphControler), mRecentLibraries(recentLibraries) { mSequence = new MySequence(*nodeGraphControler); mdConfig.userData = this; @@ -2212,9 +2852,8 @@ Imogen::~Imogen() void Imogen::ClearAll() { mNodeGraphControler->Clear(); - NodeGraphClear(); + GraphEditorClear(); InitCallbackRects(); ClearExtractedViews(); - gUndoRedoHandler.Clear(); mSequence->Clear(); } diff --git a/src/Imogen.h b/src/Imogen.h index 6ad1c930..3b374f3f 100644 --- a/src/Imogen.h +++ b/src/Imogen.h @@ -22,37 +22,23 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // - #pragma once #include #include #include #include +#include "Library.h" #include "imgui.h" #include "imgui_internal.h" -#include "Library.h" +#include "Types.h" -struct NodeGraphControler; +struct GraphControler; struct Evaluation; struct Library; struct Builder; struct MySequence; - -enum EVALUATOR_TYPE -{ - EVALUATOR_GLSL, - EVALUATOR_C, - EVALUATOR_PYTHON, - EVALUATOR_GLSLCOMPUTE, -}; - -struct EvaluatorFile -{ - std::string mDirectory; - std::string mFilename; - EVALUATOR_TYPE mEvaluatorType; -}; +struct ParameterBlock; // plugins struct RegisteredPlugin @@ -64,37 +50,33 @@ extern std::vector mRegisteredPlugins; struct Imogen { - Imogen(NodeGraphControler* nodeGraphControler); + Imogen(GraphControler* nodeGraphControler, RecentLibraries& recentLibraries); ~Imogen(); - void Init(); + void Init(bool bDebugWindow); void Finish(); void Show(Builder* builder, Library& library, bool capturing); - void ValidateCurrentMaterial(Library& library); - void DiscoverNodes(const char* extension, - const char* directory, - EVALUATOR_TYPE evaluatorType, - std::vector& files); + void CommitCurrentGraph(Library& library); - std::vector mEvaluatorFiles; void SetExistingMaterialActive(int materialIndex); void SetExistingMaterialActive(const char* materialName); void DecodeThumbnailAsync(Material* material); - static void RenderPreviewNode(int selNode, NodeGraphControler& nodeGraphControler, bool forceUI = false); + static bool RenderPreviewNode(NodeIndex selNode, GraphControler& nodeGraphControler, ParameterBlock& parameterBlock, bool forceUI = false); void HandleHotKeys(); - void NewMaterial(const std::string& materialName = "Name_Of_New_Material"); + Material& NewMaterial(const std::string& materialName = "Name_Of_New_Material"); // helper for python scripting int AddNode(const std::string& nodeType); + void DelNode(int nodeIndex); void DeleteCurrentMaterial(); void RunDeferedCommands(); static Imogen* instance; - NodeGraphControler* GetNodeGraphControler() + GraphControler* GetNodeGraphControler() { return mNodeGraphControler; } @@ -102,6 +84,23 @@ struct Imogen { return mbShowMouseState; } + void RunCommandAsync(const std::string& command, bool quitAfterRunCommand) + { + for (auto& plugin : mRegisteredPlugins) + { + if (plugin.mName == command) + { + mRunCommand = plugin.mPythonCommand; + mbQuitAfterRunCommand = quitAfterRunCommand; + break; + } + } + } + + // libraries + int NewLibrary(const std::string& directory, const std::string& name, bool addDefaultMaterial); + void OpenLibrary(int libraryIndex, bool saveCurrent); + void CloseLibrary(); protected: void ShowAppMainMenuBar(); @@ -113,14 +112,17 @@ struct Imogen void ShowNodeGraph(); void BuildCurrentMaterial(Builder* builder); void PlayPause(); - + void ShowDebugWindow(); + void ShowExtractedViews(); + int EditRecentLibraries(RecentLibraries& recentLibraries); + void ImportMaterial(); void ExportMaterial(); void Playback(bool timeHasChanged); int GetFunctionByName(const char* functionName) const; - bool ImageButton(const char* functionName, unsigned int icon, ImVec2 size); + bool ImageButton(const char* functionName, bgfx::TextureHandle icon, ImVec2 size); bool Button(const char* functionName, const char* label, ImVec2 size); static void ReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line_start); @@ -128,7 +130,7 @@ struct Imogen static void* ReadOpen(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); MySequence* mSequence; - NodeGraphControler* mNodeGraphControler; + GraphControler* mNodeGraphControler; Builder* mBuilder; bool mbShowTimeline = false; bool mbShowLibrary = false; @@ -136,12 +138,13 @@ struct Imogen bool mbShowLog = false; bool mbShowParameters = false; bool mbShowMouseState = false; + bool mbDebugWindow = false; int mLibraryViewMode = 1; float mMainMenuDest = -440.f; float mMainMenuPos = -440.f; - char* mNewPopup = nullptr; + const char* mNewPopup = nullptr; int mSelectedMaterial = -1; int mCurrentShaderIndex = -1; @@ -150,283 +153,13 @@ struct Imogen int mCurrentTime = 0; std::string mRunCommand; - + bool mbQuitAfterRunCommand = false; std::vector> mHotkeyFunctions; -}; - -struct UndoRedo -{ - UndoRedo(); - virtual ~UndoRedo(); - virtual void Undo() - { - if (mSubUndoRedo.empty()) - return; - for (int i = int(mSubUndoRedo.size()) - 1; i >= 0; i--) - { - mSubUndoRedo[i]->Undo(); - } - } - virtual void Redo() - { - for (auto& undoRedo : mSubUndoRedo) - { - undoRedo->Redo(); - } - } - template - void AddSubUndoRedo(const T& subUndoRedo) - { - mSubUndoRedo.push_back(std::make_shared(subUndoRedo)); - } - void Discard() - { - mbDiscarded = true; - } - bool IsDiscarded() const - { - return mbDiscarded; - } - -protected: - std::vector> mSubUndoRedo; - bool mbDiscarded; + RecentLibraries& mRecentLibraries; }; -struct UndoRedoHandler -{ - UndoRedoHandler() : mbProcessing(false), mCurrent(NULL) - { - } - ~UndoRedoHandler() - { - Clear(); - } - - void Undo() - { - if (mUndos.empty()) - return; - mbProcessing = true; - mUndos.back()->Undo(); - mRedos.push_back(mUndos.back()); - mUndos.pop_back(); - mbProcessing = false; - } - - void Redo() - { - if (mRedos.empty()) - return; - mbProcessing = true; - mRedos.back()->Redo(); - mUndos.push_back(mRedos.back()); - mRedos.pop_back(); - mbProcessing = false; - } - - template - void AddUndo(const T& undoRedo) - { - if (undoRedo.IsDiscarded()) - return; - if (mCurrent && &undoRedo != mCurrent) - mCurrent->AddSubUndoRedo(undoRedo); - else - mUndos.push_back(std::make_shared(undoRedo)); - mbProcessing = true; - mRedos.clear(); - mbProcessing = false; - } - - void Clear() - { - mbProcessing = true; - mUndos.clear(); - mRedos.clear(); - mbProcessing = false; - } - - bool mbProcessing; - UndoRedo* mCurrent; - // private: - - std::vector> mUndos; - std::vector> mRedos; -}; - -extern UndoRedoHandler gUndoRedoHandler; - -inline UndoRedo::UndoRedo() : mbDiscarded(false) -{ - if (!gUndoRedoHandler.mCurrent) - { - gUndoRedoHandler.mCurrent = this; - } -} - -inline UndoRedo::~UndoRedo() -{ - if (gUndoRedoHandler.mCurrent == this) - { - gUndoRedoHandler.mCurrent = NULL; - } -} - -template -struct URChange : public UndoRedo -{ - URChange(int index, - std::function GetElements, - std::function Changed = [](int index) {}) - : GetElements(GetElements), mIndex(index), Changed(Changed) - { - if (gUndoRedoHandler.mbProcessing) - return; - - mPreDo = *GetElements(mIndex); - } - virtual ~URChange() - { - if (gUndoRedoHandler.mbProcessing || mbDiscarded) - return; - - if (*GetElements(mIndex) != mPreDo) - { - mPostDo = *GetElements(mIndex); - gUndoRedoHandler.AddUndo(*this); - } - else - { - // TODO: should not be here unless asking for too much useless undo - } - } - virtual void Undo() - { - *GetElements(mIndex) = mPreDo; - Changed(mIndex); - UndoRedo::Undo(); - } - virtual void Redo() - { - UndoRedo::Redo(); - *GetElements(mIndex) = mPostDo; - Changed(mIndex); - } - - T mPreDo; - T mPostDo; - int mIndex; - - std::function GetElements; - std::function Changed; -}; - - -struct URDummy : public UndoRedo -{ - URDummy() : UndoRedo() - { - if (gUndoRedoHandler.mbProcessing) - return; - } - virtual ~URDummy() - { - if (gUndoRedoHandler.mbProcessing) - return; - - gUndoRedoHandler.AddUndo(*this); - } - virtual void Undo() - { - UndoRedo::Undo(); - } - virtual void Redo() - { - UndoRedo::Redo(); - } -}; - - -template -struct URDel : public UndoRedo -{ - URDel(int index, - std::function*()> GetElements, - std::function OnDelete = [](int index) {}, - std::function OnNew = [](int index) {}) - : GetElements(GetElements), mIndex(index), OnDelete(OnDelete), OnNew(OnNew) - { - if (gUndoRedoHandler.mbProcessing) - return; - - mDeletedElement = (*GetElements())[mIndex]; - } - virtual ~URDel() - { - if (gUndoRedoHandler.mbProcessing || mbDiscarded) - return; - // add to handler - gUndoRedoHandler.AddUndo(*this); - } - virtual void Undo() - { - GetElements()->insert(GetElements()->begin() + mIndex, mDeletedElement); - OnNew(mIndex); - UndoRedo::Undo(); - } - virtual void Redo() - { - UndoRedo::Redo(); - OnDelete(mIndex); - GetElements()->erase(GetElements()->begin() + mIndex); - } - - T mDeletedElement; - int mIndex; - - std::function*()> GetElements; - std::function OnDelete; - std::function OnNew; -}; - -template -struct URAdd : public UndoRedo -{ - URAdd(int index, - std::function*()> GetElements, - std::function OnDelete = [](int index) {}, - std::function OnNew = [](int index) {}) - : GetElements(GetElements), mIndex(index), OnDelete(OnDelete), OnNew(OnNew) - { - } - virtual ~URAdd() - { - if (gUndoRedoHandler.mbProcessing || mbDiscarded) - return; - - mAddedElement = (*GetElements())[mIndex]; - // add to handler - gUndoRedoHandler.AddUndo(*this); - } - virtual void Undo() - { - OnDelete(mIndex); - GetElements()->erase(GetElements()->begin() + mIndex); - UndoRedo::Undo(); - } - virtual void Redo() - { - UndoRedo::Redo(); - GetElements()->insert(GetElements()->begin() + mIndex, mAddedElement); - OnNew(mIndex); - } - - T mAddedElement; - int mIndex; - - std::function*()> GetElements; - std::function OnDelete; - std::function OnNew; -}; +void AddExtractedView(size_t nodeIndex); +void ClearExtractedViews(); +void ExtractedViewNodeDeleted(size_t nodeIndex); +void ExtractedViewNodeInserted(size_t nodeIndex); diff --git a/src/JSGlue.cpp b/src/JSGlue.cpp new file mode 100644 index 00000000..30690fdd --- /dev/null +++ b/src/JSGlue.cpp @@ -0,0 +1,165 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +#include "Platform.h" +#include "Bitmap.h" +#include "Utils.h" + +#include +#include + +#ifdef __EMSCRIPTEN__ +void ImWebConsoleOutput(const char* szText) +{ + printf("%s", szText); +} + +EM_JS(void, _HideLoader, (), { + document.getElementById("loader").style.display = "none"; +}); +void HideLoader() { _HideLoader(); } + +// https://stackoverflow.com/questions/25354313/saving-a-uint8array-to-a-binary-file +EM_JS(void, _DownloadImage, (const char *filename, int filenameLen, const char* data, int dataLen), { + var filenamejs = String.fromCharCode.apply(null, new Uint8Array(HEAPU8.subarray(filename, filename + filenameLen))); + var downloadBlob, downloadURL; + + downloadBlob = function(data, fileName, mimeType) { + var blob, url; + blob = new Blob([data], { + type: mimeType + }); + url = window.URL.createObjectURL(blob); + downloadURL(url, fileName); + setTimeout(function() { + return window.URL.revokeObjectURL(url); + }, 1000); + }; + + downloadURL = function(data, fileName) { + var a; + a = document.createElement('a'); + a.href = data; + a.download = fileName; + document.body.appendChild(a); + a.style = 'display: none'; + a.click(); + a.remove(); + }; + downloadBlob(new Uint8Array(HEAPU8.subarray(data, data + dataLen)), filenamejs, 'application/octet-stream'); + }); + +std::function _completeUploadCB; +EM_JS(void, _UploadDialog, (), { +document.getElementById('FileInput').click(); +}); +void UploadDialog(std::function completeUploadCB) +{ + _completeUploadCB = completeUploadCB; + _UploadDialog(); +} + +void DownloadImage(const char *filename, int filenameLen, const char* data, int dataLen) +{ + _DownloadImage(filename, filenameLen, data, dataLen); +} + +int main_Async(int argc, char** argv); +extern "C" +{ + void EMSCRIPTEN_KEEPALIVE MountJSDirectoryDone() + { + main_Async(0, 0); + } +} + +void MountJSDirectory() +{ + // EM_ASM is a macro to call in-line JavaScript code. + EM_ASM( + // Make a directory other than '/' + FS.mkdir('/offline'); + // Then mount with IDBFS type + FS.mount(IDBFS, {}, '/offline'); + + // Then sync + Module.syncdone = 0; + FS.syncfs(true, function(err) { + if (err) { + console.log("Error at mounting IDFS directory : " + err); + } + Module.syncdone = 1; + ccall('MountJSDirectoryDone'); + }); + ); + emscripten_exit_with_live_runtime(); +} + +void SyncJSDirectory() +{ + EM_ASM( + // Then sync + if (Module.syncdone == 1) { + Module.syncdone = 0; + FS.syncfs(false, function(err) { + if (err) { + console.log("Error at mounting IDFS directory : " + err); + } + Module.syncdone = 1; + }); + } + ); +} + +extern "C" +{ + void EMSCRIPTEN_KEEPALIVE OpenFileAsync(const uint8_t *buf, int length, const uint8_t* filename, int filenameLength, int posx, int posy) + { + uint8_t* currentUpload = (uint8_t *)malloc(length); + memcpy(currentUpload, buf, length); + + std::string filepath((const char*)filename, (size_t)filenameLength); + + Log("OpenFileAsync %s - % bytes\n", filepath.c_str(), length); + Image image; + if (Image::ReadMem(currentUpload, length, &image) == EVAL_OK) + { + Log("Image read OK from memory. Adding to cache.\n"); + gImageCache.AddImage(filepath, &image); + _completeUploadCB(filepath); + } + else + { + Log("Unable to read image from memory.\n"); + } + free(currentUpload); + } +} +#else +void SyncJSDirectory() +{ + +} +#endif + diff --git a/src/JSGlue.h b/src/JSGlue.h new file mode 100644 index 00000000..c9a363f1 --- /dev/null +++ b/src/JSGlue.h @@ -0,0 +1,32 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +#pragma once + +void MountJSDirectory(); +void SyncJSDirectory(); +void ImWebConsoleOutput(const char* szText); +void HideLoader(); +void DownloadImage(const char *filename, int filenameLen, const char* data, int dataLen); +void UploadDialog(std::function); diff --git a/src/Libraries.cpp b/src/Libraries.cpp new file mode 100644 index 00000000..c421e2ad --- /dev/null +++ b/src/Libraries.cpp @@ -0,0 +1,135 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "Libraries.h" +#include "Utils.h" +#include "Library.h" + +size_t RecentLibraries::AddRecent(const std::string& path, const std::string& name) +{ + RecentLibrary newRecentLibrary{ name, path }; + if (std::find(mRecentLibraries.begin(), mRecentLibraries.end(), newRecentLibrary) == mRecentLibraries.end()) + { + mRecentLibraries.push_back(newRecentLibrary); + WriteRecentLibraries(); + } + return mRecentLibraries.size() - 1; +} + +size_t RecentLibraries::AddRecent(const std::string& completePath) +{ + char drive[256]; + char dir[256]; + char filename[256]; + char ext[256]; + Splitpath(completePath.c_str(), drive, dir, filename, ext); + return AddRecent(std::string(drive) + std::string(dir), std::string(filename)); +} + +void RecentLibraries::ReadRecentLibraries() +{ + LoadRecent(this, RecentFilename); + if (mRecentLibraries.empty()) + { + // add default +#ifdef __EMSCRIPTEN__ + mRecentLibraries.push_back({ "DefaultLibrary", "" }); +#else + mRecentLibraries.push_back({ "DefaultLibrary", "./" }); +#endif + } + else + { + auto iter = mRecentLibraries.begin(); + for (; iter != mRecentLibraries.end();) + { + FILE* fp = fopen(iter->ComputeFullPath().c_str(), "rb"); + if (!fp) + { + Log("Library %s removed from recent because not found in FS\n", iter->ComputeFullPath().c_str()); + mMostRecentLibrary = -1; // something happened (deleted libs) -> display all libraries + iter = mRecentLibraries.erase(iter); + continue; + } + fclose(fp); + ++iter; + } + } +} + +void RecentLibraries::WriteRecentLibraries() +{ + SaveRecent(this, RecentFilename); +} + +bool RecentLibraries::IsValidForAddingRecent(const std::string& completePath) const +{ + if (!completePath.length()) + { + return false; + } + for (const auto& recent : mRecentLibraries) + { + if (recent.ComputeFullPath() == completePath) + { + return false; + } + } + + FILE* fp = fopen(completePath.c_str(), "rb"); + if (!fp) + { + return false; + } + fclose(fp); + + return true; +} + +bool RecentLibraries::IsValidForCreatingRecent(const std::string& path, const std::string& name) const +{ +#ifdef __EMSCRIPTEN__ + if (!name.size() || IsNamedUsed(name)) + { + return false; + } +#else + if (!path.size() || !name.size()) + { + return false; + } + if (IsNamedUsed(name)) + { + return false; + } + FILE* fp = fopen(RecentLibrary{ name, path }.ComputeFullPath().c_str(), "rb"); + if (fp) + { + fclose(fp); + return false; + } +#endif + return true; +} \ No newline at end of file diff --git a/src/Libraries.h b/src/Libraries.h new file mode 100644 index 00000000..369f8178 --- /dev/null +++ b/src/Libraries.h @@ -0,0 +1,109 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include +#include + +struct RecentLibraries +{ +#ifdef __EMSCRIPTEN__ + const char* RecentFilename = "/offline/ImogenRecent"; +#else + const char* RecentFilename = "ImogenRecent"; +#endif + RecentLibraries() + { + ReadRecentLibraries(); + } + + struct RecentLibrary + { + std::string mName; + std::string mPath; + + std::string ComputeFullPath() const + { + return mPath + mName + ".imogen"; + } + + bool operator == (const RecentLibrary& other) const + { + return mName == other.mName && mPath == other.mPath; + } + }; + + const std::vector& GetRecentLibraries() const + { + return mRecentLibraries; + } + + void ReadRecentLibraries(); + + void WriteRecentLibraries(); + + bool IsNamedUsed(const std::string& name) const + { + for (const auto& recent : mRecentLibraries) + { + if (recent.mName == name) + { + return true; + } + } + return false; + } + + size_t AddRecent(const std::string& path, const std::string& name); + size_t AddRecent(const std::string& completePath); + + bool IsValidForAddingRecent(const std::string& completePath) const; + + bool IsValidForCreatingRecent(const std::string& path, const std::string& name) const; + + std::string GetMostRecentLibraryPath() const + { + if (mMostRecentLibrary == -1) + { + return {}; + } + const auto& recentLibrary = mRecentLibraries[mMostRecentLibrary]; + return recentLibrary.ComputeFullPath(); + } + + void SetMostRecentLibraryIndex(int index) + { + mMostRecentLibrary = index; + WriteRecentLibraries(); + } + + int GetMostRecentLibraryIndex() const + { + return mMostRecentLibrary; + } + + int mMostRecentLibrary = -1; + std::vector mRecentLibraries; +}; diff --git a/src/Library.cpp b/src/Library.cpp index 04c5dd5c..a76b29c5 100644 --- a/src/Library.cpp +++ b/src/Library.cpp @@ -22,22 +22,21 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // - #include "Platform.h" + #include #include #include #include "Library.h" #include "imgui.h" -#include "rapidjson/rapidjson.h" -#include "rapidjson/document.h" -#include "rapidjson/writer.h" #include +#include "JSGlue.h" +#include "Libraries.h" int Log(const char* szFormat, ...); const std::vector MetaNode::mCategories = { - "Transform", "Generator", "Material", "Blend", "Filter", "Noise", "File", "Paint", "Cubemap", "Fur"}; + "Transform", "Generator", "Material", "Blend", "Filter", "Noise", "File", "Paint", "Cubemap", "Fur", "Tools"}; enum : uint32_t { @@ -51,7 +50,8 @@ enum : uint32_t v_animation, v_pinnedParameters, v_backgroundNode, - v_pinnedIO, + v_pinnedIO, + v_multiplexInput, v_lastVersion }; #define ADD(_fieldAdded, _fieldName) \ @@ -78,12 +78,21 @@ struct Serialize Serialize(const char* szFilename) { fp = fopen(szFilename, doWrite ? "wb" : "rb"); + if (!fp) + { + Log("Unable to open file %s for %s\n", szFilename, doWrite ? "writing" : "reading"); + } + else + { + Log("Open file %s for %s\n", szFilename, doWrite ? "writing" : "reading"); + } } ~Serialize() { if (fp) fclose(fp); + SyncJSDirectory(); } template @@ -120,7 +129,9 @@ struct Serialize Ser(count); data.resize(count); for (auto& item : data) + { Ser(&item); + } } template @@ -182,6 +193,17 @@ struct Serialize ADD(v_animation, animTrack->mAnimation); } + void Ser(MultiplexInput* multiplexInput) + { + if (doWrite) + { + fwrite(multiplexInput, sizeof(MultiplexInput), 1, fp); + } + else + { + fread(multiplexInput, sizeof(MultiplexInput), 1, fp); + } + } void Ser(InputSampler* inputSampler) { ADD(v_initial, inputSampler->mWrapU); @@ -192,7 +214,7 @@ struct Serialize void Ser(MaterialNode* materialNode) { - ADD(v_initial, materialNode->mType); + ADD(v_initial, materialNode->mNodeType); ADD(v_nodeTypeName, materialNode->mTypeName); ADD(v_initial, materialNode->mPosX); ADD(v_initial, materialNode->mPosY); @@ -215,10 +237,10 @@ struct Serialize void Ser(MaterialConnection* materialConnection) { - ADD(v_initial, materialConnection->mInputNode); - ADD(v_initial, materialConnection->mOutputNode); - ADD(v_initial, materialConnection->mInputSlot); - ADD(v_initial, materialConnection->mOutputSlot); + ADD(v_initial, materialConnection->mInputNodeIndex); + ADD(v_initial, materialConnection->mOutputNodeIndex); + ADD(v_initial, materialConnection->mInputSlotIndex); + ADD(v_initial, materialConnection->mOutputSlotIndex); } void Ser(Material* material) @@ -235,6 +257,20 @@ struct Serialize ADD(v_pinnedParameters, material->mPinnedParameters); ADD(v_pinnedIO, material->mPinnedIO); ADD(v_backgroundNode, material->mBackgroundNode); + ADD(v_multiplexInput, material->mMultiplexInputs) + if (!doWrite) + { + auto nodeCount = material->mMaterialNodes.size(); + material->mMultiplexInputs.resize(nodeCount); + material->mPinnedParameters.resize(nodeCount); + material->mPinnedIO.resize(nodeCount); + } + } + + void Ser(RecentLibraries::RecentLibrary* recentLibrary) + { + ADD(v_initial, recentLibrary->mName); + ADD(v_initial, recentLibrary->mPath); } bool Ser(Library* library) @@ -250,6 +286,20 @@ struct Serialize return true; } + bool Ser(RecentLibraries* recent) + { + if (!fp) + return false; + if (doWrite) + dataVersion = v_lastVersion - 1; + Ser(dataVersion); + if (dataVersion > v_lastVersion) + return false; // no forward compatibility + ADD(v_initial, recent->mRecentLibraries); + ADD(v_initial, recent->mMostRecentLibrary); + return true; + } + FILE* fp; uint32_t dataVersion; }; @@ -257,847 +307,41 @@ struct Serialize typedef Serialize SerializeWrite; typedef Serialize SerializeRead; -void LoadLib(Library* library, const char* szFilename) +void LoadLib(Library* library, const std::string& filename) { - SerializeRead loadSer(szFilename); + if (!filename.size()) + { + return; + } + SerializeRead loadSer(filename.c_str()); + library->mFilename = filename; loadSer.Ser(library); for (auto& material : library->mMaterials) { - material.mThumbnailTextureId = 0; - material.mRuntimeUniqueId = GetRuntimeId(); + material.mThumbnailTextureHandle = {bgfx::kInvalidHandle}; for (auto& node : material.mMaterialNodes) { - node.mRuntimeUniqueId = GetRuntimeId(); if (loadSer.dataVersion >= v_nodeTypeName) { - node.mType = uint32_t(GetMetaNodeIndex(node.mTypeName)); - } - } - } -} - -void SaveLib(Library* library, const char* szFilename) -{ - SerializeWrite(szFilename).Ser(library); -} - -unsigned int GetRuntimeId() -{ - static unsigned int runtimeId = 0; - return ++runtimeId; -} - -int GetParameterIndex(uint32_t nodeType, const char* parameterName) -{ - const MetaNode& currentMeta = gMetaNodes[nodeType]; - int i = 0; - for (const MetaParameter& param : currentMeta.mParams) - { - if (!strcmp(param.mName.c_str(), parameterName)) - return i; - i++; - } - return -1; -} - -size_t GetParameterTypeSize(ConTypes paramType) -{ - switch (paramType) - { - case Con_Angle: - case Con_Float: - return sizeof(float); - case Con_Angle2: - case Con_Float2: - return sizeof(float) * 2; - case Con_Angle3: - case Con_Float3: - return sizeof(float) * 3; - case Con_Angle4: - case Con_Color4: - case Con_Float4: - return sizeof(float) * 4; - case Con_Ramp: - return sizeof(float) * 2 * 8; - case Con_Ramp4: - return sizeof(float) * 4 * 8; - case Con_Enum: - case Con_Int: - return sizeof(int); - case Con_Int2: - return sizeof(int) * 2; - case Con_FilenameRead: - case Con_FilenameWrite: - return 1024; - case Con_ForceEvaluate: - return 0; - case Con_Bool: - return sizeof(int); - case Con_Camera: - return sizeof(Camera); - default: - assert(0); - } - return -1; -} - -static const char* parameterNames[] = { - "Float", "Float2", "Float3", "Float4", "Color4", "Int", "Int2", - "Ramp", "Angle", "Angle2", "Angle3", "Angle4", "Enum", "Structure", - "FilenameRead", "FilenameWrite", "ForceEvaluate", "Bool", "Ramp4", "Camera", "Any", -}; - -const char* GetParameterTypeName(ConTypes paramType) -{ - return parameterNames[std::min(int(paramType), int(Con_Any) - 1)]; -} - -ConTypes GetParameterType(const char* parameterName) -{ - for (size_t i = 0; i < Con_Any; i++) - { - if (!strcmp(parameterNames[i], parameterName)) - return ConTypes(i); - } - return Con_Any; -} - -size_t GetCurveCountPerParameterType(uint32_t paramType) -{ - switch (paramType) - { - case Con_Angle: - case Con_Float: - return 1; - case Con_Angle2: - case Con_Float2: - return 2; - case Con_Angle3: - case Con_Float3: - return 3; - case Con_Angle4: - case Con_Color4: - case Con_Float4: - return 4; - case Con_Ramp: - return 0; // sizeof(float) * 2 * 8; - case Con_Ramp4: - return 0; // sizeof(float) * 4 * 8; - case Con_Enum: - return 1; - case Con_Int: - return 1; - case Con_Int2: - return 2; - case Con_FilenameRead: - case Con_FilenameWrite: - return 0; - case Con_ForceEvaluate: - return 0; - case Con_Bool: - return 1; - case Con_Camera: - return 7; - default: - assert(0); - } - return 0; -} - -const char* GetCurveParameterSuffix(uint32_t paramType, int suffixIndex) -{ - static const char* suffixes[] = {".x", ".y", ".z", ".w"}; - static const char* cameraSuffixes[] = {"posX", "posY", "posZ", "dirX", "dirY", "dirZ", "FOV"}; - switch (paramType) - { - case Con_Angle: - case Con_Float: - return ""; - case Con_Angle2: - case Con_Float2: - return suffixes[suffixIndex]; - case Con_Angle3: - case Con_Float3: - return suffixes[suffixIndex]; - case Con_Angle4: - case Con_Color4: - case Con_Float4: - return suffixes[suffixIndex]; - case Con_Ramp: - return 0; // sizeof(float) * 2 * 8; - case Con_Ramp4: - return 0; // sizeof(float) * 4 * 8; - case Con_Enum: - return ""; - case Con_Int: - return ""; - case Con_Int2: - return suffixes[suffixIndex]; - case Con_FilenameRead: - case Con_FilenameWrite: - return 0; - case Con_ForceEvaluate: - return 0; - case Con_Bool: - return ""; - case Con_Camera: - return cameraSuffixes[suffixIndex]; - default: - assert(0); - } - return ""; -} - -uint32_t GetCurveParameterColor(uint32_t paramType, int suffixIndex) -{ - static const uint32_t colors[] = {0xFF1010F0, 0xFF10F010, 0xFFF01010, 0xFFF0F0F0}; - static const uint32_t cameraColors[] = { - 0xFF1010F0, 0xFF10F010, 0xFFF01010, 0xFF1010F0, 0xFF10F010, 0xFFF01010, 0xFFF0F0F0}; - switch (paramType) - { - case Con_Angle: - case Con_Float: - return 0xFF1040F0; - case Con_Angle2: - case Con_Float2: - return colors[suffixIndex]; - case Con_Angle3: - case Con_Float3: - return colors[suffixIndex]; - case Con_Angle4: - case Con_Color4: - case Con_Float4: - return colors[suffixIndex]; - case Con_Ramp: - return 0xFFAAAAAA; // sizeof(float) * 2 * 8; - case Con_Ramp4: - return 0xFFAAAAAA; // sizeof(float) * 4 * 8; - case Con_Enum: - return 0xFFAAAAAA; - case Con_Int: - return 0xFFAAAAAA; - case Con_Int2: - return colors[suffixIndex]; - case Con_FilenameRead: - case Con_FilenameWrite: - return 0; - case Con_ForceEvaluate: - return 0; - case Con_Bool: - return 0xFFF0F0F0; - case Con_Camera: - return cameraColors[suffixIndex]; - default: - assert(0); - } - return 0xFFAAAAAA; -} - -size_t GetParameterOffset(uint32_t type, uint32_t parameterIndex) -{ - const MetaNode& currentMeta = gMetaNodes[type]; - size_t ret = 0; - int i = 0; - for (const MetaParameter& param : currentMeta.mParams) - { - if (i == parameterIndex) - break; - ret += GetParameterTypeSize(param.mType); - i++; - } - return ret; -} - -ConTypes GetParameterType(uint32_t nodeType, uint32_t parameterIndex) -{ - const MetaNode& currentMeta = gMetaNodes[nodeType]; - return currentMeta.mParams[parameterIndex].mType; -} - -AnimationBase* AllocateAnimation(uint32_t valueType) -{ - switch (valueType) - { - case Con_Float: - return new Animation; - case Con_Float2: - return new Animation; - case Con_Float3: - return new Animation; - case Con_Float4: - return new Animation; - case Con_Color4: - return new Animation; - case Con_Int: - return new Animation; - case Con_Int2: - return new Animation; - case Con_Ramp: - return new Animation; - case Con_Angle: - return new Animation; - case Con_Angle2: - return new Animation; - case Con_Angle3: - return new Animation; - case Con_Angle4: - return new Animation; - case Con_Enum: - return new Animation; - case Con_Structure: - case Con_FilenameRead: - case Con_FilenameWrite: - case Con_ForceEvaluate: - return NULL; - case Con_Bool: - return new Animation; - case Con_Ramp4: - return new Animation; - case Con_Camera: - return new Animation; - } - return NULL; -} - -CurveType GetCurveTypeForParameterType(ConTypes paramType) -{ - switch (paramType) - { - case Con_Float: - return CurveSmooth; - case Con_Float2: - return CurveSmooth; - case Con_Float3: - return CurveSmooth; - case Con_Float4: - return CurveSmooth; - case Con_Color4: - return CurveSmooth; - case Con_Int: - return CurveLinear; - case Con_Int2: - return CurveLinear; - case Con_Ramp: - return CurveNone; - case Con_Angle: - return CurveSmooth; - case Con_Angle2: - return CurveSmooth; - case Con_Angle3: - return CurveSmooth; - case Con_Angle4: - return CurveSmooth; - case Con_Enum: - return CurveDiscrete; - case Con_Structure: - case Con_FilenameRead: - case Con_FilenameWrite: - case Con_ForceEvaluate: - return CurveNone; - case Con_Bool: - return CurveDiscrete; - case Con_Ramp4: - return CurveNone; - case Con_Camera: - return CurveSmooth; - } - return CurveNone; -} - -void Camera::ComputeViewProjectionMatrix(float* viewProj, float* viewInverse) -{ - Mat4x4& vp = *(Mat4x4*)viewProj; - Mat4x4 view, proj; - view.lookAtRH(mPosition, mPosition + mDirection, Vec4(0.f, 1.f, 0.f, 0.f)); - proj.glhPerspectivef2(53.f, 1.f, 0.01f, 100.f); - vp = view * proj; - - Mat4x4& vi = *(Mat4x4*)viewInverse; - vi.LookAt(mPosition, mPosition + mDirection, Vec4(0.f, 1.f, 0.f, 0.f)); -} - -std::vector gMetaNodes; -std::map gMetaNodesIndices; - -size_t GetMetaNodeIndex(const std::string& metaNodeName) -{ - auto iter = gMetaNodesIndices.find(metaNodeName.c_str()); - if (iter == gMetaNodesIndices.end()) - { - Log("Node type %s not find in the library!\n", metaNodeName.c_str()); - return -1; - } - return iter->second; -} - -size_t ComputeNodeParametersSize(size_t nodeType) -{ - size_t res = 0; - for (auto& param : gMetaNodes[nodeType].mParams) - { - res += GetParameterTypeSize(param.mType); - } - return res; -} - - -void LoadMetaNodes(const std::vector& metaNodeFilenames) -{ - static const uint32_t hcTransform = IM_COL32(200, 200, 200, 255); - static const uint32_t hcGenerator = IM_COL32(150, 200, 150, 255); - static const uint32_t hcMaterial = IM_COL32(150, 150, 200, 255); - static const uint32_t hcBlend = IM_COL32(200, 150, 150, 255); - static const uint32_t hcFilter = IM_COL32(200, 200, 150, 255); - static const uint32_t hcNoise = IM_COL32(150, 250, 150, 255); - static const uint32_t hcPaint = IM_COL32(100, 250, 180, 255); - - for (auto& filename : metaNodeFilenames) - { - std::vector metaNodes = ReadMetaNodes(filename.c_str()); - if (metaNodes.empty()) - { - IMessageBox("Errors while parsing nodes definitions.\nCheck logs.", "Node Parsing Error!"); - //exit(-1); - continue; - } - gMetaNodes.insert(gMetaNodes.end(), metaNodes.begin(), metaNodes.end()); - } - - - for (size_t i = 0; i < gMetaNodes.size(); i++) - { - gMetaNodesIndices[gMetaNodes[i].mName] = i; - } -} - -void LoadMetaNodes() -{ - std::vector metaNodeFilenames; - DiscoverFiles("json", "Nodes/", metaNodeFilenames); - LoadMetaNodes(metaNodeFilenames); -} - -void SaveMetaNodes(const char* filename) -{ - // write lib to json ----------------------- - rapidjson::Document d; - d.SetObject(); - rapidjson::Document::AllocatorType& allocator = d.GetAllocator(); - - rapidjson::Value nodelist(rapidjson::kArrayType); - - for (auto& node : gMetaNodes) - { - rapidjson::Value nodeValue; - nodeValue.SetObject(); - nodeValue.AddMember("name", rapidjson::Value(node.mName.c_str(), allocator), allocator); - nodeValue.AddMember("category", rapidjson::Value().SetInt(node.mCategory), allocator); - { - ImColor clr(node.mHeaderColor); - rapidjson::Value colorValue(rapidjson::kArrayType); - colorValue.PushBack(rapidjson::Value().SetFloat(clr.Value.x), allocator); - colorValue.PushBack(rapidjson::Value().SetFloat(clr.Value.y), allocator); - colorValue.PushBack(rapidjson::Value().SetFloat(clr.Value.z), allocator); - colorValue.PushBack(rapidjson::Value().SetFloat(clr.Value.w), allocator); - nodeValue.AddMember("color", colorValue, allocator); - } - - std::vector* cons[] = {&node.mInputs, &node.mOutputs}; - for (int i = 0; i < 2; i++) - { - auto inouts = cons[i]; - if (inouts->empty()) - continue; - - rapidjson::Value ioValue(rapidjson::kArrayType); - - for (auto& con : *inouts) - { - rapidjson::Value conValue; - conValue.SetObject(); - conValue.AddMember("name", rapidjson::Value(con.mName.c_str(), allocator), allocator); - conValue.AddMember( - "type", rapidjson::Value(GetParameterTypeName(ConTypes(con.mType)), allocator), allocator); - ioValue.PushBack(conValue, allocator); + node.mNodeType = uint32_t(GetMetaNodeIndex(node.mTypeName)); } - if (i) - nodeValue.AddMember("outputs", ioValue, allocator); - else - nodeValue.AddMember("inputs", ioValue, allocator); } - - if (!node.mParams.empty()) - { - rapidjson::Value paramValues(rapidjson::kArrayType); - for (auto& con : node.mParams) - { - rapidjson::Value conValue; - conValue.SetObject(); - conValue.AddMember("name", rapidjson::Value(con.mName.c_str(), allocator), allocator); - conValue.AddMember("type", rapidjson::Value(GetParameterTypeName(con.mType), allocator), allocator); - if (con.mRangeMinX > FLT_EPSILON || con.mRangeMaxX > FLT_EPSILON || con.mRangeMinY > FLT_EPSILON || - con.mRangeMaxY > FLT_EPSILON) - { - conValue.AddMember("rangeMinX", rapidjson::Value().SetFloat(con.mRangeMinX), allocator); - conValue.AddMember("rangeMaxX", rapidjson::Value().SetFloat(con.mRangeMaxX), allocator); - conValue.AddMember("rangeMinY", rapidjson::Value().SetFloat(con.mRangeMinY), allocator); - conValue.AddMember("rangeMaxY", rapidjson::Value().SetFloat(con.mRangeMaxY), allocator); - } - if (con.mbRelative) - conValue.AddMember("relative", rapidjson::Value().SetBool(con.mbRelative), allocator); - if (con.mbQuadSelect) - conValue.AddMember("quadSelect", rapidjson::Value().SetBool(con.mbQuadSelect), allocator); - if (con.mEnumList.size()) - { - conValue.AddMember("enum", rapidjson::Value(con.mEnumList.c_str(), allocator), allocator); - } - paramValues.PushBack(conValue, allocator); - } - nodeValue.AddMember("parameters", paramValues, allocator); - } - if (node.mbHasUI) - nodeValue.AddMember("hasUI", rapidjson::Value().SetBool(node.mbHasUI), allocator); - if (node.mbSaveTexture) - nodeValue.AddMember("saveTexture", rapidjson::Value().SetBool(node.mbSaveTexture), allocator); - - nodelist.PushBack(nodeValue, allocator); } - - d.AddMember("nodes", nodelist, allocator); - - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - d.Accept(writer); - - std::ofstream myfile; - myfile.open(filename); - myfile << buffer.GetString(); - myfile.close(); } -void ParseStringToParameter(const std::string& str, uint32_t parameterType, void *parameterPtr) +void SaveLib(Library* library, const std::string& filename) { - float* pf = (float*)parameterPtr; - int* pi = (int*)parameterPtr; - Camera* cam = (Camera*)parameterPtr; - ImVec2* iv2 = (ImVec2*)parameterPtr; - ImVec4* iv4 = (ImVec4*)parameterPtr; - switch (parameterType) - { - case Con_Angle: - case Con_Float: - sscanf(str.c_str(), "%f", pf); - break; - case Con_Angle2: - case Con_Float2: - sscanf(str.c_str(), "%f,%f", &pf[0], &pf[1]); - break; - case Con_Angle3: - case Con_Float3: - sscanf(str.c_str(), "%f,%f,%f", &pf[0], &pf[1], &pf[2]); - break; - case Con_Color4: - case Con_Float4: - case Con_Angle4: - sscanf(str.c_str(), "%f,%f,%f,%f", &pf[0], &pf[1], &pf[2], &pf[3]); - break; - case Con_Enum: - case Con_Int: - sscanf(str.c_str(), "%d", &pi[0]); - break; - case Con_Int2: - sscanf(str.c_str(), "%d,%d", &pi[0], &pi[1]); - break; - case Con_Ramp: - iv2[0] = ImVec2(0, 0); - iv2[1] = ImVec2(1, 1); - break; - case Con_Ramp4: - iv4[0] = ImVec4(0, 0, 0, 0); - iv4[1] = ImVec4(1, 1, 1, 1); - break; - case Con_FilenameRead: - strcpy((char*)parameterPtr, str.c_str()); - break; - case Con_Structure: - case Con_FilenameWrite: - case Con_ForceEvaluate: - case Con_Camera: - cam->mDirection = Vec4(0.f, 0.f, 1.f, 0.f); - cam->mUp = Vec4(0.f, 1.f, 0.f, 0.f); - break; - case Con_Bool: - pi[0] = (str == "true") ? 1 : 0; - break; - } + SerializeWrite(filename.c_str()).Ser(library); } -std::vector ReadMetaNodes(const char* filename) +void LoadRecent(RecentLibraries* recent, const char* szFilename) { - // read it back - std::vector serNodes; - - std::ifstream t(filename); - if (!t.good()) - { - Log("%s - Unable to load file.\n", filename); - return serNodes; - } - std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); - - - rapidjson::Document doc; - doc.Parse(str.c_str()); - if (doc.HasParseError()) - { - Log("Parsing error in %s\n", filename); - return serNodes; - } - - rapidjson::Value& nodesValue = doc["nodes"]; - for (rapidjson::SizeType i = 0; i < nodesValue.Size(); i++) - { - MetaNode curNode; - rapidjson::Value& node = nodesValue[i]; - if (!node.HasMember("name")) - { - // error - Log("Missing name in node %d definition (%s)\n", i, filename); - return serNodes; - } - curNode.mName = node["name"].GetString(); - if (!node.HasMember("category")) - { - // error - Log("Missing category in node %s definition (%s)\n", curNode.mName.c_str(), filename); - return serNodes; - } - curNode.mCategory = node["category"].GetInt(); - - if (node.HasMember("description")) - { - curNode.mDescription = node["description"].GetString(); - } - - if (node.HasMember("hasUI")) - curNode.mbHasUI = node["hasUI"].GetBool(); - else - curNode.mbHasUI = false; - if (node.HasMember("saveTexture")) - curNode.mbSaveTexture = node["saveTexture"].GetBool(); - else - curNode.mbSaveTexture = false; - - if (!node.HasMember("color")) - { - // error - Log("Missing color in node %s definition (%s)\n", curNode.mName.c_str(), filename); - return serNodes; - } - rapidjson::Value& color = node["color"]; - float c[4]; - if (color.Size() != 4) - { - // error - Log("wrong color component count in node %s definition (%s)\n", curNode.mName.c_str(), filename); - return serNodes; - } - for (rapidjson::SizeType i = 0; i < color.Size(); i++) - { - c[i] = color[i].GetFloat(); - } - curNode.mHeaderColor = ImColor(c[0], c[1], c[2], c[3]).operator ImU32(); - // inputs/outputs - if (node.HasMember("inputs")) - { - rapidjson::Value& inputs = node["inputs"]; - for (rapidjson::SizeType i = 0; i < inputs.Size(); i++) - { - MetaCon metaNode; - if (!inputs[i].HasMember("name") || !inputs[i].HasMember("type")) - { - // error - Log("Missing name or type in inputs for node %s definition (%s)\n", - curNode.mName.c_str(), - filename); - return serNodes; - } - - metaNode.mName = inputs[i]["name"].GetString(); - metaNode.mType = GetParameterType(inputs[i]["type"].GetString()); - if (metaNode.mType == Con_Any) - { - // error - Log("Wrong type for %s in inputs for node %s definition (%s)\n", - metaNode.mName.c_str(), - curNode.mName.c_str(), - filename); - return serNodes; - } - curNode.mInputs.emplace_back(metaNode); - } - } - if (node.HasMember("outputs")) - { - rapidjson::Value& outputs = node["outputs"]; - for (rapidjson::SizeType i = 0; i < outputs.Size(); i++) - { - MetaCon metaNode; - if (!outputs[i].HasMember("name") || !outputs[i].HasMember("type")) - { - // error - Log("Missing name or type in outputs for node %s definition (%s)\n", - curNode.mName.c_str(), - filename); - return serNodes; - } - metaNode.mName = outputs[i]["name"].GetString(); - metaNode.mType = GetParameterType(outputs[i]["type"].GetString()); - if (metaNode.mType == Con_Any) - { - // error - Log("Wrong type for %s in outputs for node %s definition (%s)\n", - metaNode.mName.c_str(), - curNode.mName.c_str(), - filename); - return serNodes; - } - curNode.mOutputs.emplace_back(metaNode); - } - } - // parameters - if (node.HasMember("parameters")) - { - rapidjson::Value& params = node["parameters"]; - for (rapidjson::SizeType i = 0; i < params.Size(); i++) - { - MetaParameter metaParam; - rapidjson::Value& param = params[i]; - if (!param.HasMember("name") || !param.HasMember("type")) - { - // error - Log("Missing name or type in parameters for node %s definition (%s)\n", - curNode.mName.c_str(), - filename); - return serNodes; - } - metaParam.mName = param["name"].GetString(); - metaParam.mType = GetParameterType(param["type"].GetString()); - if (metaParam.mType == Con_Any) - { - // error - Log("Wrong type for %s in parameters for node %s definition (%s)\n", - metaParam.mName.c_str(), - curNode.mName.c_str(), - filename); - return serNodes; - } - - if (param.HasMember("rangeMinX") && param.HasMember("rangeMaxX") && param.HasMember("rangeMinY") && - param.HasMember("rangeMaxY")) - { - metaParam.mRangeMinX = param["rangeMinX"].GetFloat(); - metaParam.mRangeMaxX = param["rangeMaxX"].GetFloat(); - metaParam.mRangeMinY = param["rangeMinY"].GetFloat(); - metaParam.mRangeMaxY = param["rangeMaxY"].GetFloat(); - } - else - { - metaParam.mRangeMinX = metaParam.mRangeMinY = metaParam.mRangeMaxX = metaParam.mRangeMaxY = 0.f; - } - if (param.HasMember("description")) - { - metaParam.mDescription = param["description"].GetString(); - } - - if (param.HasMember("loop")) - metaParam.mbLoop = param["loop"].GetBool(); - else - metaParam.mbLoop = true; - if (param.HasMember("relative")) - metaParam.mbRelative = param["relative"].GetBool(); - else - metaParam.mbRelative = false; - if (param.HasMember("quadSelect")) - metaParam.mbQuadSelect = param["quadSelect"].GetBool(); - else - metaParam.mbQuadSelect = false; - if (param.HasMember("enum")) - { - if (metaParam.mType != Con_Enum) - { - // error - Log("Mismatch type for enumerator in parameter %s for node %s definition (%s)\n", - metaParam.mName.c_str(), - curNode.mName.c_str(), - filename); - return serNodes; - } - std::string enumStr = param["enum"].GetString(); - if (enumStr.size()) - { - metaParam.mEnumList = enumStr; - if (metaParam.mEnumList.back() != '|') - metaParam.mEnumList += '|'; - } - else - { - // error - Log("Empty string for enumerator in parameter %s for node %s definition (%s)\n", - metaParam.mName.c_str(), - curNode.mName.c_str(), - filename); - return serNodes; - } - } - if (param.HasMember("default")) - { - size_t paramSize = GetParameterTypeSize(metaParam.mType); - metaParam.mDefaultValue.resize(paramSize); - std::string defaultStr = param["default"].GetString(); - ParseStringToParameter(defaultStr, metaParam.mType, metaParam.mDefaultValue.data()); - } - - curNode.mParams.emplace_back(metaParam); - } - } - - serNodes.emplace_back(curNode); - } - return serNodes; + SerializeRead loadSer(szFilename); + loadSer.Ser(recent); } -AnimationBase::AnimationPointer AnimationBase::GetPointer(int32_t frame, bool bSetting) const +void SaveRecent(RecentLibraries* recent, const char* szFilename) { - if (mFrames.empty()) - return {bSetting ? -1 : 0, 0, 0, 0, 0.f}; - if (frame <= mFrames[0]) - return {bSetting ? -1 : 0, 0, 0, 0, 0.f}; - if (frame > mFrames.back()) - { - int32_t last = int32_t(mFrames.size() - (bSetting ? 0 : 1)); - return {last, mFrames.back(), last, mFrames.back(), 0.f}; - } - for (int i = 0; i < int(mFrames.size()) - 1; i++) - { - if (mFrames[i] <= frame && mFrames[i + 1] >= frame) - { - float ratio = float(frame - mFrames[i]) / float(mFrames[i + 1] - mFrames[i]); - return {i, mFrames[i], i + 1, mFrames[i + 1], ratio}; - } - } - assert(0); - return {bSetting ? -1 : 0, 0, 0, 0, 0.f}; + SerializeWrite(szFilename).Ser(recent); } - -AnimTrack& AnimTrack::operator=(const AnimTrack& other) -{ - mNodeIndex = other.mNodeIndex; - mParamIndex = other.mParamIndex; - mValueType = other.mValueType; - delete mAnimation; - mAnimation = AllocateAnimation(mValueType); - mAnimation->Copy(other.mAnimation); - return *this; -} \ No newline at end of file diff --git a/src/Library.h b/src/Library.h index aa0b876e..2030078f 100644 --- a/src/Library.h +++ b/src/Library.h @@ -22,9 +22,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // - #pragma once - #include #include #include @@ -33,54 +31,14 @@ #include #include "Utils.h" #include - -struct Camera -{ - Vec4 mPosition; - Vec4 mDirection; - Vec4 mUp; - Vec4 mLens; // fov,.... - - Camera Lerp(const Camera& target, float t) - { - Camera ret; - ret.mPosition = ::Lerp(mPosition, target.mPosition, t); - ret.mDirection = ::Lerp(mDirection, target.mDirection, t); - ret.mDirection.Normalize(); - ret.mUp = ::Lerp(mUp, target.mUp, t); - ret.mUp.Normalize(); - ret.mLens = ::Lerp(mLens, target.mLens, t); - return ret; - } - float& operator[](int index) - { - switch (index) - { - case 0: - case 1: - case 2: - return mPosition[index]; - case 3: - case 4: - case 5: - return mDirection[index - 3]; - case 6: - return mDirection[index - 6]; - } - return mPosition[0]; - } - - void ComputeViewProjectionMatrix(float* viewProj, float* viewInverse); -}; -inline Camera Lerp(Camera a, Camera b, float t) -{ - return a.Lerp(b, t); -} +#include "Types.h" +#include "MetaNodes.h" +#include "Animation.h" // used to retrieve structure in library. left is index. right is uniqueId // if item at index doesn't correspond to uniqueid, then a search is done // based on the unique id -typedef std::pair ASyncId; +typedef std::pair ASyncId; template T* GetByAsyncId(ASyncId id, std::vector& items) { @@ -102,31 +60,9 @@ T* GetByAsyncId(ASyncId id, std::vector& items) return NULL; } -struct InputSampler -{ - InputSampler() : mWrapU(0), mWrapV(0), mFilterMin(0), mFilterMag(0) - { - } - uint32_t mWrapU; - uint32_t mWrapV; - uint32_t mFilterMin; - uint32_t mFilterMag; - - bool operator!=(const InputSampler& other) const - { - return (mWrapU != other.mWrapU || mWrapV != other.mWrapV || mFilterMin != other.mFilterMin || - mFilterMag != other.mFilterMag); - } - bool operator==(const InputSampler& other) const - { - return (mWrapU == other.mWrapU && mWrapV == other.mWrapV && mFilterMin == other.mFilterMin && - mFilterMag == other.mFilterMag); - } -}; - struct MaterialNode { - uint32_t mType; + uint32_t mNodeType; std::string mTypeName; int32_t mPosX; int32_t mPosY; @@ -137,7 +73,7 @@ struct MaterialNode uint32_t mFrameStart; uint32_t mFrameEnd; // runtime - unsigned int mRuntimeUniqueId; + RuntimeId mRuntimeUniqueId; }; struct MaterialNodeRug @@ -152,243 +88,10 @@ struct MaterialNodeRug struct MaterialConnection { - uint32_t mInputNode; - uint32_t mOutputNode; - uint8_t mInputSlot; - uint8_t mOutputSlot; -}; - -struct AnimationBase -{ - AnimationBase() - { - } - AnimationBase(const AnimationBase&& animation) - { - mFrames = animation.mFrames; - } - AnimationBase(const AnimationBase& animation) - { - mFrames = animation.mFrames; - } - std::vector mFrames; - - virtual void Allocate(size_t elementCount) - { - assert(0); - } - virtual void* GetData() - { - assert(0); - return nullptr; - } - virtual const void* GetDataConst() const - { - assert(0); - return nullptr; - } - virtual size_t GetValuesByteLength() const - { - assert(0); - return 0; - } - virtual void GetValue(uint32_t frame, void* destination) - { - assert(0); - } - virtual void SetValue(uint32_t frame, void* source) - { - assert(0); - } - virtual float GetFloatValue(uint32_t index, int componentIndex) - { - assert(0); - return 0.f; - } - virtual void SetFloatValue(uint32_t index, int componentIndex, float value) - { - assert(0); - } - virtual void Copy(AnimationBase* source) - { - mFrames = source->mFrames; - } - struct AnimationPointer - { - int mPreviousIndex; - int mPreviousFrame; - int mNextIndex; - int mNextFrame; - float mRatio; - }; - AnimationPointer GetPointer(int32_t frame, bool bSetting) const; - bool operator!=(const AnimationBase& other) const - { - if (mFrames != other.mFrames) - return true; - - size_t la = GetValuesByteLength(); - size_t lb = other.GetValuesByteLength(); - if (la != lb) - return true; - if (memcmp(this->GetDataConst(), other.GetDataConst(), la)) - return true; - return false; - } -}; - -template -struct Animation : public AnimationBase -{ - Animation() - { - } - Animation(const Animation&& animation) : AnimationBase(animation) - { - mValues = animation.mValues; - } - Animation(const Animation& animation) : AnimationBase(animation) - { - mValues = animation.mValues; - } - std::vector mValues; - - virtual void Allocate(size_t elementCount) - { - mFrames.resize(elementCount); - mValues.resize(elementCount); - } - virtual void* GetData() - { - return mValues.data(); - } - virtual const void* GetDataConst() const - { - return mValues.data(); - } - - virtual size_t GetValuesByteLength() const - { - return mValues.size() * sizeof(T); - } - virtual float GetFloatValue(uint32_t index, int componentIndex) - { - unsigned char* ptr = (unsigned char*)GetData(); - T& v = ((T*)ptr)[index]; - return GetComponent(componentIndex, v); - } - - virtual void SetFloatValue(uint32_t index, int componentIndex, float value) - { - unsigned char* ptr = (unsigned char*)GetData(); - T& v = ((T*)ptr)[index]; - SetComponent(componentIndex, v, value); - } - - virtual void GetValue(uint32_t frame, void* destination) - { - if (mValues.empty()) - return; - AnimationPointer pointer = GetPointer(frame, false); - T* dest = (T*)destination; - *dest = Lerp(mValues[pointer.mPreviousIndex], mValues[pointer.mNextIndex], pointer.mRatio); - } - - virtual void SetValue(uint32_t frame, void* source) - { - auto pointer = GetPointer(frame, true); - T value = *(T*)source; - if (frame == pointer.mPreviousFrame && !mValues.empty()) - { - mValues[pointer.mPreviousIndex] = value; - } - else - { - if (mFrames.empty() || pointer.mPreviousIndex >= mFrames.size()) - { - mFrames.push_back(frame); - mValues.push_back(value); - } - else - { - mFrames.insert(mFrames.begin() + pointer.mPreviousIndex + 1, frame); - mValues.insert(mValues.begin() + pointer.mPreviousIndex + 1, value); - } - } - } - - virtual void Copy(AnimationBase* source) - { - AnimationBase::Copy(source); - Allocate(source->mFrames.size()); - size_t valuesSize = GetValuesByteLength(); - if (valuesSize) - memcpy(GetData(), source->GetData(), valuesSize); - } - -protected: - template - float GetComponent(int componentIndex, Ty& v) - { - return float(v[componentIndex]); - } - template - void SetComponent(int componentIndex, Ty& v, float value) - { - v[componentIndex] = decltype(v[componentIndex])(value); - } - float GetComponent(int componentIndex, unsigned char& v) - { - return float(v); - } - float GetComponent(int componentIndex, int& v) - { - return float(v); - } - float GetComponent(int componentIndex, float& v) - { - return v; - } - void SetComponent(int componentIndex, unsigned char& v, float value) - { - v = (unsigned char)(value); - } - void SetComponent(int componentIndex, int& v, float value) - { - v = int(value); - } - void SetComponent(int componentIndex, float& v, float value) - { - v = value; - } -}; - -struct AnimTrack -{ - AnimTrack() - { - } - AnimTrack(const AnimTrack& other) - { - *this = other; - } - uint32_t mNodeIndex; - uint32_t mParamIndex; - uint32_t mValueType; // Con_ - AnimationBase* mAnimation = nullptr; - AnimTrack& operator=(const AnimTrack& other); - bool operator!=(const AnimTrack& other) const - { - if (mNodeIndex != other.mNodeIndex) - return true; - if (mParamIndex != other.mParamIndex) - return true; - if (mValueType != other.mValueType) - return true; - if (mAnimation->operator!=(*other.mAnimation)) - return true; - return false; - } + uint32_t mInputNodeIndex; + uint32_t mOutputNodeIndex; + uint8_t mInputSlotIndex; + uint8_t mOutputSlotIndex; }; struct Material @@ -406,6 +109,8 @@ struct Material std::vector mPinnedParameters; std::vector mPinnedIO; + std::vector mMultiplexInputs; + MaterialNode* Get(ASyncId id) { return GetByAsyncId(id, mMaterialNodes); @@ -414,12 +119,13 @@ struct Material uint32_t mBackgroundNode; // run time - unsigned int mThumbnailTextureId; - unsigned int mRuntimeUniqueId; + bgfx::TextureHandle mThumbnailTextureHandle; + RuntimeId mRuntimeUniqueId; }; struct Library { + std::string mFilename; // set when loading std::vector mMaterials; Material* Get(ASyncId id) { @@ -438,150 +144,10 @@ struct Library } }; -void LoadLib(Library* library, const char* szFilename); -void SaveLib(Library* library, const char* szFilename); - -enum ConTypes -{ - Con_Float, - Con_Float2, - Con_Float3, - Con_Float4, - Con_Color4, - Con_Int, - Con_Int2, - Con_Ramp, - Con_Angle, - Con_Angle2, - Con_Angle3, - Con_Angle4, - Con_Enum, - Con_Structure, - Con_FilenameRead, - Con_FilenameWrite, - Con_ForceEvaluate, - Con_Bool, - Con_Ramp4, - Con_Camera, - Con_Any, -}; - -enum CurveType -{ - CurveNone, - CurveDiscrete, - CurveLinear, - CurveSmooth, - CurveBezier, -}; - -size_t GetParameterTypeSize(ConTypes paramType); -int GetParameterIndex(uint32_t nodeType, const char* parameterName); - -size_t GetParameterOffset(uint32_t type, uint32_t parameterIndex); -ConTypes GetParameterType(uint32_t nodeType, uint32_t parameterIndex); -size_t GetCurveCountPerParameterType(uint32_t paramType); -void ParseStringToParameter(const std::string& str, uint32_t parameterType, void* parameterPtr); -const char* GetCurveParameterSuffix(uint32_t paramType, int suffixIndex); -uint32_t GetCurveParameterColor(uint32_t paramType, int suffixIndex); -AnimationBase* AllocateAnimation(uint32_t valueType); -CurveType GetCurveTypeForParameterType(ConTypes paramType); -struct NodeGraphControler; -void DecodeThumbnailAsync(Material* material, NodeGraphControler* nodeGraphControler); -size_t ComputeNodeParametersSize(size_t nodeType); -const char* GetParameterTypeName(ConTypes paramType); - -struct MetaCon -{ - std::string mName; - int mType; - bool operator==(const MetaCon& other) const - { - if (mName != other.mName) - return false; - if (mType != other.mType) - return false; - return true; - } -}; - -struct MetaParameter -{ - std::string mName; - ConTypes mType; - float mRangeMinX, mRangeMaxX; - float mRangeMinY, mRangeMaxY; - bool mbRelative; - bool mbQuadSelect; - bool mbLoop; - std::string mEnumList; - std::vector mDefaultValue; - std::string mDescription; - bool operator==(const MetaParameter& other) const - { - if (mName != other.mName) - return false; - if (mType != other.mType) - return false; - if (mRangeMaxX != other.mRangeMaxX) - return false; - if (mRangeMinX != other.mRangeMinX) - return false; - if (mRangeMaxY != other.mRangeMaxY) - return false; - if (mRangeMinY != other.mRangeMinY) - return false; - if (mbRelative != other.mbRelative) - return false; - if (mbQuadSelect != other.mbQuadSelect) - return false; - if (mEnumList != other.mEnumList) - return false; - return true; - } -}; - -struct MetaNode -{ - std::string mName; - uint32_t mHeaderColor; - int mCategory; - std::string mDescription; - std::vector mInputs; - std::vector mOutputs; - std::vector mParams; - - bool mbHasUI; - bool mbSaveTexture; - - bool operator==(const MetaNode& other) const - { - if (mName != other.mName) - return false; - if (mCategory != other.mCategory) - return false; - if (mHeaderColor != other.mHeaderColor) - return false; - if (mInputs != other.mInputs) - return false; - if (mOutputs != other.mOutputs) - return false; - if (mParams != other.mParams) - return false; - if (mbHasUI != other.mbHasUI) - return false; - if (mbSaveTexture != other.mbSaveTexture) - return false; - return true; - } - - static const std::vector mCategories; -}; - -extern std::vector gMetaNodes; -size_t GetMetaNodeIndex(const std::string& metaNodeName); -void LoadMetaNodes(); +void LoadLib(Library* library, const std::string& filename); +void SaveLib(Library* library, const std::string& filename); -std::vector ReadMetaNodes(const char* filename); -unsigned int GetRuntimeId(); extern Library library; +struct RecentLibraries; +void LoadRecent(RecentLibraries* recent, const char* szFilename); +void SaveRecent(RecentLibraries* recent, const char* szFilename); diff --git a/src/Mem.cpp b/src/Mem.cpp new file mode 100644 index 00000000..0c02dc50 --- /dev/null +++ b/src/Mem.cpp @@ -0,0 +1,79 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +#include "Mem.h" +#include + +#ifdef RETAIL +MemoryProfileHistoryNULL gMemoryHistory; +#else +MemoryProfileHistory_t gMemoryHistory; +#endif + +template<> bool MemoryProfileHistory<64, MODULE_COUNT>::inited = false; + +void *imguiMalloc(size_t n, void* user_data) +{ + return HeapAllocatorBase().allocate(n); +} + +void imguiFree(void *ptr, void* user_data) +{ + if (!ptr) + return; +#ifdef WIN32 + auto ptrSize = _msize(ptr); +#else + auto ptrSize = malloc_usable_size(ptr); +#endif + return HeapAllocatorBase().deallocate((unsigned char*)ptr, ptrSize); +} + + +void *imageMalloc(size_t n) +{ + return HeapAllocatorBase().allocate(n); +} + +void imageFree(void *ptr) +{ + if (!ptr) + return; +#ifdef WIN32 + auto ptrSize = _msize(ptr); +#else + auto ptrSize = malloc_usable_size(ptr); +#endif + return HeapAllocatorBase().deallocate((unsigned char*)ptr, ptrSize); +} + +void vramTextureAlloc(size_t n) +{ + gMemoryHistory.logAllocation(MODULE_TEXTURE, n); +} + +void vramTextureFree(size_t n) +{ + gMemoryHistory.logDeallocation(MODULE_TEXTURE, n); +} \ No newline at end of file diff --git a/src/Mem.h b/src/Mem.h new file mode 100644 index 00000000..b564eaaa --- /dev/null +++ b/src/Mem.h @@ -0,0 +1,195 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include +#include +#include + +enum MODULES +{ + MODULE_IMGUI, + MODULE_DEFAULT, + MODULE_TEXTURE, + MODULE_IMAGE, + MODULE_COUNT +}; + +template struct MemoryProfileHistory +{ + template struct MemoryHistory + { + //MemoryHistory() : mOffset(0) { memset(mValues, 0, sizeof(size_t) * historyLength); } + size_t mValues[historyLength2]; + size_t mOffset; + void addValue(size_t value) + { + mValues[mOffset] = value; + ++mOffset %= historyLength2; + } + size_t getValue() const + { + return mValues[(mOffset + historyLength2 - 1) % historyLength2]; + } + size_t getMin() const + { + size_t v = mValues[0]; + for (int i = 1; i < historyLength2; i++) + v = (v < mValues[i]) ? v : mValues[i]; + return v; + } + size_t getMax() const + { + size_t v = mValues[0]; + for (int i = 1; i < historyLength2; i++) + v = (v > mValues[i]) ? v : mValues[i]; + return v; + } + void clear() + { + memset(mValues, 0, historyLength2 * sizeof(size_t)); + mOffset = 0; + } + }; + typedef MemoryHistory MemHistory; + + + MemoryProfileHistory() {} + + void LogChecker(size_t module) + { + MemoryModule& mmp = mMemory[module]; + assert(mmp.mActiveAllocationCount.getValue() >= 0); + assert(mmp.mAllocationCount.getValue() >= mmp.mDeallocationCount.getValue()); + assert(mmp.mTotalFreed.getValue() <= mmp.mTotalAllocated.getValue()); + } + + void logAllocation(size_t module, size_t n) + { + if (!inited) + { + inited = true; + clear(); + } + MemoryModule& mmp = mMemory[module]; + mmp.mTotalAllocated.addValue(mmp.mTotalAllocated.getValue() + n); + mmp.mAllocationCount.addValue(mmp.mAllocationCount.getValue() + 1); + mmp.mActiveAllocated.addValue(mmp.mActiveAllocated.getValue() + n); + mmp.mActiveAllocationCount.addValue(mmp.mActiveAllocationCount.getValue() + 1); + LogChecker(module); + } + + void logDeallocation(size_t module, size_t n) + { + MemoryModule& mmp = mMemory[module]; + mmp.mTotalFreed.addValue(mmp.mTotalFreed.getValue() + n); + mmp.mDeallocationCount.addValue(mmp.mDeallocationCount.getValue() + 1); + mmp.mActiveAllocated.addValue(mmp.mActiveAllocated.getValue() - n); + mmp.mActiveAllocationCount.addValue(mmp.mActiveAllocationCount.getValue() - 1); + LogChecker(module); + } + + void dumpLeaks() {} + bool hasAllocationFor(size_t module) const { return false; } + void clear() + { + for (size_t i = 0; i < MODULE_COUNT; i++) + clearModule(i); + } + void clearModule(size_t module) { mMemory[module].clear(); } + struct MemoryModule + { + MemHistory mTotalAllocated; + MemHistory mTotalFreed; + MemHistory mAllocationCount; + MemHistory mDeallocationCount; + MemHistory mActiveAllocated; + MemHistory mActiveAllocationCount; + + void clear() + { + mTotalAllocated.clear(); + mTotalFreed.clear(); + mAllocationCount.clear(); + mDeallocationCount.clear(); + mActiveAllocated.clear(); + mActiveAllocationCount.clear(); + } + }; + + MemoryModule mMemory[maxModuleCount]; + const MemoryModule& getMem(MODULES module) const { return mMemory[module]; } + + static bool inited; +}; + +struct MemoryProfileHistoryNULL +{ + void logAllocation(size_t module, size_t n) {} + void logDeallocation(size_t module, size_t n) {} + void clearModule(size_t) { } +}; + +void InitMemProf(); +void MemoryFrameInit(); + +#ifdef RETAIL +extern MemoryProfileHistoryNULL gMemoryHistory; +#else +typedef MemoryProfileHistory<64, MODULE_COUNT> MemoryProfileHistory_t; +extern MemoryProfileHistory_t gMemoryHistory; +#endif + +template struct HeapAllocatorBase +{ + using value_type = T; + HeapAllocatorBase() {} + T* allocate(size_t n) + { + size_t sz = sizeof(T) * n; + gMemoryHistory.logAllocation(module, sz); + return static_cast(malloc(sz)); + } + void deallocate(T* p, size_t n) + { + if (!p) + return; + + size_t sz = sizeof(T) * n; + gMemoryHistory.logDeallocation(module, sz); + free(p); + } +}; + + + +void *imguiMalloc(size_t n, void* user_data); +void imguiFree(void *ptr, void* user_data); + +void *imageMalloc(size_t n); +void imageFree(void *ptr); + +void vramTextureAlloc(size_t n); +void vramTextureFree(size_t n); diff --git a/src/MetaNodes.cpp b/src/MetaNodes.cpp new file mode 100644 index 00000000..676078a9 --- /dev/null +++ b/src/MetaNodes.cpp @@ -0,0 +1,845 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include +#include "rapidjson/document.h" +#include "rapidjson/rapidjson.h" +#include "rapidjson/writer.h" + +#include "MetaNodes.h" +#include "Utils.h" +#include "Cam.h" + +std::vector gMetaNodes; +std::map gMetaNodesIndices; + +static const char* parameterNames[] = { + "Float", "Float2", "Float3", "Float4", "Color4", "Int", "Int2", + "Ramp", "Angle", "Angle2", "Angle3", "Angle4", "Enum", "Structure", + "FilenameRead", "FilenameWrite", "ForceEvaluate", "Bool", "Ramp4", "Camera", "Multiplexer", "Any", +}; + +const char* GetParameterTypeName(ConTypes paramType) +{ + return parameterNames[std::min(int(paramType), int(Con_Any) - 1)]; +} + +ConTypes GetParameterType(const char* parameterName) +{ + for (size_t i = 0; i < Con_Any; i++) + { + if (!strcmp(parameterNames[i], parameterName)) + return ConTypes(i); + } + return Con_Any; +} + + +ConTypes GetParameterType(uint32_t nodeType, uint32_t parameterIndex) +{ + const MetaNode& currentMeta = gMetaNodes[nodeType]; + return currentMeta.mParams[parameterIndex].mType; +} + +size_t GetParameterTypeSize(ConTypes paramType) +{ + switch (paramType) + { + case Con_Angle: + case Con_Float: + return sizeof(float); + case Con_Angle2: + case Con_Float2: + return sizeof(float) * 2; + case Con_Angle3: + case Con_Float3: + return sizeof(float) * 3; + case Con_Angle4: + case Con_Color4: + case Con_Float4: + return sizeof(float) * 4; + case Con_Ramp: + return sizeof(float) * 2 * 8; + case Con_Ramp4: + return sizeof(float) * 4 * 8; + case Con_Enum: + case Con_Int: + return sizeof(int); + case Con_Int2: + return sizeof(int) * 2; + case Con_FilenameRead: + case Con_FilenameWrite: + return 1024; + case Con_ForceEvaluate: + return 0; + case Con_Bool: + return sizeof(int); + case Con_Camera: + return sizeof(Camera); + case Con_Multiplexer: + return sizeof(int); + default: + assert(0); + } + return -1; +} + + + +size_t GetMetaNodeIndex(const std::string& metaNodeName) +{ + auto iter = gMetaNodesIndices.find(metaNodeName.c_str()); + if (iter == gMetaNodesIndices.end()) + { + Log("Node type %s not find in the library!\n", metaNodeName.c_str()); + return -1; + } + return iter->second; +} + + + +std::vector ReadMetaNodes(const char* filename) +{ + // read it back + std::vector serNodes; + + std::ifstream t(filename); + if (!t.good()) + { + Log("%s - Unable to load file.\n", filename); + return serNodes; + } + std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); + + + rapidjson::Document doc; + doc.Parse(str.c_str()); + if (doc.HasParseError()) + { + Log("Parsing error in %s\n", filename); + return serNodes; + } + + rapidjson::Value& nodesValue = doc["nodes"]; + for (rapidjson::SizeType i = 0; i < nodesValue.Size(); i++) + { + MetaNode curNode; + rapidjson::Value& node = nodesValue[i]; + if (!node.HasMember("name")) + { + // error + Log("Missing name in node %d definition (%s)\n", i, filename); + return serNodes; + } + curNode.mName = node["name"].GetString(); + if (!node.HasMember("category")) + { + // error + Log("Missing category in node %s definition (%s)\n", curNode.mName.c_str(), filename); + return serNodes; + } + curNode.mCategory = node["category"].GetInt(); + + if (node.HasMember("description")) + { + curNode.mDescription = node["description"].GetString(); + } + + if (node.HasMember("height")) + curNode.mHeight = node["height"].GetInt(); + else + curNode.mHeight = 100; + + if (node.HasMember("width")) + curNode.mWidth = node["width"].GetInt(); + else + curNode.mWidth = 100; + + if (node.HasMember("experimental")) + curNode.mbExperimental = node["experimental"].GetBool(); + else + curNode.mbExperimental = false; + + curNode.mbHasUI = false; + if (node.HasMember("hasUI")) + { + curNode.mbHasUI = node["hasUI"].GetBool(); + } + + curNode.mbThumbnail = true; + if (node.HasMember("thumbnail")) + { + curNode.mbThumbnail = node["thumbnail"].GetBool(); + } + + if (node.HasMember("saveTexture")) + { + curNode.mbSaveTexture = node["saveTexture"].GetBool(); + } + else + { + curNode.mbSaveTexture = false; + } + + if (!node.HasMember("color")) + { + // error + Log("Missing color in node %s definition (%s)\n", curNode.mName.c_str(), filename); + return serNodes; + } + rapidjson::Value& color = node["color"]; + float c[4]; + if (color.Size() != 4) + { + // error + Log("wrong color component count in node %s definition (%s)\n", curNode.mName.c_str(), filename); + return serNodes; + } + for (rapidjson::SizeType i = 0; i < color.Size(); i++) + { + c[i] = color[i].GetFloat(); + } + curNode.mHeaderColor = ColorF32(c[0], c[1], c[2], c[3]); + // inputs/outputs + if (node.HasMember("inputs")) + { + rapidjson::Value& inputs = node["inputs"]; + for (rapidjson::SizeType i = 0; i < inputs.Size(); i++) + { + MetaCon metaNode; + if (!inputs[i].HasMember("name") || !inputs[i].HasMember("type")) + { + // error + Log("Missing name or type in inputs for node %s definition (%s)\n", + curNode.mName.c_str(), + filename); + return serNodes; + } + + metaNode.mName = inputs[i]["name"].GetString(); + metaNode.mType = GetParameterType(inputs[i]["type"].GetString()); + if (metaNode.mType == Con_Any) + { + // error + Log("Wrong type for %s in inputs for node %s definition (%s)\n", + metaNode.mName.c_str(), + curNode.mName.c_str(), + filename); + return serNodes; + } + curNode.mInputs.emplace_back(metaNode); + } + } + if (node.HasMember("outputs")) + { + rapidjson::Value& outputs = node["outputs"]; + for (rapidjson::SizeType i = 0; i < outputs.Size(); i++) + { + MetaCon metaNode; + if (!outputs[i].HasMember("name") || !outputs[i].HasMember("type")) + { + // error + Log("Missing name or type in outputs for node %s definition (%s)\n", + curNode.mName.c_str(), + filename); + return serNodes; + } + metaNode.mName = outputs[i]["name"].GetString(); + metaNode.mType = GetParameterType(outputs[i]["type"].GetString()); + if (metaNode.mType == Con_Any) + { + // error + Log("Wrong type for %s in outputs for node %s definition (%s)\n", + metaNode.mName.c_str(), + curNode.mName.c_str(), + filename); + return serNodes; + } + curNode.mOutputs.emplace_back(metaNode); + } + } + // parameters + if (node.HasMember("parameters")) + { + rapidjson::Value& params = node["parameters"]; + for (rapidjson::SizeType i = 0; i < params.Size(); i++) + { + MetaParameter metaParam; + rapidjson::Value& param = params[i]; + if (!param.HasMember("name") || !param.HasMember("type")) + { + // error + Log("Missing name or type in parameters for node %s definition (%s)\n", + curNode.mName.c_str(), + filename); + return serNodes; + } + metaParam.mName = param["name"].GetString(); + metaParam.mType = GetParameterType(param["type"].GetString()); + metaParam.mControlType = Control_NumericEdit; + if (metaParam.mType == Con_Any) + { + // error + Log("Wrong type for %s in parameters for node %s definition (%s)\n", + metaParam.mName.c_str(), + curNode.mName.c_str(), + filename); + return serNodes; + } + + if (param.HasMember("rangeMinX") && param.HasMember("rangeMaxX") && param.HasMember("rangeMinY") && + param.HasMember("rangeMaxY")) + { + metaParam.mRangeMinX = param["rangeMinX"].GetFloat(); + metaParam.mRangeMaxX = param["rangeMaxX"].GetFloat(); + metaParam.mRangeMinY = param["rangeMinY"].GetFloat(); + metaParam.mRangeMaxY = param["rangeMaxY"].GetFloat(); + } + else + { + metaParam.mRangeMinX = metaParam.mRangeMinY = metaParam.mRangeMaxX = metaParam.mRangeMaxY = 0.f; + } + if (param.HasMember("description")) + { + metaParam.mDescription = param["description"].GetString(); + } + if (param.HasMember("control")) + { + const char* control = param["control"].GetString(); + if (!strcmp(control, "Slider")) + { + metaParam.mControlType = Control_Slider; + metaParam.mSliderMinX = 0.f; + metaParam.mSliderMaxX = 1.f; + if (param.HasMember("sliderMinX")) + { + metaParam.mSliderMinX = param["sliderMinX"].GetFloat(); + } + if (param.HasMember("sliderMaxX")) + { + metaParam.mSliderMaxX = param["sliderMaxX"].GetFloat(); + } + } + } + + if (param.HasMember("loop")) + { + metaParam.mbLoop = param["loop"].GetBool(); + } + else + { + metaParam.mbLoop = true; + } + + metaParam.mbHidden = false; + if (param.HasMember("hidden")) + { + metaParam.mbHidden = param["hidden"].GetBool(); + } + + if (param.HasMember("relative")) + metaParam.mbRelative = param["relative"].GetBool(); + else + metaParam.mbRelative = false; + if (param.HasMember("quadSelect")) + metaParam.mbQuadSelect = param["quadSelect"].GetBool(); + else + metaParam.mbQuadSelect = false; + if (param.HasMember("enum")) + { + if (metaParam.mType != Con_Enum) + { + // error + Log("Mismatch type for enumerator in parameter %s for node %s definition (%s)\n", + metaParam.mName.c_str(), + curNode.mName.c_str(), + filename); + return serNodes; + } + std::string enumStr = param["enum"].GetString(); + if (enumStr.size()) + { + metaParam.mEnumList = enumStr; + if (metaParam.mEnumList.back() != '|') + metaParam.mEnumList += '|'; + } + else + { + // error + Log("Empty string for enumerator in parameter %s for node %s definition (%s)\n", + metaParam.mName.c_str(), + curNode.mName.c_str(), + filename); + return serNodes; + } + } + if (param.HasMember("default")) + { + size_t paramSize = GetParameterTypeSize(metaParam.mType); + metaParam.mDefaultValue.resize(paramSize); + std::string defaultStr = param["default"].GetString(); + ParseStringToParameter(defaultStr, metaParam.mType, metaParam.mDefaultValue.data()); + } + + curNode.mParams.emplace_back(metaParam); + } + } + + serNodes.emplace_back(curNode); + } + return serNodes; +} + +void LoadMetaNodes(const std::vector& metaNodeFilenames) +{ + static const uint32_t hcTransform = ColorU8(200, 200, 200, 255); + static const uint32_t hcGenerator = ColorU8(150, 200, 150, 255); + static const uint32_t hcMaterial = ColorU8(150, 150, 200, 255); + static const uint32_t hcBlend = ColorU8(200, 150, 150, 255); + static const uint32_t hcFilter = ColorU8(200, 200, 150, 255); + static const uint32_t hcNoise = ColorU8(150, 250, 150, 255); + static const uint32_t hcPaint = ColorU8(100, 250, 180, 255); + + for (auto& filename : metaNodeFilenames) + { + std::vector metaNodes = ReadMetaNodes(filename.c_str()); + if (metaNodes.empty()) + { + IMessageBox("Errors while parsing nodes definitions.\nCheck logs.", "Node Parsing Error!"); + //exit(-1); + continue; + } + gMetaNodes.insert(gMetaNodes.end(), metaNodes.begin(), metaNodes.end()); + } + + + for (size_t i = 0; i < gMetaNodes.size(); i++) + { + gMetaNodesIndices[gMetaNodes[i].mName] = i; + } +} + +void LoadMetaNodes() +{ + std::vector metaNodeFilenames; + DiscoverFiles("json", "Nodes/", metaNodeFilenames); + LoadMetaNodes(metaNodeFilenames); +} + +#if 0 +void SaveMetaNodes(const char* filename) +{ + // write lib to json ----------------------- + rapidjson::Document d; + d.SetObject(); + rapidjson::Document::AllocatorType& allocator = d.GetAllocator(); + + rapidjson::Value nodelist(rapidjson::kArrayType); + + for (auto& node : gMetaNodes) + { + rapidjson::Value nodeValue; + nodeValue.SetObject(); + nodeValue.AddMember("name", rapidjson::Value(node.mName.c_str(), allocator), allocator); + nodeValue.AddMember("category", rapidjson::Value().SetInt(node.mCategory), allocator); + { + ImColor clr(node.mHeaderColor); + rapidjson::Value colorValue(rapidjson::kArrayType); + colorValue.PushBack(rapidjson::Value().SetFloat(clr.Value.x), allocator); + colorValue.PushBack(rapidjson::Value().SetFloat(clr.Value.y), allocator); + colorValue.PushBack(rapidjson::Value().SetFloat(clr.Value.z), allocator); + colorValue.PushBack(rapidjson::Value().SetFloat(clr.Value.w), allocator); + nodeValue.AddMember("color", colorValue, allocator); + } + + std::vector* cons[] = { &node.mInputs, &node.mOutputs }; + for (int i = 0; i < 2; i++) + { + auto inouts = cons[i]; + if (inouts->empty()) + continue; + + rapidjson::Value ioValue(rapidjson::kArrayType); + + for (auto& con : *inouts) + { + rapidjson::Value conValue; + conValue.SetObject(); + conValue.AddMember("name", rapidjson::Value(con.mName.c_str(), allocator), allocator); + conValue.AddMember( + "type", rapidjson::Value(GetParameterTypeName(ConTypes(con.mType)), allocator), allocator); + ioValue.PushBack(conValue, allocator); + } + if (i) + nodeValue.AddMember("outputs", ioValue, allocator); + else + nodeValue.AddMember("inputs", ioValue, allocator); + } + + if (!node.mParams.empty()) + { + rapidjson::Value paramValues(rapidjson::kArrayType); + for (auto& con : node.mParams) + { + rapidjson::Value conValue; + conValue.SetObject(); + conValue.AddMember("name", rapidjson::Value(con.mName.c_str(), allocator), allocator); + conValue.AddMember("type", rapidjson::Value(GetParameterTypeName(con.mType), allocator), allocator); + if (con.mRangeMinX > FLT_EPSILON || con.mRangeMaxX > FLT_EPSILON || con.mRangeMinY > FLT_EPSILON || + con.mRangeMaxY > FLT_EPSILON) + { + conValue.AddMember("rangeMinX", rapidjson::Value().SetFloat(con.mRangeMinX), allocator); + conValue.AddMember("rangeMaxX", rapidjson::Value().SetFloat(con.mRangeMaxX), allocator); + conValue.AddMember("rangeMinY", rapidjson::Value().SetFloat(con.mRangeMinY), allocator); + conValue.AddMember("rangeMaxY", rapidjson::Value().SetFloat(con.mRangeMaxY), allocator); + } + if (con.mbRelative) + conValue.AddMember("relative", rapidjson::Value().SetBool(con.mbRelative), allocator); + if (con.mbQuadSelect) + conValue.AddMember("quadSelect", rapidjson::Value().SetBool(con.mbQuadSelect), allocator); + if (con.mEnumList.size()) + { + conValue.AddMember("enum", rapidjson::Value(con.mEnumList.c_str(), allocator), allocator); + } + paramValues.PushBack(conValue, allocator); + } + nodeValue.AddMember("parameters", paramValues, allocator); + } + if (node.mbHasUI) + nodeValue.AddMember("hasUI", rapidjson::Value().SetBool(node.mbHasUI), allocator); + if (node.mbSaveTexture) + nodeValue.AddMember("saveTexture", rapidjson::Value().SetBool(node.mbSaveTexture), allocator); + + nodelist.PushBack(nodeValue, allocator); + } + + d.AddMember("nodes", nodelist, allocator); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + d.Accept(writer); + + std::ofstream myfile; + myfile.open(filename); + myfile << buffer.GetString(); + myfile.close(); +} +#endif + + +void ParseStringToParameter(const std::string& str, ConTypes parameterType, void* parameterPtr) +{ + float* pf = (float*)parameterPtr; + int* pi = (int*)parameterPtr; + Camera* cam = (Camera*)parameterPtr; + iVec2* iv2 = (iVec2*)parameterPtr; + iVec4* iv4 = (iVec4*)parameterPtr; + switch (parameterType) + { + case Con_Angle: + case Con_Float: + sscanf(str.c_str(), "%f", pf); + break; + case Con_Angle2: + case Con_Float2: + sscanf(str.c_str(), "%f,%f", &pf[0], &pf[1]); + break; + case Con_Angle3: + case Con_Float3: + sscanf(str.c_str(), "%f,%f,%f", &pf[0], &pf[1], &pf[2]); + break; + case Con_Color4: + case Con_Float4: + case Con_Angle4: + sscanf(str.c_str(), "%f,%f,%f,%f", &pf[0], &pf[1], &pf[2], &pf[3]); + break; + case Con_Multiplexer: + case Con_Enum: + case Con_Int: + sscanf(str.c_str(), "%d", &pi[0]); + break; + case Con_Int2: + sscanf(str.c_str(), "%d,%d", &pi[0], &pi[1]); + break; + case Con_Ramp: + iv2[0] = {0, 0}; + iv2[1] = {1, 1}; + break; + case Con_Ramp4: + iv4[0] = {0, 0, 0, 0}; + iv4[1] = {1, 1, 1, 1}; + break; + case Con_FilenameWrite: + case Con_FilenameRead: + strcpy((char*)parameterPtr, str.c_str()); + break; + case Con_Structure: + case Con_ForceEvaluate: + break; + case Con_Camera: + cam->mDirection = Vec4(0.f, 0.f, 1.f, 0.f); + cam->mUp = Vec4(0.f, 1.f, 0.f, 0.f); + break; + case Con_Bool: + pi[0] = (str == "true") ? 1 : 0; + break; + } + if (parameterType >= Con_Angle && parameterType <= Con_Angle4) + { + for (int i = 0; i <= (parameterType - Con_Angle); i++) + { + pf[i] = DegToRad(pf[i]); + } + } +} + + +int GetParameterIndex(uint32_t nodeType, const char* parameterName) +{ + const MetaNode& currentMeta = gMetaNodes[nodeType]; + int i = 0; + for (const MetaParameter& param : currentMeta.mParams) + { + if (!strcmp(param.mName.c_str(), parameterName)) + return i; + i++; + } + return -1; +} + + +size_t GetCurveCountPerParameterType(ConTypes paramType) +{ + switch (paramType) + { + case Con_Angle: + case Con_Float: + return 1; + case Con_Angle2: + case Con_Float2: + return 2; + case Con_Angle3: + case Con_Float3: + return 3; + case Con_Angle4: + case Con_Color4: + case Con_Float4: + return 4; + case Con_Ramp: + return 0; // sizeof(float) * 2 * 8; + case Con_Ramp4: + return 0; // sizeof(float) * 4 * 8; + case Con_Enum: + return 1; + case Con_Int: + return 1; + case Con_Int2: + return 2; + case Con_FilenameRead: + case Con_FilenameWrite: + return 0; + case Con_ForceEvaluate: + return 0; + case Con_Bool: + return 1; + case Con_Camera: + return 7; + case Con_Multiplexer: + return 1; + default: + assert(0); + } + return 0; +} + +const char* GetCurveParameterSuffix(ConTypes paramType, int suffixIndex) +{ + static const char* suffixes[] = { ".x", ".y", ".z", ".w" }; + static const char* cameraSuffixes[] = { "posX", "posY", "posZ", "dirX", "dirY", "dirZ", "FOV" }; + switch (paramType) + { + case Con_Angle: + case Con_Float: + return ""; + case Con_Angle2: + case Con_Float2: + return suffixes[suffixIndex]; + case Con_Angle3: + case Con_Float3: + return suffixes[suffixIndex]; + case Con_Angle4: + case Con_Color4: + case Con_Float4: + return suffixes[suffixIndex]; + case Con_Ramp: + return 0; // sizeof(float) * 2 * 8; + case Con_Ramp4: + return 0; // sizeof(float) * 4 * 8; + case Con_Enum: + return ""; + case Con_Int: + return ""; + case Con_Int2: + return suffixes[suffixIndex]; + case Con_FilenameRead: + case Con_FilenameWrite: + return 0; + case Con_ForceEvaluate: + return 0; + case Con_Bool: + return ""; + case Con_Camera: + return cameraSuffixes[suffixIndex]; + case Con_Multiplexer: + return ""; + default: + assert(0); + } + return ""; +} + +uint32_t GetCurveParameterColor(ConTypes paramType, int suffixIndex) +{ + static const uint32_t colors[] = { 0xFF1010F0, 0xFF10F010, 0xFFF01010, 0xFFF0F0F0 }; + static const uint32_t cameraColors[] = { + 0xFF1010F0, 0xFF10F010, 0xFFF01010, 0xFF1010F0, 0xFF10F010, 0xFFF01010, 0xFFF0F0F0 }; + switch (paramType) + { + case Con_Angle: + case Con_Float: + return 0xFF1040F0; + case Con_Angle2: + case Con_Float2: + return colors[suffixIndex]; + case Con_Angle3: + case Con_Float3: + return colors[suffixIndex]; + case Con_Angle4: + case Con_Color4: + case Con_Float4: + return colors[suffixIndex]; + case Con_Ramp: + return 0xFFAAAAAA; // sizeof(float) * 2 * 8; + case Con_Ramp4: + return 0xFFAAAAAA; // sizeof(float) * 4 * 8; + case Con_Enum: + return 0xFFAAAAAA; + case Con_Int: + return 0xFFAAAAAA; + case Con_Int2: + return colors[suffixIndex]; + case Con_FilenameRead: + case Con_FilenameWrite: + return 0; + case Con_ForceEvaluate: + return 0; + case Con_Bool: + return 0xFFF0F0F0; + case Con_Camera: + return cameraColors[suffixIndex]; + case Con_Multiplexer: + return 0xFFAABBCC; + default: + assert(0); + } + return 0xFFAAAAAA; +} + +size_t GetParameterOffset(uint32_t type, uint32_t parameterIndex) +{ + const MetaNode& currentMeta = gMetaNodes[type]; + size_t ret = 0; + int i = 0; + for (const MetaParameter& param : currentMeta.mParams) + { + if (i == parameterIndex) + break; + ret += GetParameterTypeSize(param.mType); + i++; + } + return ret; +} + + + +CurveType GetCurveTypeForParameterType(ConTypes paramType) +{ + switch (paramType) + { + case Con_Float: + return CurveSmooth; + case Con_Float2: + return CurveSmooth; + case Con_Float3: + return CurveSmooth; + case Con_Float4: + return CurveSmooth; + case Con_Color4: + return CurveSmooth; + case Con_Int: + return CurveLinear; + case Con_Int2: + return CurveLinear; + case Con_Ramp: + return CurveNone; + case Con_Angle: + return CurveSmooth; + case Con_Angle2: + return CurveSmooth; + case Con_Angle3: + return CurveSmooth; + case Con_Angle4: + return CurveSmooth; + case Con_Enum: + return CurveDiscrete; + case Con_Structure: + case Con_FilenameRead: + case Con_FilenameWrite: + case Con_ForceEvaluate: + return CurveNone; + case Con_Bool: + return CurveDiscrete; + case Con_Ramp4: + return CurveNone; + case Con_Camera: + return CurveSmooth; + case Con_Multiplexer: + return CurveLinear; + default: + return CurveNone; + } +} + + +size_t ComputeNodeParametersSize(size_t nodeType) +{ + size_t res = 0; + for (auto& param : gMetaNodes[nodeType].mParams) + { + res += GetParameterTypeSize(param.mType); + } + return res; +} \ No newline at end of file diff --git a/src/MetaNodes.h b/src/MetaNodes.h new file mode 100644 index 00000000..bf203723 --- /dev/null +++ b/src/MetaNodes.h @@ -0,0 +1,182 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once + +#include +#include + + +enum ConTypes +{ + Con_Float, + Con_Float2, + Con_Float3, + Con_Float4, + Con_Color4, + Con_Int, + Con_Int2, + Con_Ramp, + Con_Angle, + Con_Angle2, + Con_Angle3, + Con_Angle4, + Con_Enum, + Con_Structure, + Con_FilenameRead, + Con_FilenameWrite, + Con_ForceEvaluate, + Con_Bool, + Con_Ramp4, + Con_Camera, + Con_Multiplexer, + Con_Any, +}; + +enum ControlTypes +{ + Control_NumericEdit, + Control_Slider, +}; + +enum CurveType +{ + CurveNone, + CurveDiscrete, + CurveLinear, + CurveSmooth, + CurveBezier, +}; + +struct MetaCon +{ + std::string mName; + int mType; + bool operator==(const MetaCon& other) const + { + if (mName != other.mName) + return false; + if (mType != other.mType) + return false; + return true; + } +}; + +struct MetaParameter +{ + std::string mName; + ConTypes mType; + ControlTypes mControlType; + float mRangeMinX, mRangeMaxX; + float mRangeMinY, mRangeMaxY; + float mSliderMinX, mSliderMaxX; + bool mbRelative; + bool mbQuadSelect; + bool mbLoop; + bool mbHidden; + std::string mEnumList; + std::vector mDefaultValue; + std::string mDescription; + bool operator==(const MetaParameter& other) const + { + if (mName != other.mName) + return false; + if (mType != other.mType) + return false; + if (mRangeMaxX != other.mRangeMaxX) + return false; + if (mRangeMinX != other.mRangeMinX) + return false; + if (mRangeMaxY != other.mRangeMaxY) + return false; + if (mRangeMinY != other.mRangeMinY) + return false; + if (mbRelative != other.mbRelative) + return false; + if (mbQuadSelect != other.mbQuadSelect) + return false; + if (mEnumList != other.mEnumList) + return false; + return true; + } +}; + +struct MetaNode +{ + std::string mName; + uint32_t mHeaderColor; + int mCategory; + std::string mDescription; + std::vector mInputs; + std::vector mOutputs; + std::vector mParams; + + int mWidth; + int mHeight; + + bool mbHasUI; + bool mbSaveTexture; + bool mbExperimental; + bool mbThumbnail; + bool operator==(const MetaNode& other) const + { + if (mName != other.mName) + return false; + if (mCategory != other.mCategory) + return false; + if (mHeaderColor != other.mHeaderColor) + return false; + if (mInputs != other.mInputs) + return false; + if (mOutputs != other.mOutputs) + return false; + if (mParams != other.mParams) + return false; + if (mbHasUI != other.mbHasUI) + return false; + if (mbSaveTexture != other.mbSaveTexture) + return false; + return true; + } + + static const std::vector mCategories; +}; + +extern std::vector gMetaNodes; + +size_t GetMetaNodeIndex(const std::string& metaNodeName); +void LoadMetaNodes(); +size_t GetParameterTypeSize(ConTypes paramType); +CurveType GetCurveTypeForParameterType(ConTypes paramType); +const char* GetParameterTypeName(ConTypes paramType); +ConTypes GetParameterType(uint32_t nodeType, uint32_t parameterIndex); +void ParseStringToParameter(const std::string& str, ConTypes parameterType, void* parameterPtr); +int GetParameterIndex(uint32_t nodeType, const char* parameterName); +size_t GetParameterOffset(uint32_t type, uint32_t parameterIndex); +ConTypes GetParameterType(uint32_t nodeType, uint32_t parameterIndex); +size_t GetCurveCountPerParameterType(ConTypes paramType); +const char* GetCurveParameterSuffix(ConTypes paramType, int suffixIndex); +uint32_t GetCurveParameterColor(ConTypes paramType, int suffixIndex); +size_t ComputeNodeParametersSize(size_t nodeType); diff --git a/src/NodeGraph.cpp b/src/NodeGraph.cpp deleted file mode 100644 index 25566277..00000000 --- a/src/NodeGraph.cpp +++ /dev/null @@ -1,1603 +0,0 @@ -// https://github.com/CedricGuillemet/Imogen -// -// The MIT License(MIT) -// -// Copyright(c) 2019 Cedric Guillemet -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -#include "Platform.h" -#include "imgui.h" -#include "imgui_internal.h" -#include -#include "NodeGraph.h" -#include -#include -#include -#include "EvaluationStages.h" -#include "imgui_stdlib.h" -#include "NodeGraphControler.h" -#include -#include "imgui_markdown/imgui_markdown.h" -#include "UI.h" - -void AddExtractedView(size_t nodeIndex); -extern ImGui::MarkdownConfig mdConfig; - -static inline float Distance(ImVec2& a, ImVec2& b) -{ - return sqrtf((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); -} - -Node::Node(int type, const ImVec2& pos) -{ - mType = type; - Pos = pos; - Size = ImVec2(100, 100); - InputsCount = gMetaNodes[type].mInputs.size(); - OutputsCount = gMetaNodes[type].mOutputs.size(); - mbSelected = false; -} - -struct NodeOrder -{ - size_t mNodeIndex; - size_t mNodePriority; - bool operator<(const NodeOrder& other) const - { - return other.mNodePriority < mNodePriority; // reverse order compared to priority value: lower last - } -}; - -size_t PickBestNode(const std::vector& orders) -{ - for (auto& order : orders) - { - if (order.mNodePriority == 0) - return order.mNodeIndex; - } - // issue! - assert(0); - return -1; -} - -void RecurseSetPriority(std::vector& orders, - const std::vector& links, - size_t currentIndex, - size_t currentPriority, - size_t& undeterminedNodeCount) -{ - if (!orders[currentIndex].mNodePriority) - undeterminedNodeCount--; - - orders[currentIndex].mNodePriority = std::max(orders[currentIndex].mNodePriority, currentPriority + 1); - for (auto& link : links) - { - if (link.OutputIdx == currentIndex) - { - RecurseSetPriority(orders, links, link.InputIdx, currentPriority + 1, undeterminedNodeCount); - } - } -} - -std::vector ComputeEvaluationOrder(const std::vector& links, size_t nodeCount) -{ - std::vector orders(nodeCount); - for (size_t i = 0; i < nodeCount; i++) - { - orders[i].mNodeIndex = i; - orders[i].mNodePriority = 0; - } - size_t undeterminedNodeCount = nodeCount; - while (undeterminedNodeCount) - { - size_t currentIndex = PickBestNode(orders); - RecurseSetPriority(orders, links, currentIndex, orders[currentIndex].mNodePriority, undeterminedNodeCount); - }; - // - return orders; -} - -const float NODE_SLOT_RADIUS = 8.0f; -const ImVec2 NODE_WINDOW_PADDING(8.0f, 8.0f); - -static std::vector mOrders; -static std::vector nodes; -static std::vector mNodesClipboard; -static std::vector links; -static std::vector rugs; -static NodeRug* editRug = NULL; - -static ImVec2 editingNodeSource; -bool editingInput = false; -static ImVec2 scrolling = ImVec2(0.0f, 0.0f); -float factor = 1.0f; -float factorTarget = 1.0f; -ImVec2 captureOffset; - -enum NodeOperation -{ - NO_None, - NO_EditingLink, - NO_QuadSelecting, - NO_MovingNodes, - NO_EditInput, - NO_MovingRug, - NO_SizingRug, - NO_PanView, -}; -NodeOperation nodeOperation = NO_None; - -void HandleZoomScroll(ImRect regionRect) -{ - ImGuiIO& io = ImGui::GetIO(); - - if (regionRect.Contains(io.MousePos)) - { - if (io.MouseWheel < -FLT_EPSILON) - factorTarget *= 0.9f; - - if (io.MouseWheel > FLT_EPSILON) - factorTarget *= 1.1f; - } - - ImVec2 mouseWPosPre = (io.MousePos - ImGui::GetCursorScreenPos()) / factor; - factorTarget = ImClamp(factorTarget, 0.2f, 3.f); - factor = ImLerp(factor, factorTarget, 0.15f); - ImVec2 mouseWPosPost = (io.MousePos - ImGui::GetCursorScreenPos()) / factor; - if (ImGui::IsMousePosValid()) - { - scrolling += mouseWPosPost - mouseWPosPre; - } -} - -void NodeGraphClear() -{ - nodes.clear(); - links.clear(); - rugs.clear(); - editRug = NULL; - nodeOperation = NO_None; - factor = 1.0f; - factorTarget = 1.0f; -} - -const std::vector& NodeGraphGetLinks() -{ - return links; -} - -const std::vector& NodeGraphRugs() -{ - return rugs; -} - -NodeRug* DisplayRugs(NodeRug* editRug, ImDrawList* drawList, ImVec2 offset, float factor) -{ - ImGuiIO& io = ImGui::GetIO(); - NodeRug* ret = editRug; - - // mouse pointer over any node? - bool overAnyNode = false; - for (auto& node : nodes) - { - ImVec2 node_rect_min = offset + node.Pos * factor; - ImVec2 node_rect_max = node_rect_min + node.Size; - if (ImRect(node_rect_min, node_rect_max).Contains(io.MousePos)) - { - overAnyNode = true; - break; - } - } - - for (unsigned int rugIndex = 0; rugIndex < rugs.size(); rugIndex++) - { - auto& rug = rugs[rugIndex]; - if (&rug == editRug) - continue; - ImGui::PushID(900 + rugIndex); - ImVec2 commentSize = rug.mSize * factor; - - ImVec2 node_rect_min = offset + rug.mPos * factor; - - ImGui::SetCursorScreenPos(node_rect_min + NODE_WINDOW_PADDING); - - ImVec2 node_rect_max = node_rect_min + commentSize; - - ImRect rugRect(node_rect_min, node_rect_max); - if (rugRect.Contains(io.MousePos) && !overAnyNode) - { - if (io.MouseDoubleClicked[0]) - { - ret = &rug; - } - else if (io.KeyShift && ImGui::IsMouseClicked(0)) - { - for (auto& node : nodes) - { - ImVec2 node_rect_min = offset + node.Pos * factor; - ImVec2 node_rect_max = node_rect_min + node.Size; - if (rugRect.Overlaps(ImRect(node_rect_min, node_rect_max))) - { - node.mbSelected = true; - } - } - } - } - // drawList->AddText(io.FontDefault, 13 * ImLerp(1.f, factor, 0.5f), node_rect_min + ImVec2(5, 5), (rug.mColor & - // 0xFFFFFF) + 0xFF404040, rug.mText.c_str()); - ImGui::SetCursorScreenPos(node_rect_min + NODE_WINDOW_PADDING); - ImGui::PushStyleColor(ImGuiCol_FrameBg, 0x0); - ImGui::PushStyleColor(ImGuiCol_Border, 0x0); - ImGui::BeginChildFrame( - 88 + rugIndex, commentSize - NODE_WINDOW_PADDING * 2, ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav); - - ImGui::Markdown(rug.mText.c_str(), rug.mText.length(), mdConfig); - drawList->AddRectFilled(node_rect_min, node_rect_max, (rug.mColor & 0xFFFFFF) + 0x60000000, 10.0f, 15); - drawList->AddRect(node_rect_min, node_rect_max, (rug.mColor & 0xFFFFFF) + 0x90000000, 10.0f, 15, 2.f); - ImGui::EndChildFrame(); - ImGui::PopStyleColor(2); - ImGui::PopID(); - } - return ret; -} - -bool EditRug(NodeRug* rug, ImDrawList* drawList, ImVec2 offset, float factor) -{ - ImGuiIO& io = ImGui::GetIO(); - ImVec2 commentSize = rug->mSize * factor; - static NodeRug* movingRug = NULL; - static NodeRug* sizingRug = NULL; - - int rugIndex = int(rug - rugs.data()); - URChange undoRedoRug(rugIndex, [](int index) { return &rugs[index]; }, [](int) {}); - bool dirtyRug = false; - ImVec2 node_rect_min = offset + rug->mPos * factor; - ImVec2 node_rect_max = node_rect_min + commentSize; - ImRect rugRect(node_rect_min, node_rect_max); - ImRect insideSizingRect(node_rect_min + commentSize - ImVec2(30, 30), node_rect_min + commentSize); - ImGui::SetCursorScreenPos(node_rect_min + NODE_WINDOW_PADDING); - - - drawList->AddRectFilled(node_rect_min, node_rect_max, (rug->mColor & 0xFFFFFF) + 0xE0000000, 10.0f, 15); - drawList->AddRect(node_rect_min, node_rect_max, (rug->mColor & 0xFFFFFF) + 0xFF000000, 10.0f, 15, 2.f); - drawList->AddTriangleFilled(node_rect_min + commentSize - ImVec2(25, 8), - node_rect_min + commentSize - ImVec2(8, 25), - node_rect_min + commentSize - ImVec2(8, 8), - (rug->mColor & 0xFFFFFF) + 0x90000000); - - ImGui::SetCursorScreenPos(node_rect_min + ImVec2(5, 5)); - ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(0, 0, 0, 0)); - ImGui::PushStyleColor(ImGuiCol_Border, IM_COL32(0, 0, 0, 0)); - dirtyRug |= ImGui::InputTextMultiline("", &rug->mText, (node_rect_max - node_rect_min) - ImVec2(30, 30)); - ImGui::PopStyleColor(2); - - ImGui::SetCursorScreenPos(node_rect_min + ImVec2(10, commentSize.y - 30)); - for (int i = 0; i < 7; i++) - { - if (i > 0) - ImGui::SameLine(); - ImGui::PushID(i); - ImColor buttonColor = ImColor::HSV(i / 7.0f, 0.6f, 0.6f); - ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)buttonColor); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); - if (ImGui::Button(" ")) - { - rug->mColor = buttonColor; - dirtyRug = true; - } - ImGui::PopStyleColor(3); - ImGui::PopID(); - } - ImGui::SameLine(0, 50); - - if (ImGui::Button("Delete")) - { - undoRedoRug.Discard(); - int index = int(rug - rugs.data()); - URDel undoRedoDelRug(index, []() { return &rugs; }, [](int) {}, [](int) {}); - rugs.erase(rugs.begin() + index); - return true; - } - - bool createUndo = false; - bool commitUndo = false; - bool mouseMoved = fabsf(io.MouseDelta.x) > FLT_EPSILON && fabsf(io.MouseDelta.y) > FLT_EPSILON; - if (insideSizingRect.Contains(io.MousePos)) - if (nodeOperation == NO_None && io.MouseDown[0] /* && !mouseMoved*/) - { - sizingRug = rug; - createUndo = true; - nodeOperation = NO_SizingRug; - } - if (sizingRug && !io.MouseDown[0]) - { - sizingRug = NULL; - commitUndo = true; - nodeOperation = NO_None; - } - - if (rugRect.Contains(io.MousePos) && !insideSizingRect.Contains(io.MousePos)) - if (nodeOperation == NO_None && io.MouseDown[0] /*&& !mouseMoved*/) - { - movingRug = rug; - createUndo = true; - nodeOperation = NO_MovingRug; - } - if (movingRug && !io.MouseDown[0]) - { - commitUndo = true; - movingRug = NULL; - nodeOperation = NO_None; - } - - // undo/redo for sizing/moving - static URChange* undoRedoRugcm = NULL; - if (createUndo) - { - undoRedoRugcm = new URChange(rugIndex, [](int index) { return &rugs[index]; }, [](int) {}); - } - if (commitUndo) - { - delete undoRedoRugcm; - undoRedoRugcm = NULL; - } - if (!dirtyRug) - { - undoRedoRug.Discard(); - } - - if (sizingRug && ImGui::IsMouseDragging(0)) - sizingRug->mSize += io.MouseDelta; - if (movingRug && ImGui::IsMouseDragging(0)) - movingRug->mPos += io.MouseDelta; - - if ((io.MouseClicked[0] || io.MouseClicked[1]) && !rugRect.Contains(io.MousePos)) - return true; - return false; -} - -bool RecurseIsLinked(int from, int to) -{ - for (auto& link : links) - { - if (link.InputIdx == from) - { - if (link.OutputIdx == to) - return true; - - if (RecurseIsLinked(link.OutputIdx, to)) - return true; - } - } - return false; -} - -void NodeGraphUpdateEvaluationOrder(NodeGraphControlerBase* controler) -{ - mOrders = ComputeEvaluationOrder(links, nodes.size()); - std::sort(mOrders.begin(), mOrders.end()); - std::vector nodeOrderList(mOrders.size()); - for (size_t i = 0; i < mOrders.size(); i++) - nodeOrderList[i] = mOrders[i].mNodeIndex; - if (controler) - { - controler->UpdateEvaluationList(nodeOrderList); - } -} - -size_t NodeGraphAddNode(NodeGraphControlerBase* controler, - int type, - const std::vector* parameters, - int posx, - int posy, - int frameStart, - int frameEnd) -{ - size_t index = nodes.size(); - nodes.push_back(Node(type, ImVec2(float(posx), float(posy)))); - - controler->AddSingleNode(type); - if (parameters) - { - controler->SetParamBlock(index, *parameters); - } - controler->SetTimeSlot(index, frameStart, frameEnd); - return index; -} - -void NodeGraphAddLink(NodeGraphControlerBase* controler, int InputIdx, int InputSlot, int OutputIdx, int OutputSlot) -{ - if (InputIdx >= nodes.size() || OutputIdx >= nodes.size()) - { - Log("Error : Link node index doesn't correspond to an existing node."); - return; - } - - NodeLink nl; - nl.InputIdx = InputIdx; - nl.InputSlot = InputSlot; - nl.OutputIdx = OutputIdx; - nl.OutputSlot = OutputSlot; - links.push_back(nl); - controler->AddLink(nl.InputIdx, nl.InputSlot, nl.OutputIdx, nl.OutputSlot); -} - -ImVec2 NodeGraphGetNodePos(size_t index) -{ - return nodes[index].Pos; -} - -void NodeGraphUpdateScrolling() -{ - if (nodes.empty() && rugs.empty()) - return; - - scrolling = nodes[0].Pos; - for (auto& node : nodes) - { - scrolling.x = std::min(scrolling.x, node.Pos.x); - scrolling.y = std::min(scrolling.y, node.Pos.y); - } - for (auto& rug : rugs) - { - scrolling.x = std::min(scrolling.x, rug.mPos.x); - scrolling.y = std::min(scrolling.y, rug.mPos.y); - } - - scrolling = ImVec2(40, 40) - scrolling; -} - -void NodeGraphAddRug( - int32_t posX, int32_t posY, int32_t sizeX, int32_t sizeY, uint32_t color, const std::string comment) -{ - rugs.push_back({ImVec2(float(posX), float(posY)), ImVec2(float(sizeX), float(sizeY)), color, comment}); -} - -static void DeleteSelectedNodes(NodeGraphControlerBase* controler) -{ - URDummy urDummy; - for (int selection = int(nodes.size()) - 1; selection >= 0; selection--) - { - if (!nodes[selection].mbSelected) - continue; - URDel undoRedoDelNode(int(selection), - []() { return &nodes; }, - [controler](int index) { - // recompute link indices - for (int id = 0; id < links.size(); id++) - { - if (links[id].InputIdx > index) - links[id].InputIdx--; - if (links[id].OutputIdx > index) - links[id].OutputIdx--; - } - NodeGraphUpdateEvaluationOrder(controler); - controler->mSelectedNodeIndex = -1; - }, - [controler](int index) { - // recompute link indices - for (int id = 0; id < links.size(); id++) - { - if (links[id].InputIdx >= index) - links[id].InputIdx++; - if (links[id].OutputIdx >= index) - links[id].OutputIdx++; - } - - NodeGraphUpdateEvaluationOrder(controler); - controler->mSelectedNodeIndex = -1; - }); - - for (int id = 0; id < links.size(); id++) - { - if (links[id].InputIdx == selection || links[id].OutputIdx == selection) - controler->DelLink(links[id].OutputIdx, links[id].OutputSlot); - } - // auto iter = links.begin(); - for (size_t i = 0; i < links.size();) - { - auto& link = links[i]; - if (link.InputIdx == selection || link.OutputIdx == selection) - { - URDel undoRedoDelNodeLink( - int(i), - []() { return &links; }, - [controler](int index) { - NodeLink& link = links[index]; - controler->DelLink(link.OutputIdx, link.OutputSlot); - }, - [controler](int index) { - NodeLink& link = links[index]; - controler->AddLink(link.InputIdx, link.InputSlot, link.OutputIdx, link.OutputSlot); - }); - - links.erase(links.begin() + i); - } - else - { - i++; - } - } - - // recompute link indices - for (int id = 0; id < links.size(); id++) - { - if (links[id].InputIdx > selection) - links[id].InputIdx--; - if (links[id].OutputIdx > selection) - links[id].OutputIdx--; - } - - // delete links - nodes.erase(nodes.begin() + selection); - NodeGraphUpdateEvaluationOrder(controler); - - // inform delegate - controler->UserDeleteNode(selection); - } -} - -static void ContextMenu(ImVec2 offset, int nodeHovered, NodeGraphControlerBase* controler) -{ - ImGuiIO& io = ImGui::GetIO(); - size_t metaNodeCount = gMetaNodes.size(); - const MetaNode* metaNodes = gMetaNodes.data(); - - bool copySelection = false; - bool deleteSelection = false; - bool pasteSelection = false; - - // Draw context menu - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); - if (ImGui::BeginPopup("context_menu")) - { - Node* node = nodeHovered != -1 ? &nodes[nodeHovered] : NULL; - ImVec2 scene_pos = (ImGui::GetMousePosOnOpeningCurrentPopup() - offset) / factor; - if (node) - { - ImGui::Text(metaNodes[node->mType].mName.c_str()); - ImGui::Separator(); - - if (ImGui::MenuItem("Extract view", NULL, false)) - { - AddExtractedView(nodeHovered); - } - } - else - { - auto AddNode = [&](int i) { - auto addDelNodeLambda = [controler](int) { - NodeGraphUpdateEvaluationOrder(controler); - controler->mSelectedNodeIndex = -1; - }; - URAdd undoRedoAddRug( - int(nodes.size()), []() { return &nodes; }, addDelNodeLambda, addDelNodeLambda); - - nodes.push_back(Node(i, scene_pos)); - controler->UserAddNode(i); - addDelNodeLambda(0); - }; - - static char inputText[64] = {0}; - if (ImGui::IsWindowAppearing()) - ImGui::SetKeyboardFocusHere(); - ImGui::InputText("", inputText, sizeof(inputText)); - { - if (strlen(inputText)) - { - for (int i = 0; i < metaNodeCount; i++) - { - const char* nodeName = metaNodes[i].mName.c_str(); - bool displayNode = - !strlen(inputText) || - ImStristr(nodeName, nodeName + strlen(nodeName), inputText, inputText + strlen(inputText)); - if (displayNode && ImGui::MenuItem(nodeName, NULL, false)) - { - AddNode(i); - } - } - } - else - { - for (int i = 0; i < metaNodeCount; i++) - { - const char* nodeName = metaNodes[i].mName.c_str(); - if (metaNodes[i].mCategory == -1 && ImGui::MenuItem(nodeName, NULL, false)) - { - AddNode(i); - } - } - - for (unsigned int iCateg = 0; iCateg < controler->mCategories->size(); iCateg++) - { - if (ImGui::BeginMenu((*controler->mCategories)[iCateg].c_str())) - { - for (int i = 0; i < metaNodeCount; i++) - { - const char* nodeName = metaNodes[i].mName.c_str(); - if (metaNodes[i].mCategory == iCateg && ImGui::MenuItem(nodeName, NULL, false)) - { - AddNode(i); - } - } - ImGui::EndMenu(); - } - } - } - } - } - - ImGui::Separator(); - if (ImGui::MenuItem("Add rug", NULL, false)) - { - URAdd undoRedoAddRug(int(rugs.size()), []() { return &rugs; }, [](int) {}, [](int) {}); - rugs.push_back({scene_pos, ImVec2(400, 200), 0xFFA0A0A0, "Description\nEdit me with a double click."}); - } - ImGui::Separator(); - if (ImGui::MenuItem("Delete", "Del", false)) - { - deleteSelection = true; - } - if (ImGui::MenuItem("Copy", "CTRL+C")) - { - copySelection = true; - } - if (ImGui::MenuItem("Paste", "CTRL+V", false, !mNodesClipboard.empty())) - { - pasteSelection = true; - } - - ImGui::EndPopup(); - } - ImGui::PopStyleVar(); - - if (copySelection || (ImGui::IsWindowFocused() && io.KeyCtrl && ImGui::IsKeyPressedMap(ImGuiKey_C))) - { - mNodesClipboard.clear(); - std::vector selection; - for (size_t i = 0; i < nodes.size(); i++) - { - if (!nodes[i].mbSelected) - continue; - mNodesClipboard.push_back(nodes[i]); - selection.push_back(i); - } - controler->CopyNodes(selection); - } - - if (deleteSelection || (ImGui::IsWindowFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Delete))) - { - DeleteSelectedNodes(controler); - } - - if (pasteSelection || (ImGui::IsWindowFocused() && io.KeyCtrl && ImGui::IsKeyPressedMap(ImGuiKey_V))) - { - URDummy undoRedoDummy; - ImVec2 min(FLT_MAX, FLT_MAX); - for (auto& clipboardNode : mNodesClipboard) - { - min.x = ImMin(clipboardNode.Pos.x, min.x); - min.y = ImMin(clipboardNode.Pos.y, min.y); - } - for (auto& selnode : nodes) - selnode.mbSelected = false; - for (auto& clipboardNode : mNodesClipboard) - { - URAdd undoRedoAddRug(int(nodes.size()), []() { return &nodes; }, [](int index) {}, [](int index) {}); - nodes.push_back(clipboardNode); - nodes.back().Pos += (io.MousePos - offset) / factor - min; - nodes.back().mbSelected = true; - } - controler->PasteNodes(); - NodeGraphUpdateEvaluationOrder(controler); - } -} - -static void DisplayLinks( - ImDrawList* drawList, const ImVec2 offset, const float factor, const ImRect regionRect, int hoveredNode) -{ - for (int link_idx = 0; link_idx < links.size(); link_idx++) - { - NodeLink* link = &links[link_idx]; - Node* node_inp = &nodes[link->InputIdx]; - Node* node_out = &nodes[link->OutputIdx]; - ImVec2 p1 = offset + node_inp->GetOutputSlotPos(link->InputSlot, factor); - ImVec2 p2 = offset + node_out->GetInputSlotPos(link->OutputSlot, factor); - - // con. view clipping - if ((p1.y < 0.f && p2.y < 0.f) || (p1.y > regionRect.Max.y && p2.y > regionRect.Max.y) || - (p1.x < 0.f && p2.x < 0.f) || (p1.x > regionRect.Max.x && p2.x > regionRect.Max.x)) - continue; - - bool highlightCons = hoveredNode == link->InputIdx || hoveredNode == link->OutputIdx; - uint32_t col = gMetaNodes[node_inp->mType].mHeaderColor | (highlightCons ? 0xF0F0F0 : 0); - ; - // curves - // drawList->AddBezierCurve(p1, p1 + ImVec2(+50, 0) * factor, p2 + ImVec2(-50, 0) * factor, p2, 0xFF000000, 4.f - // * factor); drawList->AddBezierCurve(p1, p1 + ImVec2(+50, 0) * factor, p2 + ImVec2(-50, 0) * factor, p2, - // col, 3.0f * factor); - - // -/- - /* - ImVec2 p10 = p1 + ImVec2(20.f * factor, 0.f); - ImVec2 p20 = p2 - ImVec2(20.f * factor, 0.f); - - ImVec2 dif = p20 - p10; - ImVec2 p1a, p1b; - if (fabsf(dif.x) > fabsf(dif.y)) - { - p1a = p10 + ImVec2(fabsf(fabsf(dif.x) - fabsf(dif.y)) * 0.5 * sign(dif.x), 0.f); - p1b = p1a + ImVec2(fabsf(dif.y) * sign(dif.x) , dif.y); - } - else - { - p1a = p10 + ImVec2(0.f, fabsf(fabsf(dif.y) - fabsf(dif.x)) * 0.5 * sign(dif.y)); - p1b = p1a + ImVec2(dif.x, fabsf(dif.x) * sign(dif.y)); - } - drawList->AddLine(p1, p10, col, 3.f * factor); - drawList->AddLine(p10, p1a, col, 3.f * factor); - drawList->AddLine(p1a, p1b, col, 3.f * factor); - drawList->AddLine(p1b, p20, col, 3.f * factor); - drawList->AddLine(p20, p2, col, 3.f * factor); - */ - std::array pts; - int ptCount = 0; - ImVec2 dif = p2 - p1; - - ImVec2 p1a, p1b; - const float limitx = 12.f * factor; - if (dif.x < limitx) - { - ImVec2 p10 = p1 + ImVec2(limitx, 0.f); - ImVec2 p20 = p2 - ImVec2(limitx, 0.f); - - dif = p20 - p10; - p1a = p10 + ImVec2(0.f, dif.y * 0.5f); - p1b = p1a + ImVec2(dif.x, 0.f); - - pts = {p1, p10, p1a, p1b, p20, p2}; - ptCount = 6; - } - else - { - if (fabsf(dif.y) < 1.f) - { - pts = {p1, (p1 + p2) * 0.5f, p2}; - ptCount = 3; - } - else - { - if (fabsf(dif.y) < 10.f) - { - if (fabsf(dif.x) > fabsf(dif.y)) - { - p1a = p1 + ImVec2(fabsf(fabsf(dif.x) - fabsf(dif.y)) * 0.5f * sign(dif.x), 0.f); - p1b = p1a + ImVec2(fabsf(dif.y) * sign(dif.x), dif.y); - } - else - { - p1a = p1 + ImVec2(0.f, fabsf(fabsf(dif.y) - fabsf(dif.x)) * 0.5f * sign(dif.y)); - p1b = p1a + ImVec2(dif.x, fabsf(dif.x) * sign(dif.y)); - } - } - else - { - if (fabsf(dif.x) > fabsf(dif.y)) - { - float d = fabsf(dif.y) * sign(dif.x) * 0.5f; - p1a = p1 + ImVec2(d, dif.y * 0.5f); - p1b = p1a + ImVec2(fabsf(fabsf(dif.x) - fabsf(d) * 2.f) * sign(dif.x), 0.f); - } - else - { - float d = fabsf(dif.x) * sign(dif.y) * 0.5f; - p1a = p1 + ImVec2(dif.x * 0.5f, d); - p1b = p1a + ImVec2(0.f, fabsf(fabsf(dif.y) - fabsf(d) * 2.f) * sign(dif.y)); - } - } - pts = {p1, p1a, p1b, p2}; - ptCount = 4; - } - } - float highLightFactor = factor * highlightCons ? 2.0f : 1.f; - for (int pass = 0; pass < 2; pass++) - { - drawList->AddPolyline( - pts.data(), ptCount, pass ? col : 0xFF000000, false, (pass ? 5.f : 7.5f) * highLightFactor); - } - } -} - -static void HandleQuadSelection(ImDrawList* drawList, const ImVec2 offset, const float factor, ImRect contentRect) -{ - ImGuiIO& io = ImGui::GetIO(); - static ImVec2 quadSelectPos; - - ImRect editingRugRect(ImVec2(FLT_MAX, FLT_MAX), ImVec2(FLT_MAX, FLT_MAX)); - if (editRug) - { - ImVec2 commentSize = editRug->mSize * factor; - ImVec2 node_rect_min = (offset + editRug->mPos) * factor; - ImVec2 node_rect_max = node_rect_min + commentSize; - editingRugRect = ImRect(node_rect_min, node_rect_max); - } - - if (nodeOperation == NO_QuadSelecting && ImGui::IsWindowFocused()) - { - const ImVec2 bmin = ImMin(quadSelectPos, io.MousePos); - const ImVec2 bmax = ImMax(quadSelectPos, io.MousePos); - drawList->AddRectFilled(bmin, bmax, 0x40FF2020, 1.f); - drawList->AddRect(bmin, bmax, 0xFFFF2020, 1.f); - if (!io.MouseDown[0]) - { - if (!io.KeyCtrl && !io.KeyShift) - { - for (int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) - { - Node* node = &nodes[nodeIndex]; - node->mbSelected = false; - } - } - - nodeOperation = NO_None; - ImRect selectionRect(bmin, bmax); - for (int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) - { - Node* node = &nodes[nodeIndex]; - ImVec2 node_rect_min = offset + node->Pos * factor; - ImVec2 node_rect_max = node_rect_min + node->Size; - if (selectionRect.Overlaps(ImRect(node_rect_min, node_rect_max))) - { - if (io.KeyCtrl) - { - node->mbSelected = false; - } - else - { - node->mbSelected = true; - } - } - else - { - if (!io.KeyShift) - { - node->mbSelected = false; - } - } - } - } - } - else if (nodeOperation == NO_None && io.MouseDown[0] && ImGui::IsWindowFocused() && - contentRect.Contains(io.MousePos) && !editingRugRect.Contains(io.MousePos)) - { - nodeOperation = NO_QuadSelecting; - quadSelectPos = io.MousePos; - } -} - - -bool HandleConnections(ImDrawList* drawList, - int nodeIndex, - const ImVec2 offset, - const float factor, - NodeGraphControlerBase* controler, - bool bDrawOnly) -{ - static int editingNodeIndex; - static int editingSlotIndex; - - auto deleteLink = [controler](int index) { - NodeLink& link = links[index]; - controler->DelLink(link.OutputIdx, link.OutputSlot); - NodeGraphUpdateEvaluationOrder(controler); - }; - auto addLink = [controler](int index) { - NodeLink& link = links[index]; - controler->AddLink(link.InputIdx, link.InputSlot, link.OutputIdx, link.OutputSlot); - NodeGraphUpdateEvaluationOrder(controler); - }; - - size_t metaNodeCount = gMetaNodes.size(); - const MetaNode* metaNodes = gMetaNodes.data(); - ImGuiIO& io = ImGui::GetIO(); - Node* node = &nodes[nodeIndex]; - - // draw/use inputs/outputs - bool hoverSlot = false; - for (int i = 0; i < 2; i++) - { - float closestDistance = FLT_MAX; - int closestConn = -1; - ImVec2 closestTextPos; - ImVec2 closestPos; - const size_t slotCount[2] = {node->InputsCount, node->OutputsCount}; - const MetaCon* con = i ? metaNodes[node->mType].mOutputs.data() : metaNodes[node->mType].mInputs.data(); - for (int slot_idx = 0; slot_idx < slotCount[i]; slot_idx++) - { - ImVec2 p = - offset + (i ? node->GetOutputSlotPos(slot_idx, factor) : node->GetInputSlotPos(slot_idx, factor)); - float distance = Distance(p, io.MousePos); - bool overCon = (nodeOperation == NO_None || nodeOperation == NO_EditingLink) && - (distance < NODE_SLOT_RADIUS * 2.f) && (distance < closestDistance); - - const char* conText = con[slot_idx].mName.c_str(); - ImVec2 textSize; - textSize = ImGui::CalcTextSize(conText); - ImVec2 textPos = - p + ImVec2(-NODE_SLOT_RADIUS * (i ? -1.f : 1.f) * (overCon ? 3.f : 2.f) - (i ? 0 : textSize.x), - -textSize.y / 2); - - ImRect nodeRect = node->GetNodeRect(factor); - if (overCon || (nodeRect.Contains(io.MousePos - offset) && closestConn == -1 && - (editingInput == (i != 0)) && nodeOperation == NO_EditingLink)) - { - closestDistance = distance; - closestConn = slot_idx; - closestTextPos = textPos; - closestPos = p; - } - - drawList->AddCircleFilled(p, NODE_SLOT_RADIUS * 1.2f, IM_COL32(0, 0, 0, 200)); - drawList->AddCircleFilled(p, NODE_SLOT_RADIUS * 0.75f * 1.2f, IM_COL32(160, 160, 160, 200)); - drawList->AddText(io.FontDefault, 14, textPos + ImVec2(2, 2), IM_COL32(0, 0, 0, 255), conText); - drawList->AddText(io.FontDefault, 14, textPos, IM_COL32(150, 150, 150, 255), conText); - } - - if (closestConn != -1) - { - const char* conText = con[closestConn].mName.c_str(); - - hoverSlot = true; - drawList->AddCircleFilled(closestPos, NODE_SLOT_RADIUS * 2.f, IM_COL32(0, 0, 0, 200)); - drawList->AddCircleFilled(closestPos, NODE_SLOT_RADIUS * 1.5f, IM_COL32(200, 200, 200, 200)); - drawList->AddText(io.FontDefault, 16, closestTextPos + ImVec2(1, 1), IM_COL32(0, 0, 0, 255), conText); - drawList->AddText(io.FontDefault, 16, closestTextPos, IM_COL32(250, 250, 250, 255), conText); - bool inputToOutput = (!editingInput && !i) || (editingInput && i); - if (nodeOperation == NO_EditingLink && !io.MouseDown[0] && !bDrawOnly) - { - if (inputToOutput) - { - // check loopback - NodeLink nl; - if (editingInput) - nl = NodeLink(nodeIndex, closestConn, editingNodeIndex, editingSlotIndex); - else - nl = NodeLink(editingNodeIndex, editingSlotIndex, nodeIndex, closestConn); - - if (RecurseIsLinked(nl.OutputIdx, nl.InputIdx)) - { - Log("Acyclic graph. Loop is not allowed.\n"); - break; - } - bool alreadyExisting = false; - for (int linkIndex = 0; linkIndex < links.size(); linkIndex++) - { - if (links[linkIndex] == nl) - { - alreadyExisting = true; - break; - } - } - - // check already connected output - for (int linkIndex = 0; linkIndex < links.size(); linkIndex++) - { - NodeLink& link = links[linkIndex]; - if (link.OutputIdx == nl.OutputIdx && link.OutputSlot == nl.OutputSlot) - { - URDel undoRedoDel(linkIndex, []() { return &links; }, deleteLink, addLink); - controler->DelLink(link.OutputIdx, link.OutputSlot); - links.erase(links.begin() + linkIndex); - NodeGraphUpdateEvaluationOrder(controler); - break; - } - } - - if (!alreadyExisting) - { - URAdd undoRedoAdd(int(links.size()), []() { return &links; }, deleteLink, addLink); - - links.push_back(nl); - controler->AddLink(nl.InputIdx, nl.InputSlot, nl.OutputIdx, nl.OutputSlot); - NodeGraphUpdateEvaluationOrder(controler); - } - } - } - // when ImGui::IsWindowHovered() && !ImGui::IsAnyItemActive() is uncommented, one can't click the node - // input/output when mouse is over the node itself. - if (nodeOperation == NO_None && - /*ImGui::IsWindowHovered() && !ImGui::IsAnyItemActive() &&*/ io.MouseClicked[0] && !bDrawOnly) - { - nodeOperation = NO_EditingLink; - editingInput = i == 0; - editingNodeSource = closestPos; - editingNodeIndex = nodeIndex; - editingSlotIndex = closestConn; - if (editingInput) - { - // remove existing link - for (int linkIndex = 0; linkIndex < links.size(); linkIndex++) - { - NodeLink& link = links[linkIndex]; - if (link.OutputIdx == nodeIndex && link.OutputSlot == closestConn) - { - URDel undoRedoDel(linkIndex, []() { return &links; }, deleteLink, addLink); - controler->DelLink(link.OutputIdx, link.OutputSlot); - links.erase(links.begin() + linkIndex); - NodeGraphUpdateEvaluationOrder(controler); - break; - } - } - } - } - } - } - return hoverSlot; -} - -static void DrawGrid(ImDrawList* drawList, ImVec2 windowPos, const ImVec2 canvasSize, const float factor) -{ - ImU32 GRID_COLOR = IM_COL32(100, 100, 100, 40); - float GRID_SZ = 64.0f * factor; - for (float x = fmodf(scrolling.x * factor, GRID_SZ); x < canvasSize.x; x += GRID_SZ) - drawList->AddLine(ImVec2(x, 0.0f) + windowPos, ImVec2(x, canvasSize.y) + windowPos, GRID_COLOR); - for (float y = fmodf(scrolling.y * factor, GRID_SZ); y < canvasSize.y; y += GRID_SZ) - drawList->AddLine(ImVec2(0.0f, y) + windowPos, ImVec2(canvasSize.x, y) + windowPos, GRID_COLOR); -} - -// return true if node is hovered -static bool DrawNode(ImDrawList* drawList, - int nodeIndex, - const ImVec2 offset, - const float factor, - NodeGraphControlerBase* controler, - bool overInput) -{ - ImGuiIO& io = ImGui::GetIO(); - const MetaNode* metaNodes = gMetaNodes.data(); - Node* node = &nodes[nodeIndex]; - ImVec2 node_rect_min = offset + node->Pos * factor; - - bool old_any_active = ImGui::IsAnyItemActive(); - ImGui::SetCursorScreenPos(node_rect_min + NODE_WINDOW_PADDING); - - const bool nodeIsCompute = controler->NodeIsCompute(nodeIndex); - if (nodeIsCompute) - ImGui::InvisibleButton("canvas", ImVec2(100, 50) * factor); - else - ImGui::InvisibleButton("canvas", ImVec2(100, 100) * factor); - bool node_moving_active = - ImGui::IsItemActive(); // must be called right after creating the control we want to be able to move - - // Save the size of what we have emitted and whether any of the widgets are being used - bool node_widgets_active = (!old_any_active && ImGui::IsAnyItemActive()); - node->Size = ImGui::GetItemRectSize() + NODE_WINDOW_PADDING + NODE_WINDOW_PADDING; - ImVec2 node_rect_max = node_rect_min + node->Size; - - // test nested IO - drawList->ChannelsSetCurrent(1); // Background - - for (int i = 0; i < 2; i++) - { - const size_t slotCount[2] = {node->InputsCount, node->OutputsCount}; - const MetaCon* con = i ? metaNodes[node->mType].mOutputs.data() : metaNodes[node->mType].mInputs.data(); - for (int slot_idx = 0; slot_idx < slotCount[i]; slot_idx++) - { - if (!controler->IsIOPinned(nodeIndex, slot_idx, i == 1)) - { - continue; - } - ImVec2 p = - offset + (i ? node->GetOutputSlotPos(slot_idx, factor) : node->GetInputSlotPos(slot_idx, factor)); - const float arc = 28.f * (float(i) * 0.3f + 1.0f) * (i ? 1.f : -1.f); - const float ofs = 0.f; - - ImVec2 pts[3] = {p + ImVec2(arc + ofs, 0.f), p + ImVec2(0.f + ofs, -arc), p + ImVec2(0.f + ofs, arc)}; - drawList->AddTriangleFilled(pts[0], pts[1], pts[2], i ? 0xFFAA5030 : 0xFF30AA50); - drawList->AddTriangle(pts[0], pts[1], pts[2], 0xFF000000, 2.f); - } - } - - - ImGui::SetCursorScreenPos(node_rect_min); - ImGui::InvisibleButton("node", node->Size); - bool nodeHovered = false; - if (ImGui::IsItemHovered() && nodeOperation == NO_None && !overInput) - { - nodeHovered = true; - } - - if (ImGui::IsWindowFocused()) - { - if (node_widgets_active || node_moving_active) - { - if (!node->mbSelected) - { - if (!io.KeyShift) - { - for (auto& selnode : nodes) - selnode.mbSelected = false; - } - node->mbSelected = true; - } - } - } - if (node_moving_active && io.MouseDown[0]) - { - nodeOperation = NO_MovingNodes; - } - - bool currentSelectedNode = node->mbSelected; - - ImU32 node_bg_color = nodeHovered ? IM_COL32(85, 85, 85, 255) : IM_COL32(60, 60, 60, 255); - - drawList->AddRect(node_rect_min, - node_rect_max, - currentSelectedNode ? IM_COL32(255, 130, 30, 255) : IM_COL32(100, 100, 100, 0), - 2.0f, - 15, - currentSelectedNode ? 6.f : 2.f); - - ImVec2 imgPos = node_rect_min + ImVec2(14, 25); - ImVec2 imgSize = node_rect_max + ImVec2(-5, -5) - imgPos; - float imgSizeComp = std::min(imgSize.x, imgSize.y); - - drawList->AddRectFilled(node_rect_min, node_rect_max, node_bg_color, 2.0f); - float progress = controler->NodeProgress(nodeIndex); - if (progress > FLT_EPSILON && progress < 1.f - FLT_EPSILON) - { - ImVec2 progressLineA = node_rect_max - ImVec2(node->Size.x - 2.f, 3.f); - ImVec2 progressLineB = progressLineA + ImVec2(node->Size.x - 4.f, 0.f); - drawList->AddLine(progressLineA, progressLineB, 0xFF400000, 3.f); - drawList->AddLine(progressLineA, ImLerp(progressLineA, progressLineB, progress), 0xFFFF0000, 3.f); - } - ImVec2 imgPosMax = imgPos + ImVec2(imgSizeComp, imgSizeComp); - if (!nodeIsCompute) - drawList->AddRectFilled(imgPos, imgPosMax, 0xFF000000); - - ImVec2 imageSize = controler->GetEvaluationSize(nodeIndex); - float imageRatio = 1.f; - if (imageSize.x > 0.f && imageSize.y > 0.f) - imageRatio = imageSize.y / imageSize.x; - ImVec2 quadSize = imgPosMax - imgPos; - ImVec2 marge(0.f, 0.f); - if (imageRatio > 1.f) - { - marge.x = (quadSize.x - quadSize.y / imageRatio) * 0.5f; - } - else - { - marge.y = (quadSize.y - quadSize.y * imageRatio) * 0.5f; - } - - controler->DrawNodeImage(drawList, ImRect(imgPos, imgPosMax), marge, nodeIndex); - - drawList->AddRectFilled( - node_rect_min, ImVec2(node_rect_max.x, node_rect_min.y + 20), metaNodes[node->mType].mHeaderColor, 2.0f); - drawList->PushClipRect(node_rect_min, ImVec2(node_rect_max.x, node_rect_min.y + 20), true); - drawList->AddText(node_rect_min + ImVec2(2, 2), IM_COL32(0, 0, 0, 255), metaNodes[node->mType].mName.c_str()); - drawList->PopClipRect(); - - - unsigned int stage2D = gImageCache.GetTexture("Stock/Stage2D.png"); - unsigned int stagecubemap = gImageCache.GetTexture("Stock/StageCubemap.png"); - unsigned int stageCompute = gImageCache.GetTexture("Stock/StageCompute.png"); - - ImVec2 bmpInfoPos(node_rect_max - ImVec2(26, 12)); - ImVec2 bmpInfoSize(20, 20); - if (controler->NodeIsCompute(nodeIndex)) - { - drawList->AddImageQuad((ImTextureID)(uint64_t)stageCompute, - bmpInfoPos, - bmpInfoPos + ImVec2(bmpInfoSize.x, 0.f), - bmpInfoPos + bmpInfoSize, - bmpInfoPos + ImVec2(0., bmpInfoSize.y)); - } - else if (controler->NodeIs2D(nodeIndex)) - { - drawList->AddImageQuad((ImTextureID)(uint64_t)stage2D, - bmpInfoPos, - bmpInfoPos + ImVec2(bmpInfoSize.x, 0.f), - bmpInfoPos + bmpInfoSize, - bmpInfoPos + ImVec2(0., bmpInfoSize.y)); - } - else if (controler->NodeIsCubemap(nodeIndex)) - { - drawList->AddImageQuad((ImTextureID)(uint64_t)stagecubemap, - bmpInfoPos + ImVec2(0., bmpInfoSize.y), - bmpInfoPos + bmpInfoSize, - bmpInfoPos + ImVec2(bmpInfoSize.x, 0.f), - bmpInfoPos); - } - return nodeHovered; -} - -void ComputeDelegateSelection(NodeGraphControlerBase* controler) -{ - // only one selection allowed for delegate - controler->mSelectedNodeIndex = -1; - for (auto& node : nodes) - { - if (node.mbSelected) - { - if (controler->mSelectedNodeIndex == -1) - { - controler->mSelectedNodeIndex = int(&node - nodes.data()); - } - else - { - controler->mSelectedNodeIndex = -1; - return; - } - } - } -} - -void NodeGraphSelectNode(int selectedNodeIndex) -{ - for (size_t i = 0; i < nodes.size(); i++) - { - nodes[i].mbSelected = selectedNodeIndex == i; - } -} - -void NodeGraph(NodeGraphControlerBase* controler, bool enabled) -{ - ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.f); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 0.f)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.f); - - const ImVec2 windowPos = ImGui::GetCursorScreenPos(); - const ImVec2 canvasSize = ImGui::GetWindowSize(); - const ImVec2 scrollRegionLocalPos(0, 50); - - ImRect regionRect(windowPos, windowPos + canvasSize); - - HandleZoomScroll(regionRect); - ImVec2 offset = ImGui::GetCursorScreenPos() + scrolling * factor; - captureOffset = scrollRegionLocalPos + scrolling * factor + ImVec2(10.f, 0.f); - - { - ImGui::BeginChild("rugs_region", ImVec2(0, 0), true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove); - ImDrawList* drawList = ImGui::GetWindowDrawList(); - - editRug = DisplayRugs(editRug, drawList, offset, factor); - - ImGui::EndChild(); - } - - ImGui::SetCursorPos(windowPos); - ImGui::BeginGroup(); - - - ImGuiIO& io = ImGui::GetIO(); - - // Create our child canvas - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1, 1)); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); - ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(30, 30, 30, 200)); - - ImGui::SetCursorPos(scrollRegionLocalPos); - ImGui::BeginChild("scrolling_region", - ImVec2(0, 0), - true, - ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground); - ImGui::PushItemWidth(120.0f); - - ImDrawList* drawList = ImGui::GetWindowDrawList(); - - // Background or Display grid - if (!controler->RenderBackground()) - { - DrawGrid(drawList, windowPos, canvasSize, factor); - } - - bool openContextMenu = false; - - if (!enabled) - goto nodeGraphExit; - - static int hoveredNode = -1; - // Display links - drawList->ChannelsSplit(3); - drawList->ChannelsSetCurrent(1); // Background - DisplayLinks(drawList, offset, factor, regionRect, hoveredNode); - - // edit node link - if (nodeOperation == NO_EditingLink) - { - ImVec2 p1 = editingNodeSource; - ImVec2 p2 = io.MousePos; - drawList->AddLine(p1, p2, IM_COL32(200, 200, 200, 255), 3.0f); - } - - // Display nodes - drawList->PushClipRect(regionRect.Min, regionRect.Max, true); - hoveredNode = -1; - for (int i = 0; i < 2; i++) - { - for (int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) - { - Node* node = &nodes[nodeIndex]; - if (node->mbSelected != (i != 0)) - continue; - - // node view clipping - ImRect nodeRect = node->GetNodeRect(factor); - nodeRect.Min += offset; - nodeRect.Max += offset; - if (!regionRect.Overlaps(nodeRect)) - continue; - - ImGui::PushID(nodeIndex); - - // Display node contents first - // drawList->ChannelsSetCurrent(i+1); // channel 2 = Foreground channel 1 = background - - bool overInput = HandleConnections(drawList, nodeIndex, offset, factor, controler, false); - - if (DrawNode(drawList, nodeIndex, offset, factor, controler, overInput)) - hoveredNode = nodeIndex; - - HandleConnections(drawList, nodeIndex, offset, factor, controler, true); - - ImGui::PopID(); - } - } - drawList->PopClipRect(); - - if (nodeOperation == NO_MovingNodes) - { - for (auto& node : nodes) - { - if (!node.mbSelected) - continue; - node.Pos += io.MouseDelta / factor; - } - } - - // rugs - drawList->ChannelsSetCurrent(0); - - - // quad selection - HandleQuadSelection(drawList, offset, factor, regionRect); - - drawList->ChannelsMerge(); - - if (editRug) - { - if (EditRug(editRug, drawList, offset, factor)) - editRug = NULL; - } - - // releasing mouse button means it's done in any operation - if (nodeOperation == NO_PanView) - { - if (!io.MouseDown[2]) - { - nodeOperation = NO_None; - } - } - else if (nodeOperation != NO_None && !io.MouseDown[0]) - { - nodeOperation = NO_None; - } - - // Open context menu - - static int contextMenuHoverNode = -1; - if (nodeOperation == NO_None && regionRect.Contains(io.MousePos) && - (ImGui::IsMouseClicked(1) || (ImGui::IsWindowFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Tab)))) - { - openContextMenu = true; - contextMenuHoverNode = hoveredNode; - } - - if (openContextMenu) - ImGui::OpenPopup("context_menu"); - ContextMenu(offset, contextMenuHoverNode, controler); - - // Scrolling - if (ImGui::IsWindowHovered() && !ImGui::IsAnyItemActive() && io.MouseClicked[2] && nodeOperation == NO_None) - { - nodeOperation = NO_PanView; - } - if (nodeOperation == NO_PanView) - { - scrolling += io.MouseDelta / factor; - } - -nodeGraphExit:; - ImGui::PopItemWidth(); - ImGui::EndChild(); - ImGui::PopStyleColor(1); - ImGui::PopStyleVar(2); - - ComputeDelegateSelection(controler); - - ImGui::EndGroup(); - ImGui::PopStyleVar(3); -} - - -struct NodePosition -{ - int mLayer; - int mStackIndex; -}; - -void RecurseNodeGraphLayout(std::vector& positions, - std::map& stacks, - const std::vector& links, - size_t currentIndex, - int currentLayer) -{ - if (positions[currentIndex].mLayer == -1) - { - positions[currentIndex].mLayer = currentLayer; - int layer = positions[currentIndex].mLayer = currentLayer; - if (stacks.find(layer) != stacks.end()) - stacks[layer]++; - else - stacks[layer] = 0; - positions[currentIndex].mStackIndex = stacks[currentLayer]; - } - else - { - // already hooked node - if (currentLayer > positions[currentIndex].mLayer) - { - // remove stack at current pos - int currentStack = positions[currentIndex].mStackIndex; - for (auto& pos : positions) - { - if (pos.mLayer == positions[currentIndex].mLayer && pos.mStackIndex > currentStack) - { - pos.mStackIndex--; - stacks[pos.mLayer]--; - } - } - // apply new one - int layer = positions[currentIndex].mLayer = currentLayer; - if (stacks.find(layer) != stacks.end()) - stacks[layer]++; - else - stacks[layer] = 0; - positions[currentIndex].mStackIndex = stacks[currentLayer]; - } - } - - std::vector inputNodes(nodes[currentIndex].InputsCount, -1); - for (auto& link : links) - { - if (link.OutputIdx != currentIndex) - continue; - inputNodes[link.OutputSlot] = link.InputIdx; - } - for (auto inputNode : inputNodes) - { - if (inputNode == -1) - continue; - RecurseNodeGraphLayout(positions, stacks, links, inputNode, currentLayer + 1); - } -} - -void NodeGraphLayout() -{ - URDummy dummy; - std::vector nodeOrderList(mOrders.size()); - - // get stack/layer pos - std::vector nodePositions(nodes.size(), {-1, -1}); - std::map stacks; - ImRect sourceRect, destRect; - std::vector*> undos(nodes.size()); - - // compute source bounds - for (unsigned int i = 0; i < nodes.size(); i++) - { - const Node& node = nodes[i]; - sourceRect.Add(ImRect(node.Pos, node.Pos + node.Size)); - undos[i] = new URChange(i, [](int index) { return &nodes[index]; }, [](int) {}); - } - - for (unsigned int i = 0; i < nodes.size(); i++) - { - size_t nodeIndex = mOrders[nodes.size() - i - 1].mNodeIndex; - RecurseNodeGraphLayout(nodePositions, stacks, links, nodeIndex, 0); - } - - // set x,y position from layer/stack - for (unsigned int i = 0; i < nodes.size(); i++) - { - size_t nodeIndex = mOrders[i].mNodeIndex; - auto& layout = nodePositions[nodeIndex]; - nodes[nodeIndex].Pos = ImVec2(-layout.mLayer * 180.f, layout.mStackIndex * 140.f); - } - - // new bounds - for (auto& node : nodes) - { - destRect.Add(ImRect(node.Pos, node.Pos + node.Size)); - } - - // move all nodes - ImVec2 offset = sourceRect.GetCenter() - destRect.GetCenter(); - for (auto& node : nodes) - { - node.Pos += offset; - } - - // finish undo - for (auto& undo : undos) - { - delete undo; - } -} - -ImRect DisplayRectMargin(ImRect rect) -{ - // margins - static const float margin = 10.f; - rect.Min += captureOffset; - rect.Max += captureOffset; - rect.Min -= ImVec2(margin, margin); - rect.Max += ImVec2(margin, margin); - return rect; -} - -ImRect GetNodesDisplayRect() -{ - ImRect rect(ImVec2(0.f, 0.f), ImVec2(0.f, 0.f)); - for (auto& node : nodes) - { - rect.Add(ImRect(node.Pos, node.Pos + node.Size)); - } - - return DisplayRectMargin(rect); -} - -ImRect GetFinalNodeDisplayRect() -{ - NodeGraphUpdateEvaluationOrder(nullptr); - ImRect rect(ImVec2(0.f, 0.f), ImVec2(0.f, 0.f)); - if (!mOrders.empty() && !nodes.empty()) - { - auto& node = nodes[mOrders.back().mNodeIndex]; - rect = ImRect(node.Pos, node.Pos + node.Size); - } - return DisplayRectMargin(rect); -} - -bool IsIOUsed(int nodeIndex, int slotIndex, bool forOutput) -{ - for (auto& link : links) - { - if ((link.InputIdx == nodeIndex && link.InputSlot == slotIndex && forOutput) || - (link.OutputIdx == nodeIndex && link.OutputSlot == slotIndex && !forOutput)) - { - return true; - } - } - return false; -} \ No newline at end of file diff --git a/src/NodeGraph.h b/src/NodeGraph.h deleted file mode 100644 index 2cee98f2..00000000 --- a/src/NodeGraph.h +++ /dev/null @@ -1,190 +0,0 @@ -// https://github.com/CedricGuillemet/Imogen -// -// The MIT License(MIT) -// -// Copyright(c) 2019 Cedric Guillemet -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -#pragma once -#include -#include -#include -#include "imgui.h" -#include "imgui_internal.h" - -struct NodeGraphControlerBase -{ - NodeGraphControlerBase() : mSelectedNodeIndex(-1), mCategories(nullptr) - { - } - - int mSelectedNodeIndex; - const std::vector* mCategories; - - virtual void UpdateEvaluationList(const std::vector nodeOrderList) = 0; - virtual void AddLink(int InputIdx, int InputSlot, int OutputIdx, int OutputSlot) = 0; - virtual void DelLink(int index, int slot) = 0; - virtual unsigned int GetNodeTexture(size_t index) = 0; - // A new node has been added in the graph. Do a push_back on your node array - // add node for batch(loading graph) - virtual void AddSingleNode(size_t type) = 0; - // add by user interface - virtual void UserAddNode(size_t type) = 0; - // node deleted - virtual void UserDeleteNode(size_t index) = 0; - virtual ImVec2 GetEvaluationSize(size_t index) const = 0; - - virtual void SetParamBlock(size_t index, const std::vector& paramBlock) = 0; - virtual void SetTimeSlot(size_t index, int frameStart, int frameEnd) = 0; - virtual bool NodeHasUI(size_t nodeIndex) const = 0; - virtual int NodeIsProcesing(size_t nodeIndex) const = 0; - virtual float NodeProgress(size_t nodeIndex) const = 0; - virtual bool NodeIsCubemap(size_t nodeIndex) const = 0; - virtual bool NodeIs2D(size_t nodeIndex) const = 0; - virtual bool NodeIsCompute(size_t nodeIndex) const = 0; - virtual void DrawNodeImage(ImDrawList* drawList, const ImRect& rc, const ImVec2 marge, const size_t nodeIndex) = 0; - // return false if background must be rendered by node graph - virtual bool RenderBackground() = 0; - - // clipboard - virtual void CopyNodes(const std::vector nodes) = 0; - virtual void CutNodes(const std::vector nodes) = 0; - virtual void PasteNodes() = 0; - virtual bool IsIOPinned(size_t nodeIndex, size_t io, bool forOutput) const = 0; -}; - -struct Node -{ - int mType; - ImVec2 Pos, Size; - size_t InputsCount, OutputsCount; - bool mbSelected; - Node() : mbSelected(false) - { - } - Node(int type, const ImVec2& pos); - - ImVec2 GetInputSlotPos(int slot_no, float factor) const - { - return ImVec2(Pos.x * factor, Pos.y * factor + Size.y * ((float)slot_no + 1) / ((float)InputsCount + 1)); - } - ImVec2 GetOutputSlotPos(int slot_no, float factor) const - { - return ImVec2(Pos.x * factor + Size.x, - Pos.y * factor + Size.y * ((float)slot_no + 1) / ((float)OutputsCount + 1)); - } - ImRect GetNodeRect(float factor) - { - return ImRect(Pos * factor, Pos * factor + Size); - } - - bool operator!=(const Node& other) const - { - if (mType != other.mType) - return true; - if (InputsCount != other.InputsCount) - return true; - if (OutputsCount != other.OutputsCount) - return true; - if (Pos.x != other.Pos.x) - return true; - if (Pos.y != other.Pos.y) - return true; - - if (Size.x != other.Size.x) - return true; - if (Size.y != other.Size.y) - return true; - - return false; - } -}; - -struct NodeLink -{ - int InputIdx, InputSlot, OutputIdx, OutputSlot; - NodeLink() - { - } - NodeLink(int input_idx, int input_slot, int output_idx, int output_slot) - { - InputIdx = input_idx; - InputSlot = input_slot; - OutputIdx = output_idx; - OutputSlot = output_slot; - } - bool operator==(const NodeLink& other) const - { - return InputIdx == other.InputIdx && InputSlot == other.InputSlot && OutputIdx == other.OutputIdx && - OutputSlot == other.OutputSlot; - } -}; - -inline bool operator!=(const ImVec2 r1, const ImVec2 r2) -{ - if (r1.x != r2.x) - return true; - if (r1.y != r2.y) - return true; - return false; -} - -struct NodeRug -{ - ImVec2 mPos, mSize; - uint32_t mColor; - std::string mText; - - bool operator!=(const NodeRug& other) const - { - if (mPos != other.mPos) - return true; - if (mSize != other.mSize) - return false; - if (mColor != other.mColor) - return true; - if (mText != other.mText) - return true; - return false; - } -}; - -void NodeGraph(NodeGraphControlerBase* delegate, bool enabled); -void NodeGraphClear(); // delegate is not called -const std::vector& NodeGraphGetLinks(); -const std::vector& NodeGraphRugs(); -ImVec2 NodeGraphGetNodePos(size_t index); - -size_t NodeGraphAddNode(NodeGraphControlerBase* delegate, - int type, - const std::vector* parameters, - int posx, - int posy, - int frameStart, - int frameEnd); -void NodeGraphAddRug( - int32_t posX, int32_t posY, int32_t sizeX, int32_t sizeY, uint32_t color, const std::string comment); -void NodeGraphAddLink(NodeGraphControlerBase* delegate, int InputIdx, int InputSlot, int OutputIdx, int OutputSlot); -void NodeGraphUpdateEvaluationOrder(NodeGraphControlerBase* delegate); -void NodeGraphUpdateScrolling(); -void NodeGraphSelectNode(int selectedNodeIndex); -void NodeGraphLayout(); -bool IsIOUsed(int nodeIndex, int slotIndex, bool forOutput); \ No newline at end of file diff --git a/src/NodeGraphControler.cpp b/src/NodeGraphControler.cpp deleted file mode 100644 index dc9884f9..00000000 --- a/src/NodeGraphControler.cpp +++ /dev/null @@ -1,856 +0,0 @@ -// https://github.com/CedricGuillemet/Imogen -// -// The MIT License(MIT) -// -// Copyright(c) 2019 Cedric Guillemet -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -#include "Platform.h" -#include "NodeGraphControler.h" -#include "EvaluationStages.h" -#include "Library.h" -#include "EvaluationContext.h" -#include "Evaluators.h" -#include "UI.h" -#include "Utils.h" - -NodeGraphControler::NodeGraphControler() - : mbMouseDragging(false), mEditingContext(mEvaluationStages, false, 1024, 1024), mUndoRedoParamSetMouse(nullptr) -{ - mCategories = &MetaNode::mCategories; -} - -void NodeGraphControler::Clear() -{ - mSelectedNodeIndex = -1; - mBackgroundNode = -1; - mEvaluationStages.Clear(); - mEvaluationStages.mStages.clear(); - mEditingContext.Clear(); -} - -void NodeGraphControler::SetParamBlock(size_t index, const std::vector& parameters) -{ - auto& stage = mEvaluationStages.mStages[index]; - stage.mParameters = parameters; - mEvaluationStages.SetEvaluationParameters(index, parameters); - mEvaluationStages.SetEvaluationSampler(index, stage.mInputSamplers); - mEditingContext.SetTargetDirty(index, Dirty::Parameter); -} - -void NodeGraphControler::NodeIsAdded(int index) -{ - auto& stage = mEvaluationStages.mStages[index]; - mEvaluationStages.SetEvaluationParameters(index, stage.mParameters); - mEvaluationStages.SetEvaluationSampler(index, stage.mInputSamplers); - mEditingContext.SetTargetDirty(index, Dirty::Input); -}; - -void NodeGraphControler::AddSingleNode(size_t type) -{ - mEvaluationStages.AddSingleEvaluation(type); - NodeIsAdded(int(mEvaluationStages.mStages.size()) - 1); -} - -void NodeGraphControler::UserAddNode(size_t type) -{ - URAdd undoRedoAddNode(int(mEvaluationStages.mStages.size()), - [&]() { return &mEvaluationStages.mStages; }, - [](int) {}, - [&](int index) { NodeIsAdded(index); }); - - mEditingContext.UserAddStage(); - AddSingleNode(type); -} - -void NodeGraphControler::UserDeleteNode(size_t index) -{ - URDummy urdummy; - mEvaluationStages.RemoveAnimation(index); - mEvaluationStages.RemovePins(index); - mEditingContext.UserDeleteStage(index); - mEvaluationStages.UserDeleteEvaluation(index); - if (mBackgroundNode == int(index)) - { - mBackgroundNode = -1; - } - else if (mBackgroundNode > int(index)) - { - mBackgroundNode--; - } -} - -void NodeGraphControler::HandlePin(uint32_t parameterPair) -{ - auto pinIter = std::find( - mEvaluationStages.mPinnedParameters.begin(), mEvaluationStages.mPinnedParameters.end(), parameterPair); - bool hasPin = pinIter != mEvaluationStages.mPinnedParameters.end(); - bool checked = hasPin; - if (ImGui::Checkbox("", &checked)) - { - if (hasPin) - { - URDel undoRedoDelPin(int(&(*pinIter) - mEvaluationStages.mPinnedParameters.data()), - [&]() { return &mEvaluationStages.mPinnedParameters; }); - mEvaluationStages.mPinnedParameters.erase(pinIter); - } - else - { - URAdd undoRedoAddNode(int(mEvaluationStages.mPinnedParameters.size()), - [&]() { return &mEvaluationStages.mPinnedParameters; }); - mEvaluationStages.mPinnedParameters.push_back(parameterPair); - } - } -} - -bool NodeGraphControler::EditSingleParameter(unsigned int nodeIndex, - unsigned int parameterIndex, - void* paramBuffer, - const MetaParameter& param) -{ - bool dirty = false; - uint32_t parameterPair = (uint32_t(nodeIndex) << 16) + parameterIndex; - ImGui::PushID(parameterPair * 4); - HandlePin(parameterPair); - ImGui::SameLine(); - switch (param.mType) - { - case Con_Float: - dirty |= ImGui::InputFloat(param.mName.c_str(), (float*)paramBuffer); - break; - case Con_Float2: - dirty |= ImGui::InputFloat2(param.mName.c_str(), (float*)paramBuffer); - break; - case Con_Float3: - dirty |= ImGui::InputFloat3(param.mName.c_str(), (float*)paramBuffer); - break; - case Con_Float4: - dirty |= ImGui::InputFloat4(param.mName.c_str(), (float*)paramBuffer); - break; - case Con_Color4: - dirty |= ImGui::ColorPicker4(param.mName.c_str(), (float*)paramBuffer); - break; - case Con_Int: - dirty |= ImGui::InputInt(param.mName.c_str(), (int*)paramBuffer); - break; - case Con_Int2: - dirty |= ImGui::InputInt2(param.mName.c_str(), (int*)paramBuffer); - break; - case Con_Ramp: - { - RampEdit curveEditDelegate; - curveEditDelegate.mPointCount = 0; - for (int k = 0; k < 8; k++) - { - curveEditDelegate.mPts[k] = ImVec2(((float*)paramBuffer)[k * 2], ((float*)paramBuffer)[k * 2 + 1]); - if (k && curveEditDelegate.mPts[k - 1].x > curveEditDelegate.mPts[k].x) - break; - curveEditDelegate.mPointCount++; - } - float regionWidth = ImGui::GetWindowContentRegionWidth(); - if (ImCurveEdit::Edit(curveEditDelegate, ImVec2(regionWidth, regionWidth), 974)) - { - for (size_t k = 0; k < curveEditDelegate.mPointCount; k++) - { - ((float*)paramBuffer)[k * 2] = curveEditDelegate.mPts[k].x; - ((float*)paramBuffer)[k * 2 + 1] = curveEditDelegate.mPts[k].y; - } - ((float*)paramBuffer)[0] = 0.f; - ((float*)paramBuffer)[(curveEditDelegate.mPointCount - 1) * 2] = 1.f; - for (size_t k = curveEditDelegate.mPointCount; k < 8; k++) - { - ((float*)paramBuffer)[k * 2] = -1.f; - } - dirty = true; - } - } - break; - case Con_Ramp4: - { - float regionWidth = ImGui::GetWindowContentRegionWidth(); - GradientEdit gradientDelegate; - - gradientDelegate.mPointCount = 0; - - for (int k = 0; k < 8; k++) - { - gradientDelegate.mPts[k] = ((ImVec4*)paramBuffer)[k]; - if (k && gradientDelegate.mPts[k - 1].w > gradientDelegate.mPts[k].w) - break; - gradientDelegate.mPointCount++; - } - - int colorIndex; - dirty |= ImGradient::Edit(gradientDelegate, ImVec2(regionWidth, 22), colorIndex); - if (colorIndex != -1) - { - dirty |= ImGui::ColorPicker3("", &gradientDelegate.mPts[colorIndex].x); - } - if (dirty) - { - for (size_t k = 0; k < gradientDelegate.mPointCount; k++) - { - ((ImVec4*)paramBuffer)[k] = gradientDelegate.mPts[k]; - } - ((ImVec4*)paramBuffer)[0].w = 0.f; - ((ImVec4*)paramBuffer)[gradientDelegate.mPointCount - 1].w = 1.f; - for (size_t k = gradientDelegate.mPointCount; k < 8; k++) - { - ((ImVec4*)paramBuffer)[k].w = -1.f; - } - } - } - break; - case Con_Angle: - ((float*)paramBuffer)[0] = RadToDeg(((float*)paramBuffer)[0]); - dirty |= ImGui::InputFloat(param.mName.c_str(), (float*)paramBuffer); - ((float*)paramBuffer)[0] = DegToRad(((float*)paramBuffer)[0]); - break; - case Con_Angle2: - ((float*)paramBuffer)[0] = RadToDeg(((float*)paramBuffer)[0]); - ((float*)paramBuffer)[1] = RadToDeg(((float*)paramBuffer)[1]); - dirty |= ImGui::InputFloat2(param.mName.c_str(), (float*)paramBuffer); - ((float*)paramBuffer)[0] = DegToRad(((float*)paramBuffer)[0]); - ((float*)paramBuffer)[1] = DegToRad(((float*)paramBuffer)[1]); - break; - case Con_Angle3: - ((float*)paramBuffer)[0] = RadToDeg(((float*)paramBuffer)[0]); - ((float*)paramBuffer)[1] = RadToDeg(((float*)paramBuffer)[1]); - ((float*)paramBuffer)[2] = RadToDeg(((float*)paramBuffer)[2]); - dirty |= ImGui::InputFloat3(param.mName.c_str(), (float*)paramBuffer); - ((float*)paramBuffer)[0] = DegToRad(((float*)paramBuffer)[0]); - ((float*)paramBuffer)[1] = DegToRad(((float*)paramBuffer)[1]); - ((float*)paramBuffer)[2] = DegToRad(((float*)paramBuffer)[2]); - break; - case Con_Angle4: - ((float*)paramBuffer)[0] = RadToDeg(((float*)paramBuffer)[0]); - ((float*)paramBuffer)[1] = RadToDeg(((float*)paramBuffer)[1]); - ((float*)paramBuffer)[2] = RadToDeg(((float*)paramBuffer)[2]); - ((float*)paramBuffer)[3] = RadToDeg(((float*)paramBuffer)[3]); - dirty |= ImGui::InputFloat4(param.mName.c_str(), (float*)paramBuffer); - ((float*)paramBuffer)[0] = DegToRad(((float*)paramBuffer)[0]); - ((float*)paramBuffer)[1] = DegToRad(((float*)paramBuffer)[1]); - ((float*)paramBuffer)[2] = DegToRad(((float*)paramBuffer)[2]); - ((float*)paramBuffer)[3] = DegToRad(((float*)paramBuffer)[3]); - break; - case Con_FilenameWrite: - case Con_FilenameRead: - ImGui::PushID(parameterPair * 4 + 1); - dirty |= ImGui::InputText("", (char*)paramBuffer, 1024); - ImGui::SameLine(); - if (ImGui::Button("...")) - { - #ifdef NFD_OpenDialog - nfdchar_t* outPath = NULL; - nfdresult_t result = (param.mType == Con_FilenameRead) ? NFD_OpenDialog(NULL, NULL, &outPath) - : NFD_SaveDialog(NULL, NULL, &outPath); - - if (result == NFD_OKAY) - { - strcpy((char*)paramBuffer, outPath); - free(outPath); - dirty = true; - } - #endif - } - ImGui::PopID(); - ImGui::SameLine(); - ImGui::Text(param.mName.c_str()); - break; - case Con_Enum: - { - std::string cbString = param.mEnumList; - for (auto& c : cbString) - { - if (c == '|') - c = '\0'; - } - dirty |= ImGui::Combo(param.mName.c_str(), (int*)paramBuffer, cbString.c_str()); - } - break; - case Con_ForceEvaluate: - if (ImGui::Button(param.mName.c_str())) - { - EvaluationInfo evaluationInfo; - evaluationInfo.forcedDirty = 1; - evaluationInfo.uiPass = 0; - mEditingContext.RunSingle(nodeIndex, evaluationInfo); - } - break; - case Con_Bool: - { - bool checked = (*(int*)paramBuffer) != 0; - if (ImGui::Checkbox(param.mName.c_str(), &checked)) - { - *(int*)paramBuffer = checked ? 1 : 0; - dirty = true; - } - } - break; - case Con_Camera: - if (ImGui::Button("Reset")) - { - Camera* cam = (Camera*)paramBuffer; - cam->mPosition = Vec4(0.f, 0.f, 0.f); - cam->mDirection = Vec4(0.f, 0.f, 1.f); - cam->mUp = Vec4(0.f, 1.f, 0.f); - } - break; - } - ImGui::PopID(); - return dirty; -} - -void NodeGraphControler::UpdateDirtyParameter(int index) -{ - auto& stage = mEvaluationStages.mStages[index]; - mEvaluationStages.SetEvaluationParameters(index, stage.mParameters); - mEditingContext.SetTargetDirty(index, Dirty::Parameter); -} - -void NodeGraphControler::PinnedEdit() -{ - int dirtyNode = -1; - for (const auto pin : mEvaluationStages.mPinnedParameters) - { - unsigned int nodeIndex = (pin >> 16) & 0xFFFF; - unsigned int parameterIndex = pin & 0xFFFF; - - size_t nodeType = mEvaluationStages.mStages[nodeIndex].mType; - const MetaNode& metaNode = gMetaNodes[nodeType]; - if (parameterIndex >= metaNode.mParams.size()) - continue; - - ImGui::PushID(171717 + pin); - const MetaParameter& metaParam = metaNode.mParams[parameterIndex]; - unsigned char* paramBuffer = mEvaluationStages.mStages[nodeIndex].mParameters.data(); - paramBuffer += GetParameterOffset(uint32_t(nodeType), parameterIndex); - if (EditSingleParameter(nodeIndex, parameterIndex, paramBuffer, metaParam)) - dirtyNode = nodeIndex; - - ImGui::PopID(); - } - if (dirtyNode != -1) - { - UpdateDirtyParameter(dirtyNode); - } -} - -void NodeGraphControler::EditNodeParameters() -{ - size_t index = mSelectedNodeIndex; - - const MetaNode* metaNodes = gMetaNodes.data(); - bool dirty = false; - bool forceEval = false; - bool samplerDirty = false; - auto& stage = mEvaluationStages.mStages[index]; - const MetaNode& currentMeta = metaNodes[stage.mType]; - - if (ImGui::CollapsingHeader("Samplers", 0)) - { - URChange> undoRedoSampler(int(index), - [&](int index) { return &stage.mInputSamplers; }, - [&](int index) { - auto& node = mEvaluationStages.mStages[index]; - mEvaluationStages.SetEvaluationSampler( - index, stage.mInputSamplers); - mEditingContext.SetTargetDirty(index, Dirty::Sampler); - }); - - for (size_t i = 0; i < stage.mInputSamplers.size(); i++) - { - InputSampler& inputSampler = stage.mInputSamplers[i]; - static const char* wrapModes = {"REPEAT\0EDGE\0BORDER\0MIRROR"}; - static const char* filterModes = {"LINEAR\0NEAREST"}; - ImGui::PushItemWidth(80); - ImGui::PushID(int(99 + i)); - HandlePinIO(index, i, false); - ImGui::SameLine(); - ImGui::Text("Sampler %d", i); - samplerDirty |= ImGui::Combo("U", (int*)&inputSampler.mWrapU, wrapModes); - ImGui::SameLine(); - samplerDirty |= ImGui::Combo("V", (int*)&inputSampler.mWrapV, wrapModes); - ImGui::SameLine(); - ImGui::PushItemWidth(80); - samplerDirty |= ImGui::Combo("Min", (int*)&inputSampler.mFilterMin, filterModes); - ImGui::SameLine(); - samplerDirty |= ImGui::Combo("Mag", (int*)&inputSampler.mFilterMag, filterModes); - ImGui::PopItemWidth(); - ImGui::PopID(); - ImGui::PopItemWidth(); - } - if (samplerDirty) - { - mEvaluationStages.SetEvaluationSampler(index, stage.mInputSamplers); - mEditingContext.SetTargetDirty(index, Dirty::Sampler); - } - else - { - undoRedoSampler.Discard(); - } - } - if (!ImGui::CollapsingHeader(currentMeta.mName.c_str(), 0, ImGuiTreeNodeFlags_DefaultOpen)) - return; - - URChange> undoRedoParameter( - int(index), - [&](int index) { return &mEvaluationStages.mStages[index].mParameters; }, - [&](int index) { UpdateDirtyParameter(index); }); - - unsigned char* paramBuffer = stage.mParameters.data(); - int i = 0; - for (const MetaParameter& param : currentMeta.mParams) - { - ImGui::PushID(667889 + i); - - dirty |= EditSingleParameter((unsigned int)(index), i, paramBuffer, param); - - ImGui::PopID(); - paramBuffer += GetParameterTypeSize(param.mType); - i++; - } - - if (dirty) - { - UpdateDirtyParameter(int(index)); - } - else - { - undoRedoParameter.Discard(); - } -} - -void NodeGraphControler::HandlePinIO(size_t nodeIndex, size_t slotIndex, bool forOutput) -{ - if (IsIOUsed(int(nodeIndex), int(slotIndex), forOutput)) - { - return; - } - ImGui::PushID(int(nodeIndex * 256 + slotIndex * 2 + (forOutput ? 1 : 0))); - bool pinned = IsIOPinned(nodeIndex, slotIndex, forOutput); - ImGui::Checkbox("", &pinned); - mEvaluationStages.SetIOPin(nodeIndex, slotIndex, forOutput, pinned); - ImGui::PopID(); -} - -void NodeGraphControler::NodeEdit() -{ - ImGuiIO& io = ImGui::GetIO(); - - if (mSelectedNodeIndex == -1) - { - /* - for (const auto pin : mEvaluationStages.mPinnedParameters) - { - unsigned int nodeIndex = (pin >> 16) & 0xFFFF; - unsigned int parameterIndex = pin & 0xFFFF; - if (parameterIndex != 0xDEAD) - continue; - - ImGui::PushID(1717171 + nodeIndex); - uint32_t parameterPair = (uint32_t(nodeIndex) << 16) + 0xDEAD; - HandlePin(parameterPair); - ImGui::SameLine(); - Imogen::RenderPreviewNode(nodeIndex, *this); - ImGui::PopID(); - } - */ - auto& io = mEvaluationStages.mPinnedIO; - for (size_t nodeIndex = 0; nodeIndex < io.size(); nodeIndex++) - { - if ((io[nodeIndex]&1) == 0) - { - continue; - } - ImGui::PushID(int(1717171 + nodeIndex)); - uint32_t parameterPair = (uint32_t(nodeIndex) << 16) + 0xDEAD; - HandlePinIO(nodeIndex, 0, true); - ImGui::SameLine(); - Imogen::RenderPreviewNode(int(nodeIndex), *this); - ImGui::PopID(); - } - PinnedEdit(); - } - else - { - if (ImGui::CollapsingHeader("Preview", 0, ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::PushID(1717171); - ImGui::BeginGroup(); - HandlePinIO(mSelectedNodeIndex, 0, true); - unsigned int maxiMini = gImageCache.GetTexture("Stock/MaxiMini.png"); - bool selectedNodeAsBackground = mBackgroundNode == mSelectedNodeIndex; - float ofs = selectedNodeAsBackground ? 0.5f : 0.f; - if (ImGui::ImageButton( - (ImTextureID)(uint64_t)maxiMini, ImVec2(12, 13), ImVec2(0.f + ofs, 1.f), ImVec2(0.5f + ofs, 0.f))) - { - mBackgroundNode = selectedNodeAsBackground ? -1 : mSelectedNodeIndex; - } - ImGui::EndGroup(); - ImGui::SameLine(); - Imogen::RenderPreviewNode(mSelectedNodeIndex, *this); - ImGui::PopID(); - } - - EditNodeParameters(); - } -} - -void NodeGraphControler::SetTimeSlot(size_t index, int frameStart, int frameEnd) -{ - auto& stage = mEvaluationStages.mStages[index]; - stage.mStartFrame = frameStart; - stage.mEndFrame = frameEnd; -} - -void NodeGraphControler::SetTimeDuration(size_t index, int duration) -{ - auto& stage = mEvaluationStages.mStages[index]; - stage.mEndFrame = stage.mStartFrame + duration; -} - -void NodeGraphControler::InvalidateParameters() -{ - for (size_t i = 0; i < mEvaluationStages.mStages.size(); i++) - { - auto& stage = mEvaluationStages.mStages[i]; - mEvaluationStages.SetEvaluationParameters(i, stage.mParameters); - } -} - -void NodeGraphControler::SetKeyboardMouse(float rx, - float ry, - float dx, - float dy, - bool lButDown, - bool rButDown, - float wheel, - bool bCtrl, - bool bAlt, - bool bShift) -{ - if (mSelectedNodeIndex == -1) - return; - - if (!lButDown) - mbMouseDragging = false; - - if ((!lButDown && !rButDown) && mUndoRedoParamSetMouse) - { - delete mUndoRedoParamSetMouse; - mUndoRedoParamSetMouse = nullptr; - } - if ((lButDown || rButDown) && !mUndoRedoParamSetMouse) - { - mUndoRedoParamSetMouse = new URChange>( - mSelectedNodeIndex, - [&](int index) { return &mEvaluationStages.mStages[index].mParameters; }, - [&](int index) { UpdateDirtyParameter(index); }); - } - const MetaNode* metaNodes = gMetaNodes.data(); - size_t res = 0; - const MetaNode& metaNode = metaNodes[mEvaluationStages.mStages[mSelectedNodeIndex].mType]; - - unsigned char* paramBuffer = mEvaluationStages.mStages[mSelectedNodeIndex].mParameters.data(); - bool parametersUseMouse = false; - - // camera handling - for (auto& param : metaNode.mParams) - { - float* paramFlt = (float*)paramBuffer; - if (param.mType == Con_Camera) - { - Camera* cam = (Camera*)paramBuffer; - cam->mPosition += cam->mDirection * wheel; - Vec4 right = Cross(cam->mUp, cam->mDirection); - right.y = 0.f; // keep head up - right.Normalize(); - auto& io = ImGui::GetIO(); - if (io.KeyAlt) - { - if (io.MouseDown[2]) - { - cam->mPosition += (right * io.MouseDelta.x + cam->mUp * io.MouseDelta.y) * 0.01f; - } - if (io.MouseDown[1]) - { - cam->mPosition += (cam->mDirection * io.MouseDelta.y) * 0.01f; - } - if (io.MouseDown[0]) - { - Mat4x4 tr, rtUp, rtRight, trp; - tr.Translation(-(cam->mPosition)); - rtRight.RotationAxis(right, io.MouseDelta.y * 0.01f); - rtUp.RotationAxis(cam->mUp, -io.MouseDelta.x * 0.01f); - trp.Translation((cam->mPosition)); - Mat4x4 res = tr * rtRight * rtUp * trp; - cam->mPosition.TransformPoint(res); - cam->mDirection.TransformVector(res); - cam->mUp.Cross(cam->mDirection, right); - cam->mUp.Normalize(); - } - } - parametersUseMouse = true; - } - paramBuffer += GetParameterTypeSize(param.mType); - } - - // - paramBuffer = mEvaluationStages.mStages[mSelectedNodeIndex].mParameters.data(); - if (lButDown) - { - for (auto& param : metaNode.mParams) - { - float* paramFlt = (float*)paramBuffer; - if (param.mType == Con_Camera) - { - Camera* cam = (Camera*)paramBuffer; - if (cam->mDirection.LengthSq() < FLT_EPSILON) - cam->mDirection.Set(0.f, 0.f, 1.f); - cam->mPosition += cam->mDirection * wheel; - } - if (param.mbQuadSelect && param.mType == Con_Float4) - { - if (!mbMouseDragging) - { - paramFlt[2] = paramFlt[0] = rx; - paramFlt[3] = paramFlt[1] = 1.f - ry; - mbMouseDragging = true; - } - else - { - paramFlt[2] = rx; - paramFlt[3] = 1.f - ry; - } - continue; - } - - if (param.mRangeMinX != 0.f || param.mRangeMaxX != 0.f) - { - if (param.mbRelative) - { - paramFlt[0] += (param.mRangeMaxX - param.mRangeMinX) * dx; - if (param.mbLoop) - paramFlt[0] = fmodf(paramFlt[0], fabsf(param.mRangeMaxX - param.mRangeMinX)) + - min(param.mRangeMinX, param.mRangeMaxX); - } - else - { - paramFlt[0] = ImLerp(param.mRangeMinX, param.mRangeMaxX, rx); - } - } - if (param.mRangeMinY != 0.f || param.mRangeMaxY != 0.f) - { - if (param.mbRelative) - { - paramFlt[1] += (param.mRangeMaxY - param.mRangeMinY) * dy; - if (param.mbLoop) - paramFlt[1] = fmodf(paramFlt[1], fabsf(param.mRangeMaxY - param.mRangeMinY)) + - min(param.mRangeMinY, param.mRangeMaxY); - } - else - { - paramFlt[1] = ImLerp(param.mRangeMinY, param.mRangeMaxY, ry); - } - } - paramBuffer += GetParameterTypeSize(param.mType); - parametersUseMouse = true; - } - } - if (metaNode.mbHasUI || parametersUseMouse) - { - mEvaluationStages.SetKeyboardMouse(mSelectedNodeIndex, rx, ry, lButDown, rButDown, bCtrl, bAlt, bShift); - mEvaluationStages.SetEvaluationParameters(mSelectedNodeIndex, - mEvaluationStages.mStages[mSelectedNodeIndex].mParameters); - mEditingContext.SetTargetDirty(mSelectedNodeIndex, Dirty::Mouse); - } -} - -bool NodeGraphControler::NodeIs2D(size_t nodeIndex) const -{ - auto target = mEditingContext.GetRenderTarget(nodeIndex); - if (target) - return target->mImage->mNumFaces == 1; - return false; -} - -bool NodeGraphControler::NodeIsCompute(size_t nodeIndex) const -{ - /*auto buffer = mEditingContext.GetComputeBuffer(nodeIndex); - if (buffer) - return true; - return false; - */ - return (gEvaluators.GetMask(mEvaluationStages.mStages[nodeIndex].mType) & EvaluationGLSLCompute) != 0; -} - -bool NodeGraphControler::NodeIsCubemap(size_t nodeIndex) const -{ - auto target = mEditingContext.GetRenderTarget(nodeIndex); - if (target) - return target->mImage->mNumFaces == 6; - return false; -} - -ImVec2 NodeGraphControler::GetEvaluationSize(size_t nodeIndex) const -{ - int imageWidth(1), imageHeight(1); - EvaluationAPI::GetEvaluationSize(&mEditingContext, int(nodeIndex), &imageWidth, &imageHeight); - return ImVec2(float(imageWidth), float(imageHeight)); -} - -void NodeGraphControler::CopyNodes(const std::vector nodes) -{ - mStagesClipboard.clear(); - for (auto nodeIndex : nodes) - mStagesClipboard.push_back(mEvaluationStages.mStages[nodeIndex]); -} - -void NodeGraphControler::CutNodes(const std::vector nodes) -{ - mStagesClipboard.clear(); -} - -void NodeGraphControler::PasteNodes() -{ - for (auto& sourceNode : mStagesClipboard) - { - URAdd undoRedoAddNode(int(mEvaluationStages.mStages.size()), - [&]() { return &mEvaluationStages.mStages; }, - [](int) {}, - [&](int index) { NodeIsAdded(index); }); - - mEditingContext.UserAddStage(); - size_t target = mEvaluationStages.mStages.size(); - AddSingleNode(sourceNode.mType); - - auto& stage = mEvaluationStages.mStages.back(); - stage.mParameters = sourceNode.mParameters; - stage.mInputSamplers = sourceNode.mInputSamplers; - stage.mStartFrame = sourceNode.mStartFrame; - stage.mEndFrame = sourceNode.mEndFrame; - - mEvaluationStages.SetEvaluationParameters(target, stage.mParameters); - mEvaluationStages.SetEvaluationSampler(target, stage.mInputSamplers); - mEvaluationStages.SetTime(&mEditingContext, mEditingContext.GetCurrentTime(), true); - mEditingContext.SetTargetDirty(target, Dirty::All); - } -} - -// animation -AnimTrack* NodeGraphControler::GetAnimTrack(uint32_t nodeIndex, uint32_t parameterIndex) -{ - for (auto& animTrack : mEvaluationStages.mAnimTrack) - { - if (animTrack.mNodeIndex == nodeIndex && animTrack.mParamIndex == parameterIndex) - return &animTrack; - } - return NULL; -} - -void NodeGraphControler::MakeKey(int frame, uint32_t nodeIndex, uint32_t parameterIndex) -{ - if (nodeIndex == -1) - { - return; - } - URDummy urDummy; - - AnimTrack* animTrack = GetAnimTrack(nodeIndex, parameterIndex); - if (!animTrack) - { - URAdd urAdd(int(mEvaluationStages.mAnimTrack.size()), [&] { return &mEvaluationStages.mAnimTrack; }); - uint32_t parameterType = gMetaNodes[mEvaluationStages.mStages[nodeIndex].mType].mParams[parameterIndex].mType; - AnimTrack newTrack; - newTrack.mNodeIndex = nodeIndex; - newTrack.mParamIndex = parameterIndex; - newTrack.mValueType = parameterType; - newTrack.mAnimation = AllocateAnimation(parameterType); - mEvaluationStages.mAnimTrack.push_back(newTrack); - animTrack = &mEvaluationStages.mAnimTrack.back(); - } - URChange urChange(int(animTrack - mEvaluationStages.mAnimTrack.data()), - [&](int index) { return &mEvaluationStages.mAnimTrack[index]; }); - EvaluationStage& stage = mEvaluationStages.mStages[nodeIndex]; - size_t parameterOffset = GetParameterOffset(uint32_t(stage.mType), parameterIndex); - animTrack->mAnimation->SetValue(frame, &stage.mParameters[parameterOffset]); -} - -void NodeGraphControler::GetKeyedParameters(int frame, uint32_t nodeIndex, std::vector& keyed) -{ -} - -void NodeGraphControler::DrawNodeImage(ImDrawList* drawList, - const ImRect& rc, - const ImVec2 marge, - const size_t nodeIndex) -{ - if (NodeIsProcesing(nodeIndex) == 1) - { - AddUICustomDraw(drawList, rc, DrawUICallbacks::DrawUIProgress, nodeIndex, &mEditingContext); - } - else if (NodeIsCubemap(nodeIndex)) - { - AddUICustomDraw(drawList, rc, DrawUICallbacks::DrawUICubemap, nodeIndex, &mEditingContext); - } - else if (NodeIsCompute(nodeIndex)) - { - } - else - { - drawList->AddImage((ImTextureID)(int64_t)(GetNodeTexture(size_t(nodeIndex))), - rc.Min + marge, - rc.Max - marge, - ImVec2(0, 1), - ImVec2(1, 0)); - } -} - -bool NodeGraphControler::RenderBackground() -{ - if (mBackgroundNode != -1) - { - Imogen::RenderPreviewNode(mBackgroundNode, *this, true); - return true; - } - return false; -} - -void NodeGraphControler::SetParameter(int nodeIndex, - const std::string& parameterName, - const std::string& parameterValue) -{ - if (nodeIndex < 0 || nodeIndex >= mEvaluationStages.mStages.size()) - { - return; - } - size_t nodeType = mEvaluationStages.mStages[nodeIndex].mType; - int parameterIndex = GetParameterIndex(uint32_t(nodeType), parameterName.c_str()); - if (parameterIndex == -1) - { - return; - } - ConTypes parameterType = GetParameterType(uint32_t(nodeType), parameterIndex); - size_t paramOffset = GetParameterOffset(uint32_t(nodeType), parameterIndex); - ParseStringToParameter(parameterValue, parameterType, &mEvaluationStages.mStages[nodeIndex].mParameters[paramOffset]); - mEditingContext.SetTargetDirty(nodeIndex, Dirty::Parameter); -} \ No newline at end of file diff --git a/src/NodeGraphControler.h b/src/NodeGraphControler.h deleted file mode 100644 index c7b24112..00000000 --- a/src/NodeGraphControler.h +++ /dev/null @@ -1,156 +0,0 @@ -// https://github.com/CedricGuillemet/Imogen -// -// The MIT License(MIT) -// -// Copyright(c) 2019 Cedric Guillemet -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -#pragma once - -#include "NodeGraph.h" -#include "EvaluationStages.h" -#include "ImCurveEdit.h" -#include "ImGradient.h" -#include "Library.h" -#include "EvaluationContext.h" - -struct NodeGraphControler : public NodeGraphControlerBase -{ - NodeGraphControler(); - - void Clear(); - - virtual void AddSingleNode(size_t type); - virtual void UserAddNode(size_t type); - virtual void AddLink(int inputIdx, int inputSlot, int outputIdx, int outputSlot) - { - if (outputIdx >= mEvaluationStages.mStages.size()) - return; - - mEvaluationStages.AddEvaluationInput(outputIdx, outputSlot, inputIdx); - mEditingContext.SetTargetDirty(outputIdx, Dirty::Input); - mEvaluationStages.SetIOPin(inputIdx, inputSlot, true, false); - mEvaluationStages.SetIOPin(outputIdx, outputSlot, false, false); - } - virtual void DelLink(int index, int slot) - { - mEvaluationStages.DelEvaluationInput(index, slot); - mEditingContext.SetTargetDirty(index, Dirty::Input); - } - virtual void UserDeleteNode(size_t index); - virtual void SetParamBlock(size_t index, const std::vector& parameters); - - virtual unsigned int GetNodeTexture(size_t index) - { - return mEditingContext.GetEvaluationTexture(index); - } - - - virtual void SetTimeSlot(size_t index, int frameStart, int frameEnd); - void SetTimeDuration(size_t index, int duration); - - void InvalidateParameters(); - - void SetKeyboardMouse(float rx, - float ry, - float dx, - float dy, - bool lButDown, - bool rButDown, - float wheel, - bool bCtrl, - bool bAlt, - bool bShift); - - bool NodeHasUI(size_t nodeIndex) const - { - if (mEvaluationStages.mStages.size() <= nodeIndex) - return false; - return gMetaNodes[mEvaluationStages.mStages[nodeIndex].mType].mbHasUI; - } - virtual int NodeIsProcesing(size_t nodeIndex) const - { - return mEditingContext.StageIsProcessing(nodeIndex); - } - virtual float NodeProgress(size_t nodeIndex) const - { - return mEditingContext.StageGetProgress(nodeIndex); - } - virtual bool NodeIsCubemap(size_t nodeIndex) const; - virtual bool NodeIs2D(size_t nodeIndex) const; - virtual bool NodeIsCompute(size_t nodeIndex) const; - virtual void UpdateEvaluationList(const std::vector nodeOrderList) - { - mEvaluationStages.SetEvaluationOrder(nodeOrderList); - } - virtual ImVec2 GetEvaluationSize(size_t nodeIndex) const; - virtual void DrawNodeImage(ImDrawList* drawList, const ImRect& rc, const ImVec2 marge, const size_t nodeIndex); - - virtual void CopyNodes(const std::vector nodes); - virtual void CutNodes(const std::vector nodes); - virtual void PasteNodes(); - - virtual bool RenderBackground(); - - virtual bool IsIOPinned(size_t nodeIndex, size_t io, bool forOutput) const - { - return mEvaluationStages.IsIOPinned(nodeIndex, io, forOutput); - } - - // animation - const std::vector& GetAnimTrack() const - { - return mEvaluationStages.GetAnimTrack(); - } - - - void MakeKey(int frame, uint32_t nodeIndex, uint32_t parameterIndex); - void GetKeyedParameters(int frame, uint32_t nodeIndex, std::vector& keyed); - - AnimTrack* GetAnimTrack(uint32_t nodeIndex, uint32_t parameterIndex); - - void PinnedEdit(); - - - EvaluationContext mEditingContext; - EvaluationStages mEvaluationStages; - std::vector mStagesClipboard; - int mBackgroundNode; - bool mbMouseDragging; - URChange>* mUndoRedoParamSetMouse; - - EvaluationStage* Get(ASyncId id) - { - return GetByAsyncId(id, mEvaluationStages.mStages); - } - void NodeEdit(); - void SetParameter(int nodeIndex, const std::string& parameterName, const std::string& parameterValue); -protected: - bool EditSingleParameter(unsigned int nodeIndex, - unsigned int parameterIndex, - void* paramBuffer, - const MetaParameter& param); - void NodeIsAdded(int index); - void UpdateDirtyParameter(int index); - void EditNodeParameters(); - void HandlePin(uint32_t parameterPair); - void HandlePinIO(size_t nodeIndex, size_t slotIndex, bool forOutput); -}; diff --git a/src/Nodes/Crop.h b/src/Nodes/Crop.h new file mode 100644 index 00000000..4729bf4a --- /dev/null +++ b/src/Nodes/Crop.h @@ -0,0 +1,60 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +struct CropBlock +{ + float quad[4]; +}; + +DECLARE_NODE(Crop) +{ + CropBlock* params = (CropBlock*)parameters; + int croppedWidth = 256; + int croppedHeight = 256; + int width, height; + const int res = GetEvaluationSize(context, int(evaluation->inputIndices[0]), &width, &height); + if (res == EVAL_OK) + { + croppedWidth = int(width * fabsf(params->quad[2] - params->quad[0])); + croppedHeight = int(height * fabsf(params->quad[3] - params->quad[1])); + croppedWidth = std::max(croppedWidth, 8); + croppedHeight = std::max(croppedHeight, 8); + } + + int target = int(evaluation->targetIndex); + SetEvaluationPersistent(context, target, 1); + /*if (evaluation->uiPass) + { + SetEvaluationSize(context, target, width, height); + } + else + */ + { + SetEvaluationSize(context, target, croppedWidth, croppedHeight); + } + + return EVAL_OK; +} + diff --git a/src/Nodes/CubeRadiance.h b/src/Nodes/CubeRadiance.h new file mode 100644 index 00000000..46ce4b5d --- /dev/null +++ b/src/Nodes/CubeRadiance.h @@ -0,0 +1,59 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +struct CubeRadianceBlock +{ + int mode; + int size; + int sampleCount; +}; + +DECLARE_NODE(CubeRadiance) +{ + CubeRadianceBlock* params = (CubeRadianceBlock*)parameters; + int size = 128 << params->size; + NodeIndex source = int(evaluation->inputIndices[0]); + int width, height; + const int res = GetEvaluationSize(context, source, &width, &height); + if (params->size == 0 && source.IsValid() && res == EVAL_OK) + { + size = width; + } + + int target = int(evaluation->targetIndex); + SetEvaluationPersistent(context, target, 1); + if (params->mode == 0) + { + // radiance + SetEvaluationCubeSize(context, target, size, 1); + } + else + { + // irradiance + SetEvaluationCubeSize(context, target, size, int(log2(size))+1); + } + return EVAL_OK; +} + diff --git a/src/Nodes/Distance.h b/src/Nodes/Distance.h new file mode 100644 index 00000000..102793a3 --- /dev/null +++ b/src/Nodes/Distance.h @@ -0,0 +1,41 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +struct DistanceBlock +{ + int passCount; +}; + +DECLARE_NODE(Distance) +{ + DistanceBlock* param = (DistanceBlock*)parameters; + const NodeIndex source = int(evaluation->inputIndices[0]); + int width, height; + const int res = GetEvaluationSize(context, source, &width, &height); + if (source.IsValid() && res == EVAL_OK) + { + param->passCount = int(log2(width))+1; + } + return EVAL_OK; +} \ No newline at end of file diff --git a/src/Nodes/EquirectConverter.h b/src/Nodes/EquirectConverter.h new file mode 100644 index 00000000..998e52e2 --- /dev/null +++ b/src/Nodes/EquirectConverter.h @@ -0,0 +1,47 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +struct EquirectConverterBlock +{ + int mode; + int size; +}; + +DECLARE_NODE(EquirectConverter) +{ + EquirectConverterBlock* param = (EquirectConverterBlock*)parameters; + const int size = 256 << param->size; + int target = int(evaluation->targetIndex); + SetEvaluationPersistent(context, target, 1); + if (param->mode == 0) + { + SetEvaluationCubeSize(context, target, size, 0); + } + else + { + SetEvaluationSize(context, target, size, size); + } + return EVAL_OK; +} diff --git a/src/Nodes/GLTFRead.h b/src/Nodes/GLTFRead.h new file mode 100644 index 00000000..b97ad0e0 --- /dev/null +++ b/src/Nodes/GLTFRead.h @@ -0,0 +1,48 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "Cam.h" + +struct GLTFReadBlock +{ + char filename[1024]; + Camera camera; +}; + +DECLARE_NODE(GLTFRead) +{ + GLTFReadBlock* params = (GLTFReadBlock*)parameters; + const NodeIndex target = int(evaluation->targetIndex); + EnableDepthBuffer(context, target, 1); + EnableFrameClear(context, target, 1); + SetVertexSpace(context, target, 1/*VertexSpace_World*/); + + if (strlen(params->filename) && strcmp(GetEvaluationSceneName(context, target), params->filename)) + { + GLTFReadAsync(context, params->filename, target); + } + + return EVAL_OK; +} \ No newline at end of file diff --git a/src/Nodes/GradientBuilder.h b/src/Nodes/GradientBuilder.h new file mode 100644 index 00000000..39c3a9a1 --- /dev/null +++ b/src/Nodes/GradientBuilder.h @@ -0,0 +1,30 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +DECLARE_NODE(GradientBuilder) +{ + SetEvaluationSize(context, int(evaluation->targetIndex), 512, 64); + return EVAL_OK; +} \ No newline at end of file diff --git a/src/Nodes/ImageRead.h b/src/Nodes/ImageRead.h new file mode 100644 index 00000000..e1c6dfa2 --- /dev/null +++ b/src/Nodes/ImageRead.h @@ -0,0 +1,72 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +struct ImageReadBlock +{ + char filename[1024]; + char XPosFilename[1024]; + char XNegFilename[1024]; + char YPosFilename[1024]; + char YNegFilename[1024]; + char ZPosFilename[1024]; + char ZNegFilename[1024]; +}; + +DECLARE_NODE(ImageRead) +{ + ImageReadBlock* params = (ImageReadBlock*)parameters; + + const char *files[] = { params->XPosFilename, params->XNegFilename, params->YPosFilename, params->YNegFilename, params->ZPosFilename, params->ZNegFilename}; + if (!(evaluation->dirtyFlag & Dirty::Parameter)) + { + return EVAL_OK; + } + + int target = int(evaluation->targetIndex); + SetEvaluationPersistent(context, target, 1); + + if (strlen(params->filename)) + { + SetProcessing(context, target, 1); + ReadImageAsync(context, params->filename, int(evaluation->targetIndex), -1); + } + else + { + for (int i = 0; i < 6; i++) + { + if (!strlen(files[i])) + { + return EVAL_OK; + } + } + SetProcessing(context, target, 1); + for (int i = 0; i < 6; i++) + { + ReadImageAsync(context, files[i], target, i); + } + } + + return EVAL_OK; +} \ No newline at end of file diff --git a/src/Nodes/ImageWrite.h b/src/Nodes/ImageWrite.h new file mode 100644 index 00000000..94930457 --- /dev/null +++ b/src/Nodes/ImageWrite.h @@ -0,0 +1,100 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +struct ImageWriteBlock +{ + char filename[1024]; + int format; + int quality; + int width; + int height; + int mode; +}; + +DECLARE_NODE(ImageWrite) +{ + ImageWriteBlock* param = (ImageWriteBlock*)parameters; + const char* stockImages[] = {"Stock/jpg-icon.png", "Stock/png-icon.png", "Stock/tga-icon.png", "Stock/bmp-icon.png", "Stock/hdr-icon.png", "Stock/dds-icon.png", "Stock/ktx-icon.png", "Stock/mp4-icon.png"}; + Image image; + const NodeIndex source = int(evaluation->inputIndices[0]); + param->width = std::max(param->width, 8); + param->height = std::max(param->height, 8); + NodeIndex target = int(evaluation->targetIndex); + + // set info stock image + if (Image::Read(stockImages[param->format], &image) == EVAL_OK) + { + if (SetEvaluationImage(context, target, &image) == EVAL_OK) + { + } + } + + if (!source.IsValid()) + { + return EVAL_OK; + } + int imageWidth, imageHeight; + int res = GetEvaluationSize(context, source, &imageWidth, &imageHeight); + if (param->mode && res == EVAL_OK) + { + const float ratio = float(imageWidth) / float(imageHeight); + if (param->mode == 1) + { + param->height = int(param->width / ratio); + } + else if (param->mode == 2) + { + param->width = int(param->height * ratio); + } + else if (param->mode == 3) + { + param->width = imageWidth; + param->height = imageHeight; + } + } + + if (!IsBuilding(context)) + { + return EVAL_OK; + } + + + if (GetEvaluationImage(context, source, &image) == EVAL_OK) + { + auto sampler = context->mEvaluationStages.mInputSamplers[target][0]; + Image::Resize(&image, param->width, param->height, sampler); + if (Image::Write(param->filename, &image, param->format, param->quality) == EVAL_OK) + { + Log("Image %s saved.\n", param->filename); + return EVAL_OK; + } + else + { + Log("Unable to write image : %s \n", param->filename); + } + } + + return EVAL_ERR; +} \ No newline at end of file diff --git a/src/Nodes/Nodes.cpp b/src/Nodes/Nodes.cpp new file mode 100644 index 00000000..c962ec92 --- /dev/null +++ b/src/Nodes/Nodes.cpp @@ -0,0 +1,58 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "Evaluators.h" +#include "EvaluationContext.h" + +using namespace EvaluationAPI; +std::map nodeFunctions; + +struct AddNodeFunction +{ + AddNodeFunction(const std::string& nodeName, NodeFunction function) + { + nodeFunctions[nodeName] = function; + } +}; + +#define DECLARE_NODE(NODE) int NODE(void *parameters, EvaluationInfo* evaluation, EvaluationContext* context); \ +AddNodeFunction add##NODE(#NODE, NODE); \ +int NODE(void *parameters, EvaluationInfo* evaluation, EvaluationContext* context) + +#include "Crop.h" +#include "CubeRadiance.h" +#include "Distance.h" +#include "EquirectConverter.h" +#include "GLTFRead.h" +#include "GradientBuilder.h" +#include "ImageRead.h" +#include "ImageWrite.h" +#include "Paint2D.h" +#include "Paint3D.h" +#include "PhysicalSky.h" +#include "ReactionDiffusion.h" +#include "SVG.h" +#include "Thumbnail.h" + diff --git a/src/Nodes/Paint2D.h b/src/Nodes/Paint2D.h new file mode 100644 index 00000000..1d91b43a --- /dev/null +++ b/src/Nodes/Paint2D.h @@ -0,0 +1,40 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +struct Paint2DBlock +{ + int size; // 1<<(size+8) +}; + +DECLARE_NODE(Paint2D) +{ + Paint2DBlock* param = (Paint2DBlock*)parameters; + const int target = int(evaluation->targetIndex); + SetEvaluationPersistent(context, target, 1); + EnableFrameClear(context, target, 0); + SetEvaluationSize(context, target, 256<< param->size, 256<< param->size); + SetBlendingMode(context, target, BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA); + return EVAL_OK; +} \ No newline at end of file diff --git a/src/Nodes/Paint3D.h b/src/Nodes/Paint3D.h new file mode 100644 index 00000000..7217031a --- /dev/null +++ b/src/Nodes/Paint3D.h @@ -0,0 +1,55 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +DECLARE_NODE(Paint3D) +{ + const int target = int(evaluation->targetIndex); + SetEvaluationPersistent(context, target, 1); + + if (evaluation->uiPass == 1) + { + SetBlendingMode(context, target, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ZERO); + OverrideInput(context, target, 0, int(evaluation->targetIndex)); + SetVertexSpace(context, target, 1/*VertexSpace_World*/); + EnableDepthBuffer(context, target, 1); + EnableFrameClear(context, target, 1); + } + else + { + SetBlendingMode(context, target, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_INV_SRC_ALPHA); + OverrideInput(context, target, 0, InvalidNodeIndex); // remove override + SetVertexSpace(context, target, 0/*VertexSpace_UV*/); + EnableDepthBuffer(context, target, 0); + EnableFrameClear(context, target, 0); + } + + // use scene from input node + void *scene; + if (GetEvaluationScene(context, int(evaluation->inputIndices[0]), &scene) == EVAL_OK) + { + SetEvaluationScene(context, target, scene); + } + return EVAL_OK; +} \ No newline at end of file diff --git a/src/Nodes/PhysicalSky.h b/src/Nodes/PhysicalSky.h new file mode 100644 index 00000000..316d202f --- /dev/null +++ b/src/Nodes/PhysicalSky.h @@ -0,0 +1,44 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +struct PhysicalSkyBlock +{ + float ambient[4]; + float lightdir[4], Kr[4]; + float rayleigh_brightness, mie_brightness, spot_brightness, scatter_strength, rayleigh_strength, mie_strength; + float rayleigh_collection_power, mie_collection_power, mie_distribution; + int size; +}; + +DECLARE_NODE(PhysicalSky) +{ + PhysicalSkyBlock* param = (PhysicalSkyBlock*)parameters; + const int size = 256 << param->size; + const int target = int(evaluation->targetIndex); + SetEvaluationPersistent(context, target, 1); + + SetEvaluationCubeSize(context, target, size, 0); + return EVAL_OK; +} diff --git a/src/Nodes/ReactionDiffusion.h b/src/Nodes/ReactionDiffusion.h new file mode 100644 index 00000000..2b10c007 --- /dev/null +++ b/src/Nodes/ReactionDiffusion.h @@ -0,0 +1,48 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +struct ReactionDiffusionBlock +{ + float boost; + float divisor; + float colorStep; + int PassCount; + int size; +}; + +DECLARE_NODE(ReactionDiffusion) +{ + ReactionDiffusionBlock* param = (ReactionDiffusionBlock*)parameters; + if (!(evaluation->dirtyFlag & Dirty::Parameter)) + { + return EVAL_OK; + } + + const int target = int(evaluation->targetIndex); + SetEvaluationPersistent(context, target, 1); + + SetEvaluationSize(context, target, 256<< param->size, 256<< param->size); + return EVAL_OK; +} \ No newline at end of file diff --git a/src/Nodes/SVG.h b/src/Nodes/SVG.h new file mode 100644 index 00000000..faae6129 --- /dev/null +++ b/src/Nodes/SVG.h @@ -0,0 +1,55 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +struct SVGParam +{ + char filename[1024]; + float dpi; +}; + +DECLARE_NODE(SVG) +{ + SVGParam* param = (SVGParam*)parameters; + Image image; + if (param->dpi <= 1.0) + { + param->dpi = 96.0; + } + if (!(evaluation->dirtyFlag & Dirty::Parameter)) + { + return EVAL_OK; + } + if (strlen(param->filename)) + { + if (Image::LoadSVG(param->filename, &image, param->dpi) == EVAL_OK) + { + const int target = int(evaluation->targetIndex); + SetEvaluationPersistent(context, target, 1); + + SetEvaluationImage(context, target, &image); + } + } + return EVAL_OK; +} \ No newline at end of file diff --git a/src/Nodes/Thumbnail.h b/src/Nodes/Thumbnail.h new file mode 100644 index 00000000..eddbf1a4 --- /dev/null +++ b/src/Nodes/Thumbnail.h @@ -0,0 +1,50 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +DECLARE_NODE(Thumbnail) +{ + Image image; + if (Image::Read("Stock/thumbnail-icon.png", &image) == EVAL_OK) + { + SetEvaluationImage(context, int(evaluation->targetIndex), &image); + } + + if (!IsBuilding(context)) + { + return EVAL_OK; + } + + if (GetEvaluationImage(context, int(evaluation->inputIndices[0]), &image) == EVAL_OK) + { + InputSampler sampler{}; + Image::Resize(&image, 256, 256, sampler); + if (SetThumbnailImage(context, &image) == EVAL_OK) + { + return EVAL_OK; + } + } + + return EVAL_ERR; +} diff --git a/src/ParameterBlock.cpp b/src/ParameterBlock.cpp new file mode 100644 index 00000000..8839a3e8 --- /dev/null +++ b/src/ParameterBlock.cpp @@ -0,0 +1,150 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include +#include +#include "ParameterBlock.h" +#include "Cam.h" +#include "Utils.h" + + +ParameterBlock& ParameterBlock::InitDefault() +{ + const MetaNode* metaNodes = gMetaNodes.data(); + const MetaNode& currentMeta = metaNodes[mNodeType]; + const size_t paramsSize = ComputeNodeParametersSize(mNodeType); + mDump.resize(paramsSize, 0); + unsigned char* paramBuffer = mDump.data(); + int i = 0; + for (const MetaParameter& param : currentMeta.mParams) + { + if (!param.mDefaultValue.empty()) + { + memcpy(paramBuffer, param.mDefaultValue.data(), param.mDefaultValue.size()); + } + + paramBuffer += GetParameterTypeSize(param.mType); + } + return *this; +} + +float ParameterBlock::GetParameterComponentValue(int parameterIndex, int componentIndex) const +{ + size_t paramOffset = GetParameterOffset(uint32_t(mNodeType), parameterIndex); + const unsigned char* ptr = &mDump.data()[paramOffset]; + const MetaNode* metaNodes = gMetaNodes.data(); + const MetaNode& currentMeta = metaNodes[mNodeType]; + switch (currentMeta.mParams[parameterIndex].mType) + { + case Con_Angle: + case Con_Float: + return ((float*)ptr)[componentIndex]; + case Con_Angle2: + case Con_Float2: + return ((float*)ptr)[componentIndex]; + case Con_Angle3: + case Con_Float3: + return ((float*)ptr)[componentIndex]; + case Con_Angle4: + case Con_Color4: + case Con_Float4: + return ((float*)ptr)[componentIndex]; + case Con_Ramp: + return 0; + case Con_Ramp4: + return 0; + case Con_Enum: + case Con_Int: + return float(((int*)ptr)[componentIndex]); + case Con_Int2: + return float(((int*)ptr)[componentIndex]); + case Con_FilenameRead: + case Con_FilenameWrite: + return 0; + case Con_ForceEvaluate: + return 0; + case Con_Bool: + return float(((bool*)ptr)[componentIndex]); + case Con_Camera: + return float((*(Camera*)ptr)[componentIndex]); + default: + return 0.f; + } +} + +template type ParameterBlock::GetParameter(const char* parameterName, type defaultValue, ConTypes parameterType) const +{ + const MetaNode& currentMeta = gMetaNodes[mNodeType]; + const unsigned char* paramBuffer = mDump.data(); + for (const MetaParameter& param : currentMeta.mParams) + { + if (param.mType == parameterType) + { + if (parameterName == nullptr || (!strcmp(param.mName.c_str(), parameterName))) + { + return *(type*)paramBuffer; + } + } + paramBuffer += GetParameterTypeSize(param.mType); + } + return defaultValue; +} + +template type* ParameterBlock::GetParameterPtr(const char* parameterName, type* defaultValue, ConTypes parameterType) const +{ + const MetaNode& currentMeta = gMetaNodes[mNodeType]; + const unsigned char* paramBuffer = mDump.data(); + for (const MetaParameter& param : currentMeta.mParams) + { + if (param.mType == parameterType) + { + if (parameterName == nullptr || (!strcmp(param.mName.c_str(), parameterName))) + { + return (type*)paramBuffer; + } + } + paramBuffer += GetParameterTypeSize(param.mType); + } + return defaultValue; +} + +int ParameterBlock::GetIntParameter(const char* parameterName, int defaultValue) const +{ + return GetParameter(parameterName, defaultValue, Con_Int); +} + +Camera* ParameterBlock::GetCamera() const +{ + return GetParameterPtr(nullptr, nullptr, Con_Camera); +} + +void* ParameterBlock::Data(size_t parameterIndex) +{ + assert(parameterIndex< gMetaNodes[mNodeType].mParams.size()); + size_t parameterOffset = GetParameterOffset(mNodeType, parameterIndex); + uint8_t* data = (uint8_t*)Data(); + data += parameterOffset; + return data; +} \ No newline at end of file diff --git a/src/ParameterBlock.h b/src/ParameterBlock.h new file mode 100644 index 00000000..67f4a608 --- /dev/null +++ b/src/ParameterBlock.h @@ -0,0 +1,61 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once + +#include +#include +#include "MetaNodes.h" + +struct Camera; + +struct ParameterBlock +{ + ParameterBlock(uint16_t nodeType) : mNodeType(nodeType) + { + } + ParameterBlock(uint16_t nodeType, const std::vector& dump) : mDump(dump), mNodeType(nodeType) + { + } + + operator const std::vector&() const { return mDump; } + + ParameterBlock& InitDefault(); + float GetParameterComponentValue(int parameterIndex, int componentIndex) const; + Camera* GetCamera() const; + int GetIntParameter(const char* parameterName, int defaultValue) const; + void *Data(size_t parameterInde); + void* Data() { return mDump.data(); } + const void* Data() const { return mDump.data(); } + +protected: + std::vector mDump; + uint16_t mNodeType; + + template type GetParameter(const char* parameterName, type defaultValue, ConTypes parameterType) const; + template type* GetParameterPtr(const char* parameterName, type* defaultValue, ConTypes parameterType) const; + +}; + diff --git a/src/Platform.h b/src/Platform.h index d925350c..f65a897a 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -25,11 +25,24 @@ #pragma once -#ifdef EMSCRIPTEN + +#ifdef __EMSCRIPTEN__ +#define BUILDTYPE " Web Edition" +#else +#define BUILDTYPE " Desktop Edition" +#endif +#define IMOGENTITLE "Imogen 0.14 " +#define IMOGENCOMPLETETITLE IMOGENTITLE BUILDTYPE + +#include +#include + +#ifdef __EMSCRIPTEN__ #include #include -#include + +#define USE_SDL 1 typedef int TaskSetPartition; struct PinnedTask @@ -63,8 +76,8 @@ struct TaskScheduler #elif WIN32 -#include -#include +#include +#include #include #include #include @@ -72,15 +85,36 @@ struct TaskScheduler #include #include #include "ffmpegCodec.h" -#include "libtcc/libtcc.h" #include "ffmpegCodec.h" #include "TaskScheduler.h" #include "nfd.h" #define USE_FFMPEG 1 #define USE_PYTHON 1 -#define USE_GLDEBUG 1 -#define USE_LIBTCC 1 +#define USE_SDL 1 + +typedef enki::IPinnedTask PinnedTask; +typedef enki::ITaskSet TaskSet; +typedef enki::TaskSetPartition TaskSetPartition; +typedef enki::TaskScheduler TaskScheduler; + +#elif __linux__ + +#include +#include +#include +#include +#include +#include "TaskScheduler.h" +#include "nfd.h" +#include +#include +#include "ffmpegCodec.h" +#include + +#define USE_FFMPEG 1 +#define USE_PYTHON 1 +#define USE_SDL 1 typedef enki::IPinnedTask PinnedTask; typedef enki::ITaskSet TaskSet; @@ -91,4 +125,4 @@ typedef enki::TaskScheduler TaskScheduler; #error unknown platform -#endif \ No newline at end of file +#endif diff --git a/src/Scene.cpp b/src/Scene.cpp new file mode 100644 index 00000000..5eb2d4b8 --- /dev/null +++ b/src/Scene.cpp @@ -0,0 +1,187 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "Platform.h" +#include "Scene.h" +#include "Evaluators.h" + +std::weak_ptr Scene::mDefaultScene; + +void Scene::Mesh::Primitive::Draw(bgfx::ViewId viewId, bgfx::ProgramHandle program) const +{ + bgfx::setIndexBuffer(mIbh); + for (auto i = 0; i < mStreams.size(); i++) + { + bgfx::setVertexBuffer(i, mStreams[i]); + } + + assert(program.idx); + bgfx::submit(viewId, program); +} + + +Scene::Mesh::Primitive::~Primitive() +{ + for (auto i = 0; i < mStreams.size(); i++) + { + bgfx::destroy(mStreams[i]); + } + if (mIbh.idx != bgfx::kInvalidHandle) + { + bgfx::destroy(mIbh); + } +} + +void Scene::Mesh::Primitive::AddBuffer(const void* data, unsigned int format, unsigned int stride, unsigned int count) +{ + mDecl.begin(); + switch (format) + { + case Format::UV: + mDecl.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float); + /*if (!bgfx::getCaps()->originBottomLeft) + { + float *pv = (float*)data; + for (unsigned int i = 0;i Scene::BuildDefaultScene() +{ + if (!mDefaultScene.expired()) + { + return mDefaultScene.lock(); + } + auto defaultScene = std::make_shared(); + defaultScene->mMeshes.resize(1); + defaultScene->mBounds.resize(1); + auto& mesh = defaultScene->mMeshes.back(); + mesh.mPrimitives.resize(1); + auto& prim = mesh.mPrimitives.back(); + static float fsUVInv[] = { 0.f, 1.f, + 1.f, 1.f, + 0.f, 0.f, + 1.f, 0.f}; + static float fsUV[] = { 0.f, 0.f, + 1.f, 0.f, + 0.f, 1.f, + 1.f, 1.f }; + static float fsPos[] = { 0.f, 0.f, 0.f, + 1.f, 0.f, 0.f, + 0.f, 1.f, 0.f, + 1.f, 1.f, 0.f }; + + float *puv = bgfx::getCaps()->originBottomLeft ? fsUVInv : fsUV; + auto& bounds = defaultScene->mBounds.back(); + bounds.AddPoint(*(Vec3*)&fsPos[0]); + bounds.AddPoint(*(Vec3*)&fsPos[1]); + bounds.AddPoint(*(Vec3*)&fsPos[2]); + static const uint16_t fsIdx[] = { 0, 1, 2, 1, 3, 2 }; + prim.AddBuffer(puv, Scene::Mesh::Format::UV, 2 * sizeof(float), 4); + prim.AddBuffer(fsPos, Scene::Mesh::Format::POS, 3 * sizeof(float), 4); + prim.AddIndexBuffer(fsIdx, 2, 6); + + // add node and transform + defaultScene->mWorldTransforms.resize(1); + defaultScene->mWorldTransforms[0].Identity(); + defaultScene->mMeshIndex.resize(1, 0); + mDefaultScene = defaultScene; + return defaultScene; +} + +Bounds Scene::ComputeBounds() const +{ + Bounds bounds; + for (unsigned int i = 0; i < mMeshIndex.size(); i++) + { + int index = mMeshIndex[i]; + if (index == -1) + { + continue; + } + bounds.AddBounds(mBounds[index], mWorldTransforms[index]); + } + return bounds; +} \ No newline at end of file diff --git a/src/Scene.h b/src/Scene.h new file mode 100644 index 00000000..4f9dbdb1 --- /dev/null +++ b/src/Scene.h @@ -0,0 +1,78 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include +#include "Utils.h" +#include "Types.h" + +struct EvaluationContext; +struct EvaluationInfo; + +struct Scene +{ + Scene() + { + } + virtual ~Scene(); + static std::shared_ptr BuildDefaultScene(); + struct Mesh + { + struct Format + { + enum + { + POS = 1 << 0, + NORM = 1 << 1, + COL = 1 << 2, + UV = 1 << 3, + }; + }; + struct Primitive + { + ~Primitive(); + std::vector mStreams; + bgfx::IndexBufferHandle mIbh = {bgfx::kInvalidHandle}; + bgfx::VertexDecl mDecl; + + uint32_t mVertexCount; + uint32_t mIndexCount; + void AddBuffer(const void* data, unsigned int format, unsigned int stride, unsigned int count); + void AddIndexBuffer(const void* data, unsigned int stride, unsigned int count); + void Draw(bgfx::ViewId viewId, bgfx::ProgramHandle program) const; + }; + std::vector mPrimitives; + void Draw(bgfx::ViewId viewId, bgfx::ProgramHandle program) const; + }; + std::vector mMeshes; + std::vector mBounds; + std::vector mWorldTransforms; + std::vector mMeshIndex; + std::string mName; + void Draw(EvaluationInfo& evaluationInfo, bgfx::ViewId viewId, bgfx::ProgramHandle program) const; + Bounds ComputeBounds() const; +protected: + static std::weak_ptr mDefaultScene; +}; \ No newline at end of file diff --git a/src/Shaders/AO.fs b/src/Shaders/AO.fs new file mode 100644 index 00000000..f2e30a9f --- /dev/null +++ b/src/Shaders/AO.fs @@ -0,0 +1,119 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 strength;// = 0.6; +uniform vec4 area;// = 0.0075; +uniform vec4 falloff;// = 0.00001; +uniform vec4 radius;// = 0.016; + + +float hash(vec2 p) // replace this by something better +{ + p = 50.0*fract( p*0.3183099 + vec2(0.71,0.113)); + return -1.0+2.0*fract( p.x*p.y*(p.x+p.y) ); +} + +vec3 normal_from_depth(float depth, vec2 texcoords, vec2 dx, vec2 dy) +{ + vec2 offset1 = dy;//dFdy(v_texcoord0); + vec2 offset2 = dx;//dFdx(v_texcoord0); + + float depth1 = texture2D(Sampler0, texcoords + offset1).x; + float depth2 = texture2D(Sampler0, texcoords + offset2).x; + + vec3 p1 = vec3(offset1, depth1 - depth); + vec3 p2 = vec3(offset2, depth2 - depth); + + vec3 normal = cross(p1, p2); + + return normalize(normal); +} + +void main() +{ + // constants + + int samples = 48; + + vec3 sample_sphere[48];//=vec3[48]( + sample_sphere[0] = vec3( 0.5381, 0.1856,-0.4319); + sample_sphere[1] = vec3( 0.1379, 0.2486, 0.4430); + sample_sphere[2] = vec3( 0.3371, 0.5679,-0.0057); + sample_sphere[3] = vec3(-0.6999,-0.0451,-0.0019); + sample_sphere[4] = vec3( 0.0689,-0.1598,-0.8547); + sample_sphere[5] = vec3( 0.0560, 0.0069,-0.1843); + sample_sphere[6] = vec3(-0.0146, 0.1402, 0.0762); + sample_sphere[7] = vec3( 0.0100,-0.1924,-0.0344); + sample_sphere[8] = vec3(-0.3577,-0.5301,-0.4358); + sample_sphere[9] = vec3(-0.3169, 0.1063, 0.0158); + sample_sphere[10] = vec3( 0.0103,-0.5869, 0.0046); + sample_sphere[11] = vec3(-0.0897,-0.4940, 0.3287); + sample_sphere[12] = vec3( 0.7119,-0.0154,-0.0918); + sample_sphere[13] = vec3(-0.0533, 0.0596,-0.5411); + sample_sphere[14] = vec3( 0.0352,-0.0631, 0.5460); + sample_sphere[15] = vec3(-0.4776, 0.2847,-0.0271); + sample_sphere[16] = vec3( 0.1482, -0.2644, -0.4988 ); + sample_sphere[17] = vec3( -0.1400, -0.2298, -0.4256 ); + sample_sphere[18] = vec3( -0.1811, 0.4853, -0.2447 ); + sample_sphere[19] = vec3( 0.3576, -0.3214, 0.4342 ); + sample_sphere[20] = vec3( 0.1268, -0.4914, -0.4651 ); + sample_sphere[21] = vec3( 0.3022, -0.2270, -0.0141 ); + sample_sphere[22] = vec3( 0.1402, -0.0520, -0.4085 ); + sample_sphere[23] = vec3( 0.2906, 0.1609, 0.4733 ); + sample_sphere[24] = vec3( 0.3814, -0.4596, 0.0633 ); + sample_sphere[25] = vec3( 0.4851, -0.2032, -0.4316 ); + sample_sphere[26] = vec3( -0.4744, -0.4820, -0.4254 ); + sample_sphere[27] = vec3( 0.1481, 0.0160, 0.0672 ); + sample_sphere[28] = vec3( -0.1199, -0.1149, 0.2206 ); + sample_sphere[29] = vec3( -0.2901, 0.4013, -0.4735 ); + sample_sphere[30] = vec3( 0.4643, 0.0459, 0.3613 ); + sample_sphere[31] = vec3( 0.4495, -0.1273, 0.1282 ); + sample_sphere[32] = vec3( -0.2672, 0.0208, -0.2687 ); + sample_sphere[33] = vec3( -0.0878, -0.1253, 0.3974 ); + sample_sphere[34] = vec3( -0.1237, -0.1445, 0.2443 ); + sample_sphere[35] = vec3( 0.0879, -0.4289, -0.2810 ); + sample_sphere[36] = vec3( 0.3218, -0.0686, 0.1749 ); + sample_sphere[37] = vec3( -0.2435, 0.1608, -0.4664 ); + sample_sphere[38] = vec3( -0.3292, 0.3501, 0.2427 ); + sample_sphere[39] = vec3( -0.0968, -0.0698, 0.2560 ); + sample_sphere[40] = vec3( -0.0343, 0.0098, -0.3571 ); + sample_sphere[41] = vec3( 0.3354, -0.4162, -0.0135 ); + sample_sphere[42] = vec3( 0.0088, 0.0495, 0.3811 ); + sample_sphere[43] = vec3( 0.2173, -0.1393, -0.4038 ); + sample_sphere[44] = vec3( -0.4144, -0.3722, -0.4927 ); + sample_sphere[45] = vec3( -0.1846, -0.4077, 0.3831 ); + sample_sphere[46] = vec3( -0.0111, 0.1529, 0.1266 ); + sample_sphere[47] = vec3( -0.0739, 0.2930, -0.1468 ); + + //samples + vec2 uvs = v_texcoord0 * 3.; + vec3 random = normalize(vec3(hash(uvs),hash(uvs+vec2(1.0, 1.0)),hash(uvs+vec2(2.0, 2.0)))); + float depth = texture2D(Sampler0, v_texcoord0).x; + vec3 clipSpaceNormal = normal_from_depth(depth, v_texcoord0, dFdx(v_texcoord0), dFdy(v_texcoord0));//texture2D(normalTexture, v_texcoord0).xyz *2.0 - 1.0; + + //clipSpaceNormal.z = -clipSpaceNormal.z; + vec3 position = vec3(v_texcoord0, depth); + // occ + float radius_depth = radius.x/(depth+0.01); + float occlusion = 0.0; + for(int i=0; i < samples; i++) + { + vec3 ray = radius_depth * reflect(sample_sphere[i], random); + vec3 hemi_ray = position + sign(dot(ray,clipSpaceNormal)) * ray; + + float occ_depth = texture2D(Sampler0, clamp(hemi_ray.xy,0.0,1.0)).x; + float difference = occ_depth - depth; + + occlusion += step(falloff.x, difference) * (1.0-smoothstep(falloff.x, area.x, difference)); + } + + + float ao = 1.0 - strength.x * occlusion * (1.0 / float(samples)); + + //return vec4(clipSpaceNormal*0.5+0.5, 1.0); + gl_FragColor = vec4(ao, ao, ao, ao); +} diff --git a/src/Shaders/Blend.fs b/src/Shaders/Blend.fs new file mode 100644 index 00000000..1341f9af --- /dev/null +++ b/src/Shaders/Blend.fs @@ -0,0 +1,48 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); +SAMPLER2D(Sampler1, 1); + +uniform vec4 A; +uniform vec4 B; +uniform vec4 operation; + +void main() +{ + vec4 res; + vec4 a = texture2D(Sampler0, v_texcoord0) * A; + vec4 b = texture2D(Sampler1, v_texcoord0) * B; + vec4 white = vec4(1.0, 1.0, 1.0, 1.0); + int op = int(operation.x); + if (op == 0) // Add + res = a + b; + else if (op == 1) // Multiply + res = a * b; + else if (op == 2) // Darken + res = min(a, b); + else if (op == 3) // Lighten + res = max(a, b); + else if (op == 4) // Average + res = (a + b) * 0.5; + else if (op == 5) // Screen + res = white - ((white - b) * (white - a)); + else if (op == 6) // Color Burn + res = white - (white - a) / b; + else if (op == 7) // Color Dodge + res = a / (white - b); + else if (op == 8) // Soft Light + res = 2.0 * a * b + a * a - 2.0 * a * a * b; + else if (op == 9) // Subtract + res = a - b; + else if (op == 10) // Difference + res = abs(b - a); + else if (op == 11) // Inverse Difference + res = white - abs(white - a - b); + else if (op == 12) // Exclusion + res = b + a - (2.0 * a * b); + + gl_FragColor = res; +} \ No newline at end of file diff --git a/src/Shaders/Blit.fs b/src/Shaders/Blit.fs new file mode 100644 index 00000000..d818c044 --- /dev/null +++ b/src/Shaders/Blit.fs @@ -0,0 +1,11 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); + +void main() +{ + gl_FragColor = texture2D(Sampler0, v_texcoord0); +} diff --git a/src/Shaders/Blur.fs b/src/Shaders/Blur.fs new file mode 100644 index 00000000..c8869593 --- /dev/null +++ b/src/Shaders/Blur.fs @@ -0,0 +1,59 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 type; +uniform vec4 angle; +uniform vec4 strength; + +void main() +{ + float g[15]; + g[0] = 0.023089; + g[1] = 0.034587; + g[2] = 0.048689; + g[3] = 0.064408; + g[4] = 0.080066; + g[5] = 0.093531; + g[6] = 0.102673; + g[7] = 0.105915; + g[8] = 0.102673; + g[9] = 0.093531; + g[10] = 0.080066; + g[11] = 0.064408; + g[12] = 0.048689; + g[13] = 0.034587; + g[14] = 0.023089; + + vec4 col = vec4(0.0, 0.0, 0.0, 0.0); + int itype = int(type.x); + if (itype == 0) + { + vec2 dir = vec2(cos(angle.x), sin(angle.x)); + for(int i = 0;i<15;i++) + { + col += texture2D(Sampler0, v_texcoord0 + dir * strength.x * float(i-7)) * g[i]; + } + } + else + { + // box + float sum = 0.; + for (int j = 0;j<15;j++) + { + for(int i = 0;i<15;i++) + { + float w = g[i] * g[j]; + col += texture2D(Sampler0, v_texcoord0 + vec2(float(i-7), float(j-7)) * strength.x) * w; + sum += w; + } + } + col /= sum; + + } + + gl_FragColor = col; +} \ No newline at end of file diff --git a/src/Shaders/ChannelPacker.fs b/src/Shaders/ChannelPacker.fs new file mode 100644 index 00000000..b5a44762 --- /dev/null +++ b/src/Shaders/ChannelPacker.fs @@ -0,0 +1,58 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); +SAMPLER2D(Sampler1, 1); +SAMPLER2D(Sampler2, 2); +SAMPLER2D(Sampler3, 3); + +uniform vec4 R; +uniform vec4 G; +uniform vec4 B; +uniform vec4 A; + +void main() +{ + vec4 lu[4]; + lu[0] = texture2D(Sampler0, v_texcoord0); + lu[1] = texture2D(Sampler1, v_texcoord0); + lu[2] = texture2D(Sampler2, v_texcoord0); + lu[3] = texture2D(Sampler3, v_texcoord0); + + int T[4]; + int C[4]; + T[0] = int(mod((R.x/4.),4.)); + C[0] = int(mod(R.x,4.)); + T[1] = int(mod((G.x/4.),4.)); + C[1] = int(mod(G.x,4.)); + T[2] = int(mod((B.x/4.),4.)); + C[2] = int(mod(B.x,4.)); + T[3] = int(mod((A.x/4.),4.)); + C[3] = int(mod(A.x,4.)); + + vec4 res = vec4(0.,0.,0.,0.); + + for (int component = 0; component < 4; component++) + { + for (int t = 0; t < 4; t++) + { + for (int c = 0; c < 4; c++) + { + res[component] += lu[t][c] * ((T[component] == t && C[component] == c) ? 1. : 0.); + } + } + } + + if (R.x>15.) + res.x = 1. - res.x; + if (G.x>15.) + res.y = 1. - res.y; + if (B.x>15.) + res.z = 1. - res.z; + if (A.x>15.) + res.w = 1. - res.w; + + gl_FragColor = res; +} diff --git a/src/Shaders/Checker.fs b/src/Shaders/Checker.fs new file mode 100644 index 00000000..1a10f4b3 --- /dev/null +++ b/src/Shaders/Checker.fs @@ -0,0 +1,11 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +void main() +{ + vec2 nuv = v_texcoord0 - vec2(0.5, 0.5); + float res = mod(floor(nuv.x)+floor(nuv.y), 2.0); + gl_FragColor = vec4(res, res, res, res); +} \ No newline at end of file diff --git a/src/Shaders/Circle.fs b/src/Shaders/Circle.fs new file mode 100644 index 00000000..a8b4bc9d --- /dev/null +++ b/src/Shaders/Circle.fs @@ -0,0 +1,14 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +uniform vec4 radius; +uniform vec4 T; + +void main() +{ + float c = Circle(v_texcoord0, radius.x, T.x); + gl_FragColor = vec4(c, c, c, c); +} diff --git a/src/Shaders/CircleSplatter.fs b/src/Shaders/CircleSplatter.fs new file mode 100644 index 00000000..1bbe17d3 --- /dev/null +++ b/src/Shaders/CircleSplatter.fs @@ -0,0 +1,28 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +uniform vec4 distance; +uniform vec4 radius; +uniform vec4 angle; +uniform vec4 count; + +void main() +{ + vec4 col = vec4(0.0, 0.0, 0.0, 0.0); + for (int i=0;i<128;i++) + { + if (i0.5)?1.0:0.0 ); + uv = mix(uv, p.zx*sign(n.y), (abs(n.y)>0.5)?1.0:0.0 ); + return uv; +} + +vec2 envMapEquirect(vec3 wcNormal, float flipEnvMap) { + //I assume envMap texture2D has been flipped the WebGL way (pixel 0,0 is a the bottom) + //therefore we flip wcNorma.y as acos(1) = 0 + float phi = acos(-wcNormal.y); + float theta = atan2(flipEnvMap * wcNormal.x, wcNormal.z) + PI; + return vec2(theta / TwoPI, 1.0 - phi / PI); +} + +vec2 envMapEquirect(vec3 wcNormal) { + //-1.0 for left handed coordinate system oriented texture (usual case) + return envMapEquirect(wcNormal, -1.0); +} + +float Smooth( float x ) +{ + return smoothstep( 0., 1., saturate( x ) ); +} + +// distance functions + +float Cylinder( vec3 p, float r, float height ) +{ + float d = length( p.xz ) - r; + d = max( d, abs( p.y ) - height ); + return d; +} + +float Substract( float a, float b ) +{ + return max( a, -b ); +} + +float SubstractRound( float a, float b, float r ) +{ + vec2 u = max( vec2( r + a, r - b ), vec2( 0.0, 0.0 ) ); + return min( -r, max( a, -b ) ) + length( u ); +} + +float Union( float a, float b ) +{ + return min( a, b ); +} + +float Box( vec3 p, vec3 b ) +{ + vec3 d = abs( p ) - b; + return min( max( d.x, max( d.y, d.z ) ), 0.0 ) + length( max( d, 0.0 ) ); +} + +float Sphere( vec3 p, float s ) +{ + return length( p ) - s; +} + +float Torus( vec3 p, float sr, float lr ) +{ + return length( vec2( length( p.xz ) - lr, p.y ) ) - sr; +} + +float Disc( vec3 p, float r, float t ) +{ + float l = length( p.xz ) - r; + return l < 0. ? abs( p.y ) - t : length( vec2( p.y, l ) ) - t; +} + +float UnionRound( float a, float b, float k ) +{ + float h = clamp( 0.5 + 0.5 * ( b - a ) / k, 0.0, 1.0 ); + return mix( b, a, h ) - k * h * ( 1.0 - h ); +} + +float sdRoundBox( vec3 p, vec3 b, float r ) +{ + vec3 d = abs(p) - b; + return length(max(d,0.0)) - r + + min(max(d.x,max(d.y,d.z)),0.0); // remove this line for an only partially signed sdf +} diff --git a/src/Shaders/CommonFS.shader b/src/Shaders/CommonFS.shader new file mode 100644 index 00000000..96172e36 --- /dev/null +++ b/src/Shaders/CommonFS.shader @@ -0,0 +1,112 @@ + +mat3 cotangent_frame( vec3 N, vec3 p, vec2 uv ) +{ + // get edge vectors of the pixel triangle + vec3 dp1 = dFdx( p ); + vec3 dp2 = dFdy( p ); + vec2 duv1 = dFdx( uv ); + vec2 duv2 = dFdy( uv ); + + // solve the linear system + vec3 dp2perp = cross( dp2, N ); + vec3 dp1perp = cross( N, dp1 ); + vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; + vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; + + // construct a scale-invariant frame + float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) ); + return mat3( T * invmax, B * invmax, N ); +} + +float GetHeight(sampler2D heightSampler, vec2 texCoords) +{ + return texture2D(heightSampler, texCoords).r; +} + +//Parallax Occlusion Mapping from: https://learnopengl.com/Advanced-Lighting/Parallax-Mapping +vec2 ParallaxMapping(sampler2D heightSampler, vec2 texCoords, vec3 viewDir, float depthFactor) +{ + float height_scale = depthFactor; + // number of depth layers + float minLayers = 8.0; + float maxLayers = 32.0; + float numLayers = mix(maxLayers, minLayers, min(abs(viewDir.z), 1.0)); + // calculate the size of each layer + float layerDepth = 1.0 / numLayers; + // depth of current layer + float currentLayerDepth = 0.0; + // the amount to shift the texture coordinates per layer (from vector P) + vec2 P = viewDir.xy * height_scale; + vec2 deltaTexCoords = P / numLayers; + + // get initial values + vec2 currentTexCoords = texCoords; + float currentDepthMapValue = GetHeight(heightSampler, currentTexCoords); + + while(currentLayerDepth < currentDepthMapValue) + { + // shift texture coordinates along direction of P + currentTexCoords -= deltaTexCoords; + // get depthmap value at current texture coordinates + currentDepthMapValue = GetHeight(heightSampler, currentTexCoords); + // get depth of next layer + currentLayerDepth += layerDepth; + } + + // get texture coordinates before collision (reverse operations) + vec2 prevTexCoords = currentTexCoords + deltaTexCoords; + + // get depth after and before collision for linear interpolation + float afterDepth = currentDepthMapValue - currentLayerDepth; + float beforeDepth = GetHeight(heightSampler, prevTexCoords) + layerDepth - currentLayerDepth; + + // interpolation of texture coordinates + float weight = afterDepth / (afterDepth - beforeDepth); + vec2 finalTexCoords = mix(currentTexCoords, prevTexCoords, weight); + + return finalTexCoords; +} + +vec3 hash3( vec2 p ) +{ + vec3 q = vec3( dot(p,vec2(127.1,311.7)), + dot(p,vec2(269.5,183.3)), + dot(p,vec2(419.2,371.9)) ); + return fract(sin(q)*43758.5453); +} + +/* +vec4 cubemap2D( sampler2D sam, in vec3 d ) +{ + vec3 n = abs(d); + vec3 s = dFdx(d); + vec3 t = dFdy(d); + if(n.x>n.y && n.x>n.z) {d=d.xyz;s=s.xyz;t=t.xyz;} + else if(n.y>n.x && n.y>n.z) {d=d.yzx;s=s.yzx;t=t.yzx;} + else {d=d.zxy;s=s.zxy;t=t.zxy;} + vec2 q = d.yz/d.x; + return texture2Dgrad( sam, + 0.5*q + 0.5, + 0.5*(s.yz-q*s.x)/d.x, + 0.5*(t.yz-q*t.x)/d.x ); +} +*/ + +/* +SAMPLER2D(Sampler0, 0); +SAMPLER2D(Sampler1, 1); +SAMPLER2D(Sampler2, 2); +SAMPLER2D(Sampler3, 3); +SAMPLER2D(Sampler4, 4); +SAMPLER2D(Sampler5, 5); +SAMPLER2D(Sampler6, 6); +SAMPLER2D(Sampler7, 7); +SAMPLERCUBE(CubeSampler0, 8); +SAMPLERCUBE(CubeSampler1, 9); +SAMPLERCUBE(CubeSampler2, 10); +SAMPLERCUBE(CubeSampler3, 11); +SAMPLERCUBE(CubeSampler4, 12); +SAMPLERCUBE(CubeSampler5, 13); +SAMPLERCUBE(CubeSampler6, 14); +SAMPLERCUBE(CubeSampler7, 15); +*/ diff --git a/src/Shaders/Crop.fs b/src/Shaders/Crop.fs new file mode 100644 index 00000000..cf76a191 --- /dev/null +++ b/src/Shaders/Crop.fs @@ -0,0 +1,29 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 quad; + +void main() +{ + if (u_pass.x == 1.) + { + vec4 q = vec4(min(quad.x, quad.z), + min(quad.y, quad.w), + max(quad.x, quad.z), + max(quad.y, quad.w)); + float barx = min(step(q.x, v_texcoord0.x), step(v_texcoord0.x, q.z)); + float bary = min(step(q.y, v_texcoord0.y), step(v_texcoord0.y, q.w)); + float colFactor = min(barx, bary); + gl_FragColor = texture2D(Sampler0, v_texcoord0) * max(colFactor, 0.5); + return; + } + + vec4 q = quad; + vec2 uv = vec2(mix(min(q.x, q.z), max(q.x, q.z), v_texcoord0.x), mix(min(q.y, q.w), max(q.y, q.w), v_texcoord0.y)); + gl_FragColor = texture2D(Sampler0, uv); +} \ No newline at end of file diff --git a/src/Shaders/CubeRadiance.fs b/src/Shaders/CubeRadiance.fs new file mode 100644 index 00000000..1b7f945b --- /dev/null +++ b/src/Shaders/CubeRadiance.fs @@ -0,0 +1,133 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLERCUBE(CubeSampler0, 8); + +uniform vec4 mode; // radiance, irradiance +uniform vec4 sampleCount; + +vec3 get_world_normal(vec2 uv) +{ + vec3 dir = mul(u_viewRot, vec4(uv * 2.0 - 1.0, 1.0, 0.0)).xyz; + return normalize(dir); +} +// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/ +float random(vec2 co) +{ + float a = 12.9898; + float b = 78.233; + float c = 43758.5453; + float dt= dot(co.xy ,vec2(a,b)); + float sn= mod(dt,3.14); + return fract(sin(sn) * c); +} + +float hash(float n) +{ + return fract(sin(n) * 437587.5453); +} + +vec2 hammersley2d(int i, int N) +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + /* + int bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + float rdi = float(bits) * 2.3283064365386963e-10; + return vec2(float(i) /float(N), rdi); + */ + float n = float(i)/float(N); + return vec2(n, random(vec2(abs(hash(n)), n))); +} + +// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf +vec3 importanceSample_GGX(vec2 Xi, float roughness, vec3 normal) +{ + // Maps a 2D point to a hemisphere with spread based on roughness + float alpha = roughness * roughness; + float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); + + // Tangent space + vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangentX = normalize(cross(up, normal)); + vec3 tangentY = normalize(cross(normal, tangentX)); + + // Convert to world Space + return normalize(tangentX * H.x + tangentY * H.y + normal * H.z); +} + +// Normal Distribution function +float D_GGX(float dotNH, float roughness) +{ + float alpha = roughness * roughness; + float alpha2 = alpha * alpha; + float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0; + return (alpha2)/(PI * denom*denom); +} + +vec3 prefilterEnvMap(vec3 R, float roughness) +{ + vec3 N = R; + vec3 V = R; + //int numSamples = sampleCount; + vec3 color = vec3(0.0, 0.0, 0.0); + float totalWeight = sampleCount.x; + float envMapDim = u_textureSize[0].x/pow(u_target.z, 2.0);// 256.0;//textureSize(CubeSampler0, u_target.z).x; + for(int i = 0; i < 1024; i++) + { + if (i 0.0) + { + // Filtering based on https://placeholderart.wordpress.com/2015/07/28/implementation-notes-runtime-environment-map-filtering-for-image-based-lighting/ + + float dotNH = clamp(dot(N, H), 0.0, 1.0); + float dotVH = clamp(dot(V, H), 0.0, 1.0); + + // Probability Distribution Function + float pdf = D_GGX(dotNH, roughness) * dotNH / (4.0 * dotVH) + 0.0001; + // Slid angle of current smple + float omegaS = 1.0 / (sampleCount.x * pdf); + // Solid angle of 1 pixel across all cube faces + float omegaP = 4.0 * PI / (6.0 * envMapDim * envMapDim); + // Biased (+1.0) mip level for better result + float mipLevel = roughness == 0.0 ? 0.0 : max(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f); + color += textureCubeLod(CubeSampler0, L, mipLevel).rgb * dotNL; + totalWeight += dotNL; + } + } + } + return (color / totalWeight); +} + +void main() +{ + vec3 N = get_world_normal(v_texcoord0); + N.y = -N.y; + if (mode.x == 0.) + { + //radiance + gl_FragColor = vec4(prefilterEnvMap(N, 0.5), 1.0); + } + else + { + // irradiance + float roughness = u_target.z/max(u_target.w - 1., 1.); + gl_FragColor = vec4(prefilterEnvMap(N, roughness), 1.0); + } +} diff --git a/bin/Nodes/GLSL/CubemapView.glsl b/src/Shaders/CubemapView.fs similarity index 66% rename from bin/Nodes/GLSL/CubemapView.glsl rename to src/Shaders/CubemapView.fs index 203575ac..6ed0b4fa 100644 --- a/bin/Nodes/GLSL/CubemapView.glsl +++ b/src/Shaders/CubemapView.fs @@ -1,9 +1,14 @@ -layout (std140) uniform CubemapViewBlock -{ - vec2 view; - int mode; - float LOD; -} CubemapViewParam; +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLERCUBE(CubeSampler0, 8); + +uniform vec4 view; +uniform vec4 mode; +uniform vec4 LOD; vec4 CrossView(vec2 uv) { @@ -30,7 +35,7 @@ vec4 CrossView(vec2 uv) nd = vec3(d.x, d.y*cs.y - d.z*sn.y, d.y*sn.y + d.z*cs.y); } - return textureLod(CubeSampler0, nd, CubemapViewParam.LOD); + return textureCubeLod(CubeSampler0, nd, LOD.x); } vec4 getUV(vec2 I) @@ -39,7 +44,7 @@ vec4 getUV(vec2 I) vec2 b = vec2(-2.0*I.x,-I.x+I.y); vec2 c = vec2(-I.x-I.y, I.x-I.y); - vec4 uv = vec4(0.0); + vec4 uv = vec4(0.0, 0.0, 0.0, 0.0); if(max(max(max(a.x, a.y),max(b.x, b.y)),max(c.x,c.y)) <= 1.0) { @@ -62,7 +67,7 @@ vec4 IsometricView(vec2 uv) nuv = getUV(I-vec2(0.5,0.0)); else nuv = vec4(1.0, 1.0, 1.0, 0.0)-getUV(vec2(I.x, -I.y)+vec2(0.5,0.0)); - return textureLod(CubeSampler0, nuv.xyz*2.0-1.0, CubemapViewParam.LOD) *abs(nuv.w); + return textureCubeLod(CubeSampler0, nuv.xyz*2.0-1.0, LOD.x) *abs(nuv.w); } vec4 Projection(vec2 uv) @@ -70,13 +75,13 @@ vec4 Projection(vec2 uv) vec2 ng = uv * vec2(PI, PI * 0.5); vec2 a = cos(ng); vec2 b = sin(ng); - return textureLod(CubeSampler0, normalize(vec3(a.x*a.y, -b.y, b.x*a.y)), CubemapViewParam.LOD); + return textureCubeLod(CubeSampler0, normalize(vec3(a.x*a.y, -b.y, b.x*a.y)), LOD.x); } vec4 CameraView(vec2 uv) { - float an = CubemapViewParam.view.x * PI * 2.0; - float dn = CubemapViewParam.view.y * PI * 0.5; + float an = view.x * PI * 2.0; + float dn = view.y * PI * 0.5; float cdn = cos(dn); vec3 ro = vec3( 2.0*sin(an)*cdn, sin(dn)*2.0, 2.0*cos(an)*cdn ); @@ -87,21 +92,22 @@ vec4 CameraView(vec2 uv) vec3 rd = normalize( uv.x*uu - uv.y*vv + 1.5*ww ); - return textureLod(CubeSampler0, rd, CubemapViewParam.LOD); + return textureCubeLod(CubeSampler0, rd, LOD.x); } -vec4 CubemapView() +void main() { - vec2 uv = vUV * 2.0 - 1.0; - switch(CubemapViewParam.mode) - { - case 0: - return Projection(uv); - case 1: - return IsometricView(uv); - case 2: - return CrossView(uv); - case 3: - return CameraView(uv); - } + vec4 res; + vec2 uv = v_texcoord0 * 2.0 - 1.0; + int imode = int(mode.x); + if (imode == 0) + res = Projection(uv); + else if (imode == 1) + res = IsometricView(uv); + else if (imode == 2) + res = CrossView(uv); + else + res = CameraView(uv); + + gl_FragColor = res; } diff --git a/bin/Nodes/GLSL/Disolve.glsl b/src/Shaders/Disolve.fs similarity index 66% rename from bin/Nodes/GLSL/Disolve.glsl rename to src/Shaders/Disolve.fs index 603f1444..085a8cf8 100644 --- a/bin/Nodes/GLSL/Disolve.glsl +++ b/src/Shaders/Disolve.fs @@ -1,14 +1,18 @@ -layout (std140) uniform DisolveBlock -{ - int PassCount; - float Frequency; - float Strength; - float Randomization; - float VerticalShift; -}; +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 frequency; +uniform vec4 strength; +uniform vec4 randomization; +uniform vec4 verticalShift; - // simplex noise obviously not by me, see main() below +// simplex noise obviously not by me, see main() below vec3 mod289(vec3 x){ return x - floor(x * (1.0 / 289.0)) * 289.0; } @@ -64,7 +68,7 @@ float simplex(vec3 v){ vec4 s0 = floor(b0)*2.0 + 1.0; vec4 s1 = floor(b1)*2.0 + 1.0; - vec4 sh = -step(h, vec4(0.0)); + vec4 sh = -step(h, vec4(0.0, 0.0, 0.0, 0.0)); vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; @@ -128,36 +132,37 @@ vec3 curlNoise(vec3 p) return vec3( x , y , z ); } -vec4 Disolve() +void main() { - vec2 uv = vUV; + vec2 uv = v_texcoord0; uv *= 1.; - // noise seed - vec3 v = vec3(uv, float(EvaluationParam.passNumber)*0.05); - float disp_freq = Frequency; // param - v.xy *= disp_freq; - // get first some density variation - vec4 disp = 0.5*mix(vec4(0), pow(0.5+0.5*vec4(fbm3(-2.0*v+11.2)), vec4(2)), 0.05); - v.xy /= disp_freq; - // add to randomization coordinates - v += disp.x*Randomization; //param - - // vector field ("fluid" direction) - vec2 off = 0.25*curlNoise(vec3(v)).xy;// vec2(fbm3(v), fbm3(v+99.0)); - off.y = min(0.0, off.y-VerticalShift); - // maybe apply density to vector field too? - //off /= 1.0+disp.x*10.0; - vec2 uv2 = vUV; - // get "emitter" from buffer A - vec4 res = vec4(0.); - //res += texture(Sampler0, uv2)*0.9; - // mutate previous state with field direction - res += texture(Sampler0, (0.5+0.5*(1.0*(-1.0+2.0*uv2)))+off*Strength); // param - - // disperse and output - //res = pow( 0.97*clamp(res-disp, 0.0, 111.0), vec4(1.002*(1.0+disp))); - res = pow( clamp(res-disp, 0.0, 1.0), vec4(1.002*(1.0+disp))); + // noise seed + vec3 v = vec3(uv, float(u_pass.x)*0.05); + float disp_freq = frequency.x; // param + v.xy *= disp_freq; + // get first some density variation + float fbv = fbm3(-2.0*v+11.2); + vec4 disp = 0.5*mix(vec4(0.0, 0.0, 0.0, 0.0), pow(0.5+0.5*vec4(fbv, fbv, fbv, fbv), vec4(2.0, 2.0, 2.0, 2.0)), 0.05); + v.xy /= disp_freq; + // add to randomization coordinates + v += disp.x*randomization.x; //param + + // vector field ("fluid" direction) + vec2 off = 0.25*curlNoise(vec3(v)).xy;// vec2(fbm3(v), fbm3(v+99.0)); + off.y = min(0.0, off.y-verticalShift.x); + // maybe apply density to vector field too? + //off /= 1.0+disp.x*10.0; + vec2 uv2 = v_texcoord0; + // get "emitter" from buffer A + vec4 res = vec4(0.0, 0.0, 0.0, 0.0); + //res += texture2D(Sampler0, uv2)*0.9; + // mutate previous state with field direction + res += texture2D(Sampler0, (0.5+0.5*(1.0*(-1.0+2.0*uv2)))+off*strength.x); // param + + // disperse and output + //res = pow( 0.97*clamp(res-disp, 0.0, 111.0), vec4(1.002*(1.0+disp))); + res = pow( clamp(res-disp, 0.0, 1.0), vec4(1.002*(1.0+disp))); - return res; + gl_FragColor = res; } diff --git a/src/Shaders/DisplayCubemap.fs b/src/Shaders/DisplayCubemap.fs new file mode 100644 index 00000000..e2196960 --- /dev/null +++ b/src/Shaders/DisplayCubemap.fs @@ -0,0 +1,17 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLERCUBE(CubeSampler0, 8); + +void main() +{ + vec2 uv = (v_texcoord0 - 0.5) * 2.0; + vec2 ng = uv * vec2(3.14159265, 1.57079633); + vec2 a = cos(ng); + vec2 b = sin(ng); + gl_FragColor = textureCube(CubeSampler0, normalize(vec3(a.x*a.y, -b.y, b.x*a.y))); + gl_FragColor.a = 1.0; +} diff --git a/bin/Nodes/GLSL/Distance.glsl b/src/Shaders/Distance.fs similarity index 60% rename from bin/Nodes/GLSL/Distance.glsl rename to src/Shaders/Distance.fs index 843ed785..24f78a70 100644 --- a/bin/Nodes/GLSL/Distance.glsl +++ b/src/Shaders/Distance.fs @@ -1,37 +1,42 @@ -layout (std140) uniform DistanceBlock -{ - int passCount; -}; +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 passCount; // source // https://www.shadertoy.com/view/ldVGWc vec4 Pack(vec4 coord) { - float s = float(textureSize(Sampler0, 0).x); + float s = u_textureSize[0].x; return coord / s; } vec4 Unpack(vec4 v) { - float s = float(textureSize(Sampler0, 0).x); + float s = u_textureSize[0].x; return v * s; -} +} -vec4 StepJFA (in vec2 fragCoord, in float level, float c_maxSteps) +vec4 StepJFA (vec2 fragCoord, float level, float c_maxSteps) { level = clamp(level, 0.0, c_maxSteps); float stepwidth = floor(exp2(c_maxSteps - level)+0.5); float bestDistanceIn = 9999.0; float bestDistanceOut = 9999.0; - vec4 bestCoord = vec4(0.0); + vec4 bestCoord = vec4(0.0, 0.0, 0.0, 0.0); for (int y = -1; y <= 1; ++y) { for (int x = -1; x <= 1; ++x) { vec2 sampleCoord = fragCoord + vec2(x,y) * stepwidth; - vec4 data = texture(Sampler0, sampleCoord / vec2(textureSize(Sampler0, 0).xy)); + vec4 data = texture2D(Sampler0, sampleCoord / u_textureSize[0].xy); vec4 seedCoord = Unpack(data); float dist = length(seedCoord.xy - fragCoord); @@ -52,34 +57,36 @@ vec4 StepJFA (in vec2 fragCoord, in float level, float c_maxSteps) return Pack(bestCoord); } -vec4 Distance() +void main() { - if (EvaluationParam.passNumber == 0) + vec4 res; + if (u_pass.y == 0.) { - float v = texture(Sampler0, vUV).x; + float v = texture2D(Sampler0, v_texcoord0).x; if (v > 0.5) { - return Pack(vec4(gl_FragCoord.xy, vec2(10000.0))); + res = Pack(vec4(gl_FragCoord.xy, vec2(10000.0, 10000.0))); } else { - return Pack(vec4(vec2(10000.0), gl_FragCoord.xy)); + res = Pack(vec4(vec2(10000.0, 10000.0), gl_FragCoord.xy)); } } - else if (EvaluationParam.passNumber != (passCount - 1)) + else if (u_pass.y < (passCount.x - 1.)) { - return StepJFA(gl_FragCoord.xy, float(EvaluationParam.passNumber-1), float(passCount-2)); + res = StepJFA(gl_FragCoord.xy, u_pass.y-1., (passCount.x-2.)); } else { // display result - vec4 data = texture(Sampler0, vUV); + vec4 data = texture2D(Sampler0, v_texcoord0); vec4 seedCoord = Unpack(data); float distIn = length(seedCoord.xy - gl_FragCoord.xy) / 128.0; float distOut = length(seedCoord.zw - gl_FragCoord.xy) / 128.0; float d = 0.5 + distOut * 0.5 - distIn * 0.5; - return vec4(d, d, d, 1.0); + res = vec4(d, d, d, 1.0); } + gl_FragColor = res; } diff --git a/bin/Nodes/GLSL/EdgeDetect.glsl b/src/Shaders/EdgeDetect.fs similarity index 82% rename from bin/Nodes/GLSL/EdgeDetect.glsl rename to src/Shaders/EdgeDetect.fs index bbce47f3..05f281f0 100644 --- a/bin/Nodes/GLSL/EdgeDetect.glsl +++ b/src/Shaders/EdgeDetect.fs @@ -1,7 +1,11 @@ -layout (std140) uniform EdgeDetectBlock -{ - float radius; -} EdgeDetectParam; +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 radius; // Use these parameters to fiddle with settings float step = 1.0; @@ -12,7 +16,7 @@ float intensity(in vec4 color){ vec4 ctap(vec2 p) { - return texture(Sampler0, p); + return texture2D(Sampler0, p); } vec3 sobel(float stepx, float stepy, vec2 center){ @@ -43,8 +47,8 @@ vec3 sobel(float stepx, float stepy, vec2 center){ } -vec4 EdgeDetect() +void main() { - float e = EdgeDetectParam.radius; - return vec4(sobel(e, e, vUV), 1.0); + float e = radius.x; + gl_FragColor = vec4(sobel(e, e, v_texcoord0), 1.0); } diff --git a/src/Shaders/EquirectConverter.fs b/src/Shaders/EquirectConverter.fs new file mode 100644 index 00000000..7cc268bd --- /dev/null +++ b/src/Shaders/EquirectConverter.fs @@ -0,0 +1,39 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); +SAMPLERCUBE(CubeSampler0, 8); + +uniform vec4 mode; + +vec4 EquirectToCubemap(vec2 vuv) +{ + vec3 dir = mul(u_viewRot, vec4(vuv * 2.0 - 1.0, 1.0, 0.0)).xyz; + vec2 uv = envMapEquirect(normalize(dir)); + vec4 tex = texture2D(Sampler0, vec2(uv.x, 1.0-uv.y)); + return tex; +} + +vec4 CubemapToEquirect(vec2 vuv) +{ + vec2 uv = vuv * 2.0 - 1.0; + vec2 ng = uv * PI * vec2(1.0, 0.5); + vec2 a = cos(ng); + vec2 b = sin(ng); + return textureCube(CubeSampler0, normalize(vec3(a.x*a.y, -b.y, b.x*a.y))); +} + +void main() +{ + vec4 res; + int imode = int(mode.x); + if (imode == 0) + res = EquirectToCubemap(v_texcoord0); + else + res = CubemapToEquirect(v_texcoord0); + res.a = 1.0; + gl_FragColor = res; +} diff --git a/src/Shaders/GLTFRead.fs b/src/Shaders/GLTFRead.fs new file mode 100644 index 00000000..ce790b66 --- /dev/null +++ b/src/Shaders/GLTFRead.fs @@ -0,0 +1,12 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +void main() +{ + vec3 lightdir = normalize(vec3(1.0, 1.0, 1.0)); + float dt = max(dot(lightdir, normalize(v_normal)), 0.5); + dt -= max(dot(-lightdir, normalize(v_normal)), 0.0) * 0.3; + gl_FragColor = vec4(dt, dt, dt, 1.0); +} diff --git a/bin/Nodes/GLSL/GradientBuilder.glsl b/src/Shaders/GradientBuilder.fs similarity index 56% rename from bin/Nodes/GLSL/GradientBuilder.glsl rename to src/Shaders/GradientBuilder.fs index a1cfa494..c505a11f 100644 --- a/bin/Nodes/GLSL/GradientBuilder.glsl +++ b/src/Shaders/GradientBuilder.fs @@ -1,6 +1,13 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +uniform vec4 gradient[8]; + vec4 GetRamp(float v, vec4 arr[8]) { - for (int i = 0;i<(arr.length()-1);i++) + for (int i = 0;i<7;i++) { if (v >= arr[i].w && v <= arr[i+1].w) { @@ -12,15 +19,10 @@ vec4 GetRamp(float v, vec4 arr[8]) } } - return vec4(0.0); + return vec4(0.0, 0.0, 0.0, 0.0); } -layout (std140) uniform GradientBuilderBlock -{ - vec4 ramp[8]; -} GradientBuilderParam; - -vec4 GradientBuilder() +void main() { - return vec4(GetRamp(vUV.x, GradientBuilderParam.ramp).xyz, 1.0); + gl_FragColor = vec4(GetRamp(v_texcoord0.x, gradient).xyz, 1.0); } \ No newline at end of file diff --git a/src/Shaders/Invert.fs b/src/Shaders/Invert.fs new file mode 100644 index 00000000..805b9b64 --- /dev/null +++ b/src/Shaders/Invert.fs @@ -0,0 +1,13 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); + +void main() +{ + vec4 res = vec4(1.0,1.0,1.0,1.0) - texture2D(Sampler0, v_texcoord0); + res.a = 1.0; + gl_FragColor = res; +} diff --git a/src/Shaders/Kaleidoscope.fs b/src/Shaders/Kaleidoscope.fs new file mode 100644 index 00000000..722532c4 --- /dev/null +++ b/src/Shaders/Kaleidoscope.fs @@ -0,0 +1,37 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 center; +uniform vec4 startAngle; +uniform vec4 splits; +uniform vec4 symetry; + +void main() +{ + vec2 center = vec2(0.5, 0.5); + + vec2 uv = v_texcoord0 - center.xy; + float l = length(uv); + + float ng = atan2(uv.y, uv.x) + PI - startAngle.x; + float modulo = (2.* PI) / (splits.x + 1.); + float count = mod((ng / modulo) *2.0, 2.0); + ng = mod(ng, modulo); + if ((symetry.x > 0.001) && (count>1.)) + { + ng = modulo - mod(ng, modulo); + } + else + { + ng = mod(ng, modulo); + } + ng += startAngle.x; + vec2 uv2 = vec2(-cos(-ng), sin(-ng)) * l + center.xy; + vec4 tex = texture2D(Sampler0, uv2); + gl_FragColor = tex; +} diff --git a/bin/Nodes/GLSL/LambertMaterial.glsl b/src/Shaders/LambertMaterial.fs similarity index 76% rename from bin/Nodes/GLSL/LambertMaterial.glsl rename to src/Shaders/LambertMaterial.fs index 0eacd757..4dc9e90d 100644 --- a/bin/Nodes/GLSL/LambertMaterial.glsl +++ b/src/Shaders/LambertMaterial.fs @@ -1,3 +1,13 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 view; + //=============================================================================================== // some code by knarkowicz https://www.shadertoy.com/view/4sSfzK // , Iq : https://www.shadertoy.com/view/MtsGWH @@ -12,7 +22,7 @@ float castRay( vec3 ro, vec3 rd ) for( float t = mint; t < maxt; t += delt ) { vec3 p = ro + rd*t; - float h = texture(Sampler0, p.xz ).x * 0.1; + float h = texture2D(Sampler0, p.xz ).x * 0.1; if( p.y < h ) { // interpolate the intersection distance @@ -27,18 +37,14 @@ float castRay( vec3 ro, vec3 rd ) return 999.; } -layout (std140) uniform LambertMaterialBlock -{ - vec2 view; -} LambertMaterialParam; - -vec4 LambertMaterial() +void main() { - vec2 p = vUV * 2.0 - 1.0; + #if 0 + vec2 p = v_texcoord0 * 2.0 - 1.0; // camera movement - float an = LambertMaterialParam.view.x * PI * 2.0; - float dn = LambertMaterialParam.view.y * PI * 0.5; + float an = view.x * PI * 2.0; + float dn = view.y * PI * 0.5; float cdn = cos(dn); vec3 ro = vec3( 2.5*sin(an)*cdn, 1.0 + sin(dn)*2.0, 2.5*cos(an)*cdn ); vec3 ta = vec3( 0.0, 1.0, 0.0 ); @@ -52,11 +58,11 @@ vec4 LambertMaterial() // sphere center vec3 sc = vec3(0.0,1.0,0.0); - vec3 col = texture(Sampler1, envMapEquirect(rd)).xyz; + vec3 col = texture2D(Sampler1, envMapEquirect(rd)).xyz; if (castRay(ro, rd)<10.0) { - col = vec3(1.0); + col = vec3(1.0, 1.0, 1.0); } /* @@ -70,7 +76,7 @@ vec4 LambertMaterial() float l = length(di); float occ = 1.0 - dot(nor,di/l)*1.0*1.0/(l*l); - col = texture( Sampler0, 0.25*pos.xz ).xyz; + col = texture2D( Sampler0, 0.25*pos.xz ).xyz; col *= occ; col *= exp(-0.1*h); } @@ -94,5 +100,7 @@ vec4 LambertMaterial() */ col = sqrt( col ); //col *= 0.1; - return vec4( col, 1.0 ); + gl_FragColor = vec4( col, 1.0 ); + #endif + gl_FragColor = vec4( 1.0, 0.0, 1.0, 1.0 ); } diff --git a/src/Shaders/Lens.fs b/src/Shaders/Lens.fs new file mode 100644 index 00000000..c5d9d6f4 --- /dev/null +++ b/src/Shaders/Lens.fs @@ -0,0 +1,25 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 factor; +uniform vec4 vignette; + +vec3 Distort(vec2 uv) +{ + float distCoeff = factor.x; + uv -= 0.5; + float r2 = dot(uv,uv); + float f = 1.+r2*distCoeff; + f /= 1.+0.5*distCoeff; + return vec3(uv*f+0.5, sqrt(r2)); +} + +void main() +{ + vec3 dis = Distort(v_texcoord0.xy); + gl_FragColor = texture2D(Sampler0, dis.xy) * mix(1.0, min(1.18-dis.z, 1.0), vignette.x); +} diff --git a/src/Shaders/MADD.fs b/src/Shaders/MADD.fs new file mode 100644 index 00000000..06a1cc5c --- /dev/null +++ b/src/Shaders/MADD.fs @@ -0,0 +1,14 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 mulColor; +uniform vec4 addColor; + +void main() +{ + gl_FragColor = texture2D(Sampler0, v_texcoord0) * mulColor + addColor; +} diff --git a/src/Shaders/NGon.fs b/src/Shaders/NGon.fs new file mode 100644 index 00000000..a5c17431 --- /dev/null +++ b/src/Shaders/NGon.fs @@ -0,0 +1,30 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +uniform vec4 sides; +uniform vec4 radius; +uniform vec4 T; +uniform vec4 startAngle; + +void main() +{ + vec2 p = v_texcoord0 - vec2(0.5, 0.5); + + vec2 d = vec2(cos(startAngle.x), sin(startAngle.x)); + float ng = 0.0; + float col = 0.0; + + int sideCount = int(sides.x); + for (int i=0;i<64;i++) + { + vec2 rd = Rotate2D(d, ng); + ng += (PI * 2.0) / sides.x; + float d = smoothstep(mix(-radius.x, 0.0, T.x), 0.001, dot(p,rd)-radius.x) * ((i>= sideCount)?0.:1.); + col = max(col, d); + } + col = 1.0 - col; + gl_FragColor = vec4(col, col, col, col); +} diff --git a/src/Shaders/Node.vs b/src/Shaders/Node.vs new file mode 100644 index 00000000..aff44c6d --- /dev/null +++ b/src/Shaders/Node.vs @@ -0,0 +1,31 @@ +$input a_texcoord0, a_color0, a_position, a_normal +$output v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "Common.shader" + +uniform vec4 u_uvTransform; + +void main() +{ + if (u_target.y > 0.5) + { + mat4 mvp = u_worldViewProjection; + mvp[0] *= u_uvTransform.x * 0.5; + mvp[1] *= u_uvTransform.y * 0.5; + gl_Position = mul(mvp, vec4(a_position.xyz, 1.0)); + + vec2 clipSpaceTr = u_uvTransform.zw + u_uvTransform.xy * vec2(0.5, 0.5); + gl_Position.xy += clipSpaceTr * gl_Position.w; + } + else + { + vec2 trPos = a_position.xy * u_uvTransform.xy + u_uvTransform.zw; + gl_Position = vec4(trPos.xy, 0.5, 1.0); + } + + v_texcoord0 = a_texcoord0; + v_color0 = a_color0; + v_normal = mul(u_world, vec4(a_normal, 0.0)).xyz; + v_positionWorld = mul(u_world, vec4(a_position, 1.0)).xyz; +} \ No newline at end of file diff --git a/src/Shaders/NormalMap.fs b/src/Shaders/NormalMap.fs new file mode 100644 index 00000000..fa7103bd --- /dev/null +++ b/src/Shaders/NormalMap.fs @@ -0,0 +1,24 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 spread; +uniform vec4 invert; + +vec2 stdNormalMap(vec2 uv) +{ + float height = texture2D(Sampler0, uv).r; + if (invert.x > 0.001) + { + height = 1.0 - height; + } + return -vec2(dFdx(height), dFdy(height)); +} + +void main() +{ + gl_FragColor = vec4(stdNormalMap(v_texcoord0) * spread.x + 0.5, 1., 1.); +} diff --git a/bin/Nodes/GLSL/NormalMapBlending.glsl b/src/Shaders/NormalMapBlending.fs similarity index 79% rename from bin/Nodes/GLSL/NormalMapBlending.glsl rename to src/Shaders/NormalMapBlending.fs index ef2f60f6..cf8794f2 100644 --- a/bin/Nodes/GLSL/NormalMapBlending.glsl +++ b/src/Shaders/NormalMapBlending.fs @@ -1,7 +1,16 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); +SAMPLER2D(Sampler1, 1); //////////////////////////////////////////////////////////////////////////////////////// // Normal map blending by ZigguratVertigo https://www.shadertoy.com/view/4t2SzR +uniform vec4 mode; + #define TECHNIQUE_RNM 0 #define TECHNIQUE_PartialDerivatives 1 #define TECHNIQUE_Whiteout 2 @@ -103,32 +112,28 @@ vec3 NormalBlend_Overlay(vec3 n1, vec3 n2) } // Combine normals -vec3 CombineNormal(vec3 n1, vec3 n2, int technique) +vec3 CombineNormal(vec3 n1, vec3 n2) { - if (technique == TECHNIQUE_RNM) + int imode = int(mode.x); + if (imode == TECHNIQUE_RNM) return NormalBlend_RNM(n1, n2); - else if (technique == TECHNIQUE_PartialDerivatives) + else if (imode == TECHNIQUE_PartialDerivatives) return NormalBlend_PartialDerivatives(n1, n2); - else if (technique == TECHNIQUE_Whiteout) + else if (imode == TECHNIQUE_Whiteout) return NormalBlend_Whiteout(n1, n2); - else if (technique == TECHNIQUE_UDN) + else if (imode == TECHNIQUE_UDN) return NormalBlend_UDN(n1, n2); - else if (technique == TECHNIQUE_Unity) + else if (imode == TECHNIQUE_Unity) return NormalBlend_Unity(n1, n2); - else if (technique == TECHNIQUE_Linear) + else if (imode == TECHNIQUE_Linear) return NormalBlend_Linear(n1, n2); else return NormalBlend_Overlay(n1, n2); } -layout (std140) uniform NormalMapBlendingBlock -{ - int technique; -} NormalMapBlendingParam; - -vec4 NormalMapBlending() +void main() { - vec3 n1 = texture(Sampler0, vUV).xyz; - vec3 n2 = texture(Sampler1, vUV).xyz; - return vec4(CombineNormal(n1, n2, NormalMapBlendingParam.technique) * 0.5 + 0.5, 1.0); + vec3 n1 = texture2D(Sampler0, v_texcoord0).xyz; + vec3 n2 = texture2D(Sampler1, v_texcoord0).xyz; + gl_FragColor = vec4(CombineNormal(n1, n2) * 0.5 + 0.5, 1.0); } diff --git a/bin/Nodes/GLSL/PBR.glsl b/src/Shaders/PBR.fs similarity index 77% rename from bin/Nodes/GLSL/PBR.glsl rename to src/Shaders/PBR.fs index c02beb6c..1c1ae572 100644 --- a/bin/Nodes/GLSL/PBR.glsl +++ b/src/Shaders/PBR.fs @@ -1,12 +1,21 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); +SAMPLER2D(Sampler1, 1); +SAMPLER2D(Sampler2, 2); +SAMPLER2D(Sampler3, 3); +SAMPLERCUBE(CubeSampler4, 4); + ///////////////////////////////////////////////////////////////////////// // PBR by knarkowicz https://www.shadertoy.com/view/4sSfzK -layout (std140) uniform PBRBlock -{ - vec2 view; - float displacementFactor; - int geometry; -} PBRParam; +uniform vec4 view; +uniform vec4 displacementFactor; +uniform vec4 geometry; float camHeight = -0.2; @@ -68,18 +77,18 @@ vec3 EnvBRDFApprox( vec3 specularColor, float roughness, float ndotv ) vec3 EnvRemap( vec3 c ) { - return pow( 2. * c, vec3( 2.2 ) ); + return pow( 2. * c, vec3(2.2, 2.2, 2.2) ); } float displace(vec3 p) { float disp = boxmap(Sampler3, p, normalize(p), 1.0 ).x; - return -disp * PBRParam.displacementFactor; + return -disp * displacementFactor.x; } float DoorKnob( vec3 p, mat3 localToWorld ) { - p = p * localToWorld; + p = mul(localToWorld, p); // ring vec3 t = p; @@ -87,7 +96,7 @@ float DoorKnob( vec3 p, mat3 localToWorld ) float r = Substract( Disc( t, 0.9, .1 ), Cylinder( t, .7, 2. ) ); vec3 t2 = t - vec3( 0., 0., 1.0 ); Rotate( t2.xz, 0.25 * PI ); - r = Substract( r, Box( t2, vec3( .5 ) ) ); + r = Substract( r, Box( t2, vec3(0.5, 0.5, 0.5) ) ); r = Union( r, Disc( t + vec3( 0., 0.05, 0. ), 0.85, .05 ) ); t = p; @@ -109,24 +118,18 @@ float Scene( vec3 p, mat3 localToWorld ) vec3 centerMesh = vec3(0., -camHeight, 0.); float ret = 0.; - switch(PBRParam.geometry) - { - case 0: + int igeometry = int(geometry.x); + if (igeometry == 0) ret = DoorKnob(p, localToWorld); - break; - case 1: + else if (igeometry == 1) ret = Sphere(p+centerMesh, 1.0); - break; - case 2: - ret = Box(p+centerMesh, vec3(0.5)); - break; - case 3: + else if (igeometry == 2) + ret = Box(p+centerMesh, vec3(0.5, 0.5, 0.5)); + else if (igeometry == 3) ret = max(p.y, 0.); - break; - case 4: + if (igeometry == 4) ret = Cylinder(p+centerMesh, 0.7, 0.7); - break; - } + ret += displace(p); return ret; } @@ -140,13 +143,11 @@ float CastRay( in vec3 ro, in vec3 rd, mat3 localToWorld ) for ( int i = 0; i < 50; ++i ) { - if ( h < 0.001 || t > maxd ) + if ( h > 0.001 && t < maxd ) { - break; + h = Scene( ro + rd * t, localToWorld ); + t += h; } - - h = Scene( ro + rd * t, localToWorld ); - t += h; } if ( t > maxd ) @@ -182,13 +183,13 @@ float SceneAO( vec3 p, vec3 n, mat3 localToWorld ) return Smooth( 1.0 - 12.0 * ao ); } -vec4 PBR() +void main() { - vec2 p = vUV * 2.0 - 1.0; + vec2 p = v_texcoord0 * 2.0 - 1.0; // camera movement - float an = PBRParam.view.x * PI * 2.0; - float dn = PBRParam.view.y * PI * 0.5; + float an = view.x * PI * 2.0; + float dn = view.y * PI * 0.5; float cdn = cos(dn); vec3 ro = vec3( 2.0*sin(an)*cdn, camHeight + sin(dn)*2.0, 2.0*cos(an)*cdn ); @@ -205,22 +206,34 @@ vec4 PBR() mat3 localToWorld = mat3(vec3(1.0,0.0,0.0), vec3(0.0,1.0,0.0), vec3(0.0,0.0,1.0)); - vec3 lightColor = vec3( 2. ); + vec3 lightColor = vec3( 2., 2., 2. ); vec3 lightDir = normalize( vec3( .7, .9, -.2 ) ); - vec3 col = texture(CubeSampler4, InvertCubeY(rd)).xyz; + vec3 col = textureCube(CubeSampler4, InvertCubeY(rd)).xyz; float t = CastRay( ro, rd, localToWorld ); if ( t > 0.0 ) { + /* + displacement mapping + mat3 tbn = cotangent_frame( normal, pos, texcoord ); + + vec3 eyeToFragment = -rd;//(inverse(tbn) * -rd); todo + + texcoord = ParallaxMapping(Sampler2, texcoord, eyeToFragment, depthFactor.x); + + vec3 texNorm = texture2D(Sampler1, texcoord).xyz * 2.0 - 1.0; + + vec3 worldNormal = normalize(mul(tbn, texNorm)); + */ vec3 pos = ro + t * rd; vec3 normal = SceneNormal( pos, localToWorld ); vec3 viewDir = -rd; vec3 refl = reflect( rd, normal ); - vec3 diffuse = vec3( 0. ); - vec3 specular = vec3( 0. ); + vec3 diffuse = vec3( 0., 0., 0. ); + vec3 specular = vec3( 0., 0., 0. ); - vec3 baseColor = pow(boxmap(Sampler0, pos, normalize(pos), 1.0 ).xyz, vec3( 2.2 ) ); + vec3 baseColor = pow(boxmap(Sampler0, pos, normalize(pos), 1.0 ).xyz, vec3( 2.2, 2.2, 2.2) ); float roughness = boxmap(Sampler2, pos, normalize(pos), 1.0 ).x; vec3 diffuseColor = baseColor; @@ -236,7 +249,7 @@ vec4 PBR() vec3 envSpecularColor = EnvBRDFApprox( specularColor, roughnessE, ndotv ); - vec3 env = texture(CubeSampler4, InvertCubeY(refl), roughnessE*12.0).xyz; + vec3 env = textureCube(CubeSampler4, InvertCubeY(refl), roughnessE*12.0).xyz; diffuse += diffuseColor * EnvRemap(env); specular += envSpecularColor * env; @@ -255,6 +268,6 @@ vec4 PBR() col = diffuse + specular; } - col = pow( col * .4, vec3( 1. / 2.2 ) ); - return vec4(col,1.0); + col = pow( col * .4, vec3( 1. / 2.2, 1./2.2, 1./2.2 ) ); + gl_FragColor = vec4(col,1.0); } \ No newline at end of file diff --git a/src/Shaders/Paint2D.fs b/src/Shaders/Paint2D.fs new file mode 100644 index 00000000..b4c16889 --- /dev/null +++ b/src/Shaders/Paint2D.fs @@ -0,0 +1,37 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); + +vec4 brushSample(vec2 uv, float radius) +{ + vec2 nuv = (uv) / radius + vec2(0.5, 0.5); + float alphaMul = min(min(step(0.0, nuv.x), step(nuv.x, 1.0)), min(step(0.0, nuv.y), step(nuv.y, 1.0))); + return texture2D(Sampler0, nuv) * alphaMul; +} + +void main() +{ + vec4 res = vec4(0.0, 0.0, 0.0, 0.0); + float brushRadius = 0.25; + vec4 brush = brushSample(v_texcoord0-u_mouse.xy, brushRadius); + if (u_pass.x == 1.) + { + res = brush; + } + // paint pass + if (u_mouse.z > 0.0) + { + res = brush; + } + if (u_mouse.w > 0.0) + { + res = brush; + res.xyz = vec3(0.0, 0.0, 0.0); + } + + gl_FragColor = vec4(res.xyz*res.w, res.w); +} \ No newline at end of file diff --git a/src/Shaders/Paint3D.fs b/src/Shaders/Paint3D.fs new file mode 100644 index 00000000..47415018 --- /dev/null +++ b/src/Shaders/Paint3D.fs @@ -0,0 +1,61 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); +SAMPLER2D(Sampler1, 1); + +vec4 brushSample(vec2 uv, float radius) +{ + vec2 nuv = (uv) / radius + vec2(0.5, 0.5); + float alphaMul = min(min(step(0.0, nuv.x), step(nuv.x, 1.0)), min(step(0.0, nuv.y), step(nuv.y, 1.0))); + return texture2D(Sampler1, nuv) * alphaMul; +} + +vec4 brushSampleMouse(vec3 positionWorld) +{ + vec4 wPos = mul(u_viewProjection, vec4(positionWorld, 1.0)); + mat4 projMat = mat4( + vec4(1.0, 0.0, 0.0, 0.0), + vec4(0.0, 1.0, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(-(u_mouse.xy * 2.0 - 1.0), 0.0, 1.0)); + + vec4 projUV = mul(projMat, wPos); + return brushSample(projUV.xy/projUV.w, 0.3); +} + +void main() +{ + if (u_pass.x == 1.) + { + vec3 lightdir = normalize(vec3(1.0, 1.0, 1.0)); + float dt = max(dot(lightdir, normalize(v_normal)), 0.5); + vec4 tex = texture2D(Sampler0, v_texcoord0) * dt; + + + gl_FragColor = vec4(tex.xyz, 1.0) + brushSampleMouse(v_positionWorld) * vec4(1.0, 0.0, 0.0, 1.0); + } + else + { + vec4 res = vec4(0.0, 0.0, 0.0, 0.0); + if (u_keyModifier.x != 0. || u_keyModifier.y != 0. || u_keyModifier.z != 0.) + { + gl_FragColor = res; + return; + } + // paint pass + if (u_mouse.z > 0.0) + { + res = brushSampleMouse(v_positionWorld); + } + if (u_mouse.w > 0.0) + { + res = brushSampleMouse(v_positionWorld); + res.xyz = vec3(0.0, 0.0, 0.0); + } + gl_FragColor = vec4(res.xyz*res.w, res.w); + } +} \ No newline at end of file diff --git a/src/Shaders/Palette.fs b/src/Shaders/Palette.fs new file mode 100644 index 00000000..048b0d1c --- /dev/null +++ b/src/Shaders/Palette.fs @@ -0,0 +1,263 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 palette; +uniform vec4 ditherStrength; + +float find_closest(int x, int y, float c0) +{ + int dither[64]; + + dither[0] = 0; + dither[1] = 32; + dither[2] = 8; + dither[3] = 40; + dither[4] = 2; + dither[5] = 34; + dither[6] = 10; + dither[7] = 42; + dither[8] = 48; + dither[9] = 16; + + dither[10] = 56; + dither[11] = 24; + dither[12] = 50; + dither[13] = 18; + dither[14] = 58; + dither[15] = 26; + dither[16] = 12; + dither[17] = 44; + dither[18] = 4; + dither[19] = 36; + + dither[20] = 14; + dither[21] = 46; + dither[22] = 6; + dither[23] = 38; + dither[24] = 60; + dither[25] = 28; + dither[26] = 52; + dither[27] = 20; + dither[28] = 62; + dither[29] = 30; + + dither[30] = 54; + dither[31] = 22; + dither[32] = 3; + dither[33] = 35; + dither[34] = 11; + dither[35] = 43; + dither[36] = 1; + dither[37] = 33; + dither[38] = 9; + dither[39] = 41; + + dither[40] = 51; + dither[41] = 19; + dither[42] = 59; + dither[43] = 27; + dither[44] = 49; + dither[45] = 17; + dither[46] = 57; + dither[47] = 25; + dither[48] = 15; + dither[49] = 47; + + dither[50] = 7; + dither[51] = 39; + dither[52] = 13; + dither[53] = 45; + dither[54] = 5; + dither[55] = 37; + dither[56] = 63; + dither[57] = 31; + dither[58] = 55; + dither[59] = 23; + + dither[60] = 61; + dither[61] = 29; + dither[62] = 53; + dither[63] = 21; + + float limit = 0.0; + if(x < 8) + { + limit = float(dither[x*8+y]+1)/64.0; + } + + if(c0 < limit) + return 0.0; + return 1.0; +} + +#define best(X) {\ + vec4 best = pal[0];\ + for (int i = 1;i= arr[i].x && v <= arr[i+1].x) + { + // linear + //float t = (v-arr[i].x)/(arr[i+1].x-arr[i].x); + // smooth + float t = smoothstep(arr[i].x, arr[i+1].x, v); + return mix(arr[i].y, arr[i+1].y, t); + } + } + + return 0.0; +} + +void main() +{ + vec4 r; + vec4 tex = texture2D(Sampler0, v_texcoord0); + if (u_inputIndices[0].y > -1.) + r = texture2D(Sampler1, vec2(tex.x, 0.5)); + else + r = tex * GetRamp(tex.x, ramp); + + gl_FragColor = r; +} \ No newline at end of file diff --git a/src/Shaders/ReactionDiffusion.fs b/src/Shaders/ReactionDiffusion.fs new file mode 100644 index 00000000..9fd85d5c --- /dev/null +++ b/src/Shaders/ReactionDiffusion.fs @@ -0,0 +1,70 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); + +// adapted from https://www.shadertoy.com/view/4sccRj +uniform vec4 boost; +uniform vec4 divisor; +uniform vec4 colorStep; + +vec4 getSample(vec2 offset, vec2 fragCoord) +{ + return vec4(texture2D(Sampler0, (fragCoord.xy + offset) / u_viewport.xy).xyz, 1.0); +} + +vec4 T(float u, float v, vec2 fragCoord) +{ + return getSample(vec2(u,v), fragCoord); +} + +float f(float i) +{ + return exp(-i*i/4.)/sqrt(4.*PI); +} + +#define F(i) (f(i)) + +#define GH(i) T(float(i), 0., fc)*F(float(i)) +#define GV(i) T(0., float(i), fc)*F(float(i)) +#define BLURH (GH(-4) + GH(-3) + GH(-2) + GH(-1) + GH(0) + GH(1) + GH(2) + GH(3) + GH(4)) +#define BLURV (GV(-4) + GV(-3) + GV(-2) + GV(-1) + GV(0) + GV(1) + GV(2) + GV(3) + GV(4)) + +vec4 dopass(vec2 uv, vec2 fc) +{ + vec4 col = T(-1., -1., fc)*0.05 + T( 0., -1., fc)*0.20 + T( 1., -1., fc)*0.05 + + T(-1., 0., fc)*0.20 - T( 0., 0., fc)*1.00 + T( 1., 0., fc)*0.20 + + T(-1., 1., fc)*0.05 + T( 0., 1., fc)*0.20 + T( 1., 1., fc)*0.05; + col /= 8.0; + col = T(0., 0., fc) - col*50.0; + col -= 0.5; + col = col*boost.x; + col = smoothstep(vec4(-0.5, -0.5, -0.5, -0.5), vec4(0.5, 0.5, 0.5, 0.5), col); + float ra = length(col.xyz)/sqrt(divisor.x); + col = mix(col, vec4(ra,ra,ra,ra), colorStep.x); + return col; +} + +void main() +{ + vec2 fc = gl_FragCoord.xy; + int ip = int(mod(u_pass.y,3.)); + if (ip == 0) + { + vec4 col = BLURH; + col /= col.w; + gl_FragColor = col; + return; + } + if (ip == 1) + { + vec4 col = BLURV; + col /= col.w; + gl_FragColor = col; + return; + } + gl_FragColor = dopass(v_texcoord0, fc); +} diff --git a/src/Shaders/Sine.fs b/src/Shaders/Sine.fs new file mode 100644 index 00000000..a11605bd --- /dev/null +++ b/src/Shaders/Sine.fs @@ -0,0 +1,17 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +uniform vec4 translation; +uniform vec4 frequency; +uniform vec4 angle; + +void main() +{ + vec2 nuv = v_texcoord0 - vec2(0.5, 0.5) + translation.xy; + nuv = vec2(cos(angle.x), sin(angle.x)) * (nuv * frequency.x * PI * 2.0); + float r = cos(nuv.x + nuv.y) * 0.5 + 0.5; + gl_FragColor = vec4(r, r, r, r); +} diff --git a/src/Shaders/SmoothStep.fs b/src/Shaders/SmoothStep.fs new file mode 100644 index 00000000..816ed219 --- /dev/null +++ b/src/Shaders/SmoothStep.fs @@ -0,0 +1,15 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 low; +uniform vec4 high; + +void main() +{ + vec4 tex = texture2D(Sampler0, v_texcoord0); + gl_FragColor = smoothstep(low.x, high.x, tex); +} diff --git a/src/Shaders/Swirl.fs b/src/Shaders/Swirl.fs new file mode 100644 index 00000000..ef060be7 --- /dev/null +++ b/src/Shaders/Swirl.fs @@ -0,0 +1,20 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 angles; + +void main() +{ + vec2 uv = v_texcoord0 - vec2(0.5, 0.5); + float len = length(uv) / (SQRT2 * 0.5); + float angle = mix(angles.x, angles.y, len); + vec2 nuv = Rotate2D(uv, angle) + vec2(0.5, 0.5); + vec4 tex = texture2D(Sampler0, nuv); + + gl_FragColor = tex; +} diff --git a/src/Shaders/Tile.fs b/src/Shaders/Tile.fs new file mode 100644 index 00000000..64eb02e0 --- /dev/null +++ b/src/Shaders/Tile.fs @@ -0,0 +1,124 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); +SAMPLER2D(Sampler1, 1); + +// starting point : https://www.shadertoy.com/view/4d2Xzh +uniform vec4 translation; +uniform vec4 quincunx; +uniform vec4 noiseFactor; +uniform vec4 rotationFactor; +uniform vec4 scale; +uniform vec4 innerScale; + +float hash(float n) +{ + return fract(sin(n) * 437587.5453); +} + +float noise(vec2 p) +{ + return hash(p.x + p.y * 571.0); +} + +float smoothNoise2(vec2 p) +{ + vec2 p0 = floor(p + vec2(0.0, 0.0)); + vec2 p1 = floor(p + vec2(1.0, 0.0)); + vec2 p2 = floor(p + vec2(0.0, 1.0)); + vec2 p3 = floor(p + vec2(1.0, 1.0)); + vec2 pf = fract(p); + return mix( mix(noise(p0), noise(p1), pf.x), + mix(noise(p2), noise(p3), pf.x), pf.y); +} + +vec2 cellPoint(vec2 cell) +{ + float cellsize = 0.5; + vec2 vnoise = vec2(noise(cell) + cos(cell.y) * cellsize, + noise(cell*cellsize) + sin(cell.x) * cellsize) * noiseFactor.x; + float quincunxX = mod(cell.y,2.) * cellsize * quincunx.x; + float quincunxY = mod(cell.x,2.) * cellsize * quincunx.y; + return vnoise + vec2(quincunxX, quincunxY); +} + +vec4 getCell(vec2 t, out float rad, out float idx, out vec2 uvAtCellCenter) +{ + vec2 p = floor(t); + float nd = 1e10; + vec2 nc; + vec2 nq; + + { + for(int y = -1; y < 2; y += 1) + { + for(int x = -1; x < 2; x += 1) + { + vec2 b = vec2(float(x), float(y)); + vec2 q = b + p; + vec2 c = q + cellPoint(q); + vec2 r = c - t; + + float d = dot(r, r); + + if(d < nd) + { + nd = d; + nc = c; + nq = q; + uvAtCellCenter = c / scale.x - translation.xy; + } + } + } + } + rad = 1.0; + idx = nq.x + nq.y; + + { + for(int y = -1; y < 2; y += 1) + { + for(int x = -1; x < 2; x += 1) + { + if(x!=0 || y!=0) + { + + vec2 b = vec2(float(x), float(y)); + vec2 q = b + nq; + vec2 c = q + cellPoint(q); + + rad = min(rad, distance(nc, c) * 0.5); + } + } + } + } + return vec4((t - nc) / rad, nc); +} + +vec4 getSprite(vec2 uv, float ng) +{ + mat2 rot = mat2(vec2(cos(ng), -sin(ng)), vec2(sin(ng), cos(ng))); + uv = mul(rot, uv); + uv /= innerScale.x; + uv += 0.5; + //uv = max(min(uv, vec2(1.0)), vec2(0.0)); + return texture2D(Sampler0, uv); +} + +void main() +{ + float rad, idx; + vec2 uvAtCellCenter; + vec2 tt = (v_texcoord0 + translation.xy) * scale.x; + vec4 c = getCell(tt, rad, idx, uvAtCellCenter); + vec4 multiplier = vec4(1.0, 1.0, 1.0, 1.0); + if (u_inputIndices[0].y > -1.) + { + multiplier = texture2D(Sampler1, uvAtCellCenter); + } + vec4 spr = getSprite(c.xy, idx * rotationFactor.x) * multiplier; + gl_FragColor = vec4(spr.xyz, 1.0); +} diff --git a/src/Shaders/Transform.fs b/src/Shaders/Transform.fs new file mode 100644 index 00000000..27dd287f --- /dev/null +++ b/src/Shaders/Transform.fs @@ -0,0 +1,21 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 translate; +uniform vec4 scale; +uniform vec4 rotate; + +void main() +{ + vec2 rs = (v_texcoord0+vec2(translate.x, 1.0 - translate.y)) * scale.xy; + rs -= 0.5; + vec2 ro = vec2(rs.x*cos(rotate.x) - rs.y * sin(rotate.x), rs.x*sin(rotate.x) + rs.y * cos(rotate.x)); + ro += 0.5; + vec2 nuv = ro; + vec4 tex = texture2D(Sampler0, nuv); + gl_FragColor = tex; +} diff --git a/src/Shaders/Voronoi.fs b/src/Shaders/Voronoi.fs new file mode 100644 index 00000000..86fc4ff4 --- /dev/null +++ b/src/Shaders/Voronoi.fs @@ -0,0 +1,70 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); + +uniform vec4 translation; +uniform vec4 size; +uniform vec4 noise; +uniform vec4 colorInterpolation; +uniform vec4 distanceBlend; + + +float rand(float n){return fract(sin(n) * 43758.5453123);} + +float sdAxisAlignedRect(vec2 uv, vec2 tl, vec2 br) +{ + vec2 d = max(tl-uv, uv-br); + return length(max(vec2(0.0, 0.0), d)) + min(0.0, max(d.x, d.y)); +} + +float sdAxisAlignedRectManhattan(vec2 uv, vec2 tl, vec2 br) +{ + vec2 d = max(tl-uv, uv-br); + vec2 dif = vec2(max(vec2(0.0, 0.0), d)) + min(0.0, max(d.x, d.y)); + return max(dif.x, dif.y); +} + +void main() +{ + + vec2 nuv = v_texcoord0 + translation.xy; + //vec2 pst = floor(v_texcoord0*size.x); + vec2 p = floor(nuv*size.x); + vec2 f = fract(nuv*size.x); + + float k = 1.0+63.0*pow(1.0-colorInterpolation.x,4.0); + + vec3 va = vec3(0.,0.,0.); + float wt = 0.0; + vec3 color; + for( int j=-2; j<=2; j++ ) + { + for( int i=-2; i<=2; i++ ) + { + vec2 g = vec2( float(i),float(j) ); + vec3 o = hash3( p + g )*vec3(noise.x,noise.x,1.0); + + vec2 r = g - f + o.xy; + float d = mix(sqrt(dot(r,r)), abs(r.x)+abs(r.y), distanceBlend.x); + float ww = pow( 1.0-smoothstep(0.0,1.414,d), k ); + + if (u_inputIndices[0].x > -1.) + { + color = texture2D(Sampler0, (p + g + o.xy ) / size.x - translation.xy).xyz; + } + else + { + color = vec3(o.zzz); + } + va += color * ww; + wt += ww; + } + } + + vec3 result = va/wt; + gl_FragColor = vec4(result, 1.); +} \ No newline at end of file diff --git a/src/Shaders/Warp.fs b/src/Shaders/Warp.fs new file mode 100644 index 00000000..8cf2ef46 --- /dev/null +++ b/src/Shaders/Warp.fs @@ -0,0 +1,25 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" +#include "Common.shader" + +SAMPLER2D(Sampler0, 0); +SAMPLER2D(Sampler1, 1); + +uniform vec4 strength; +uniform vec4 mode; + +void main() +{ + vec4 texOffset = texture2D(Sampler1, v_texcoord0); + vec2 nuv = v_texcoord0; + int imode = int(mode.x); + if (imode == 0) + nuv += (texOffset.xy-0.5) * strength.x; + else + nuv += vec2(cos(texOffset.x * PI * 2.0), sin(texOffset.x * PI * 2.0)) * strength.x; + vec4 tex = texture2D(Sampler0, nuv); + + gl_FragColor = tex; +} diff --git a/src/Shaders/WorleyNoise.fs b/src/Shaders/WorleyNoise.fs new file mode 100644 index 00000000..d1d9de75 --- /dev/null +++ b/src/Shaders/WorleyNoise.fs @@ -0,0 +1,69 @@ +$input v_texcoord0, v_color0, v_positionWorld, v_normal + +#include "bgfx_shader.sh" +#include "CommonFS.shader" + +// https://github.com/Erkaman/glsl-worley +uniform vec4 translation; +uniform vec4 scale; +uniform vec4 jitter; +uniform vec4 manhattan; + +// Permutation polynomial: (34x^2 + x) mod 289 +vec3 permute(vec3 x) +{ + return mod((34.0 * x + 1.0) * x, 289.0); +} + +vec3 dist(vec3 x, vec3 y, bool manhattanDistance) +{ + return manhattanDistance ? abs(x) + abs(y) : (x * x + y * y); +} + +float worley(vec2 P, float jitter, bool manhattanDistance) +{ + float K= 0.142857142857; // 1/7 + float Ko= 0.428571428571 ;// 3/7 + vec2 Pi = mod(floor(P), 289.0); + vec2 Pf = fract(P); + vec3 oi = vec3(-1.0, 0.0, 1.0); + vec3 of = vec3(-0.5, 0.5, 1.5); + vec3 px = permute(Pi.x + oi); + vec3 p = permute(px.x + Pi.y + oi); // p11, p12, p13 + vec3 ox = fract(p*K) - Ko; + vec3 oy = mod(floor(p*K),7.0)*K - Ko; + vec3 dx = Pf.x + 0.5 + jitter*ox; + vec3 dy = Pf.y - of + jitter*oy; + vec3 d1 = dist(dx,dy, manhattanDistance); // d11, d12 and d13, squared + p = permute(px.y + Pi.y + oi); // p21, p22, p23 + ox = fract(p*K) - Ko; + oy = mod(floor(p*K),7.0)*K - Ko; + dx = Pf.x - 0.5 + jitter*ox; + dy = Pf.y - of + jitter*oy; + vec3 d2 = dist(dx,dy, manhattanDistance); // d21, d22 and d23, squared + p = permute(px.z + Pi.y + oi); // p31, p32, p33 + ox = fract(p*K) - Ko; + oy = mod(floor(p*K),7.0)*K - Ko; + dx = Pf.x - 1.5 + jitter*ox; + dy = Pf.y - of + jitter*oy; + vec3 d3 = dist(dx,dy, manhattanDistance); // d31, d32 and d33, squared + // Sort out the two smallest distances (F1, F2) + vec3 d1a = min(d1, d2); + d2 = max(d1, d2); // Swap to keep candidates for F2 + d2 = min(d2, d3); // neither F1 nor F2 are now in d3 + d1 = min(d1a, d2); // F1 is now in d1 + d2 = max(d1a, d2); // Swap to keep candidates for F2 + d1.xy = (d1.x < d1.y) ? d1.xy : d1.yx; // Swap if smaller + d1.xz = (d1.x < d1.z) ? d1.xz : d1.zx; // F1 is in d1.x + d1.yz = min(d1.yz, d2.yz); // F2 is now not in d2.yz + d1.y = min(d1.y, d1.z); // nor in d1.z + d1.y = min(d1.y, d2.x); // F2 is in d1.y, we're done. + return sqrt(d1.x); +} + +void main() +{ + float w = worley((v_texcoord0 + translation.xy) * scale.x, jitter.x, manhattan.x > 0.001); + gl_FragColor = vec4(w, w, w, w); +} + diff --git a/src/Shaders/bgfx_compute.sh b/src/Shaders/bgfx_compute.sh new file mode 100644 index 00000000..623747ec --- /dev/null +++ b/src/Shaders/bgfx_compute.sh @@ -0,0 +1,362 @@ +/* + * Copyright 2011-2019 Branimir Karadzic. All rights reserved. + * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause + */ + +#ifndef BGFX_COMPUTE_H_HEADER_GUARD +#define BGFX_COMPUTE_H_HEADER_GUARD + +#include "bgfx_shader.sh" + +#ifndef __cplusplus + +#if BGFX_SHADER_LANGUAGE_GLSL +# define __UAV_REG_0 4 +# define __UAV_REG_1 5 +# define __UAV_REG_2 6 +# define __UAV_REG_3 7 +#else +# define __UAV_REG_0 16 +# define __UAV_REG_1 17 +# define __UAV_REG_2 18 +# define __UAV_REG_3 19 +#endif // BGFX_SHADER_LANGUAGE_GLSL + +#define FRAMEBUFFER_IMAGE2D_RW(_name, _format, _reg) IMAGE2D_RW(_name, _format, __UAV_REG_ ## _reg) + +#if BGFX_SHADER_LANGUAGE_GLSL + +#define SHARED shared + +#define __IMAGE_XX(_name, _format, _reg, _image, _access) \ + layout(_format, binding=_reg) _access uniform highp _image _name + +#define readwrite +#define IMAGE2D_RO( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2D, readonly) +#define UIMAGE2D_RO(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2D, readonly) +#define IMAGE2D_WR( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2D, writeonly) +#define UIMAGE2D_WR(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2D, writeonly) +#define IMAGE2D_RW( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2D, readwrite) +#define UIMAGE2D_RW(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2D, readwrite) + +#define IMAGE2D_ARRAY_RO( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2DArray, readonly) +#define UIMAGE2D_ARRAY_RO(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2DArray, readonly) +#define IMAGE2D_ARRAY_WR( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2DArray, writeonly) +#define UIMAGE2D_ARRAY_WR(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2DArray, writeonly) +#define IMAGE2D_ARRAY_RW( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image2DArray, readwrite) +#define UIMAGE2D_ARRAY_RW(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage2DArray, readwrite) + +#define IMAGE3D_RO( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image3D, readonly) +#define UIMAGE3D_RO(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage3D, readonly) +#define IMAGE3D_WR( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image3D, writeonly) +#define UIMAGE3D_WR(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage3D, writeonly) +#define IMAGE3D_RW( _name, _format, _reg) __IMAGE_XX(_name, _format, _reg, image3D, readwrite) +#define UIMAGE3D_RW(_name, _format, _reg) __IMAGE_XX(_name, _format, _reg, uimage3D, readwrite) + +#define __BUFFER_XX(_name, _type, _reg, _access) \ + layout(std430, binding=_reg) _access buffer _name ## Buffer \ + { \ + _type _name[]; \ + } + +#define BUFFER_RO(_name, _type, _reg) __BUFFER_XX(_name, _type, _reg, readonly) +#define BUFFER_RW(_name, _type, _reg) __BUFFER_XX(_name, _type, _reg, readwrite) +#define BUFFER_WR(_name, _type, _reg) __BUFFER_XX(_name, _type, _reg, writeonly) + +#define NUM_THREADS(_x, _y, _z) layout (local_size_x = _x, local_size_y = _y, local_size_z = _z) in; + +#define atomicFetchAndAdd(_mem, _data, _original) _original = atomicAdd(_mem, _data) +#define atomicFetchAndAnd(_mem, _data, _original) _original = atomicAnd(_mem, _data) +#define atomicFetchAndMax(_mem, _data, _original) _original = atomicMax(_mem, _data) +#define atomicFetchAndMin(_mem, _data, _original) _original = atomicMin(_mem, _data) +#define atomicFetchAndOr(_mem, _data, _original) _original = atomicOr(_mem, _data) +#define atomicFetchAndXor(_mem, _data, _original) _original = atomicXor(_mem, _data) +#define atomicFetchAndExchange(_mem, _data, _original) _original = atomicExchange(_mem, _data) +#define atomicFetchCompareExchange(_mem, _compare, _data, _original) _original = atomicCompSwap(_mem,_compare, _data) + +#else + +#define SHARED groupshared + +#define r32ui uint +#define rg32ui uint2 +#define rgba32ui uint4 +#define r32f float +#define r16f float +#define rg16f float2 +#define rgba16f float4 +#if BGFX_SHADER_LANGUAGE_HLSL +# define rgba8 unorm float4 +# define rg8 unorm float2 +# define r8 unorm float +#else +# define rgba8 float4 +# define rg8 float2 +# define r8 float +#endif // BGFX_SHADER_LANGUAGE_HLSL +#define rgba32f float4 + +#define IMAGE2D_RO( _name, _format, _reg) \ + Texture2D<_format> _name ## Texture : REGISTER(t, _reg); \ + static BgfxROImage2D_ ## _format _name = { _name ## Texture } + +#define UIMAGE2D_RO(_name, _format, _reg) IMAGE2D_RO(_name, _format, _reg) + +#define IMAGE2D_RW( _name, _format, _reg) \ + RWTexture2D<_format> _name ## Texture : REGISTER(u, _reg); \ + static BgfxRWImage2D_ ## _format _name = { _name ## Texture } + +#define IMAGE2D_WR( _name, _format, _reg) IMAGE2D_RW(_name, _format, _reg) +#define UIMAGE2D_WR(_name, _format, _reg) IMAGE2D_RW(_name, _format, _reg) +#define UIMAGE2D_RW(_name, _format, _reg) IMAGE2D_RW(_name, _format, _reg) + +#define IMAGE2D_ARRAY_RO(_name, _format, _reg) \ + Texture2DArray<_format> _name ## Texture : REGISTER(t, _reg); \ + static BgfxROImage2DArray_ ## _format _name = { _name ## Texture } + +#define UIMAGE2D_ARRAY_RO(_name, _format, _reg) IMAGE2D_ARRAY_RO(_name, _format, _reg) + +#define IMAGE2D_ARRAY_RW(_name, _format, _reg) \ + RWTexture2DArray<_format> _name ## Texture : REGISTER(u, _reg); \ + static BgfxRWImage2DArray_ ## _format _name = { _name ## Texture } + +#define UIMAGE2D_ARRAY_RW(_name, _format, _reg) IMAGE2D_ARRAY_RW(_name, _format, _reg) +#define IMAGE2D_ARRAY_WR( _name, _format, _reg) IMAGE2D_ARRAY_RW(_name, _format, _reg) +#define UIMAGE2D_ARRAY_WR(_name, _format, _reg) IMAGE2D_ARRAY_RW(_name, _format, _reg) + +#define IMAGE3D_RO( _name, _format, _reg) \ + Texture3D<_format> _name ## Texture : REGISTER(t, _reg); \ + static BgfxROImage3D_ ## _format _name = { _name ## Texture } + +#define UIMAGE3D_RO(_name, _format, _reg) IMAGE3D_RO(_name, _format, _reg) + +#define IMAGE3D_RW( _name, _format, _reg) \ + RWTexture3D<_format> _name ## Texture : REGISTER(u, _reg); \ + static BgfxRWImage3D_ ## _format _name = { _name ## Texture } + +#define UIMAGE3D_RW(_name, _format, _reg) IMAGE3D_RW(_name, _format, _reg) +#define IMAGE3D_WR( _name, _format, _reg) IMAGE3D_RW(_name, _format, _reg) +#define UIMAGE3D_WR(_name, _format, _reg) IMAGE3D_RW(_name, _format, _reg) + +#if BGFX_SHADER_LANGUAGE_METAL +#define BUFFER_RO(_name, _struct, _reg) StructuredBuffer<_struct> _name : REGISTER(t, _reg) +#define BUFFER_RW(_name, _struct, _reg) RWStructuredBuffer <_struct> _name : REGISTER(u, _reg) +#define BUFFER_WR(_name, _struct, _reg) BUFFER_RW(_name, _struct, _reg) +#else +#define BUFFER_RO(_name, _struct, _reg) Buffer<_struct> _name : REGISTER(t, _reg) +#define BUFFER_RW(_name, _struct, _reg) RWBuffer<_struct> _name : REGISTER(u, _reg) +#define BUFFER_WR(_name, _struct, _reg) BUFFER_RW(_name, _struct, _reg) +#endif + +#define NUM_THREADS(_x, _y, _z) [numthreads(_x, _y, _z)] + +#define __IMAGE_IMPL_S(_format, _storeComponents, _type, _loadComponents) \ + \ + struct BgfxROImage2D_ ## _format \ + { \ + Texture2D<_format> m_texture; \ + }; \ + \ + struct BgfxRWImage2D_ ## _format \ + { \ + RWTexture2D<_format> m_texture; \ + }; \ + \ + struct BgfxROImage2DArray_ ## _format \ + { \ + Texture2DArray<_format> m_texture; \ + }; \ + \ + struct BgfxRWImage2DArray_ ## _format \ + { \ + RWTexture2DArray<_format> m_texture; \ + }; \ + \ + struct BgfxROImage3D_ ## _format \ + { \ + Texture3D<_format> m_texture; \ + }; \ + \ + struct BgfxRWImage3D_ ## _format \ + { \ + RWTexture3D<_format> m_texture; \ + }; \ + +#define __IMAGE_IMPL_A(_format, _storeComponents, _type, _loadComponents) \ + __IMAGE_IMPL_S(_format, _storeComponents, _type, _loadComponents) \ + \ + _type imageLoad(BgfxROImage2D_ ## _format _image, ivec2 _uv) \ + { \ + return _image.m_texture[_uv]._loadComponents; \ + } \ + \ + ivec2 imageSize(BgfxROImage2D_ ## _format _image) \ + { \ + uvec2 result; \ + _image.m_texture.GetDimensions(result.x, result.y); \ + return ivec2(result); \ + } \ + \ + _type imageLoad(BgfxRWImage2D_ ## _format _image, ivec2 _uv) \ + { \ + return _image.m_texture[_uv]._loadComponents; \ + } \ + \ + ivec2 imageSize(BgfxRWImage2D_ ## _format _image) \ + { \ + uvec2 result; \ + _image.m_texture.GetDimensions(result.x, result.y); \ + return ivec2(result); \ + } \ + \ + void imageStore(BgfxRWImage2D_ ## _format _image, ivec2 _uv, _type _value) \ + { \ + _image.m_texture[_uv] = _value._storeComponents; \ + } \ + \ + _type imageLoad(BgfxROImage2DArray_ ## _format _image, ivec3 _uvw) \ + { \ + return _image.m_texture[_uvw]._loadComponents; \ + } \ + \ + ivec3 imageSize(BgfxROImage2DArray_ ## _format _image) \ + { \ + uvec3 result; \ + _image.m_texture.GetDimensions(result.x, result.y, result.z); \ + return ivec3(result); \ + } \ + \ + _type imageLoad(BgfxRWImage2DArray_ ## _format _image, ivec3 _uvw) \ + { \ + return _image.m_texture[_uvw]._loadComponents; \ + } \ + \ + void imageStore(BgfxRWImage2DArray_ ## _format _image, ivec3 _uvw, _type _value) \ + { \ + _image.m_texture[_uvw] = _value._storeComponents; \ + } \ + \ + ivec3 imageSize(BgfxRWImage2DArray_ ## _format _image) \ + { \ + uvec3 result; \ + _image.m_texture.GetDimensions(result.x, result.y, result.z); \ + return ivec3(result); \ + } \ + \ + _type imageLoad(BgfxROImage3D_ ## _format _image, ivec3 _uvw) \ + { \ + return _image.m_texture[_uvw]._loadComponents; \ + } \ + \ + ivec3 imageSize(BgfxROImage3D_ ## _format _image) \ + { \ + uvec3 result; \ + _image.m_texture.GetDimensions(result.x, result.y, result.z); \ + return ivec3(result); \ + } \ + \ + _type imageLoad(BgfxRWImage3D_ ## _format _image, ivec3 _uvw) \ + { \ + return _image.m_texture[_uvw]._loadComponents; \ + } \ + \ + ivec3 imageSize(BgfxRWImage3D_ ## _format _image) \ + { \ + uvec3 result; \ + _image.m_texture.GetDimensions(result.x, result.y, result.z); \ + return ivec3(result); \ + } \ + \ + void imageStore(BgfxRWImage3D_ ## _format _image, ivec3 _uvw, _type _value) \ + { \ + _image.m_texture[_uvw] = _value._storeComponents; \ + } + +#define __IMAGE_IMPL_ATOMIC(_format, _storeComponents, _type, _loadComponents) \ + \ + void imageAtomicAdd(BgfxRWImage2D_ ## _format _image, ivec2 _uv, _type _value) \ + { \ + InterlockedAdd(_image.m_texture[_uv], _value._storeComponents); \ + } \ + + +__IMAGE_IMPL_A(rgba8, xyzw, vec4, xyzw) +__IMAGE_IMPL_A(rg8, xy, vec4, xyyy) +__IMAGE_IMPL_A(r8, x, vec4, xxxx) +__IMAGE_IMPL_A(rg16f, xy, vec4, xyyy) +#if BGFX_SHADER_LANGUAGE_HLSL +__IMAGE_IMPL_S(rgba16f, xyzw, vec4, xyzw) +__IMAGE_IMPL_S(r16f, x, vec4, xxxx) +#else +__IMAGE_IMPL_A(rgba16f, xyzw, vec4, xyzw) +__IMAGE_IMPL_A(r16f, x, vec4, xxxx) +#endif // BGFX_SHADER_LANGUAGE_HLSL +__IMAGE_IMPL_A(r32f, x, vec4, xxxx) +__IMAGE_IMPL_A(rgba32f, xyzw, vec4, xyzw) +__IMAGE_IMPL_A(r32ui, x, uvec4, xxxx) +__IMAGE_IMPL_A(rg32ui, xy, uvec4, xyyy) +__IMAGE_IMPL_A(rgba32ui, xyzw, uvec4, xyzw) + +__IMAGE_IMPL_ATOMIC(r32ui, x, uvec4, xxxx) + +#define atomicAdd(_mem, _data) InterlockedAdd(_mem, _data) +#define atomicAnd(_mem, _data) InterlockedAnd(_mem, _data) +#define atomicMax(_mem, _data) InterlockedMax(_mem, _data) +#define atomicMin(_mem, _data) InterlockedMin(_mem, _data) +#define atomicOr(_mem, _data) InterlockedOr(_mem, _data) +#define atomicXor(_mem, _data) InterlockedXor(_mem, _data) +#define atomicFetchAndAdd(_mem, _data, _original) InterlockedAdd(_mem, _data, _original) +#define atomicFetchAndAnd(_mem, _data, _original) InterlockedAnd(_mem, _data, _original) +#define atomicFetchAndMax(_mem, _data, _original) InterlockedMax(_mem, _data, _original) +#define atomicFetchAndMin(_mem, _data, _original) InterlockedMin(_mem, _data, _original) +#define atomicFetchAndOr(_mem, _data, _original) InterlockedOr(_mem, _data, _original) +#define atomicFetchAndXor(_mem, _data, _original) InterlockedXor(_mem, _data, _original) +#define atomicFetchAndExchange(_mem, _data, _original) InterlockedExchange(_mem, _data, _original) +#define atomicFetchCompareExchange(_mem, _compare, _data, _original) InterlockedCompareExchange(_mem,_compare, _data, _original) + +// InterlockedCompareStore + +#define barrier() GroupMemoryBarrierWithGroupSync() +#define memoryBarrier() GroupMemoryBarrierWithGroupSync() +#define memoryBarrierAtomicCounter() GroupMemoryBarrierWithGroupSync() +#define memoryBarrierBuffer() AllMemoryBarrierWithGroupSync() +#define memoryBarrierImage() GroupMemoryBarrierWithGroupSync() +#define memoryBarrierShared() GroupMemoryBarrierWithGroupSync() +#define groupMemoryBarrier() GroupMemoryBarrierWithGroupSync() + +#endif // BGFX_SHADER_LANGUAGE_GLSL + +#define dispatchIndirect( \ + _buffer \ + , _offset \ + , _numX \ + , _numY \ + , _numZ \ + ) \ + _buffer[_offset*2+0] = uvec4(_numX, _numY, _numZ, 0u) + +#define drawIndirect( \ + _buffer \ + , _offset \ + , _numVertices \ + , _numInstances \ + , _startVertex \ + , _startInstance \ + ) \ + _buffer[_offset*2+0] = uvec4(_numVertices, _numInstances, _startVertex, _startInstance) + +#define drawIndexedIndirect( \ + _buffer \ + , _offset \ + , _numIndices \ + , _numInstances \ + , _startIndex \ + , _startVertex \ + , _startInstance \ + ) \ + _buffer[_offset*2+0] = uvec4(_numIndices, _numInstances, _startIndex, _startVertex); \ + _buffer[_offset*2+1] = uvec4(_startInstance, 0u, 0u, 0u) + +#endif // __cplusplus + +#endif // BGFX_COMPUTE_H_HEADER_GUARD diff --git a/src/Shaders/bgfx_shader.sh b/src/Shaders/bgfx_shader.sh new file mode 100644 index 00000000..3b669458 --- /dev/null +++ b/src/Shaders/bgfx_shader.sh @@ -0,0 +1,590 @@ +/* + * Copyright 2011-2019 Branimir Karadzic. All rights reserved. + * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause + */ + +#ifndef BGFX_SHADER_H_HEADER_GUARD +#define BGFX_SHADER_H_HEADER_GUARD + +#if !defined(BGFX_CONFIG_MAX_BONES) +# define BGFX_CONFIG_MAX_BONES 32 +#endif // !defined(BGFX_CONFIG_MAX_BONES) + +#ifndef __cplusplus + +#if BGFX_SHADER_LANGUAGE_HLSL > 3 +# define BRANCH [branch] +# define LOOP [loop] +# define UNROLL [unroll] +#else +# define BRANCH +# define LOOP +# define UNROLL +#endif // BGFX_SHADER_LANGUAGE_HLSL > 3 + +#if BGFX_SHADER_LANGUAGE_HLSL > 3 && BGFX_SHADER_TYPE_FRAGMENT +# define EARLY_DEPTH_STENCIL [earlydepthstencil] +#else +# define EARLY_DEPTH_STENCIL +#endif // BGFX_SHADER_LANGUAGE_HLSL > 3 && BGFX_SHADER_TYPE_FRAGMENT + +#if BGFX_SHADER_LANGUAGE_GLSL +# define ARRAY_BEGIN(_type, _name, _count) _type _name[_count] = _type[]( +# define ARRAY_END() ) +#else +# define ARRAY_BEGIN(_type, _name, _count) _type _name[_count] = { +# define ARRAY_END() } +#endif // BGFX_SHADER_LANGUAGE_GLSL + +#if BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL +# define CONST(_x) static const _x +# define dFdx(_x) ddx(_x) +# define dFdy(_y) ddy(-_y) +# define inversesqrt(_x) rsqrt(_x) +# define fract(_x) frac(_x) + +# define bvec2 bool2 +# define bvec3 bool3 +# define bvec4 bool4 + +# if BGFX_SHADER_LANGUAGE_HLSL > 4 +# define REGISTER(_type, _reg) register(_type[_reg]) +# else +# define REGISTER(_type, _reg) register(_type ## _reg) +# endif // BGFX_SHADER_LANGUAGE_HLSL + +# if BGFX_SHADER_LANGUAGE_HLSL > 3 || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL +# if BGFX_SHADER_LANGUAGE_HLSL > 4 || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL +# define dFdxCoarse(_x) ddx_coarse(_x) +# define dFdxFine(_x) ddx_fine(_x) +# define dFdyCoarse(_y) ddy_coarse(-_y) +# define dFdyFine(_y) ddy_fine(-_y) +# endif // BGFX_SHADER_LANGUAGE_HLSL > 4 + +# if BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL +float intBitsToFloat(int _x) { return asfloat(_x); } +vec2 intBitsToFloat(uint2 _x) { return asfloat(_x); } +vec3 intBitsToFloat(uint3 _x) { return asfloat(_x); } +vec4 intBitsToFloat(uint4 _x) { return asfloat(_x); } +# endif // BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL + +float uintBitsToFloat(uint _x) { return asfloat(_x); } +vec2 uintBitsToFloat(uint2 _x) { return asfloat(_x); } +vec3 uintBitsToFloat(uint3 _x) { return asfloat(_x); } +vec4 uintBitsToFloat(uint4 _x) { return asfloat(_x); } + +uint floatBitsToUint(float _x) { return asuint(_x); } +uvec2 floatBitsToUint(vec2 _x) { return asuint(_x); } +uvec3 floatBitsToUint(vec3 _x) { return asuint(_x); } +uvec4 floatBitsToUint(vec4 _x) { return asuint(_x); } + +int floatBitsToInt(float _x) { return asint(_x); } +ivec2 floatBitsToInt(vec2 _x) { return asint(_x); } +ivec3 floatBitsToInt(vec3 _x) { return asint(_x); } +ivec4 floatBitsToInt(vec4 _x) { return asint(_x); } + +uint bitfieldReverse(uint _x) { return reversebits(_x); } +uint2 bitfieldReverse(uint2 _x) { return reversebits(_x); } +uint3 bitfieldReverse(uint3 _x) { return reversebits(_x); } +uint4 bitfieldReverse(uint4 _x) { return reversebits(_x); } + +# if !BGFX_SHADER_LANGUAGE_SPIRV +uint packHalf2x16(vec2 _x) +{ + return (f32tof16(_x.y)<<16) | f32tof16(_x.x); +} + +vec2 unpackHalf2x16(uint _x) +{ + return vec2(f16tof32(_x & 0xffff), f16tof32(_x >> 16) ); +} +# endif // !BGFX_SHADER_LANGUAGE_SPIRV + +struct BgfxSampler2D +{ + SamplerState m_sampler; + Texture2D m_texture; +}; + +struct BgfxISampler2D +{ + Texture2D m_texture; +}; + +struct BgfxUSampler2D +{ + Texture2D m_texture; +}; + +struct BgfxSampler2DArray +{ + SamplerState m_sampler; + Texture2DArray m_texture; +}; + +struct BgfxSampler2DShadow +{ + SamplerComparisonState m_sampler; + Texture2D m_texture; +}; + +struct BgfxSampler2DArrayShadow +{ + SamplerComparisonState m_sampler; + Texture2DArray m_texture; +}; + +struct BgfxSampler3D +{ + SamplerState m_sampler; + Texture3D m_texture; +}; + +struct BgfxISampler3D +{ + Texture3D m_texture; +}; + +struct BgfxUSampler3D +{ + Texture3D m_texture; +}; + +struct BgfxSamplerCube +{ + SamplerState m_sampler; + TextureCube m_texture; +}; + +struct BgfxSamplerCubeShadow +{ + SamplerComparisonState m_sampler; + TextureCube m_texture; +}; + +struct BgfxSampler2DMS +{ + Texture2DMS m_texture; +}; + +vec4 bgfxTexture2D(BgfxSampler2D _sampler, vec2 _coord) +{ + return _sampler.m_texture.Sample(_sampler.m_sampler, _coord); +} + +vec4 bgfxTexture2DLod(BgfxSampler2D _sampler, vec2 _coord, float _level) +{ + return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level); +} + +vec4 bgfxTexture2DLodOffset(BgfxSampler2D _sampler, vec2 _coord, float _level, ivec2 _offset) +{ + return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level, _offset); +} + +vec4 bgfxTexture2DProj(BgfxSampler2D _sampler, vec3 _coord) +{ + vec2 coord = _coord.xy * rcp(_coord.z); + return _sampler.m_texture.Sample(_sampler.m_sampler, coord); +} + +vec4 bgfxTexture2DProj(BgfxSampler2D _sampler, vec4 _coord) +{ + vec2 coord = _coord.xy * rcp(_coord.w); + return _sampler.m_texture.Sample(_sampler.m_sampler, coord); +} + +vec4 bgfxTexture2DGrad(BgfxSampler2D _sampler, vec2 _coord, vec2 _dPdx, vec2 _dPdy) +{ + return _sampler.m_texture.SampleGrad(_sampler.m_sampler, _coord, _dPdx, _dPdy); +} + +vec4 bgfxTexture2DArray(BgfxSampler2DArray _sampler, vec3 _coord) +{ + return _sampler.m_texture.Sample(_sampler.m_sampler, _coord); +} + +vec4 bgfxTexture2DArrayLod(BgfxSampler2DArray _sampler, vec3 _coord, float _lod) +{ + return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _lod); +} + +vec4 bgfxTexture2DArrayLodOffset(BgfxSampler2DArray _sampler, vec3 _coord, float _level, ivec2 _offset) +{ + return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level, _offset); +} + +float bgfxShadow2D(BgfxSampler2DShadow _sampler, vec3 _coord) +{ + return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, _coord.xy, _coord.z); +} + +float bgfxShadow2DProj(BgfxSampler2DShadow _sampler, vec4 _coord) +{ + vec3 coord = _coord.xyz * rcp(_coord.w); + return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, coord.xy, coord.z); +} + +vec4 bgfxShadow2DArray(BgfxSampler2DArrayShadow _sampler, vec4 _coord) +{ + return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, _coord.xyz, _coord.w); +} + +vec4 bgfxTexture3D(BgfxSampler3D _sampler, vec3 _coord) +{ + return _sampler.m_texture.Sample(_sampler.m_sampler, _coord); +} + +vec4 bgfxTexture3DLod(BgfxSampler3D _sampler, vec3 _coord, float _level) +{ + return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level); +} + +ivec4 bgfxTexture3D(BgfxISampler3D _sampler, vec3 _coord) +{ + uvec3 size; + _sampler.m_texture.GetDimensions(size.x, size.y, size.z); + return _sampler.m_texture.Load(ivec4(_coord * size, 0) ); +} + +uvec4 bgfxTexture3D(BgfxUSampler3D _sampler, vec3 _coord) +{ + uvec3 size; + _sampler.m_texture.GetDimensions(size.x, size.y, size.z); + return _sampler.m_texture.Load(ivec4(_coord * size, 0) ); +} + +vec4 bgfxTextureCube(BgfxSamplerCube _sampler, vec3 _coord) +{ + return _sampler.m_texture.Sample(_sampler.m_sampler, _coord); +} + +vec4 bgfxTextureCubeLod(BgfxSamplerCube _sampler, vec3 _coord, float _level) +{ + return _sampler.m_texture.SampleLevel(_sampler.m_sampler, _coord, _level); +} + +float bgfxShadowCube(BgfxSamplerCubeShadow _sampler, vec4 _coord) +{ + return _sampler.m_texture.SampleCmpLevelZero(_sampler.m_sampler, _coord.xyz, _coord.w); +} + +vec4 bgfxTexelFetch(BgfxSampler2D _sampler, ivec2 _coord, int _lod) +{ + return _sampler.m_texture.Load(ivec3(_coord, _lod) ); +} + +vec4 bgfxTexelFetchOffset(BgfxSampler2D _sampler, ivec2 _coord, int _lod, ivec2 _offset) +{ + return _sampler.m_texture.Load(ivec3(_coord, _lod), _offset ); +} + +vec2 bgfxTextureSize(BgfxSampler2D _sampler, int _lod) +{ + vec2 result; + _sampler.m_texture.GetDimensions(result.x, result.y); + return result; +} + +vec4 bgfxTextureGather(BgfxSampler2D _sampler, vec2 _coord) +{ + return _sampler.m_texture.GatherRed(_sampler.m_sampler, _coord ); +} +vec4 bgfxTextureGatherOffset(BgfxSampler2D _sampler, vec2 _coord, ivec2 _offset) +{ + return _sampler.m_texture.GatherRed(_sampler.m_sampler, _coord, _offset ); +} +vec4 bgfxTextureGather(BgfxSampler2DArray _sampler, vec3 _coord) +{ + return _sampler.m_texture.GatherRed(_sampler.m_sampler, _coord ); +} + +ivec4 bgfxTexelFetch(BgfxISampler2D _sampler, ivec2 _coord, int _lod) +{ + return _sampler.m_texture.Load(ivec3(_coord, _lod) ); +} + +uvec4 bgfxTexelFetch(BgfxUSampler2D _sampler, ivec2 _coord, int _lod) +{ + return _sampler.m_texture.Load(ivec3(_coord, _lod) ); +} + +vec4 bgfxTexelFetch(BgfxSampler2DMS _sampler, ivec2 _coord, int _sampleIdx) +{ + return _sampler.m_texture.Load(_coord, _sampleIdx); +} + +vec4 bgfxTexelFetch(BgfxSampler2DArray _sampler, ivec3 _coord, int _lod) +{ + return _sampler.m_texture.Load(ivec4(_coord, _lod) ); +} + +vec4 bgfxTexelFetch(BgfxSampler3D _sampler, ivec3 _coord, int _lod) +{ + return _sampler.m_texture.Load(ivec4(_coord, _lod) ); +} + +vec3 bgfxTextureSize(BgfxSampler3D _sampler, int _lod) +{ + vec3 result; + _sampler.m_texture.GetDimensions(result.x, result.y, result.z); + return result; +} + +# define SAMPLER2D(_name, _reg) \ + uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \ + uniform Texture2D _name ## Texture : REGISTER(t, _reg); \ + static BgfxSampler2D _name = { _name ## Sampler, _name ## Texture } +# define ISAMPLER2D(_name, _reg) \ + uniform Texture2D _name ## Texture : REGISTER(t, _reg); \ + static BgfxISampler2D _name = { _name ## Texture } +# define USAMPLER2D(_name, _reg) \ + uniform Texture2D _name ## Texture : REGISTER(t, _reg); \ + static BgfxUSampler2D _name = { _name ## Texture } +# define sampler2D BgfxSampler2D +# define texture2D(_sampler, _coord) bgfxTexture2D(_sampler, _coord) +# define texture2DLod(_sampler, _coord, _level) bgfxTexture2DLod(_sampler, _coord, _level) +# define texture2DLodOffset(_sampler, _coord, _level, _offset) bgfxTexture2DLodOffset(_sampler, _coord, _level, _offset) +# define texture2DProj(_sampler, _coord) bgfxTexture2DProj(_sampler, _coord) +# define texture2DGrad(_sampler, _coord, _dPdx, _dPdy) bgfxTexture2DGrad(_sampler, _coord, _dPdx, _dPdy) + +# define SAMPLER2DARRAY(_name, _reg) \ + uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \ + uniform Texture2DArray _name ## Texture : REGISTER(t, _reg); \ + static BgfxSampler2DArray _name = { _name ## Sampler, _name ## Texture } +# define sampler2DArray BgfxSampler2DArray +# define texture2DArray(_sampler, _coord) bgfxTexture2DArray(_sampler, _coord) +# define texture2DArrayLod(_sampler, _coord, _lod) bgfxTexture2DArrayLod(_sampler, _coord, _lod) +# define texture2DArrayLodOffset(_sampler, _coord, _level, _offset) bgfxTexture2DArrayLodOffset(_sampler, _coord, _level, _offset) + +# define SAMPLER2DMS(_name, _reg) \ + uniform Texture2DMS _name ## Texture : REGISTER(t, _reg); \ + static BgfxSampler2DMS _name = { _name ## Texture } +# define sampler2DMS BgfxSampler2DMS + +# define SAMPLER2DSHADOW(_name, _reg) \ + uniform SamplerComparisonState _name ## SamplerComparison : REGISTER(s, _reg); \ + uniform Texture2D _name ## Texture : REGISTER(t, _reg); \ + static BgfxSampler2DShadow _name = { _name ## SamplerComparison, _name ## Texture } +# define sampler2DShadow BgfxSampler2DShadow +# define shadow2D(_sampler, _coord) bgfxShadow2D(_sampler, _coord) +# define shadow2DProj(_sampler, _coord) bgfxShadow2DProj(_sampler, _coord) + +# define SAMPLER2DARRAYSHADOW(_name, _reg) \ + SamplerComparisonState _name ## SamplerComparison : REGISTER(s, _reg); \ + Texture2DArray _name ## Texture : REGISTER(t, _reg); \ + BgfxSampler2DArrayShadow _name = { _name ## SamplerComparison, _name ## Texture } +# define sampler2DArrayShadow BgfxSampler2DArrayShadow +# define shadow2DArray(_sampler, _coord) bgfxShadow2DArray(_sampler, _coord) + +# define SAMPLER3D(_name, _reg) \ + uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \ + uniform Texture3D _name ## Texture : REGISTER(t, _reg); \ + static BgfxSampler3D _name = { _name ## Sampler, _name ## Texture } +# define ISAMPLER3D(_name, _reg) \ + uniform Texture3D _name ## Texture : REGISTER(t, _reg); \ + static BgfxISampler3D _name = { _name ## Texture } +# define USAMPLER3D(_name, _reg) \ + uniform Texture3D _name ## Texture : REGISTER(t, _reg); \ + static BgfxUSampler3D _name = { _name ## Texture } +# define sampler3D BgfxSampler3D +# define texture3D(_sampler, _coord) bgfxTexture3D(_sampler, _coord) +# define texture3DLod(_sampler, _coord, _level) bgfxTexture3DLod(_sampler, _coord, _level) + +# define SAMPLERCUBE(_name, _reg) \ + uniform SamplerState _name ## Sampler : REGISTER(s, _reg); \ + uniform TextureCube _name ## Texture : REGISTER(t, _reg); \ + static BgfxSamplerCube _name = { _name ## Sampler, _name ## Texture } +# define samplerCube BgfxSamplerCube +# define textureCube(_sampler, _coord) bgfxTextureCube(_sampler, _coord) +# define textureCubeLod(_sampler, _coord, _level) bgfxTextureCubeLod(_sampler, _coord, _level) + +# define SAMPLERCUBESHADOW(_name, _reg) \ + uniform SamplerComparisonState _name ## SamplerComparison : REGISTER(s, _reg); \ + uniform TextureCube _name ## Texture : REGISTER(t, _reg); \ + static BgfxSamplerCubeShadow _name = { _name ## SamplerComparison, _name ## Texture } +# define samplerCubeShadow BgfxSamplerCubeShadow +# define shadowCube(_sampler, _coord) bgfxShadowCube(_sampler, _coord) + +# define texelFetch(_sampler, _coord, _lod) bgfxTexelFetch(_sampler, _coord, _lod) +# define texelFetchOffset(_sampler, _coord, _lod, _offset) bgfxTexelFetchOffset(_sampler, _coord, _lod, _offset) +# define textureSize(_sampler, _lod) bgfxTextureSize(_sampler, _lod) +# define textureGather(_sampler, _coord) bgfxTextureGather(_sampler, _coord) +# define textureGatherOffset(_sampler, _coord, _offset) bgfxTextureGatherOffset(_sampler, _coord, _offset) +# else + +# define sampler2DShadow sampler2D + +vec4 bgfxTexture2DProj(sampler2D _sampler, vec3 _coord) +{ + return tex2Dproj(_sampler, vec4(_coord.xy, 0.0, _coord.z) ); +} + +vec4 bgfxTexture2DProj(sampler2D _sampler, vec4 _coord) +{ + return tex2Dproj(_sampler, _coord); +} + +float bgfxShadow2D(sampler2DShadow _sampler, vec3 _coord) +{ +#if 0 + float occluder = tex2D(_sampler, _coord.xy).x; + return step(_coord.z, occluder); +#else + return tex2Dproj(_sampler, vec4(_coord.xy, _coord.z, 1.0) ).x; +#endif // 0 +} + +float bgfxShadow2DProj(sampler2DShadow _sampler, vec4 _coord) +{ +#if 0 + vec3 coord = _coord.xyz * rcp(_coord.w); + float occluder = tex2D(_sampler, coord.xy).x; + return step(coord.z, occluder); +#else + return tex2Dproj(_sampler, _coord).x; +#endif // 0 +} + +# define SAMPLER2D(_name, _reg) uniform sampler2D _name : REGISTER(s, _reg) +# define SAMPLER2DMS(_name, _reg) uniform sampler2DMS _name : REGISTER(s, _reg) +# define texture2D(_sampler, _coord) tex2D(_sampler, _coord) +# define texture2DProj(_sampler, _coord) bgfxTexture2DProj(_sampler, _coord) + +# define SAMPLER2DARRAY(_name, _reg) SAMPLER2D(_name, _reg) +# define texture2DArray(_sampler, _coord) texture2D(_sampler, (_coord).xy) +# define texture2DArrayLod(_sampler, _coord, _lod) texture2DLod(_sampler, _coord, _lod) + +# define SAMPLER2DSHADOW(_name, _reg) uniform sampler2DShadow _name : REGISTER(s, _reg) +# define shadow2D(_sampler, _coord) bgfxShadow2D(_sampler, _coord) +# define shadow2DProj(_sampler, _coord) bgfxShadow2DProj(_sampler, _coord) + +# define SAMPLER3D(_name, _reg) uniform sampler3D _name : REGISTER(s, _reg) +# define texture3D(_sampler, _coord) tex3D(_sampler, _coord) + +# define SAMPLERCUBE(_name, _reg) uniform samplerCUBE _name : REGISTER(s, _reg) +# define textureCube(_sampler, _coord) texCUBE(_sampler, _coord) + +# if BGFX_SHADER_LANGUAGE_HLSL == 2 +# define texture2DLod(_sampler, _coord, _level) tex2D(_sampler, (_coord).xy) +# define texture2DGrad(_sampler, _coord, _dPdx, _dPdy) tex2D(_sampler, _coord) +# define texture3DLod(_sampler, _coord, _level) tex3D(_sampler, (_coord).xyz) +# define textureCubeLod(_sampler, _coord, _level) texCUBE(_sampler, (_coord).xyz) +# else +# define texture2DLod(_sampler, _coord, _level) tex2Dlod(_sampler, vec4( (_coord).xy, 0.0, _level) ) +# define texture2DGrad(_sampler, _coord, _dPdx, _dPdy) tex2Dgrad(_sampler, _coord, _dPdx, _dPdy) +# define texture3DLod(_sampler, _coord, _level) tex3Dlod(_sampler, vec4( (_coord).xyz, _level) ) +# define textureCubeLod(_sampler, _coord, _level) texCUBElod(_sampler, vec4( (_coord).xyz, _level) ) +# endif // BGFX_SHADER_LANGUAGE_HLSL == 2 + +# endif // BGFX_SHADER_LANGUAGE_HLSL > 3 + +vec3 instMul(vec3 _vec, mat3 _mtx) { return mul(_mtx, _vec); } +vec3 instMul(mat3 _mtx, vec3 _vec) { return mul(_vec, _mtx); } +vec4 instMul(vec4 _vec, mat4 _mtx) { return mul(_mtx, _vec); } +vec4 instMul(mat4 _mtx, vec4 _vec) { return mul(_vec, _mtx); } + +bvec2 lessThan(vec2 _a, vec2 _b) { return _a < _b; } +bvec3 lessThan(vec3 _a, vec3 _b) { return _a < _b; } +bvec4 lessThan(vec4 _a, vec4 _b) { return _a < _b; } + +bvec2 lessThanEqual(vec2 _a, vec2 _b) { return _a <= _b; } +bvec3 lessThanEqual(vec3 _a, vec3 _b) { return _a <= _b; } +bvec4 lessThanEqual(vec4 _a, vec4 _b) { return _a <= _b; } + +bvec2 greaterThan(vec2 _a, vec2 _b) { return _a > _b; } +bvec3 greaterThan(vec3 _a, vec3 _b) { return _a > _b; } +bvec4 greaterThan(vec4 _a, vec4 _b) { return _a > _b; } + +bvec2 greaterThanEqual(vec2 _a, vec2 _b) { return _a >= _b; } +bvec3 greaterThanEqual(vec3 _a, vec3 _b) { return _a >= _b; } +bvec4 greaterThanEqual(vec4 _a, vec4 _b) { return _a >= _b; } + +bvec2 notEqual(vec2 _a, vec2 _b) { return _a != _b; } +bvec3 notEqual(vec3 _a, vec3 _b) { return _a != _b; } +bvec4 notEqual(vec4 _a, vec4 _b) { return _a != _b; } + +bvec2 equal(vec2 _a, vec2 _b) { return _a == _b; } +bvec3 equal(vec3 _a, vec3 _b) { return _a == _b; } +bvec4 equal(vec4 _a, vec4 _b) { return _a == _b; } + +float mix(float _a, float _b, float _t) { return lerp(_a, _b, _t); } +vec2 mix(vec2 _a, vec2 _b, vec2 _t) { return lerp(_a, _b, _t); } +vec3 mix(vec3 _a, vec3 _b, vec3 _t) { return lerp(_a, _b, _t); } +vec4 mix(vec4 _a, vec4 _b, vec4 _t) { return lerp(_a, _b, _t); } + +float mod(float _a, float _b) { return _a - _b * floor(_a / _b); } +vec2 mod(vec2 _a, vec2 _b) { return _a - _b * floor(_a / _b); } +vec3 mod(vec3 _a, vec3 _b) { return _a - _b * floor(_a / _b); } +vec4 mod(vec4 _a, vec4 _b) { return _a - _b * floor(_a / _b); } + +#else +# define CONST(_x) const _x +# define atan2(_x, _y) atan(_x, _y) +# define mul(_a, _b) ( (_a) * (_b) ) +# define saturate(_x) clamp(_x, 0.0, 1.0) +# define SAMPLER2D(_name, _reg) uniform sampler2D _name +# define SAMPLER2DMS(_name, _reg) uniform sampler2DMS _name +# define SAMPLER3D(_name, _reg) uniform sampler3D _name +# define SAMPLERCUBE(_name, _reg) uniform samplerCube _name +# define SAMPLER2DSHADOW(_name, _reg) uniform sampler2DShadow _name + +# define SAMPLER2DARRAY(_name, _reg) uniform sampler2DArray _name +# define SAMPLER2DMSARRAY(_name, _reg) uniform sampler2DMSArray _name +# define SAMPLERCUBEARRAY(_name, _reg) uniform samplerCubeArray _name +# define SAMPLER2DARRAYSHADOW(_name, _reg) uniform sampler2DArrayShadow _name + +# define ISAMPLER2D(_name, _reg) uniform isampler2D _name +# define USAMPLER2D(_name, _reg) uniform usampler2D _name +# define ISAMPLER3D(_name, _reg) uniform isampler3D _name +# define USAMPLER3D(_name, _reg) uniform usampler3D _name + +# if BGFX_SHADER_LANGUAGE_GLSL >= 130 +# define texture2D(_sampler, _coord) texture2D(_sampler, _coord) +# define texture2DArray(_sampler, _coord) texture2D(_sampler, _coord) +# define texture3D(_sampler, _coord) texture2D(_sampler, _coord) +# endif // BGFX_SHADER_LANGUAGE_GLSL >= 130 + +vec3 instMul(vec3 _vec, mat3 _mtx) { return mul(_vec, _mtx); } +vec3 instMul(mat3 _mtx, vec3 _vec) { return mul(_mtx, _vec); } +vec4 instMul(vec4 _vec, mat4 _mtx) { return mul(_vec, _mtx); } +vec4 instMul(mat4 _mtx, vec4 _vec) { return mul(_mtx, _vec); } + +float rcp(float _a) { return 1.0/_a; } +vec2 rcp(vec2 _a) { return vec2(1.0)/_a; } +vec3 rcp(vec3 _a) { return vec3(1.0)/_a; } +vec4 rcp(vec4 _a) { return vec4(1.0)/_a; } +#endif // BGFX_SHADER_LANGUAGE_* + +vec2 vec2_splat(float _x) { return vec2(_x, _x); } +vec3 vec3_splat(float _x) { return vec3(_x, _x, _x); } +vec4 vec4_splat(float _x) { return vec4(_x, _x, _x, _x); } + +#if BGFX_SHADER_LANGUAGE_GLSL >= 130 || BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL +uvec2 uvec2_splat(uint _x) { return uvec2(_x, _x); } +uvec3 uvec3_splat(uint _x) { return uvec3(_x, _x, _x); } +uvec4 uvec4_splat(uint _x) { return uvec4(_x, _x, _x, _x); } +#endif // BGFX_SHADER_LANGUAGE_GLSL >= 130 || BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_SPIRV || BGFX_SHADER_LANGUAGE_METAL + +mat4 mtxFromRows(vec4 _0, vec4 _1, vec4 _2, vec4 _3) +{ +#if BGFX_SHADER_LANGUAGE_GLSL + return transpose(mat4(_0, _1, _2, _3) ); +#else + return mat4(_0, _1, _2, _3); +#endif // BGFX_SHADER_LANGUAGE_GLSL +} + +mat4 mtxFromCols(vec4 _0, vec4 _1, vec4 _2, vec4 _3) +{ +#if BGFX_SHADER_LANGUAGE_GLSL + return mat4(_0, _1, _2, _3); +#else + return transpose(mat4(_0, _1, _2, _3) ); +#endif // BGFX_SHADER_LANGUAGE_GLSL +} +#define u_alphaRef u_alphaRef4.x + +#endif // __cplusplus + +#endif // BGFX_SHADER_H_HEADER_GUARD diff --git a/src/Shaders/varying.def.sc b/src/Shaders/varying.def.sc new file mode 100644 index 00000000..68c5f503 --- /dev/null +++ b/src/Shaders/varying.def.sc @@ -0,0 +1,11 @@ +vec2 a_texcoord0 : TEXCOORD0; +vec4 a_color0 : COLOR0; +vec3 a_position : POSITION; +vec3 a_normal : NORMAL; + + +vec2 v_texcoord0 : TEXCOORD0; +vec3 v_position : POSITION; +vec3 v_normal : NORMAL; +vec4 v_color0 : COLOR0; +vec3 v_positionWorld : TEXCOORD1; diff --git a/src/Types.cpp b/src/Types.cpp new file mode 100644 index 00000000..058b358b --- /dev/null +++ b/src/Types.cpp @@ -0,0 +1,390 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include +#include "Types.h" +#include "bgfx/defines.h" +#include "Utils.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// matrix will receive the calculated perspective matrix. +// You would have to upload to your shader +// or use glLoadMatrixf if you aren't using shaders. +void Mat4x4::glhPerspectivef2(float fovyInDegrees, float aspectRatio, float znear, float zfar) +{ + float ymax, xmax; + ymax = znear * tanf(fovyInDegrees * 3.14159f / 360.0f); + xmax = ymax * aspectRatio; + glhFrustumf2(-xmax, xmax, -ymax, ymax, znear, zfar); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void Mat4x4::glhFrustumf2(float left, float right, float bottom, float top, float znear, float zfar) +{ + float temp, temp2, temp3, temp4; + temp = 2.0f * znear; + temp2 = right - left; + temp3 = top - bottom; + temp4 = zfar - znear; + m16[0] = temp / temp2; + m16[1] = 0.0; + m16[2] = 0.0; + m16[3] = 0.0; + m16[4] = 0.0; + m16[5] = temp / temp3; + m16[6] = 0.0; + m16[7] = 0.0; + m16[8] = (right + left) / temp2; + m16[9] = (top + bottom) / temp3; + m16[10] = (-zfar - znear) / temp4; + m16[11] = -1.0f; + m16[12] = 0.0; + m16[13] = 0.0; + m16[14] = (-temp * zfar) / temp4; + m16[15] = 0.0; +} + +void Mat4x4::lookAtRH(const Vec4& eye, const Vec4& at, const Vec4& up) +{ + Vec4 X, Y, Z, tmp; + + Z.Normalize(eye - at); + Y.Normalize(up); + + tmp.Cross(Y, Z); + X.Normalize(tmp); + + tmp.Cross(Z, X); + Y.Normalize(tmp); + + m[0][0] = X.x; + m[0][1] = Y.x; + m[0][2] = Z.x; + m[0][3] = 0.0f; + + m[1][0] = X.y; + m[1][1] = Y.y; + m[1][2] = Z.y; + m[1][3] = 0.0f; + + m[2][0] = X.z; + m[2][1] = Y.z; + m[2][2] = Z.z; + m[2][3] = 0.0f; + + m[3][0] = -X.Dot(eye); + m[3][1] = -Y.Dot(eye); + m[3][2] = -Z.Dot(eye); + m[3][3] = 1.0f; +} + + +void Mat4x4::lookAtLH(const Vec4& eye, const Vec4& at, const Vec4& up) +{ + Vec4 X, Y, Z, tmp; + + Z.Normalize(at - eye); + Y.Normalize(up); + + tmp.Cross(Y, Z); + X.Normalize(tmp); + + tmp.Cross(Z, X); + Y.Normalize(tmp); + + m[0][0] = X.x; + m[0][1] = Y.x; + m[0][2] = Z.x; + m[0][3] = 0.0f; + + m[1][0] = X.y; + m[1][1] = Y.y; + m[1][2] = Z.y; + m[1][3] = 0.0f; + + m[2][0] = X.z; + m[2][1] = Y.z; + m[2][2] = Z.z; + m[2][3] = 0.0f; + + m[3][0] = -X.Dot(eye); + m[3][1] = -Y.Dot(eye); + m[3][2] = -Z.Dot(eye); + m[3][3] = 1.0f; +} + +void Mat4x4::LookAt(const Vec4& eye, const Vec4& at, const Vec4& up) +{ + Vec4 X, Y, Z, tmp; + + Z.Normalize(at - eye); + Y.Normalize(up); + + tmp.Cross(Y, Z); + X.Normalize(tmp); + + tmp.Cross(Z, X); + Y.Normalize(tmp); + + m[0][0] = X.x; + m[0][1] = X.y; + m[0][2] = X.z; + m[0][3] = 0.0f; + + m[1][0] = Y.x; + m[1][1] = Y.y; + m[1][2] = Y.z; + m[1][3] = 0.0f; + + m[2][0] = Z.x; + m[2][1] = Z.y; + m[2][2] = Z.z; + m[2][3] = 0.0f; + + m[3][0] = eye.x; + m[3][1] = eye.y; + m[3][2] = eye.z; + m[3][3] = 1.0f; +} + +void Mat4x4::PerspectiveFovLH2(const float fovy, const float aspect, const float zn, const float zf) +{ + /* + xScale 0 0 0 + 0 yScale 0 0 + 0 0 zf/(zf-zn) 1 + 0 0 -zn*zf/(zf-zn) 0 + where: + */ + /* + + pout->m[0][0] =3D 1.0f / (aspect * tan(fovy/2.0f)); + + pout->m[1][1] =3D 1.0f / tan(fovy/2.0f); + + pout->m[2][2] =3D zf / (zf - zn); + + pout->m[2][3] =3D 1.0f; + + pout->m[3][2] =3D (zf * zn) / (zn - zf); + + pout->m[3][3] =3D 0.0f; + + + + float yscale = cosf(fovy*0.5f); + + float xscale = yscale / aspect; + + */ + m[0][0] = 1.0f / (aspect * tanf(fovy * 0.5f)); + m[0][1] = 0.0f; + m[0][2] = 0.0f; + m[0][3] = 0.0f; + + m[1][0] = 0.0f; + m[1][1] = 1.0f / tanf(fovy * 0.5f); + m[1][2] = 0.0f; + m[1][3] = 0.0f; + + m[2][0] = 0.0f; + m[2][1] = 0.0f; + m[2][2] = zf / (zf - zn); + m[2][3] = 1.0f; + + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = (zf * zn) / (zn - zf); + m[3][3] = 0.0f; +} + +void Mat4x4::OrthoOffCenterLH(const float l, float r, float b, const float t, float zn, const float zf) +{ + m[0][0] = 2 / (r - l); + m[0][1] = 0.0f; + m[0][2] = 0.0f; + m[0][3] = 0.0f; + + m[1][0] = 0.0f; + m[1][1] = 2 / (t - b); + m[1][2] = 0.0f; + m[1][3] = 0.0f; + + m[2][0] = 0.0f; + m[2][1] = 0.0f; + m[2][2] = 1.0f / (zf - zn); + m[2][3] = 0.0f; + + m[3][0] = (l + r) / (l - r); + m[3][1] = (t + b) / (b - t); + m[3][2] = zn / (zn - zf); + m[3][3] = 1.0f; +} + +float Mat4x4::Inverse(const Mat4x4& srcMatrix, bool affine) +{ + *this = srcMatrix; + return Inverse(affine); +} + +float Mat4x4::Inverse(bool affine) +{ + float det = 0; + + if (affine) + { + det = GetDeterminant(); + float s = 1 / det; + float v00 = (m[1][1] * m[2][2] - m[1][2] * m[2][1]) * s; + float v01 = (m[2][1] * m[0][2] - m[2][2] * m[0][1]) * s; + float v02 = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * s; + float v10 = (m[1][2] * m[2][0] - m[1][0] * m[2][2]) * s; + float v11 = (m[2][2] * m[0][0] - m[2][0] * m[0][2]) * s; + float v12 = (m[0][2] * m[1][0] - m[0][0] * m[1][2]) * s; + float v20 = (m[1][0] * m[2][1] - m[1][1] * m[2][0]) * s; + float v21 = (m[2][0] * m[0][1] - m[2][1] * m[0][0]) * s; + float v22 = (m[0][0] * m[1][1] - m[0][1] * m[1][0]) * s; + float v30 = -(v00 * m[3][0] + v10 * m[3][1] + v20 * m[3][2]); + float v31 = -(v01 * m[3][0] + v11 * m[3][1] + v21 * m[3][2]); + float v32 = -(v02 * m[3][0] + v12 * m[3][1] + v22 * m[3][2]); + m[0][0] = v00; + m[0][1] = v01; + m[0][2] = v02; + m[1][0] = v10; + m[1][1] = v11; + m[1][2] = v12; + m[2][0] = v20; + m[2][1] = v21; + m[2][2] = v22; + m[3][0] = v30; + m[3][1] = v31; + m[3][2] = v32; + } + else + { + // transpose matrix + float src[16]; + for (int i = 0; i < 4; ++i) + { + src[i] = m16[i * 4]; + src[i + 4] = m16[i * 4 + 1]; + src[i + 8] = m16[i * 4 + 2]; + src[i + 12] = m16[i * 4 + 3]; + } + + // calculate pairs for first 8 elements (cofactors) + float tmp[12]; // temp array for pairs + tmp[0] = src[10] * src[15]; + tmp[1] = src[11] * src[14]; + tmp[2] = src[9] * src[15]; + tmp[3] = src[11] * src[13]; + tmp[4] = src[9] * src[14]; + tmp[5] = src[10] * src[13]; + tmp[6] = src[8] * src[15]; + tmp[7] = src[11] * src[12]; + tmp[8] = src[8] * src[14]; + tmp[9] = src[10] * src[12]; + tmp[10] = src[8] * src[13]; + tmp[11] = src[9] * src[12]; + + // calculate first 8 elements (cofactors) + m16[0] = (tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7]) - (tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7]); + m16[1] = (tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7]) - (tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7]); + m16[2] = (tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7]) - (tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7]); + m16[3] = (tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6]) - (tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6]); + m16[4] = (tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3]) - (tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3]); + m16[5] = (tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3]) - (tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3]); + m16[6] = (tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3]) - (tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3]); + m16[7] = (tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2]) - (tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2]); + + // calculate pairs for second 8 elements (cofactors) + tmp[0] = src[2] * src[7]; + tmp[1] = src[3] * src[6]; + tmp[2] = src[1] * src[7]; + tmp[3] = src[3] * src[5]; + tmp[4] = src[1] * src[6]; + tmp[5] = src[2] * src[5]; + tmp[6] = src[0] * src[7]; + tmp[7] = src[3] * src[4]; + tmp[8] = src[0] * src[6]; + tmp[9] = src[2] * src[4]; + tmp[10] = src[0] * src[5]; + tmp[11] = src[1] * src[4]; + + // calculate second 8 elements (cofactors) + m16[8] = (tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15]) - (tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15]); + m16[9] = (tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15]) - (tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15]); + m16[10] = (tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15]) - (tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15]); + m16[11] = (tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14]) - (tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14]); + m16[12] = (tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9]) - (tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10]); + m16[13] = (tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10]) - (tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8]); + m16[14] = (tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8]) - (tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9]); + m16[15] = (tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9]) - (tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8]); + + // calculate determinant + det = src[0] * m16[0] + src[1] * m16[1] + src[2] * m16[2] + src[3] * m16[3]; + + // calculate matrix inverse + float invdet = 1 / det; + for (int j = 0; j < 16; ++j) + { + m16[j] *= invdet; + } + } + + return det; + +} + +uint32_t InputSampler::Value() const +{ + static const uint32_t wrapu[] = { 0, BGFX_SAMPLER_U_CLAMP, BGFX_SAMPLER_U_BORDER, 0 }; + static const uint32_t wrapv[] = { 0, BGFX_SAMPLER_V_CLAMP, BGFX_SAMPLER_V_BORDER, 0 }; + static const uint32_t filterMin[] = { 0, BGFX_SAMPLER_MIN_POINT }; + static const uint32_t filterMag[] = { 0, BGFX_SAMPLER_MIN_POINT }; + return wrapu[mWrapU] + wrapv[mWrapV] + filterMin[mFilterMin] + filterMag[mFilterMag]; +} + +void Bounds::AddPoint(const Vec3 pt) +{ + mMin.x = Min(mMin.x, pt.x); + mMin.y = Min(mMin.y, pt.y); + mMin.z = Min(mMin.z, pt.z); + mMax.x = Max(mMax.x, pt.x); + mMax.y = Max(mMax.y, pt.y); + mMax.z = Max(mMax.z, pt.z); +} + +void Bounds::AddBounds(const Bounds bounds, const Mat4x4& matrix) +{ + for(int i = 0; i < 8; i++) + { + Vec4 p((i & 1) ? bounds.mMax.x : bounds.mMin.x, + (i & 2) ? bounds.mMax.y : bounds.mMin.y, + (i & 4) ? bounds.mMax.z : bounds.mMin.z); + p.TransformPoint(matrix); + AddPoint({p.x, p.y, p.z}); + } +} + +Vec4 Bounds::Center() const +{ + return Vec4(mMin.x + mMax.x, mMin.y + mMax.y, mMin.z + mMax.z) * 0.5f; +} \ No newline at end of file diff --git a/src/Types.h b/src/Types.h new file mode 100644 index 00000000..79f82f40 --- /dev/null +++ b/src/Types.h @@ -0,0 +1,931 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +#pragma once +#include +#include +#include +#include +#include +#include + +static const uint16_t InvalidNodeIndex = 0xFFFF; +static const uint8_t InvalidSlotIndex = 0xFF; + +struct InputSampler +{ + InputSampler() : mWrapU(0), mWrapV(0), mFilterMin(0), mFilterMag(0) + { + } + + bool operator!=(const InputSampler& other) const + { + return (mWrapU != other.mWrapU || mWrapV != other.mWrapV || mFilterMin != other.mFilterMin || + mFilterMag != other.mFilterMag); + } + + bool operator==(const InputSampler& other) const + { + return (mWrapU == other.mWrapU && mWrapV == other.mWrapV && mFilterMin == other.mFilterMin && + mFilterMag == other.mFilterMag); + } + + uint32_t Value() const; + + uint32_t mWrapU; + uint32_t mWrapV; + uint32_t mFilterMin; + uint32_t mFilterMag; +}; + +typedef std::vector InputSamplers; + + +struct NodeIndex +{ + NodeIndex() : mNodeIndex(InvalidNodeIndex) {} + /*NodeIndex(int nodeIndex) : mNodeIndex(uint16_t(nodeIndex)) + { + assert(nodeIndex >= 0); + }*/ + NodeIndex(uint16_t nodeIndex) : mNodeIndex(uint16_t(nodeIndex)) + { + assert(nodeIndex == InvalidNodeIndex || nodeIndex < InvalidNodeIndex); + } + + bool IsValid() const + { + return mNodeIndex != InvalidNodeIndex; + } + + void SetInvalid() + { + mNodeIndex = -1; + } + + operator int() const + { + assert(IsValid()); + return int(mNodeIndex); + } + + bool operator == (const NodeIndex& other) const { return mNodeIndex == other.mNodeIndex; } + bool operator != (const NodeIndex& other) const { return mNodeIndex != other.mNodeIndex; } + + NodeIndex& operator -- () + { + mNodeIndex --; + return *this; + } + + NodeIndex operator -- (int) + { + mNodeIndex--; + return *this; + } + + NodeIndex& operator ++ () + { + mNodeIndex ++; + return *this; + } + + NodeIndex operator ++ (int) + { + mNodeIndex++; + return *this; + } + +private: + uint16_t mNodeIndex; + + bool operator != (int value) const { return true; } + bool operator == (int value) const { return false; } +}; + +struct SlotIndex +{ + SlotIndex() : mSlotIndex(InvalidSlotIndex) {} + SlotIndex(int slotIndex) : mSlotIndex(uint8_t(slotIndex)) {} + + uint8_t mSlotIndex; + + bool IsValid() const + { + return mSlotIndex != InvalidSlotIndex; + } + + operator int() const + { + assert(IsValid()); + return int(mSlotIndex); + } +}; + +struct RuntimeId +{ + RuntimeId() : mRuntimeId(GetRuntimeId()) + { + } + + RuntimeId(const RuntimeId& other) : mRuntimeId(other.mRuntimeId) + { + } + + bool operator == (RuntimeId& other) const + { + return mRuntimeId == other.mRuntimeId; + } + +private: + uint32_t mRuntimeId; + + uint32_t GetRuntimeId() + { + static uint32_t runtimeId = 10; + return ++runtimeId; + } +}; + +struct MultiplexInput +{ + NodeIndex mInputs[8] = { InvalidNodeIndex, InvalidNodeIndex, InvalidNodeIndex, InvalidNodeIndex, InvalidNodeIndex, InvalidNodeIndex, InvalidNodeIndex, InvalidNodeIndex }; +}; + +typedef std::vector InputSamplers; + + +struct Mat4x4; + +struct iVec2 +{ + int x, y; + inline iVec2 operator*(float f) const + { + return { int(x * f), int(y * f) }; + } + inline iVec2 operator-(const iVec2& v) const + { + return { x - v.x, y - v.y }; + } + inline iVec2 operator+(const iVec2& v) const + { + return { x + v.x, y + v.y }; + } + int& operator[](size_t index) + { + return ((int*)&x)[index]; + } + const int& operator[](size_t index) const + { + return ((int*)&x)[index]; + } +}; + +struct iVec3 +{ + int x, y, z; + inline iVec3 operator*(float f) const + { + return { int(x * f), int(y * f), int(z * f) }; + } + inline iVec3 operator-(const iVec3& v) const + { + return { x - v.x, y - v.y, z - v.z }; + } + inline iVec3 operator+(const iVec3& v) const + { + return { x + v.x, y + v.y, z + v.z }; + } + int& operator[](size_t index) + { + return ((int*)&x)[index]; + } + const int& operator[](size_t index) const + { + return ((int*)&x)[index]; + } +}; + +struct iVec4 +{ + int x, y, z, w; + inline iVec4 operator*(float f) const + { + return { int(x * f), int(y * f), int(z * f), int(w * f) }; + } + inline iVec4 operator-(const iVec4& v) const + { + return { x - v.x, y - v.y, z - v.z, w - v.w }; + } + inline iVec4 operator+(const iVec4& v) const + { + return { x + v.x, y + v.y, z + v.z, w + v.w }; + } + int& operator[](size_t index) + { + return ((int*)&x)[index]; + } + const int& operator[](size_t index) const + { + return ((int*)&x)[index]; + } +}; + +struct Vec2 +{ + float x, y; + inline Vec2 operator*(float f) const + { + return { x * f, y * f }; + } + inline Vec2 operator-(const Vec2& v) const + { + return { x - v.x, y - v.y }; + } + inline Vec2 operator+(const Vec2& v) const + { + return { x + v.x, y + v.y }; + } + float& operator[](size_t index) + { + return ((float*)&x)[index]; + } + const float& operator[](size_t index) const + { + return ((float*)&x)[index]; + } +}; + +struct Vec3 +{ + float x, y, z; + inline Vec3 operator*(float f) const + { + return { x * f, y * f, z * f }; + } + inline Vec3 operator-(const Vec3& v) const + { + return { x - v.x, y - v.y, z - v.z }; + } + inline Vec3 operator+(const Vec3& v) const + { + return { x + v.x, y + v.y, z + v.z }; + } + float& operator[](size_t index) + { + return ((float*)&x)[index]; + } + const float& operator[](size_t index) const + { + return ((float*)&x)[index]; + } +}; + +struct Vec4 +{ +public: + Vec4(const Vec4& other) : x(other.x), y(other.y), z(other.z), w(other.w) + { + } + Vec4() + { + } + Vec4(float _x, float _y, float _z = 0.f, float _w = 0.f) : x(_x), y(_y), z(_z), w(_w) + { + } + Vec4(int _x, int _y, int _z = 0, int _w = 0) : x((float)_x), y((float)_y), z((float)_z), w((float)_w) + { + } + Vec4(float v) : x(v), y(v), z(v), w(v) + { + } + + void Lerp(const Vec4& v, float t) + { + x += (v.x - x) * t; + y += (v.y - y) * t; + z += (v.z - z) * t; + w += (v.w - w) * t; + } + void LerpColor(const Vec4& v, float t) + { + for (int i = 0; i < 4; i++) + (*this)[i] = sqrtf(((*this)[i] * (*this)[i]) * (1.f - t) + (v[i] * v[i]) * (t)); + } + void Lerp(const Vec4& v, const Vec4& v2, float t) + { + *this = v; + Lerp(v2, t); + } + + inline void Set(float v) + { + x = y = z = w = v; + } + inline void Set(float _x, float _y, float _z = 0.f, float _w = 0.f) + { + x = _x; + y = _y; + z = _z; + w = _w; + } + + inline Vec4& operator-=(const Vec4& v) + { + x -= v.x; + y -= v.y; + z -= v.z; + w -= v.w; + return *this; + } + inline Vec4& operator+=(const Vec4& v) + { + x += v.x; + y += v.y; + z += v.z; + w += v.w; + return *this; + } + inline Vec4& operator*=(const Vec4& v) + { + x *= v.x; + y *= v.y; + z *= v.z; + w *= v.w; + return *this; + } + inline Vec4& operator*=(float v) + { + x *= v; + y *= v; + z *= v; + w *= v; + return *this; + } + + inline Vec4 operator*(float f) const; + inline Vec4 operator-() const; + inline Vec4 operator-(const Vec4& v) const; + inline Vec4 operator+(const Vec4& v) const; + inline Vec4 operator*(const Vec4& v) const; + + inline const Vec4& operator+() const + { + return (*this); + } + inline float Length() const + { + return sqrtf(x * x + y * y + z * z); + }; + inline float LengthSq() const + { + return (x * x + y * y + z * z); + }; + inline Vec4 Normalize() + { + (*this) *= (1.f / Length() + FLT_EPSILON); + return (*this); + } + inline Vec4 Normalize(const Vec4& v) + { + this->Set(v.x, v.y, v.z, v.w); + this->Normalize(); + return (*this); + } + inline int LongestAxis() const + { + int res = 0; + res = (fabsf((*this)[1]) > fabsf((*this)[res])) ? 1 : res; + res = (fabsf((*this)[2]) > fabsf((*this)[res])) ? 2 : res; + return res; + } + inline void Cross(const Vec4& v) + { + Vec4 res; + res.x = y * v.z - z * v.y; + res.y = z * v.x - x * v.z; + res.z = x * v.y - y * v.x; + + x = res.x; + y = res.y; + z = res.z; + w = 0.f; + } + inline void Cross(const Vec4& v1, const Vec4& v2) + { + x = v1.y * v2.z - v1.z * v2.y; + y = v1.z * v2.x - v1.x * v2.z; + z = v1.x * v2.y - v1.y * v2.x; + w = 0.f; + } + inline float Dot(const Vec4& v) const + { + return (x * v.x) + (y * v.y) + (z * v.z) + (w * v.w); + } + + void IsMaxOf(const Vec4& v) + { + x = (v.x > x) ? v.x : x; + y = (v.y > y) ? v.y : y; + z = (v.z > z) ? v.z : z; + w = (v.w > w) ? v.z : w; + } + void IsMinOf(const Vec4& v) + { + x = (v.x > x) ? x : v.x; + y = (v.y > y) ? y : v.y; + z = (v.z > z) ? z : v.z; + w = (v.w > w) ? z : v.w; + } + + bool IsInside(const Vec4& min, const Vec4& max) const + { + if (min.x > x || max.x < x || min.y > y || max.y < y || min.z > z || max.z < z) + return false; + return true; + } + + Vec4 Symetrical(const Vec4& v) const + { + Vec4 res; + float dist = SignedDistanceTo(v); + res = v; + res -= (*this) * dist * 2.f; + + return res; + } + /*void transform(const Mat4x4& matrix); + void transform(const Vec4 & s, const Mat4x4& matrix); + */ + void TransformVector(const Mat4x4& matrix); + void TransformPoint(const Mat4x4& matrix); + + void TransformVector(const Vec4& v, const Mat4x4& matrix) + { + (*this) = v; + this->TransformVector(matrix); + } + void TransformPoint(const Vec4& v, const Mat4x4& matrix) + { + (*this) = v; + this->TransformPoint(matrix); + } + + // quaternion slerp + // void slerp(const Vec4 &q1, const Vec4 &q2, float t ); + + inline float SignedDistanceTo(const Vec4& point) const; + float& operator[](size_t index) + { + return ((float*)&x)[index]; + } + const float& operator[](size_t index) const + { + return ((float*)&x)[index]; + } + + float x, y, z, w; +}; + +inline Vec4 Vec4::operator*(float f) const +{ + return Vec4(x * f, y * f, z * f, w * f); +} +inline Vec4 Vec4::operator-() const +{ + return Vec4(-x, -y, -z, -w); +} +inline Vec4 Vec4::operator-(const Vec4& v) const +{ + return Vec4(x - v.x, y - v.y, z - v.z, w - v.w); +} +inline Vec4 Vec4::operator+(const Vec4& v) const +{ + return Vec4(x + v.x, y + v.y, z + v.z, w + v.w); +} +inline Vec4 Vec4::operator*(const Vec4& v) const +{ + return Vec4(x * v.x, y * v.y, z * v.z, w * v.w); +} +inline float Vec4::SignedDistanceTo(const Vec4& point) const +{ + return (point.Dot(Vec4(x, y, z))) - w; +} + +inline Vec4 Normalized(const Vec4& v) +{ + Vec4 res; + res = v; + res.Normalize(); + return res; +} +inline Vec4 Cross(const Vec4& v1, const Vec4& v2) +{ + Vec4 res; + res.x = v1.y * v2.z - v1.z * v2.y; + res.y = v1.z * v2.x - v1.x * v2.z; + res.z = v1.x * v2.y - v1.y * v2.x; + res.w = 0.f; + return res; +} + +inline float Dot(const Vec4& v1, const Vec4& v2) +{ + return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z); +} + + +inline void FPU_MatrixF_x_MatrixF(const float* a, const float* b, float* r) +{ + r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12]; + r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13]; + r[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14]; + r[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15]; + + r[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12]; + r[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13]; + r[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14]; + r[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15]; + + r[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12]; + r[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13]; + r[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14]; + r[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15]; + + r[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12]; + r[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13]; + r[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14]; + r[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15]; +} + + +struct Mat4x4 +{ +public: + union { + float m[4][4]; + float m16[16]; + struct + { + Vec4 right, up, dir, position; + } V; + }; + + Mat4x4(float v1, + float v2, + float v3, + float v4, + float v5, + float v6, + float v7, + float v8, + float v9, + float v10, + float v11, + float v12, + float v13, + float v14, + float v15, + float v16) + { + m16[0] = v1; + m16[1] = v2; + m16[2] = v3; + m16[3] = v4; + m16[4] = v5; + m16[5] = v6; + m16[6] = v7; + m16[7] = v8; + m16[8] = v9; + m16[9] = v10; + m16[10] = v11; + m16[11] = v12; + m16[12] = v13; + m16[13] = v14; + m16[14] = v15; + m16[15] = v16; + } + Mat4x4(const Mat4x4& other) + { + memcpy(&m16[0], &other.m16[0], sizeof(float) * 16); + } + Mat4x4(const Vec4& r, const Vec4& u, const Vec4& d, const Vec4& p) + { + set(r, u, d, p); + } + Mat4x4() + { + } + void set(const Vec4& r, const Vec4& u, const Vec4& d, const Vec4& p) + { + V.right = r; + V.up = u; + V.dir = d; + V.position = p; + } + void set(float v1, + float v2, + float v3, + float v4, + float v5, + float v6, + float v7, + float v8, + float v9, + float v10, + float v11, + float v12, + float v13, + float v14, + float v15, + float v16) + { + m16[0] = v1; + m16[1] = v2; + m16[2] = v3; + m16[3] = v4; + m16[4] = v5; + m16[5] = v6; + m16[6] = v7; + m16[7] = v8; + m16[8] = v9; + m16[9] = v10; + m16[10] = v11; + m16[11] = v12; + m16[12] = v13; + m16[13] = v14; + m16[14] = v15; + m16[15] = v16; + } + static Mat4x4 GetIdentity() + { + return Mat4x4(1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f); + } + operator float* () + { + return m16; + } + operator const float* () const + { + return m16; + } + void Translation(float _x, float _y, float _z) + { + this->Translation(Vec4(_x, _y, _z)); + } + + void Translation(const Vec4& vt) + { + V.right.Set(1.f, 0.f, 0.f, 0.f); + V.up.Set(0.f, 1.f, 0.f, 0.f); + V.dir.Set(0.f, 0.f, 1.f, 0.f); + V.position.Set(vt.x, vt.y, vt.z, 1.f); + } + void TranslationScale(const Vec4& vt, const Vec4& scale) + { + V.right.Set(scale.x, 0.f, 0.f, 0.f); + V.up.Set(0.f, scale.y, 0.f, 0.f); + V.dir.Set(0.f, 0.f, scale.z, 0.f); + V.position.Set(vt.x, vt.y, vt.z, 1.f); + } + + inline void RotationY(const float angle) + { + float c = cosf(angle); + float s = sinf(angle); + + V.right.Set(c, 0.f, -s, 0.f); + V.up.Set(0.f, 1.f, 0.f, 0.f); + V.dir.Set(s, 0.f, c, 0.f); + V.position.Set(0.f, 0.f, 0.f, 1.f); + } + + inline void RotationX(const float angle) + { + float c = cosf(angle); + float s = sinf(angle); + + V.right.Set(1.f, 0.f, 0.f, 0.f); + V.up.Set(0.f, c, s, 0.f); + V.dir.Set(0.f, -s, c, 0.f); + V.position.Set(0.f, 0.f, 0.f, 1.f); + } + + inline void RotationZ(const float angle) + { + float c = cosf(angle); + float s = sinf(angle); + + V.right.Set(c, s, 0.f, 0.f); + V.up.Set(-s, c, 0.f, 0.f); + V.dir.Set(0.f, 0.f, 1.f, 0.f); + V.position.Set(0.f, 0.f, 0, 1.f); + } + inline void Scale(float _s) + { + V.right.Set(_s, 0.f, 0.f, 0.f); + V.up.Set(0.f, _s, 0.f, 0.f); + V.dir.Set(0.f, 0.f, _s, 0.f); + V.position.Set(0.f, 0.f, 0.f, 1.f); + } + inline void Scale(float _x, float _y, float _z) + { + V.right.Set(_x, 0.f, 0.f, 0.f); + V.up.Set(0.f, _y, 0.f, 0.f); + V.dir.Set(0.f, 0.f, _z, 0.f); + V.position.Set(0.f, 0.f, 0.f, 1.f); + } + inline void Scale(const Vec4& s) + { + Scale(s.x, s.y, s.z); + } + + inline Mat4x4& operator*=(const Mat4x4& mat) + { + Mat4x4 tmpMat; + tmpMat = *this; + tmpMat.Multiply(mat); + *this = tmpMat; + return *this; + } + inline Mat4x4 operator*(const Mat4x4& mat) const + { + Mat4x4 matT; + matT.Multiply(*this, mat); + return matT; + } + + inline void Multiply(const Mat4x4& matrix) + { + Mat4x4 tmp; + tmp = *this; + + FPU_MatrixF_x_MatrixF((float*)&tmp, (float*)&matrix, (float*)this); + } + + inline void Multiply(const Mat4x4& m1, const Mat4x4& m2) + { + FPU_MatrixF_x_MatrixF((float*)&m1, (float*)&m2, (float*)this); + } + + void glhPerspectivef2(float fovyInDegrees, float aspectRatio, float znear, float zfar); + void glhFrustumf2(float left, float right, float bottom, float top, float znear, float zfar); + void PerspectiveFovLH2(const float fovy, const float aspect, const float zn, const float zf); + void OrthoOffCenterLH(const float l, float r, float b, const float t, float zn, const float zf); + void lookAtRH(const Vec4& eye, const Vec4& at, const Vec4& up); + void lookAtLH(const Vec4& eye, const Vec4& at, const Vec4& up); + void LookAt(const Vec4& eye, const Vec4& at, const Vec4& up); + void rotationQuaternion(const Vec4& q); + + inline float GetDeterminant() const + { + return m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - + m[0][2] * m[1][1] * m[2][0] - m[0][1] * m[1][0] * m[2][2] - m[0][0] * m[1][2] * m[2][1]; + } + + float Inverse(const Mat4x4& srcMatrix, bool affine = false); + float Inverse(bool affine = false); + void Identity() + { + V.right.Set(1.f, 0.f, 0.f, 0.f); + V.up.Set(0.f, 1.f, 0.f, 0.f); + V.dir.Set(0.f, 0.f, 1.f, 0.f); + V.position.Set(0.f, 0.f, 0.f, 1.f); + } + inline void transpose() + { + Mat4x4 tmpm; + for (int l = 0; l < 4; l++) + { + for (int c = 0; c < 4; c++) + { + tmpm.m[l][c] = m[c][l]; + } + } + (*this) = tmpm; + } + void RotationAxis(const Vec4& axis, float angle); + /* + void Lerp(const Mat4x4& r, const Mat4x4& t, float s) + { + right = LERP(r.right, t.right, s); + up = LERP(r.up, t.up, s); + dir = LERP(r.dir, t.dir, s); + position = LERP(r.position, t.position, s); + } + */ + void RotationYawPitchRoll(const float yaw, const float pitch, const float roll); + + inline void OrthoNormalize() + { + V.right.Normalize(); + V.up.Normalize(); + V.dir.Normalize(); + } +}; + + +inline void Vec4::TransformVector(const Mat4x4& matrix) +{ + Vec4 out; + + out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0]; + out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1]; + out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2]; + out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3]; + + x = out.x; + y = out.y; + z = out.z; + w = out.w; +} + +inline void Vec4::TransformPoint(const Mat4x4& matrix) +{ + Vec4 out; + + out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + matrix.m[3][0]; + out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + matrix.m[3][1]; + out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + matrix.m[3][2]; + out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + matrix.m[3][3]; + + x = out.x; + y = out.y; + z = out.z; + w = out.w; +} + + +inline void Mat4x4::RotationAxis(const Vec4& axis, float angle) +{ + float length2 = axis.LengthSq(); + if (length2 < FLT_EPSILON) + { + Identity(); + return; + } + + Vec4 n = axis * (1.f / sqrtf(length2)); + float s = sinf(angle); + float c = cosf(angle); + float k = 1.f - c; + + float xx = n.x * n.x * k + c; + float yy = n.y * n.y * k + c; + float zz = n.z * n.z * k + c; + float xy = n.x * n.y * k; + float yz = n.y * n.z * k; + float zx = n.z * n.x * k; + float xs = n.x * s; + float ys = n.y * s; + float zs = n.z * s; + + m[0][0] = xx; + m[0][1] = xy + zs; + m[0][2] = zx - ys; + m[0][3] = 0.f; + m[1][0] = xy - zs; + m[1][1] = yy; + m[1][2] = yz + xs; + m[1][3] = 0.f; + m[2][0] = zx + ys; + m[2][1] = yz - xs; + m[2][2] = zz; + m[2][3] = 0.f; + m[3][0] = 0.f; + m[3][1] = 0.f; + m[3][2] = 0.f; + m[3][3] = 1.f; +} + +struct Bounds +{ + Vec3 mMin{FLT_MAX, FLT_MAX, FLT_MAX}; + Vec3 mMax{-FLT_MAX, -FLT_MAX, -FLT_MAX}; + + void AddPoint(const Vec3 pt); + void AddBounds(const Bounds bounds, const Mat4x4& matrix); + Vec4 Center() const; +}; diff --git a/src/UI.cpp b/src/UI.cpp index 70e8aa4e..7dda864c 100644 --- a/src/UI.cpp +++ b/src/UI.cpp @@ -28,12 +28,14 @@ #include "UI.h" #include "Utils.h" #include "imgui_internal.h" +#include "IconsFontAwesome5.h" +#include "Evaluators.h" static inline ImVec4 operator*(const ImVec4& lhs, const float t) { return ImVec4(lhs.x * t, lhs.y * t, lhs.z * t, lhs.w * t); } - +/* ImVec4 GradientEdit::GetPoint(float t) { if (GetPointCount() == 0) @@ -51,7 +53,7 @@ ImVec4 GradientEdit::GetPoint(float t) } return mPts[GetPointCount() - 1]; } - +*/ void ImguiAppLog::AddLog(const char* fmt, ...) { int old_size = Buf.size(); @@ -183,14 +185,31 @@ void SetStyle() } extern ImGui::MarkdownConfig mdConfig; +ImFont *smallAF, *bigAF, *mediumAF; void InitFonts() { ImGuiIO& io = ImGui::GetIO(); io.Fonts->Clear(); - // Base font + static const ImWchar icons_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0}; + + ImFontConfig icons_config; + icons_config.MergeMode = true; + icons_config.PixelSnapH = true; + float fontSize_ = 16.f; - io.Fonts->AddFontFromFileTTF("Stock/Fonts/OpenSans-SemiBold.ttf", fontSize_); + + static const char* defaultFontPath = "Stock/Fonts/OpenSans-SemiBold.ttf"; + io.Fonts->AddFontFromFileTTF(defaultFontPath, fontSize_); + smallAF = io.Fonts->AddFontFromFileTTF("Stock/Fonts/" FONT_ICON_FILE_NAME_FAS, fontSize_, &icons_config, icons_ranges); + + mediumAF = io.Fonts->AddFontFromFileTTF(defaultFontPath, 20.f); + io.Fonts->AddFontFromFileTTF("Stock/Fonts/" FONT_ICON_FILE_NAME_FAS, 20.f, &icons_config, icons_ranges); + + bigAF = io.Fonts->AddFontFromFileTTF(defaultFontPath, 24.f); + io.Fonts->AddFontFromFileTTF("Stock/Fonts/" FONT_ICON_FILE_NAME_FAS, 24.f, &icons_config, icons_ranges); + + // Bold headings H2 and H3 mdConfig.headingFormats[1].font = io.Fonts->AddFontFromFileTTF("Stock/Fonts/OpenSans-ExtraBold.ttf", fontSize_); mdConfig.headingFormats[2].font = mdConfig.headingFormats[1].font; @@ -204,116 +223,75 @@ struct ImogenDrawCallback NodeUICallBackFunc mFunc; ImRect mClippedRect; ImRect mOrginalRect; - size_t mNodeIndex; + NodeIndex mNodeIndex; EvaluationContext* mEvaluationContext; }; std::vector mCallbackRects; + +void UICallbackNodeDeleted(NodeIndex nodeIndex) +{ + auto iter = mCallbackRects.begin(); + for (; iter != mCallbackRects.end(); ) + { + if (iter->mNodeIndex == nodeIndex) + { + iter = mCallbackRects.erase(iter); + continue; + } + if (iter->mNodeIndex > nodeIndex) + { + iter->mNodeIndex--; + } + ++iter; + } +} + +void UICallbackNodeInserted(NodeIndex nodeIndex) +{ + for (auto& extract : mCallbackRects) + { + if (extract.mNodeIndex >= nodeIndex) + { + extract.mNodeIndex++; + } + } +} +extern Evaluators gEvaluators; static void NodeUICallBack(const ImDrawList* parent_list, const ImDrawCmd* cmd) { - // Backup GL state - GLenum last_active_texture; - glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture); - glActiveTexture(GL_TEXTURE0); - GLint last_program; - glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); - GLint last_texture; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); - - GLint last_sampler; - glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler); - GLint last_array_buffer; - glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); - GLint last_vertex_array; - glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); -#ifdef GL_POLYGON_MODE - GLint last_polygon_mode[2]; - glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); -#endif - GLint last_viewport[4]; - glGetIntegerv(GL_VIEWPORT, last_viewport); - GLint last_scissor_box[4]; - glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); - GLenum last_blend_src_rgb; - glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb); - GLenum last_blend_dst_rgb; - glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb); - GLenum last_blend_src_alpha; - glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha); - GLenum last_blend_dst_alpha; - glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha); - GLenum last_blend_equation_rgb; - glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb); - GLenum last_blend_equation_alpha; - glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha); - GLboolean last_enable_blend = glIsEnabled(GL_BLEND); - GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); - GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); - GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); ImGuiIO& io = ImGui::GetIO(); if (!mCallbackRects.empty()) { ImogenDrawCallback& cb = mCallbackRects[intptr_t(cmd->UserCallbackData)]; - ImRect cbRect = cb.mOrginalRect; - float h = cbRect.Max.y - cbRect.Min.y; - float w = cbRect.Max.x - cbRect.Min.x; - glViewport(int(cbRect.Min.x), int(io.DisplaySize.y - cbRect.Max.y), int(w), int(h)); - - cbRect.Min.x = ImMax(cbRect.Min.x, cmd->ClipRect.x); - ImRect clippedRect = cb.mClippedRect; - glScissor(int(clippedRect.Min.x), - int(io.DisplaySize.y - clippedRect.Max.y), - int(clippedRect.Max.x - clippedRect.Min.x), - int(clippedRect.Max.y - clippedRect.Min.y)); - glEnable(GL_SCISSOR_TEST); + ImRect cr = cb.mClippedRect; + /*bgfx::setScissor(int(cr.Min.x), + int(cr.Min.y), + int(cr.Max.x - cr.Min.x), + int(cr.Max.y - cr.Min.y)); + */ + bgfx::setScissor(0,0,100,100); + cr = cb.mOrginalRect; + float sx = (cr.Max.x - cr.Min.x) / io.DisplaySize.x * 2.f; + float sy = -(cr.Max.y - cr.Min.y) / io.DisplaySize.y * 2.f; + float tx = cr.Min.x / io.DisplaySize.x * 2.f - 1.f; + float ty = -cr.Min.y / io.DisplaySize.y * 2.f + 1.f; + float uvt[4] = {sx, sy, tx, ty }; + bgfx::setUniform(gEvaluators.u_uvTransform, uvt); cb.mFunc(cb.mEvaluationContext, cb.mNodeIndex); } - // Restore modified GL state - glUseProgram(last_program); - glBindTexture(GL_TEXTURE_2D, last_texture); -#ifdef GL_SAMPLER_BINDING - glBindSampler(0, last_sampler); -#endif - glActiveTexture(last_active_texture); -#ifdef GL_VERTEX_ARRAY_BINDING - glBindVertexArray(last_vertex_array); -#endif - glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); - glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); - glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); - if (last_enable_blend) - glEnable(GL_BLEND); - else - glDisable(GL_BLEND); - if (last_enable_cull_face) - glEnable(GL_CULL_FACE); - else - glDisable(GL_CULL_FACE); - if (last_enable_depth_test) - glEnable(GL_DEPTH_TEST); - else - glDisable(GL_DEPTH_TEST); - if (last_enable_scissor_test) - glEnable(GL_SCISSOR_TEST); - else - glDisable(GL_SCISSOR_TEST); -#ifdef GL_POLYGON_MODE - glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); -#endif - glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); - glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); - glBindFramebuffer(GL_FRAMEBUFFER, 0); } void InitCallbackRects() { mCallbackRects.clear(); } -size_t AddNodeUICallbackRect(NodeUICallBackFunc func, const ImRect& rect, size_t nodeIndex, EvaluationContext* context) + +size_t AddNodeUICallbackRect(NodeUICallBackFunc func, const ImRect& rect, NodeIndex nodeIndex, EvaluationContext* context) { ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImVec2 mi = draw_list->GetClipRectMin(); @@ -326,7 +304,7 @@ size_t AddNodeUICallbackRect(NodeUICallBackFunc func, const ImRect& rect, size_t } void AddUICustomDraw( - ImDrawList* drawList, const ImRect& rc, NodeUICallBackFunc func, size_t nodeIndex, EvaluationContext* context) + ImDrawList* drawList, const ImRect& rc, NodeUICallBackFunc func, NodeIndex nodeIndex, EvaluationContext* context) { drawList->AddCallback((ImDrawCallback)(NodeUICallBack), (void*)(AddNodeUICallbackRect(func, rc, nodeIndex, context))); diff --git a/src/UI.h b/src/UI.h index 9ca4c563..643ba842 100644 --- a/src/UI.h +++ b/src/UI.h @@ -22,13 +22,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // - #pragma once #include "ImCurveEdit.h" -#include "ImGradient.h" #include "imgui_markdown/imgui_markdown.h" #include +#include "Types.h" void SetStyle(); void InitFonts(); @@ -129,60 +128,16 @@ struct RampEdit : public ImCurveEdit::Delegate ImVec2 mMin, mMax; }; -struct GradientEdit : public ImGradient::Delegate -{ - GradientEdit() - { - mPointCount = 0; - } - - size_t GetPointCount() - { - return mPointCount; - } - - ImVec4* GetPoints() - { - return mPts; - } - - virtual int EditPoint(int pointIndex, ImVec4 value) - { - mPts[pointIndex] = value; - SortValues(); - for (size_t i = 0; i < GetPointCount(); i++) - { - if (mPts[i].w == value.w) - return int(i); - } - return pointIndex; - } - virtual void AddPoint(ImVec4 value) - { - if (mPointCount >= 8) - return; - mPts[mPointCount++] = value; - SortValues(); - } - virtual ImVec4 GetPoint(float t); - ImVec4 mPts[8]; - size_t mPointCount; - -private: - void SortValues() - { - auto b = std::begin(mPts); - auto e = std::begin(mPts) + GetPointCount(); - std::sort(b, e, [](ImVec4 a, ImVec4 b) { return a.w < b.w; }); - } -}; - // draw callbacks struct ImRect; struct ImDrawList; struct EvaluationContext; -typedef void (*NodeUICallBackFunc)(EvaluationContext* context, size_t nodeIndex); +typedef void (*NodeUICallBackFunc)(EvaluationContext* context, NodeIndex nodeIndex); void AddUICustomDraw( - ImDrawList* drawList, const ImRect& rc, NodeUICallBackFunc func, size_t nodeIndex, EvaluationContext* context); + ImDrawList* drawList, const ImRect& rc, NodeUICallBackFunc func, NodeIndex nodeIndex, EvaluationContext* context); void InitCallbackRects(); +void UICallbackNodeDeleted(NodeIndex nodeIndex); +void UICallbackNodeInserted(NodeIndex nodeIndex); + +extern ImFont *smallAF, *bigAF, *mediumAF; \ No newline at end of file diff --git a/src/UndoRedo.h b/src/UndoRedo.h new file mode 100644 index 00000000..bfda73ce --- /dev/null +++ b/src/UndoRedo.h @@ -0,0 +1,398 @@ +// https://github.com/CedricGuillemet/Imogen +// +// The MIT License(MIT) +// +// Copyright(c) 2019 Cedric Guillemet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +#pragma once + +#include + +struct UndoRedo +{ + UndoRedo(); + virtual ~UndoRedo(); + + virtual void Undo() + { + if (mSubUndoRedo.empty()) + return; + for (int i = int(mSubUndoRedo.size()) - 1; i >= 0; i--) + { + mSubUndoRedo[i]->Undo(); + } + } + virtual void Redo() + { + for (auto& undoRedo : mSubUndoRedo) + { + undoRedo->Redo(); + } + } + template + void AddSubUndoRedo(const T& subUndoRedo) + { + mSubUndoRedo.push_back(std::make_shared(subUndoRedo)); + } + + bool HasSubUndoRedo() const + { + return !mSubUndoRedo.empty(); + } + + virtual size_t GetMemSize() const = 0; + virtual size_t GetMemUsed() const + { + size_t ret = 0; + for (const auto& sub : mSubUndoRedo) + { + ret += sub->GetMemSize(); + } + return ret; + } + +protected: + std::vector> mSubUndoRedo; +}; + +struct UndoRedoHandler +{ + UndoRedoHandler() : mbProcessing(false), mCurrent(NULL) + { + } + ~UndoRedoHandler() + { + Clear(); + } + + void Undo() + { + if (mUndos.empty()) + return; + mbProcessing = true; + mUndos.back()->Undo(); + mRedos.push_back(mUndos.back()); + mUndos.pop_back(); + mbProcessing = false; + } + + void Redo() + { + if (mRedos.empty()) + return; + mbProcessing = true; + mRedos.back()->Redo(); + mUndos.push_back(mRedos.back()); + mRedos.pop_back(); + mbProcessing = false; + } + + template + void AddUndo(const T& undoRedo) + { + if (mCurrent && &undoRedo != mCurrent) + mCurrent->AddSubUndoRedo(undoRedo); + else + mUndos.push_back(std::make_shared(undoRedo)); + mbProcessing = true; + mRedos.clear(); + mbProcessing = false; + } + + void Clear() + { + mbProcessing = true; + mUndos.clear(); + mRedos.clear(); + mbProcessing = false; + } + + size_t GetMemUsed() const + { + size_t ret = 0; + for (const auto& undo : mUndos) + { + ret += undo->GetMemUsed(); + } + for (const auto& redo : mRedos) + { + ret += redo->GetMemUsed(); + } + return ret; + + } + + bool mbProcessing; + UndoRedo* mCurrent; + // private: + + std::vector> mUndos; + std::vector> mRedos; +}; + +extern UndoRedoHandler gUndoRedoHandler; + +inline UndoRedo::UndoRedo() +{ + if (!gUndoRedoHandler.mCurrent) + { + gUndoRedoHandler.mCurrent = this; + } +} + +inline UndoRedo::~UndoRedo() +{ + if (gUndoRedoHandler.mCurrent == this) + { + gUndoRedoHandler.mCurrent = NULL; + } +} + +template +struct URChange : public UndoRedo +{ + URChange(int index, + std::function GetElements, + std::function Changed = [](int index) {}) + : GetElements(GetElements), mIndex(index), Changed(Changed) + { + if (gUndoRedoHandler.mbProcessing) + return; + + mPreDo = *GetElements(mIndex); + } + + virtual ~URChange() + { + if (gUndoRedoHandler.mbProcessing) + return; + + mPostDo = *GetElements(mIndex); + gUndoRedoHandler.AddUndo(*this); + } + + void Undo() override + { + *GetElements(mIndex) = mPreDo; + Changed(mIndex); + UndoRedo::Undo(); + } + + void Redo() override + { + UndoRedo::Redo(); + *GetElements(mIndex) = mPostDo; + Changed(mIndex); + } + + size_t GetMemSize() const override + { + return sizeof(URChange); + } + + T mPreDo; + T mPostDo; + int mIndex; + + std::function GetElements; + std::function Changed; +}; + + +template +struct URChangeValue : public UndoRedo +{ + URChangeValue(T& value, + std::function Changed = []() {}) + : mValue(value), Changed(Changed) + { + if (gUndoRedoHandler.mbProcessing) + return; + + mPreDo = mValue; + } + + virtual ~URChangeValue() + { + if (gUndoRedoHandler.mbProcessing) + return; + + mPostDo = mValue; + gUndoRedoHandler.AddUndo(*this); + } + + void Undo() override + { + mValue = mPreDo; + Changed(); + UndoRedo::Undo(); + } + + void Redo() override + { + UndoRedo::Redo(); + mValue = mPostDo; + Changed(); + } + + size_t GetMemSize() const override + { + return sizeof(URChangeValue); + } + + T mPreDo; + T mPostDo; + T& mValue; + + std::function Changed; +}; + + +struct URDummy : public UndoRedo +{ + URDummy() : UndoRedo() + { + if (gUndoRedoHandler.mbProcessing) + return; + } + + virtual ~URDummy() + { + if (gUndoRedoHandler.mbProcessing) + return; + + gUndoRedoHandler.AddUndo(*this); + } + + void Undo() override + { + UndoRedo::Undo(); + } + + void Redo() override + { + UndoRedo::Redo(); + } + + size_t GetMemSize() const override + { + return sizeof(URDummy); + } +}; + + +template +struct URDel : public UndoRedo +{ + URDel(int index, + std::function*()> GetElements, + std::function OnDelete = [](int index) {}, + std::function OnNew = [](int index) {}) + : GetElements(GetElements), mIndex(index), OnDelete(OnDelete), OnNew(OnNew) + { + if (gUndoRedoHandler.mbProcessing) + return; + + mDeletedElement = (*GetElements())[mIndex]; + } + + virtual ~URDel() + { + if (gUndoRedoHandler.mbProcessing) + return; + // add to handler + gUndoRedoHandler.AddUndo(*this); + } + + void Undo() override + { + GetElements()->insert(GetElements()->begin() + mIndex, mDeletedElement); + OnNew(mIndex); + UndoRedo::Undo(); + } + + void Redo() override + { + UndoRedo::Redo(); + OnDelete(mIndex); + GetElements()->erase(GetElements()->begin() + mIndex); + } + + size_t GetMemSize() const override + { + return sizeof(URDummy); + } + + T mDeletedElement; + int mIndex; + + std::function*()> GetElements; + std::function OnDelete; + std::function OnNew; +}; + +template +struct URAdd : public UndoRedo +{ + URAdd(int index, + std::function*()> GetElements, + std::function OnDelete = [](int index) {}, + std::function OnNew = [](int index) {}) + : GetElements(GetElements), mIndex(index), OnDelete(OnDelete), OnNew(OnNew) + { + } + + virtual ~URAdd() + { + if (gUndoRedoHandler.mbProcessing) + return; + + mAddedElement = (*GetElements())[mIndex]; + // add to handler + gUndoRedoHandler.AddUndo(*this); + } + + void Undo() override + { + OnDelete(mIndex); + GetElements()->erase(GetElements()->begin() + mIndex); + UndoRedo::Undo(); + } + + void Redo() override + { + UndoRedo::Redo(); + GetElements()->insert(GetElements()->begin() + mIndex, mAddedElement); + OnNew(mIndex); + } + + size_t GetMemSize() const override + { + return sizeof(URAdd); + } + + T mAddedElement; + int mIndex; + + std::function*()> GetElements; + std::function OnDelete; + std::function OnNew; +}; diff --git a/src/Utils.cpp b/src/Utils.cpp index aaf84897..ba744959 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -23,21 +23,12 @@ // SOFTWARE. // -#include "Platform.h" #include "Platform.h" #include #include "Utils.h" #include "EvaluationStages.h" #include "tinydir.h" -void TexParam(TextureID MinFilter, TextureID MagFilter, TextureID WrapS, TextureID WrapT, TextureID texMode) -{ - glTexParameteri(texMode, GL_TEXTURE_MIN_FILTER, MinFilter); - glTexParameteri(texMode, GL_TEXTURE_MAG_FILTER, MagFilter); - glTexParameteri(texMode, GL_TEXTURE_WRAP_S, WrapS); - glTexParameteri(texMode, GL_TEXTURE_WRAP_T, WrapT); -} - std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) { size_t start_pos = 0; @@ -49,181 +40,6 @@ std::string ReplaceAll(std::string str, const std::string& from, const std::stri return str; } -void FullScreenTriangle::Init() -{ - float fsVts[] = {0.f, 0.f, 2.f, 0.f, 0.f, 2.f}; - glGenBuffers(1, &mFsVA); - glBindBuffer(GL_ARRAY_BUFFER, mFsVA); - glBufferData(GL_ARRAY_BUFFER, 3 * sizeof(float) * 2, fsVts, GL_STATIC_DRAW); - - - glGenVertexArrays(1, &mGLFullScreenVertexArrayName); - glBindVertexArray(mGLFullScreenVertexArrayName); - glBindBuffer(GL_ARRAY_BUFFER, mFsVA); - glVertexAttribPointer(SemUV0, 2, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(SemUV0); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -void FullScreenTriangle::Render() -{ - glBindVertexArray(mGLFullScreenVertexArrayName); - glDrawArrays(GL_TRIANGLES, 0, 3); - glBindVertexArray(0); -} - -void FullScreenTriangle::Finish() -{ - glDeleteBuffers(1, &mFsVA); - glDeleteVertexArrays(1, &mGLFullScreenVertexArrayName); -} - -unsigned int LoadShader(const std::string& shaderString, const char* fileName) -{ - TextureID programObject = glCreateProgram(); - if (programObject == 0) - return 0; - - GLint compiled; - const char* shaderTypeStrings[] = {"#version 300 es\nprecision highp float;\nprecision highp int;\nprecision highp sampler2D;\nprecision highp samplerCube;\n#define VERTEX_SHADER\n", - "#version 300 es\nprecision highp float;\nprecision highp int;\nprecision highp sampler2D;\nprecision highp samplerCube;\n#define FRAGMENT_SHADER\n"}; - - - TextureID shaderTypes[] = {GL_VERTEX_SHADER, GL_FRAGMENT_SHADER}; - TextureID compiledShader[2]; - - for (int i = 0; i < 2; i++) - { - // Create the shader object - int shader = glCreateShader(shaderTypes[i]); - - if (shader == 0) - return false; - - int stringsCount = 2; - const char** strings = (const char**)malloc(sizeof(char*) * stringsCount); // new const char*[stringsCount]; - int* stringLength = (int*)malloc(sizeof(int) * stringsCount); // new int[stringsCount]; - strings[0] = shaderTypeStrings[i]; - stringLength[0] = int(strlen(shaderTypeStrings[i])); - strings[stringsCount - 1] = shaderString.c_str(); - stringLength[stringsCount - 1] = int(shaderString.length()); - - // Load and compile the shader source - glShaderSource(shader, stringsCount, strings, stringLength); - glCompileShader(shader); - - - free(stringLength); - free(strings); - - // Check the compile status - glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); - if (compiled == 0) - { - GLint info_len = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len); - if (info_len > 1) - { - char* info_log = (char*)malloc(sizeof(char) * info_len); - glGetShaderInfoLog(shader, info_len, NULL, info_log); - Log("Error compiling shader: %s \n", fileName); - Log(info_log); - Log("\n"); - free(info_log); - } - glDeleteShader(shader); - return 0; - } - compiledShader[i] = shader; - } - - - GLint linked; - - for (int i = 0; i < 2; i++) - glAttachShader(programObject, compiledShader[i]); - - - // Link the program - glLinkProgram(programObject); - - glBindAttribLocation(programObject, SemUV0, "inUV"); - - // Check the link status - glGetProgramiv(programObject, GL_LINK_STATUS, &linked); - if (linked == 0) - { - GLint info_len = 0; - glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &info_len); - if (info_len > 1) - { - char* info_log = (char*)malloc(sizeof(char) * info_len); - glGetProgramInfoLog(programObject, info_len, NULL, info_log); - Log("Error linking program:\n"); - Log(info_log); - free(info_log); - } - glDeleteProgram(programObject); - return 0; - } - - // Delete these here because they are attached to the program object. - for (int i = 0; i < 2; i++) - glDeleteShader(compiledShader[i]); - - // attributes - return programObject; -} - - -unsigned int LoadShaderTransformFeedback(const std::string& shaderString, const char* filename) -{ - GLuint programHandle = glCreateProgram(); - GLuint vsHandle = glCreateShader(GL_VERTEX_SHADER); - - const char* src[2] = {"#version 430\n", shaderString.c_str()}; - int size[2]; - for (int j = 0; j < 2; j++) - size[j] = int(strlen(src[j])); - - glShaderSource(vsHandle, 2, src, size); - glCompileShader(vsHandle); - - GLint compiled; - // Check the compile status - glGetShaderiv(vsHandle, GL_COMPILE_STATUS, &compiled); - if (compiled == 0) - { - GLint info_len = 0; - glGetShaderiv(vsHandle, GL_INFO_LOG_LENGTH, &info_len); - if (info_len > 1) - { - char info_log[2048]; - glGetShaderInfoLog(vsHandle, info_len, NULL, info_log); - Log("Error compiling Transform Feedback shader %s\n", filename); - Log(info_log); - } - return 0; - } - - glAttachShader(programHandle, vsHandle); - - static const char* varyings[] = { "outCompute0", "outCompute1", "outCompute2", "outCompute3", - "outCompute4", "outCompute5", "outCompute6", "outCompute7", - "outCompute8", "outCompute9", "outCompute10", "outCompute11", - "outCompute12", "outCompute13", "outCompute14" }; - - glTransformFeedbackVaryings( - programHandle, sizeof(varyings) / sizeof(const char*), varyings, GL_INTERLEAVED_ATTRIBS); - - glLinkProgram(programHandle); - - return programHandle; -} - - std::vector outputs; void AddLogOutput(LogOutput output) { @@ -235,13 +51,13 @@ int Log(const char* szFormat, ...) va_list ptr_arg; va_start(ptr_arg, szFormat); - static char buf[10240]; + static char buf[102400]; vsprintf(buf, szFormat, ptr_arg); static FILE* fp = fopen("log.txt", "wt"); if (fp) { - fprintf(fp, buf); + fprintf(fp, "%s", buf); fflush(fp); } for (auto output : outputs) @@ -250,233 +66,7 @@ int Log(const char* szFormat, ...) return 0; } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// matrix will receive the calculated perspective matrix. -// You would have to upload to your shader -// or use glLoadMatrixf if you aren't using shaders. -void Mat4x4::glhPerspectivef2(float fovyInDegrees, float aspectRatio, float znear, float zfar) -{ - float ymax, xmax; - ymax = znear * tanf(fovyInDegrees * 3.14159f / 360.0f); - xmax = ymax * aspectRatio; - glhFrustumf2(-xmax, xmax, -ymax, ymax, znear, zfar); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -void Mat4x4::glhFrustumf2(float left, float right, float bottom, float top, float znear, float zfar) -{ - float temp, temp2, temp3, temp4; - temp = 2.0f * znear; - temp2 = right - left; - temp3 = top - bottom; - temp4 = zfar - znear; - m16[0] = temp / temp2; - m16[1] = 0.0; - m16[2] = 0.0; - m16[3] = 0.0; - m16[4] = 0.0; - m16[5] = temp / temp3; - m16[6] = 0.0; - m16[7] = 0.0; - m16[8] = (right + left) / temp2; - m16[9] = (top + bottom) / temp3; - m16[10] = (-zfar - znear) / temp4; - m16[11] = -1.0f; - m16[12] = 0.0; - m16[13] = 0.0; - m16[14] = (-temp * zfar) / temp4; - m16[15] = 0.0; -} - -void Mat4x4::lookAtRH(const Vec4& eye, const Vec4& at, const Vec4& up) -{ - Vec4 X, Y, Z, tmp; - - Z.Normalize(eye - at); - Y.Normalize(up); - - tmp.Cross(Y, Z); - X.Normalize(tmp); - - tmp.Cross(Z, X); - Y.Normalize(tmp); - - m[0][0] = X.x; - m[0][1] = Y.x; - m[0][2] = Z.x; - m[0][3] = 0.0f; - - m[1][0] = X.y; - m[1][1] = Y.y; - m[1][2] = Z.y; - m[1][3] = 0.0f; - - m[2][0] = X.z; - m[2][1] = Y.z; - m[2][2] = Z.z; - m[2][3] = 0.0f; - - m[3][0] = -X.Dot(eye); - m[3][1] = -Y.Dot(eye); - m[3][2] = -Z.Dot(eye); - m[3][3] = 1.0f; -} - - -void Mat4x4::lookAtLH(const Vec4& eye, const Vec4& at, const Vec4& up) -{ - Vec4 X, Y, Z, tmp; - - Z.Normalize(at - eye); - Y.Normalize(up); - - tmp.Cross(Y, Z); - X.Normalize(tmp); - - tmp.Cross(Z, X); - Y.Normalize(tmp); - - m[0][0] = X.x; - m[0][1] = Y.x; - m[0][2] = Z.x; - m[0][3] = 0.0f; - - m[1][0] = X.y; - m[1][1] = Y.y; - m[1][2] = Z.y; - m[1][3] = 0.0f; - - m[2][0] = X.z; - m[2][1] = Y.z; - m[2][2] = Z.z; - m[2][3] = 0.0f; - - m[3][0] = -X.Dot(eye); - m[3][1] = -Y.Dot(eye); - m[3][2] = -Z.Dot(eye); - m[3][3] = 1.0f; -} - -void Mat4x4::LookAt(const Vec4& eye, const Vec4& at, const Vec4& up) -{ - Vec4 X, Y, Z, tmp; - - Z.Normalize(at - eye); - Y.Normalize(up); - - tmp.Cross(Y, Z); - X.Normalize(tmp); - - tmp.Cross(Z, X); - Y.Normalize(tmp); - - m[0][0] = X.x; - m[0][1] = X.y; - m[0][2] = X.z; - m[0][3] = 0.0f; - - m[1][0] = Y.x; - m[1][1] = Y.y; - m[1][2] = Y.z; - m[1][3] = 0.0f; - - m[2][0] = Z.x; - m[2][1] = Z.y; - m[2][2] = Z.z; - m[2][3] = 0.0f; - - m[3][0] = eye.x; - m[3][1] = eye.y; - m[3][2] = eye.z; - m[3][3] = 1.0f; -} - -void Mat4x4::PerspectiveFovLH2(const float fovy, const float aspect, const float zn, const float zf) -{ - /* - xScale 0 0 0 - 0 yScale 0 0 - 0 0 zf/(zf-zn) 1 - 0 0 -zn*zf/(zf-zn) 0 - where: - */ - /* - + pout->m[0][0] =3D 1.0f / (aspect * tan(fovy/2.0f)); - + pout->m[1][1] =3D 1.0f / tan(fovy/2.0f); - + pout->m[2][2] =3D zf / (zf - zn); - + pout->m[2][3] =3D 1.0f; - + pout->m[3][2] =3D (zf * zn) / (zn - zf); - + pout->m[3][3] =3D 0.0f; - - - - float yscale = cosf(fovy*0.5f); - - float xscale = yscale / aspect; - - */ - m[0][0] = 1.0f / (aspect * tanf(fovy * 0.5f)); - m[0][1] = 0.0f; - m[0][2] = 0.0f; - m[0][3] = 0.0f; - - m[1][0] = 0.0f; - m[1][1] = 1.0f / tanf(fovy * 0.5f); - m[1][2] = 0.0f; - m[1][3] = 0.0f; - - m[2][0] = 0.0f; - m[2][1] = 0.0f; - m[2][2] = zf / (zf - zn); - m[2][3] = 1.0f; - - m[3][0] = 0.0f; - m[3][1] = 0.0f; - m[3][2] = (zf * zn) / (zn - zf); - m[3][3] = 0.0f; -} - -void Mat4x4::OrthoOffCenterLH(const float l, float r, float b, const float t, float zn, const float zf) -{ - m[0][0] = 2 / (r - l); - m[0][1] = 0.0f; - m[0][2] = 0.0f; - m[0][3] = 0.0f; - - m[1][0] = 0.0f; - m[1][1] = 2 / (t - b); - m[1][2] = 0.0f; - m[1][3] = 0.0f; - - m[2][0] = 0.0f; - m[2][1] = 0.0f; - m[2][2] = 1.0f / (zf - zn); - m[2][3] = 0.0f; - - m[3][0] = (l + r) / (l - r); - m[3][1] = (t + b) / (b - t); - m[3][2] = zn / (zn - zf); - m[3][3] = 1.0f; -} - -void TagTime(const char* tagInfo) -{ - static uint64_t lastTime = -1; - if (lastTime == -1) - { - lastTime = SDL_GetPerformanceCounter(); - Log("%s\n", tagInfo); - return; - } - uint64_t t = SDL_GetPerformanceCounter(); - - double v = double(t - lastTime) / double(SDL_GetPerformanceFrequency()); - Log("%s : %5.3f s\n", tagInfo, float(v)); - lastTime = t; -} - -void DiscoverFiles(const char* extension, const char* directory, std::vector& files) +void DiscoverFiles(const char* ext, const char* directory, std::vector& files) { tinydir_dir dir; tinydir_open(&dir, directory); @@ -486,7 +76,7 @@ void DiscoverFiles(const char* extension, const char* directory, std::vector #include #include - -void TagTime(const char* tagInfo); - -typedef unsigned int TextureID; -static const int SemUV0 = 0; - -class FullScreenTriangle -{ -public: - FullScreenTriangle() : mGLFullScreenVertexArrayName(-1) - { - } - ~FullScreenTriangle() - { - } - void Init(); - void Render(); - void Finish(); - -protected: - TextureID mGLFullScreenVertexArrayName; - TextureID mFsVA; -}; - - -void TexParam(TextureID MinFilter, TextureID MagFilter, TextureID WrapS, TextureID WrapT, TextureID texMode); +#include "Platform.h" std::string ReplaceAll(std::string str, const std::string& from, const std::string& to); -unsigned int LoadShader(const std::string& shaderString, const char* fileName); -unsigned int LoadShaderTransformFeedback(const std::string& shaderString, const char* fileName); - typedef void (*LogOutput)(const char* szText); void AddLogOutput(LogOutput output); @@ -75,759 +47,10 @@ inline int align(int value, int alignment) return (value + alignment - 1) & ~(alignment - 1); } -struct Mat4x4; - -struct iVec2 -{ - int x, y; - inline iVec2 operator*(float f) const - { - return {int(x * f), int(y * f)}; - } - inline iVec2 operator-(const iVec2& v) const - { - return {x - v.x, y - v.y}; - } - inline iVec2 operator+(const iVec2& v) const - { - return {x + v.x, y + v.y}; - } - int& operator[](size_t index) - { - return ((int*)&x)[index]; - } - const int& operator[](size_t index) const - { - return ((int*)&x)[index]; - } -}; - -struct iVec3 -{ - int x, y, z; - inline iVec3 operator*(float f) const - { - return {int(x * f), int(y * f), int(z * f)}; - } - inline iVec3 operator-(const iVec3& v) const - { - return {x - v.x, y - v.y, z - v.z}; - } - inline iVec3 operator+(const iVec3& v) const - { - return {x + v.x, y + v.y, z + v.z}; - } - int& operator[](size_t index) - { - return ((int*)&x)[index]; - } - const int& operator[](size_t index) const - { - return ((int*)&x)[index]; - } -}; - -struct iVec4 -{ - int x, y, z, w; - inline iVec4 operator*(float f) const - { - return {int(x * f), int(y * f), int(z * f), int(w * f)}; - } - inline iVec4 operator-(const iVec4& v) const - { - return {x - v.x, y - v.y, z - v.z, w - v.w}; - } - inline iVec4 operator+(const iVec4& v) const - { - return {x + v.x, y + v.y, z + v.z, w + v.w}; - } - int& operator[](size_t index) - { - return ((int*)&x)[index]; - } - const int& operator[](size_t index) const - { - return ((int*)&x)[index]; - } -}; - -struct Vec2 -{ - float x, y; - inline Vec2 operator*(float f) const - { - return {x * f, y * f}; - } - inline Vec2 operator-(const Vec2& v) const - { - return {x - v.x, y - v.y}; - } - inline Vec2 operator+(const Vec2& v) const - { - return {x + v.x, y + v.y}; - } - float& operator[](size_t index) - { - return ((float*)&x)[index]; - } - const float& operator[](size_t index) const - { - return ((float*)&x)[index]; - } -}; - -struct Vec3 -{ - float x, y, z; - inline Vec3 operator*(float f) const - { - return {x * f, y * f, z * f}; - } - inline Vec3 operator-(const Vec3& v) const - { - return {x - v.x, y - v.y, z - v.z}; - } - inline Vec3 operator+(const Vec3& v) const - { - return {x + v.x, y + v.y, z + v.z}; - } - float& operator[](size_t index) - { - return ((float*)&x)[index]; - } - const float& operator[](size_t index) const - { - return ((float*)&x)[index]; - } -}; - -struct Vec4 -{ -public: - Vec4(const Vec4& other) : x(other.x), y(other.y), z(other.z), w(other.w) - { - } - Vec4() - { - } - Vec4(float _x, float _y, float _z = 0.f, float _w = 0.f) : x(_x), y(_y), z(_z), w(_w) - { - } - Vec4(int _x, int _y, int _z = 0, int _w = 0) : x((float)_x), y((float)_y), z((float)_z), w((float)_w) - { - } - Vec4(float v) : x(v), y(v), z(v), w(v) - { - } - - void Lerp(const Vec4& v, float t) - { - x += (v.x - x) * t; - y += (v.y - y) * t; - z += (v.z - z) * t; - w += (v.w - w) * t; - } - void LerpColor(const Vec4& v, float t) - { - for (int i = 0; i < 4; i++) - (*this)[i] = sqrtf(((*this)[i] * (*this)[i]) * (1.f - t) + (v[i] * v[i]) * (t)); - } - void Lerp(const Vec4& v, const Vec4& v2, float t) - { - *this = v; - Lerp(v2, t); - } - - inline void Set(float v) - { - x = y = z = w = v; - } - inline void Set(float _x, float _y, float _z = 0.f, float _w = 0.f) - { - x = _x; - y = _y; - z = _z; - w = _w; - } - - inline Vec4& operator-=(const Vec4& v) - { - x -= v.x; - y -= v.y; - z -= v.z; - w -= v.w; - return *this; - } - inline Vec4& operator+=(const Vec4& v) - { - x += v.x; - y += v.y; - z += v.z; - w += v.w; - return *this; - } - inline Vec4& operator*=(const Vec4& v) - { - x *= v.x; - y *= v.y; - z *= v.z; - w *= v.w; - return *this; - } - inline Vec4& operator*=(float v) - { - x *= v; - y *= v; - z *= v; - w *= v; - return *this; - } - - inline Vec4 operator*(float f) const; - inline Vec4 operator-() const; - inline Vec4 operator-(const Vec4& v) const; - inline Vec4 operator+(const Vec4& v) const; - inline Vec4 operator*(const Vec4& v) const; - - inline const Vec4& operator+() const - { - return (*this); - } - inline float Length() const - { - return sqrtf(x * x + y * y + z * z); - }; - inline float LengthSq() const - { - return (x * x + y * y + z * z); - }; - inline Vec4 Normalize() - { - (*this) *= (1.f / Length() + FLT_EPSILON); - return (*this); - } - inline Vec4 Normalize(const Vec4& v) - { - this->Set(v.x, v.y, v.z, v.w); - this->Normalize(); - return (*this); - } - inline int LongestAxis() const - { - int res = 0; - res = (fabsf((*this)[1]) > fabsf((*this)[res])) ? 1 : res; - res = (fabsf((*this)[2]) > fabsf((*this)[res])) ? 2 : res; - return res; - } - inline void Cross(const Vec4& v) - { - Vec4 res; - res.x = y * v.z - z * v.y; - res.y = z * v.x - x * v.z; - res.z = x * v.y - y * v.x; - - x = res.x; - y = res.y; - z = res.z; - w = 0.f; - } - inline void Cross(const Vec4& v1, const Vec4& v2) - { - x = v1.y * v2.z - v1.z * v2.y; - y = v1.z * v2.x - v1.x * v2.z; - z = v1.x * v2.y - v1.y * v2.x; - w = 0.f; - } - inline float Dot(const Vec4& v) const - { - return (x * v.x) + (y * v.y) + (z * v.z) + (w * v.w); - } - - void IsMaxOf(const Vec4& v) - { - x = (v.x > x) ? v.x : x; - y = (v.y > y) ? v.y : y; - z = (v.z > z) ? v.z : z; - w = (v.w > w) ? v.z : w; - } - void IsMinOf(const Vec4& v) - { - x = (v.x > x) ? x : v.x; - y = (v.y > y) ? y : v.y; - z = (v.z > z) ? z : v.z; - w = (v.w > w) ? z : v.w; - } - - bool IsInside(const Vec4& min, const Vec4& max) const - { - if (min.x > x || max.x < x || min.y > y || max.y < y || min.z > z || max.z < z) - return false; - return true; - } - - Vec4 Symetrical(const Vec4& v) const - { - Vec4 res; - float dist = SignedDistanceTo(v); - res = v; - res -= (*this) * dist * 2.f; - - return res; - } - /*void transform(const Mat4x4& matrix); - void transform(const Vec4 & s, const Mat4x4& matrix); - */ - void TransformVector(const Mat4x4& matrix); - void TransformPoint(const Mat4x4& matrix); - - void TransformVector(const Vec4& v, const Mat4x4& matrix) - { - (*this) = v; - this->TransformVector(matrix); - } - void TransformPoint(const Vec4& v, const Mat4x4& matrix) - { - (*this) = v; - this->TransformPoint(matrix); - } - - // quaternion slerp - // void slerp(const Vec4 &q1, const Vec4 &q2, float t ); - - inline float SignedDistanceTo(const Vec4& point) const; - float& operator[](size_t index) - { - return ((float*)&x)[index]; - } - const float& operator[](size_t index) const - { - return ((float*)&x)[index]; - } - - float x, y, z, w; -}; - -inline Vec4 Vec4::operator*(float f) const -{ - return Vec4(x * f, y * f, z * f, w * f); -} -inline Vec4 Vec4::operator-() const -{ - return Vec4(-x, -y, -z, -w); -} -inline Vec4 Vec4::operator-(const Vec4& v) const -{ - return Vec4(x - v.x, y - v.y, z - v.z, w - v.w); -} -inline Vec4 Vec4::operator+(const Vec4& v) const -{ - return Vec4(x + v.x, y + v.y, z + v.z, w + v.w); -} -inline Vec4 Vec4::operator*(const Vec4& v) const -{ - return Vec4(x * v.x, y * v.y, z * v.z, w * v.w); -} -inline float Vec4::SignedDistanceTo(const Vec4& point) const -{ - return (point.Dot(Vec4(x, y, z))) - w; -} - -inline Vec4 Normalized(const Vec4& v) -{ - Vec4 res; - res = v; - res.Normalize(); - return res; -} -inline Vec4 Cross(const Vec4& v1, const Vec4& v2) -{ - Vec4 res; - res.x = v1.y * v2.z - v1.z * v2.y; - res.y = v1.z * v2.x - v1.x * v2.z; - res.z = v1.x * v2.y - v1.y * v2.x; - res.w = 0.f; - return res; -} - -inline float Dot(const Vec4& v1, const Vec4& v2) -{ - return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z); -} - - -inline void FPU_MatrixF_x_MatrixF(const float* a, const float* b, float* r) -{ - r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12]; - r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13]; - r[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14]; - r[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15]; - - r[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12]; - r[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13]; - r[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14]; - r[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15]; - - r[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12]; - r[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13]; - r[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14]; - r[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15]; - - r[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12]; - r[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13]; - r[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14]; - r[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15]; -} - - -struct Mat4x4 -{ -public: - union { - float m[4][4]; - float m16[16]; - struct - { - Vec4 right, up, dir, position; - } V; - }; - - Mat4x4(float v1, - float v2, - float v3, - float v4, - float v5, - float v6, - float v7, - float v8, - float v9, - float v10, - float v11, - float v12, - float v13, - float v14, - float v15, - float v16) - { - m16[0] = v1; - m16[1] = v2; - m16[2] = v3; - m16[3] = v4; - m16[4] = v5; - m16[5] = v6; - m16[6] = v7; - m16[7] = v8; - m16[8] = v9; - m16[9] = v10; - m16[10] = v11; - m16[11] = v12; - m16[12] = v13; - m16[13] = v14; - m16[14] = v15; - m16[15] = v16; - } - Mat4x4(const Mat4x4& other) - { - memcpy(&m16[0], &other.m16[0], sizeof(float) * 16); - } - Mat4x4(const Vec4& r, const Vec4& u, const Vec4& d, const Vec4& p) - { - set(r, u, d, p); - } - Mat4x4() - { - } - void set(const Vec4& r, const Vec4& u, const Vec4& d, const Vec4& p) - { - V.right = r; - V.up = u; - V.dir = d; - V.position = p; - } - void set(float v1, - float v2, - float v3, - float v4, - float v5, - float v6, - float v7, - float v8, - float v9, - float v10, - float v11, - float v12, - float v13, - float v14, - float v15, - float v16) - { - m16[0] = v1; - m16[1] = v2; - m16[2] = v3; - m16[3] = v4; - m16[4] = v5; - m16[5] = v6; - m16[6] = v7; - m16[7] = v8; - m16[8] = v9; - m16[9] = v10; - m16[10] = v11; - m16[11] = v12; - m16[12] = v13; - m16[13] = v14; - m16[14] = v15; - m16[15] = v16; - } - static Mat4x4 GetIdentity() - { - return Mat4x4(1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f); - } - operator float*() - { - return m16; - } - operator const float*() const - { - return m16; - } - void Translation(float _x, float _y, float _z) - { - this->Translation(Vec4(_x, _y, _z)); - } - - void Translation(const Vec4& vt) - { - V.right.Set(1.f, 0.f, 0.f, 0.f); - V.up.Set(0.f, 1.f, 0.f, 0.f); - V.dir.Set(0.f, 0.f, 1.f, 0.f); - V.position.Set(vt.x, vt.y, vt.z, 1.f); - } - void TranslationScale(const Vec4& vt, const Vec4& scale) - { - V.right.Set(scale.x, 0.f, 0.f, 0.f); - V.up.Set(0.f, scale.y, 0.f, 0.f); - V.dir.Set(0.f, 0.f, scale.z, 0.f); - V.position.Set(vt.x, vt.y, vt.z, 1.f); - } - - inline void RotationY(const float angle) - { - float c = cosf(angle); - float s = sinf(angle); - - V.right.Set(c, 0.f, -s, 0.f); - V.up.Set(0.f, 1.f, 0.f, 0.f); - V.dir.Set(s, 0.f, c, 0.f); - V.position.Set(0.f, 0.f, 0.f, 1.f); - } - - inline void RotationX(const float angle) - { - float c = cosf(angle); - float s = sinf(angle); - - V.right.Set(1.f, 0.f, 0.f, 0.f); - V.up.Set(0.f, c, s, 0.f); - V.dir.Set(0.f, -s, c, 0.f); - V.position.Set(0.f, 0.f, 0.f, 1.f); - } - - inline void RotationZ(const float angle) - { - float c = cosf(angle); - float s = sinf(angle); - - V.right.Set(c, s, 0.f, 0.f); - V.up.Set(-s, c, 0.f, 0.f); - V.dir.Set(0.f, 0.f, 1.f, 0.f); - V.position.Set(0.f, 0.f, 0, 1.f); - } - inline void Scale(float _s) - { - V.right.Set(_s, 0.f, 0.f, 0.f); - V.up.Set(0.f, _s, 0.f, 0.f); - V.dir.Set(0.f, 0.f, _s, 0.f); - V.position.Set(0.f, 0.f, 0.f, 1.f); - } - inline void Scale(float _x, float _y, float _z) - { - V.right.Set(_x, 0.f, 0.f, 0.f); - V.up.Set(0.f, _y, 0.f, 0.f); - V.dir.Set(0.f, 0.f, _z, 0.f); - V.position.Set(0.f, 0.f, 0.f, 1.f); - } - inline void Scale(const Vec4& s) - { - Scale(s.x, s.y, s.z); - } - - inline Mat4x4& operator*=(const Mat4x4& mat) - { - Mat4x4 tmpMat; - tmpMat = *this; - tmpMat.Multiply(mat); - *this = tmpMat; - return *this; - } - inline Mat4x4 operator*(const Mat4x4& mat) const - { - Mat4x4 matT; - matT.Multiply(*this, mat); - return matT; - } - - inline void Multiply(const Mat4x4& matrix) - { - Mat4x4 tmp; - tmp = *this; - - FPU_MatrixF_x_MatrixF((float*)&tmp, (float*)&matrix, (float*)this); - } - - inline void Multiply(const Mat4x4& m1, const Mat4x4& m2) - { - FPU_MatrixF_x_MatrixF((float*)&m1, (float*)&m2, (float*)this); - } - - void glhPerspectivef2(float fovyInDegrees, float aspectRatio, float znear, float zfar); - void glhFrustumf2(float left, float right, float bottom, float top, float znear, float zfar); - void PerspectiveFovLH2(const float fovy, const float aspect, const float zn, const float zf); - void OrthoOffCenterLH(const float l, float r, float b, const float t, float zn, const float zf); - void lookAtRH(const Vec4& eye, const Vec4& at, const Vec4& up); - void lookAtLH(const Vec4& eye, const Vec4& at, const Vec4& up); - void LookAt(const Vec4& eye, const Vec4& at, const Vec4& up); - void rotationQuaternion(const Vec4& q); - - inline float GetDeterminant() const - { - return m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - - m[0][2] * m[1][1] * m[2][0] - m[0][1] * m[1][0] * m[2][2] - m[0][0] * m[1][2] * m[2][1]; - } - - float Inverse(const Mat4x4& srcMatrix, bool affine = false); - float Inverse(bool affine = false); - void Identity() - { - V.right.Set(1.f, 0.f, 0.f, 0.f); - V.up.Set(0.f, 1.f, 0.f, 0.f); - V.dir.Set(0.f, 0.f, 1.f, 0.f); - V.position.Set(0.f, 0.f, 0.f, 1.f); - } - inline void transpose() - { - Mat4x4 tmpm; - for (int l = 0; l < 4; l++) - { - for (int c = 0; c < 4; c++) - { - tmpm.m[l][c] = m[c][l]; - } - } - (*this) = tmpm; - } - void RotationAxis(const Vec4& axis, float angle); - /* - void Lerp(const Mat4x4& r, const Mat4x4& t, float s) - { - right = LERP(r.right, t.right, s); - up = LERP(r.up, t.up, s); - dir = LERP(r.dir, t.dir, s); - position = LERP(r.position, t.position, s); - } - */ - void RotationYawPitchRoll(const float yaw, const float pitch, const float roll); - - inline void OrthoNormalize() - { - V.right.Normalize(); - V.up.Normalize(); - V.dir.Normalize(); - } -}; - - -inline void Vec4::TransformVector(const Mat4x4& matrix) -{ - Vec4 out; - - out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0]; - out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1]; - out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2]; - out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3]; - - x = out.x; - y = out.y; - z = out.z; - w = out.w; -} - -inline void Vec4::TransformPoint(const Mat4x4& matrix) -{ - Vec4 out; - - out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + matrix.m[3][0]; - out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + matrix.m[3][1]; - out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + matrix.m[3][2]; - out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + matrix.m[3][3]; - - x = out.x; - y = out.y; - z = out.z; - w = out.w; -} - - -inline void Mat4x4::RotationAxis(const Vec4& axis, float angle) -{ - float length2 = axis.LengthSq(); - if (length2 < FLT_EPSILON) - { - Identity(); - return; - } - - Vec4 n = axis * (1.f / sqrtf(length2)); - float s = sinf(angle); - float c = cosf(angle); - float k = 1.f - c; - - float xx = n.x * n.x * k + c; - float yy = n.y * n.y * k + c; - float zz = n.z * n.z * k + c; - float xy = n.x * n.y * k; - float yz = n.y * n.z * k; - float zx = n.z * n.x * k; - float xs = n.x * s; - float ys = n.y * s; - float zs = n.z * s; - - m[0][0] = xx; - m[0][1] = xy + zs; - m[0][2] = zx - ys; - m[0][3] = 0.f; - m[1][0] = xy - zs; - m[1][1] = yy; - m[1][2] = yz + xs; - m[1][3] = 0.f; - m[2][0] = zx + ys; - m[2][1] = yz - xs; - m[2][2] = zz; - m[2][3] = 0.f; - m[3][0] = 0.f; - m[3][1] = 0.f; - m[3][2] = 0.f; - m[3][3] = 1.f; -} - void IMessageBox(const char* text, const char* title); void DiscoverFiles(const char* extension, const char* directory, std::vector& files); -inline float sign(float v) -{ - return (v >= 0.f) ? 1.f : -1.f; -} void OpenShellURL(const std::string& url); -void GetTextureDimension(unsigned int textureId, int* w, int* h); std::string GetName(const std::string& name); std::string GetGroup(const std::string& name); @@ -841,11 +64,16 @@ void Swap(T& a, T& b) } template -T min(const T& a, const T& b) +T Min(const T& a, const T& b) { return (a < b) ? a : b; } +template +T Max(const T& a, const T& b) +{ + return (a > b) ? a : b; +} enum EvaluationStatus { @@ -865,3 +93,42 @@ inline float DegToRad(float a) { return a / 180.f * PI; } + +void Splitpath(const char* completePath, char* drive, char* dir, char* filename, char* ext); + +inline std::vector ReadFile(const char* szFileName) +{ + FILE* fp = fopen(szFileName, "rb"); + if (fp) + { + fseek(fp, 0, SEEK_END); + auto bufSize = ftell(fp); + fseek(fp, 0, SEEK_SET); + //char* buf = new char[bufSize]; + std::vector buf(bufSize); + fread(buf.data(), bufSize, 1, fp); + fclose(fp); + return buf; + } + return {}; +} + +inline float Saturate(float v) +{ + return Min(Max(v, 0.f), 1.f); +} + +inline uint32_t ColorU8(uint8_t R, uint8_t G, uint8_t B, uint8_t A) +{ + return (((uint32_t)(A)<<24) | ((uint32_t)(B)<<16) | ((uint32_t)(G)<<8) | ((uint32_t)(R))); +} + +inline uint32_t ColorF32(float R, float G, float B, float A) +{ + uint32_t out; + out = (uint32_t)(Saturate(R) * 255.f + 0.5f) << 0; + out |= (uint32_t)(Saturate(G) * 255.f + 0.5f) << 8; + out |= (uint32_t)(Saturate(B) * 255.f + 0.5f) << 16; + out |= (uint32_t)(Saturate(A) * 255.f + 0.5f) << 24; + return out; +} \ No newline at end of file diff --git a/bin/shell_minimal.html b/src/index.html similarity index 51% rename from bin/shell_minimal.html rename to src/index.html index 7ec9f82c..979995d8 100644 --- a/bin/shell_minimal.html +++ b/src/index.html @@ -1,9 +1,18 @@ + + + - Imogen 0.13 + Loading Imogen ...