diff --git a/App/CMakeLists.txt b/App/CMakeLists.txt index 06d530c2ff..c89d01fd29 100644 --- a/App/CMakeLists.txt +++ b/App/CMakeLists.txt @@ -18,10 +18,10 @@ # ***** END LICENSE BLOCK ***** set(Natron_SOURCES NatronApp_main.cpp) -if(WINDOWS) - list(APPEND Natron_SOURCES ../Natron.rc) -endif() add_executable(Natron ${Natron_SOURCES}) +if(WIN32) + target_sources(Natron PRIVATE ../Natron.rc) +endif() if(APPLE) set_target_properties(Natron PROPERTIES MACOSX_BUNDLE TRUE @@ -59,3 +59,40 @@ install(FILES ../Gui/Resources/Images/natronIcon256_linux.png DESTINATION "${CMAKE_INSTALL_DATADIR}/pixmaps") install(FILES ../Gui/Resources/Images/natronProjectIcon_linux.png DESTINATION "${CMAKE_INSTALL_DATADIR}/pixmaps") + +IF(WIN32 AND DEPLOYQT_FOUND) + SET(CONFIG_FILE ${CMAKE_CURRENT_BINARY_DIR}/install_deps_${CMAKE_BUILD_TYPE}.cmake) + + # Find and install needed DLLs + file(GENERATE OUTPUT + "${CONFIG_FILE}" CONTENT + [[ + EXECUTE_PROCESS(COMMAND del ${INSTALL_BINPATH}/*.dll) + SET(TARGET_APP $) + FILE(GET_RUNTIME_DEPENDENCIES + RESOLVED_DEPENDENCIES_VAR deps_resolved + UNRESOLVED_DEPENDENCIES_VAR deps_unresolved + EXECUTABLES ${TARGET_APP} + DIRECTORIES ${CMAKELIBPATH} + PRE_EXCLUDE_REGEXES "api-ms-*" "ext-ms-*" + POST_EXCLUDE_REGEXES ".*system32/.*\\.dll" + ) + MESSAGE(STATUS "Resolving runtime dependencies for ${TARGET_APP}") + FOREACH(dep ${deps_resolved}) + FILE(INSTALL ${dep} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) + MESSAGE(STATUS "Installing ${dep}") + ENDFOREACH() + FOREACH(dep ${deps_unresolved}) + MESSAGE(WARNING "Runtime dependency ${dep} could not be resolved.") + ENDFOREACH() + EXECUTE_PROCESS(COMMAND ${DEPLOYQT_EXE} --no-angle --compiler-runtime ${INSTALL_BINPATH}/Natron.exe) + ]]) + + INSTALL(CODE "SET(INSTALL_BINPATH \"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}\")") + INSTALL(CODE "SET(DEPLOYQT_EXE \"${DEPLOYQT_EXE}\")") + INSTALL(CODE "SET(CMAKELIBPATH \"${CMAKE_SYSTEM_LIBRARY_PATH};${CMAKE_MINGW_SYSTEM_LIBRARY_PATH};${MINGWPATH}\")") + INSTALL(SCRIPT ${CONFIG_FILE}) + INSTALL(DIRECTORY ${Python3_LIBRARY_DIRS}/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR} + DESTINATION lib + PATTERN "*.pyc" EXCLUDE) +ENDIF() \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 48dd73e220..b7f804f31a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,17 @@ if(WIN32) endif() find_package(Python3 COMPONENTS Interpreter Development) +if(WIN32) + # Search qtdeploy executable + find_program(DEPLOYQT_EXE windeployqt.exe) + if(NOT ${DEPLOYQT_EXE} STREQUAL "") + set(DEPLOYQT_FOUND 1) + else() + set(DEPLOYQT_FOUND 0) + message(STATUS "windeployqt.exe not found, will not deploy Qt dependencies") + endif() +endif() + if(IS_DEBUG_BUILD AND WIN32) # Explicitly setting SHIBOKEN_PYTHON_LIBRARIES variable to avoid PYTHON_DEBUG_LIBRARY-NOTFOUND # link errors on Windows debug builds. diff --git a/Engine/AppManager.cpp b/Engine/AppManager.cpp index 9174556ee2..5e76273087 100644 --- a/Engine/AppManager.cpp +++ b/Engine/AppManager.cpp @@ -315,6 +315,8 @@ AppManager::loadFromArgs(const CLArgs& cl) std::cout << "argv[" << i << "] = " << StrUtils::utf16_to_utf8( std::wstring(_imp->commandLineArgsWide[i]) ) << std::endl; } #endif + // This should fix GL widgets when undocked + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); // This needs to be done BEFORE creating qApp because // on Linux, X11 will create a context that would corrupt @@ -323,6 +325,7 @@ AppManager::loadFromArgs(const CLArgs& cl) _imp->renderingContextPool.reset( new GPUContextPool() ); initializeOpenGLFunctionsOnce(true); + // QCoreApplication will hold a reference to that appManagerArgc integer until it dies. // Thus ensure that the QCoreApplication is destroyed when returning this function. initializeQApp(_imp->nArgs, &_imp->commandLineArgsUtf8.front()); // calls QCoreApplication::QCoreApplication(), which calls setlocale() diff --git a/Global/Enums.h b/Global/Enums.h index 37f75d66ce..acd1bab91a 100644 --- a/Global/Enums.h +++ b/Global/Enums.h @@ -299,6 +299,8 @@ enum PixmapEnum NATRON_PIXMAP_VIEWER_GAMMA_DISABLED, NATRON_PIXMAP_VIEWER_GAIN_ENABLED, NATRON_PIXMAP_VIEWER_GAIN_DISABLED, + NATRON_PIXMAP_VIEWER_DITHER_ENABLED, + NATRON_PIXMAP_VIEWER_DITHER_DISABLED, NATRON_PIXMAP_SCRIPT_CLEAR_OUTPUT, NATRON_PIXMAP_SCRIPT_EXEC_SCRIPT, diff --git a/Gui/CurveWidget.cpp b/Gui/CurveWidget.cpp index 67fe8b60e4..68dd1777fc 100644 --- a/Gui/CurveWidget.cpp +++ b/Gui/CurveWidget.cpp @@ -164,6 +164,7 @@ CurveWidget::initializeGL() // always running in the main thread assert( qApp && qApp->thread() == QThread::currentThread() ); appPTR->initializeOpenGLFunctionsOnce(); + makeCurrent(); } void diff --git a/Gui/DopeSheetView.cpp b/Gui/DopeSheetView.cpp index b0c7bc0164..7bccaed593 100644 --- a/Gui/DopeSheetView.cpp +++ b/Gui/DopeSheetView.cpp @@ -3171,6 +3171,8 @@ DopeSheetView::initializeGL() return; } + makeCurrent(); + _imp->generateKeyframeTextures(); } diff --git a/Gui/GuiApplicationManager.cpp b/Gui/GuiApplicationManager.cpp index 25df689ca0..54049f28a2 100644 --- a/Gui/GuiApplicationManager.cpp +++ b/Gui/GuiApplicationManager.cpp @@ -790,6 +790,12 @@ GuiApplicationManager::getIcon(PixmapEnum e, path = NATRON_IMAGES_PATH "interp_curve_z.png"; break; // DON'T add a default: case here + case NATRON_PIXMAP_VIEWER_DITHER_ENABLED: + path = NATRON_IMAGES_PATH "dither_enabled.png"; + break; + case NATRON_PIXMAP_VIEWER_DITHER_DISABLED: + path = NATRON_IMAGES_PATH "dither_disabled.png"; + break; } // switch if ( path.empty() ) { assert(!"Missing image."); diff --git a/Gui/GuiResources.qrc b/Gui/GuiResources.qrc index 3d9ac34815..6218b77fd9 100644 --- a/Gui/GuiResources.qrc +++ b/Gui/GuiResources.qrc @@ -159,6 +159,8 @@ Resources/Images/curve.png Resources/Images/cuspPoints.png Resources/Images/diskcache_icon.png + Resources/Images/dither_enabled.png + Resources/Images/dither_disabled.png Resources/Images/dot_icon.png Resources/Images/ellipse.png Resources/Images/enter_group.png diff --git a/Gui/Resources/Images/dither_disabled.png b/Gui/Resources/Images/dither_disabled.png new file mode 100644 index 0000000000..536fdfbfe9 Binary files /dev/null and b/Gui/Resources/Images/dither_disabled.png differ diff --git a/Gui/Resources/Images/dither_enabled.png b/Gui/Resources/Images/dither_enabled.png new file mode 100644 index 0000000000..294cfb9536 Binary files /dev/null and b/Gui/Resources/Images/dither_enabled.png differ diff --git a/Gui/Shaders.cpp b/Gui/Shaders.cpp index 5fe11d0c62..d36e532898 100644 --- a/Gui/Shaders.cpp +++ b/Gui/Shaders.cpp @@ -29,202 +29,242 @@ NATRON_NAMESPACE_ENTER -const char* fragRGB = - "uniform sampler2D Tex;\n" - "uniform float gain;\n" - "uniform float offset;\n" - "uniform int lut;\n" - "uniform float gamma;\n" - "\n" - "float linear_to_srgb(float c) {\n" - " return (c<=0.0031308) ? (12.92*c) : (((1.0+0.055)*pow(c,1.0/2.4))-0.055);\n" - "}\n" - "float linear_to_rec709(float c) {" - " return (c<0.018) ? (4.500*c) : (1.099*pow(c,0.45) - 0.099);\n" - "}\n" - "float linear_to_bt1886(float c) {" - " return pow(c,1.0/2.4);\n" - "}\n" - "void main() {\n" - " vec4 color_tmp = texture2D(Tex,gl_TexCoord[0].st);\n" - " color_tmp.rgb = (color_tmp.rgb * gain) + offset;\n" - " if (lut == 0) { // srgb\n" -// << TO SRGB - " color_tmp.r = linear_to_srgb(color_tmp.r);\n" - " color_tmp.g = linear_to_srgb(color_tmp.g);\n" - " color_tmp.b = linear_to_srgb(color_tmp.b);\n" -// << END TO SRGB - " } else if (lut == 2) { // Rec 709\n" -// << TO REC 709 - " color_tmp.r = linear_to_rec709(color_tmp.r);\n" - " color_tmp.g = linear_to_rec709(color_tmp.g);\n" - " color_tmp.b = linear_to_rec709(color_tmp.b);\n" -// << END TO REC 709 - " } else if (lut == 3) { // BT1886\n" -// << TO BT1886 - " color_tmp.r = linear_to_bt1886(color_tmp.r);\n" - " color_tmp.g = linear_to_bt1886(color_tmp.g);\n" - " color_tmp.b = linear_to_bt1886(color_tmp.b);\n" -// << END TO BT1886 - " }\n" - " if (gamma <= 0.) {\n" - " color_tmp.r = (color_tmp.r >= 1.) ? 1. : 0.;\n" - " color_tmp.g = (color_tmp.g >= 1.) ? 1. : 0.;\n" - " color_tmp.b = (color_tmp.b >= 1.) ? 1. : 0.;\n" - " } else {\n" - " color_tmp.r = pow(color_tmp.r, 1./gamma);\n" - " color_tmp.g = pow(color_tmp.g, 1./gamma);\n" - " color_tmp.b = pow(color_tmp.b, 1./gamma);\n" - " }\n" - " gl_FragColor = color_tmp;\n" - "}\n" -; -const char* vertRGB = - "void main()\n" - "{\n" - " gl_TexCoord[0] = gl_MultiTexCoord0;" - " gl_Position = ftransform();\n" - "}\n" - "\n" -; +const char* fragRGB = R"( + uniform sampler2D Tex; + uniform float gain; + uniform float offset; + uniform int lut; + uniform float gamma; + uniform int dither; + + #if __VERSION__ < 150 + float rnd(vec2 p) + { + return 1.0 - 2.0*fract(sin(dot(p.xy ,vec2(12.9898,78.233))) * 43758.5453); + } + #else + float rnd(vec2 p) + { + int n = int(p.x * 40.0 + p.y * 6400.0); + n = (n << 13) ^ n; + return 1.0 - float( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0; + } + #endif + + float linear_to_srgb(float c) { + return (c<=0.0031308) ? (12.92*c) : (((1.0+0.055)*pow(c,1.0/2.4))-0.055); + } + float linear_to_rec709(float c) { + return (c<0.018) ? (4.500*c) : (1.099*pow(c,0.45) - 0.099); + } + float linear_to_bt1886(float c) { + return pow(c,1.0/2.4); + } + void main() { + vec4 color_tmp = texture2D(Tex,gl_TexCoord[0].st); + color_tmp.rgb = (color_tmp.rgb * gain) + offset; + if (lut == 0) { // srgb + // << TO SRGB + color_tmp.r = linear_to_srgb(color_tmp.r); + color_tmp.g = linear_to_srgb(color_tmp.g); + color_tmp.b = linear_to_srgb(color_tmp.b); + // << END TO SRGB + } else if (lut == 2) { // Rec 709 + // << TO REC 709 + color_tmp.r = linear_to_rec709(color_tmp.r); + color_tmp.g = linear_to_rec709(color_tmp.g); + color_tmp.b = linear_to_rec709(color_tmp.b); + // << END TO REC 709 + } else if (lut == 3) { // BT1886 + // << TO BT1886 + color_tmp.r = linear_to_bt1886(color_tmp.r); + color_tmp.g = linear_to_bt1886(color_tmp.g); + color_tmp.b = linear_to_bt1886(color_tmp.b); + // << END TO BT1886 + } + if (gamma <= 0.) { + color_tmp.r = (color_tmp.r >= 1.) ? 1. : 0.; + color_tmp.g = (color_tmp.g >= 1.) ? 1. : 0.; + color_tmp.b = (color_tmp.b >= 1.) ? 1. : 0.; + } else { + color_tmp.r = pow(color_tmp.r, 1./gamma); + color_tmp.g = pow(color_tmp.g, 1./gamma); + color_tmp.b = pow(color_tmp.b, 1./gamma); + } + + if (dither){ + //dithering + ivec2 texsize = textureSize2D(Tex, 0); + vec2 coord = gl_TexCoord[0].st / texsize; + + vec3 c = color_tmp.rgb; + float a = color_tmp.a; + float scale = 255.0; + float seed = 32; + + vec2 pr = (0.9 + 0.1 * seed) * coord.xy * 1000.1; + vec2 pg = (0.9 + 0.1 * seed) * coord.xy * 1000.2; + vec2 pb = (0.9 + 0.1 * seed) * coord.xy * 1000.3; + + + gl_FragColor = vec4(c.rgb + vec3(rnd(pr), rnd(pg), rnd(pb)) * vec3(0.5) / vec3(scale), a); + } else { + gl_FragColor = vec4(color_tmp.rgb, color_tmp.a); + } + } +)"; +const char* vertRGB = R"( + void main() + { + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = ftransform(); + } + )"; /*There's a black texture used for when the user disconnect the viewer It's not just a shader,because we still need coordinates feedback. */ -const char* blackFrag = - "uniform sampler2D Tex;\n" - "void main()\n" - "{\n" - " gl_FragColor = texture2D(Tex,gl_TexCoord[0].st);\n" - "}\n"; -const char *histogramComputation_frag = - "#extension GL_ARB_texture_rectangle : enable\n" - "uniform sampler2DRect Tex;\n" - "uniform int channel;\n" - "void main()\n" - "{\n" - " gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n" - "}\n" -; -const char *histogramComputationVertex_vert = - "#extension GL_ARB_texture_rectangle : enable\n" - "uniform sampler2DRect Tex;\n" - "uniform int channel;\n" - "attribute vec2 TexCoord;\n" - "void main()\n" - "{\n" - "\n" - " vec4 c = texture2DRect(Tex, TexCoord.xy );\n" - "\n" - " float sel = 0.0;\n" - " if(channel == 0){ // luminance\n" - " sel = 0.299*c.r + 0.587*c.g +0.114*c.b;\n" - " }else if(channel == 1){ // red\n" - " sel = c.r;\n" - " }else if(channel == 2){ //green\n" - " sel = c.g;\n" - " }else if(channel == 3){ // blue\n" - " sel = c.b;\n" - " }else if(channel == 4){ // alpha\n" - " sel = c.a;\n" - " }\n" - " clamp(sel, 0.0, 1.0);\n" - "// set new point position to the color intensity in [-1.0,1.0] interval\n" - "// as this is homogeneous coord. clip space\n" - " gl_Position.x =(2.0-4.0/257.0)*sel-1.0+2.0/257.0;\n" - " gl_Position.y = 0.0;\n" - " gl_Position.z = 0.0;\n" - "}\n" -; -const char *histogramRendering_frag = - "#extension GL_ARB_texture_rectangle : enable\n" - "uniform sampler2DRect HistogramTex;\n" - "uniform sampler2DRect MaximumRedTex;\n" - "uniform sampler2DRect MaximumGreenTex;\n" - "uniform sampler2DRect MaximumBlueTex;\n" - "uniform int channel;\n" - "void main()\n" - "{\n" - " if(channel == 0){\n" - " gl_FragColor =vec4(0.8,0.8,0.8,0.8);\n" - " }else if(channel == 1){\n" - " gl_FragColor =vec4(1.0,0.0,0.0,0.8);\n" - " }else if(channel == 2){\n" - " gl_FragColor =vec4(0.0,1.0,0.0,0.8);\n" - " }else if(channel == 3){\n" - " gl_FragColor =vec4(0.0,0.0,1.0,0.8);\n" - " }\n" - " \n" - "}\n" -; -const char *histogramRenderingVertex_vert = - "#extension GL_ARB_texture_rectangle : enable\n" - "uniform sampler2DRect HistogramTex;\n" - "uniform sampler2DRect MaximumRedTex;\n" - "uniform sampler2DRect MaximumGreenTex;\n" - "uniform sampler2DRect MaximumBlueTex;\n" - "uniform int channel;\n" - "attribute vec3 TexCoord;\n" - "void main()\n" - "{\n" - "\n" - " vec4 c = texture2DRect(HistogramTex, TexCoord.xy );\n" - " float bottom = TexCoord.z;\n" - " float maximum = 0.0;\n" - " float maximumRed = texture2DRect(MaximumRedTex,vec2(0.0,0.0)).r;\n" - " float maximumGreen = texture2DRect(MaximumGreenTex,vec2(0.0,0.0)).r;\n" - " float maximumBlue = texture2DRect(MaximumBlueTex,vec2(0.0,0.0)).r;\n" - " maximum = max(max(maximumRed,maximumGreen),maximumBlue);\n" - " if(maximum == 0.0){\n" - " maximum = 1000000.0;\n" - " }\n" - "// set new point position to the color intensity in [-1.0,1.0] interval\n" - "// as this is homogeneous coord. clip space\n" - " gl_Position.x =(2.0-4.0/257.0)*(TexCoord.x/255.0)-1.0+2.0/257.0;\n" - " if(bottom == 1.0){\n" - " gl_Position.y = -1.0;\n" - " }else{\n" - " float y = c.r/maximum;\n" - " gl_Position.y = 2.0*y-1.0;\n" - " }\n" - " gl_Position.z = 0.0;\n" - "}\n" -; -const char* minimal_vert = - "#extension GL_ARB_texture_rectangle : enable\n" - "gl_TexCoord[0]=gl_MultiTexCoord0;" - "gl_Position = ftransform();" +const char* blackFrag = R"( + uniform sampler2D Tex; + void main() + { + gl_FragColor = texture2D(Tex,gl_TexCoord[0].st); + }; +)"; + +const char *histogramComputation_frag = R"( + #extension GL_ARB_texture_rectangle : enable + uniform sampler2DRect Tex; + uniform int channel; + void main() + { + gl_FragColor = vec4(1.0,0.0,0.0,1.0); + } +)"; + +const char *histogramComputationVertex_vert = R"( + #extension GL_ARB_texture_rectangle : enable + uniform sampler2DRect Tex; + uniform int channel; + attribute vec2 TexCoord; + void main() + { + + vec4 c = texture2DRect(Tex, TexCoord.xy ); + + float sel = 0.0; + if(channel == 0){ // luminance + sel = 0.299*c.r + 0.587*c.g +0.114*c.b; + }else if(channel == 1){ // red + sel = c.r; + }else if(channel == 2){ //green + sel = c.g; + }else if(channel == 3){ // blue + sel = c.b; + }else if(channel == 4){ // alpha + sel = c.a; + } + clamp(sel, 0.0, 1.0); + // set new point position to the color intensity in [-1.0,1.0] interval + // as this is homogeneous coord. clip space + gl_Position.x =(2.0-4.0/257.0)*sel-1.0+2.0/257.0; + gl_Position.y = 0.0; + gl_Position.z = 0.0; + } +)"; + +const char *histogramRendering_frag = R"( + #extension GL_ARB_texture_rectangle : enable + uniform sampler2DRect HistogramTex; + uniform sampler2DRect MaximumRedTex; + uniform sampler2DRect MaximumGreenTex; + uniform sampler2DRect MaximumBlueTex; + uniform int channel; + void main() + { + if(channel == 0){ + gl_FragColor =vec4(0.8,0.8,0.8,0.8); + }else if(channel == 1){ + gl_FragColor =vec4(1.0,0.0,0.0,0.8); + }else if(channel == 2){ + gl_FragColor =vec4(0.0,1.0,0.0,0.8); + }else if(channel == 3){ + gl_FragColor =vec4(0.0,0.0,1.0,0.8); + } + + } +)"; + +const char *histogramRenderingVertex_vert = R"( + #extension GL_ARB_texture_rectangle : enable + uniform sampler2DRect HistogramTex; + uniform sampler2DRect MaximumRedTex; + uniform sampler2DRect MaximumGreenTex; + uniform sampler2DRect MaximumBlueTex; + uniform int channel; + attribute vec3 TexCoord; + void main() + { + + vec4 c = texture2DRect(HistogramTex, TexCoord.xy ); + float bottom = TexCoord.z; + float maximum = 0.0; + float maximumRed = texture2DRect(MaximumRedTex,vec2(0.0,0.0)).r; + float maximumGreen = texture2DRect(MaximumGreenTex,vec2(0.0,0.0)).r; + float maximumBlue = texture2DRect(MaximumBlueTex,vec2(0.0,0.0)).r; + maximum = max(max(maximumRed,maximumGreen),maximumBlue); + if(maximum == 0.0){ + maximum = 1000000.0; + } + // set new point position to the color intensity in [-1.0,1.0] interval + // as this is homogeneous coord. clip space + gl_Position.x =(2.0-4.0/257.0)*(TexCoord.x/255.0)-1.0+2.0/257.0; + if(bottom == 1.0){ + gl_Position.y = -1.0; + }else{ + float y = c.r/maximum; + gl_Position.y = 2.0*y-1.0; + } + gl_Position.z = 0.0; + } +)"; + +const char* minimal_vert = R"( + #extension GL_ARB_texture_rectangle : enable + gl_TexCoord[0]=gl_MultiTexCoord0; + gl_Position = ftransform(); ; const char *histogramMaximum_frag = - "#extension GL_ARB_texture_rectangle : enable\n" - "uniform sampler2DRect Tex;\n" - "void main()\n" - "{\n" - " vec4 a,b,c,d;\n" - " vec2 texCoord = gl_TexCoord[0].st;\n" - " texCoord.s = (texCoord.s-0.5) * 4.0 + 0.5;\n" - " a = texture2DRect(Tex,texCoord.st);\n" - " vec2 texCoord1,texCoord2,texCoord3;\n" - " texCoord1 = texCoord.st + vec2(1.0,0.0);\n" - " texCoord2 = texCoord.st + vec2(2.0,0.0);\n" - " texCoord3 = texCoord.st + vec2(3.0,0.0);\n" - " if(texCoord1.s <= 256.0){\n" - " b = texture2DRect(Tex,texCoord1);\n" - " }else{\n" - " b = a;\n" - " }\n" - " if(texCoord2.s <= 256.0){\n" - " c = texture2DRect(Tex,texCoord2);\n" - " }else{\n" - " c = a;\n" - " }\n" - " if(texCoord3.s <= 256.0){\n" - " d = texture2DRect(Tex,texCoord3);\n" - " }else{\n" - " d = a;\n" - " }\n" - " gl_FragColor = vec4(max(max(a.r,b.r),max(c.r,d.r)),0.0,0.0,1.0);\n" - "}\n" -; + #extension GL_ARB_texture_rectangle : enable + uniform sampler2DRect Tex; + void main() + { + vec4 a,b,c,d; + vec2 texCoord = gl_TexCoord[0].st; + texCoord.s = (texCoord.s-0.5) * 4.0 + 0.5; + a = texture2DRect(Tex,texCoord.st); + vec2 texCoord1,texCoord2,texCoord3; + texCoord1 = texCoord.st + vec2(1.0,0.0); + texCoord2 = texCoord.st + vec2(2.0,0.0); + texCoord3 = texCoord.st + vec2(3.0,0.0); + if(texCoord1.s <= 256.0){ + b = texture2DRect(Tex,texCoord1); + }else{ + b = a; + } + if(texCoord2.s <= 256.0){ + c = texture2DRect(Tex,texCoord2); + }else{ + c = a; + } + if(texCoord3.s <= 256.0){ + d = texture2DRect(Tex,texCoord3); + }else{ + d = a; + } + gl_FragColor = vec4(max(max(a.r,b.r),max(c.r,d.r)),0.0,0.0,1.0); + } +)"; + NATRON_NAMESPACE_EXIT diff --git a/Gui/Shaders.h b/Gui/Shaders.h index 7d8835d1e6..a3575b7bad 100644 --- a/Gui/Shaders.h +++ b/Gui/Shaders.h @@ -32,6 +32,7 @@ NATRON_NAMESPACE_ENTER extern const char* fragRGB; extern const char* vertRGB; +extern const char* fragDither; /*There's a black texture used for when the user disconnect the viewer It's not just a shader,because we still need coordinates feedback. diff --git a/Gui/ViewerGL.cpp b/Gui/ViewerGL.cpp index eeb97bf44e..be89fe1ce9 100644 --- a/Gui/ViewerGL.cpp +++ b/Gui/ViewerGL.cpp @@ -1720,6 +1720,14 @@ ViewerGL::setLut(int lut) _imp->displayingImageLut = (ViewerColorSpaceEnum)lut; } +void +ViewerGL::setDither(bool dither) +{ + // always running in the main thread + assert( qApp && qApp->thread() == QThread::currentThread() ); + _imp->enableDisplayDither = dither; +} + #define QMouseEventLocalPos(e) ( e->localPos() ) void diff --git a/Gui/ViewerGL.h b/Gui/ViewerGL.h index 631fe88bf8..5b11058506 100644 --- a/Gui/ViewerGL.h +++ b/Gui/ViewerGL.h @@ -394,6 +394,8 @@ public Q_SLOTS: void setLut(int lut); + void setDither(bool dither); + bool isWipeHandleVisible() const; void setZoomOrPannedSinceLastFit(bool enabled); diff --git a/Gui/ViewerGLPrivate.cpp b/Gui/ViewerGLPrivate.cpp index 957837e3de..159d501256 100644 --- a/Gui/ViewerGLPrivate.cpp +++ b/Gui/ViewerGLPrivate.cpp @@ -80,6 +80,7 @@ ViewerGL::Implementation::Implementation(ViewerGL* this_, , zoomOrPannedSinceLastFit(false) , oldClick() , displayingImageLut(eViewerColorSpaceSRGB) + , enableDisplayDither(false) , ms(eMouseStateUndefined) , hs(eHoverStateNothing) , textRenderingColor(200, 200, 200, 255) @@ -856,6 +857,7 @@ ViewerGL::Implementation::activateShaderRGB(int texIndex) shaderRGB->setUniformValue("lut", (GLint)displayingImageLut); float gamma = displayTextures[texIndex].gamma; shaderRGB->setUniformValue("gamma", gamma); + shaderRGB->setUniformValue("dither", (GLint)enableDisplayDither); } bool diff --git a/Gui/ViewerGLPrivate.h b/Gui/ViewerGLPrivate.h index c3d66782d8..dafc7deebe 100644 --- a/Gui/ViewerGLPrivate.h +++ b/Gui/ViewerGLPrivate.h @@ -166,6 +166,7 @@ struct ViewerGL::Implementation bool zoomOrPannedSinceLastFit; //< true if the user zoomed or panned the image since the last call to fitToRoD QPoint oldClick; ViewerColorSpaceEnum displayingImageLut; + bool enableDisplayDither; MouseStateEnum ms; /*!< Holds the mouse state*/ HoverStateEnum hs; const QColor textRenderingColor; diff --git a/Gui/ViewerTab.cpp b/Gui/ViewerTab.cpp index 92853dcf54..bffc6d77fd 100644 --- a/Gui/ViewerTab.cpp +++ b/Gui/ViewerTab.cpp @@ -524,6 +524,24 @@ ViewerTab::ViewerTab(const std::list & existingNodesContext, QObject::connect( _imp->checkerboardButton, SIGNAL(clicked(bool)), this, SLOT(onCheckerboardButtonClicked()) ); _imp->secondRowLayout->addWidget(_imp->checkerboardButton); + QPixmap ditheringEnabled, ditheringDisabled; + appPTR->getIcon(NATRON_PIXMAP_VIEWER_DITHER_ENABLED, pixmapIconSize, &ditheringEnabled); + appPTR->getIcon(NATRON_PIXMAP_VIEWER_DITHER_DISABLED, pixmapIconSize, &ditheringDisabled); + QIcon icDthr; + icDthr.addPixmap(ditheringEnabled, QIcon::Normal, QIcon::On); + icDthr.addPixmap(ditheringDisabled, QIcon::Normal, QIcon::Off); + _imp->ditherButton = new Button(icDthr, QString(), _imp->secondSettingsRow); + _imp->ditherButton->setFocusPolicy(Qt::NoFocus); + _imp->ditherButton->setCheckable(true); + _imp->ditherButton->setChecked(false); + _imp->ditherButton->setDown(false); + _imp->ditherButton->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("If checked, the viewer draws a checkerboard under input A instead of black (disabled under the wipe area and in stack modes)."), NATRON_NAMESPACE::WhiteSpaceNormal) ); + _imp->ditherButton->setFixedSize(buttonSize); + _imp->ditherButton->setIconSize(buttonIconSize); + QObject::connect( _imp->ditherButton, SIGNAL(clicked(bool)), this, SLOT(onDitherButtonClicked()) ); + _imp->secondRowLayout->addWidget(_imp->ditherButton); + + _imp->viewsComboBox = new ComboBox(_imp->secondSettingsRow); _imp->viewsComboBox->setToolTip( QString::fromUtf8("

") + tr("Active view:") + QString::fromUtf8("

") + tr( "Tells the viewer what view should be displayed.") ); diff --git a/Gui/ViewerTab.h b/Gui/ViewerTab.h index c94f7f3c83..adcb63b9f8 100644 --- a/Gui/ViewerTab.h +++ b/Gui/ViewerTab.h @@ -396,6 +396,7 @@ public Q_SLOTS: void hideAllToolbars(); void onCheckerboardButtonClicked(); + void onDitherButtonClicked(); void onPickerButtonClicked(bool); diff --git a/Gui/ViewerTab40.cpp b/Gui/ViewerTab40.cpp index 76529f87b8..64dbb14bc1 100644 --- a/Gui/ViewerTab40.cpp +++ b/Gui/ViewerTab40.cpp @@ -675,6 +675,15 @@ ViewerTab::onCheckerboardButtonClicked() _imp->viewer->redraw(); } +void +ViewerTab::onDitherButtonClicked() +{ + _imp->ditherEnabled = !_imp->ditherEnabled; + _imp->ditherButton->setDown(_imp->ditherEnabled); + _imp->viewer->setDither(_imp->ditherEnabled); + _imp->viewer->redraw(); +} + bool ViewerTab::isCheckerboardEnabled() const { diff --git a/Gui/ViewerTabPrivate.cpp b/Gui/ViewerTabPrivate.cpp index a99997976d..caa27eca63 100644 --- a/Gui/ViewerTabPrivate.cpp +++ b/Gui/ViewerTabPrivate.cpp @@ -97,6 +97,7 @@ ViewerTabPrivate::ViewerTabPrivate(ViewerTab* publicInterface, , gammaSlider(NULL) , viewerColorSpace(NULL) , checkerboardButton(NULL) + , ditherButton(NULL) , pickerButton(NULL) , viewsComboBox(NULL) , currentViewIndex(0) diff --git a/Gui/ViewerTabPrivate.h b/Gui/ViewerTabPrivate.h index c2a0df662b..402d31c9fd 100644 --- a/Gui/ViewerTabPrivate.h +++ b/Gui/ViewerTabPrivate.h @@ -115,6 +115,7 @@ struct ViewerTabPrivate ScaleSliderQWidget* gammaSlider; ComboBox* viewerColorSpace; Button* checkerboardButton; + Button* ditherButton; Button* pickerButton; ComboBox* viewsComboBox; ViewIdx currentViewIndex; @@ -192,6 +193,7 @@ struct ViewerTabPrivate bool isFileDialogViewer; mutable QMutex checkerboardMutex; bool checkerboardEnabled; + bool ditherEnabled; mutable QMutex fpsMutex; double fps; diff --git a/Renderer/CMakeLists.txt b/Renderer/CMakeLists.txt index b54e1f254c..0b29c2d848 100644 --- a/Renderer/CMakeLists.txt +++ b/Renderer/CMakeLists.txt @@ -18,7 +18,7 @@ # ***** END LICENSE BLOCK ***** set(NatronRenderer_SOURCES NatronRenderer_main.cpp) -if(WINDOWS) +if(WIN32) list(APPEND NatronRenderer_SOURCES ../Natron.rc) endif() add_executable(NatronRenderer ${NatronRenderer_SOURCES}) diff --git a/libs/gflags/CMakeLists.txt b/libs/gflags/CMakeLists.txt index 01397809aa..0bc3f2af5c 100644 --- a/libs/gflags/CMakeLists.txt +++ b/libs/gflags/CMakeLists.txt @@ -30,7 +30,7 @@ set(gflags_SOURCES src/gflags_completions.cc src/gflags_reporting.cc ) -if(WINDOWS) +if(WIN32) set(gflags_HEADERS ${gflags_HEADERS} src/windows_port.h) set(gflags_SOURCES ${gflags_SOURCES} src/windows_port.cc) endif() diff --git a/tools/utils/sourceList.py b/tools/utils/sourceList.py index 13d236f4d9..b1e5871026 100644 --- a/tools/utils/sourceList.py +++ b/tools/utils/sourceList.py @@ -15,7 +15,7 @@ def list_typesystem_cpp_sources(typesystem, out): sources = [f"{package.lower()}_module_wrapper.cpp"] sources.extend([f"{typename.lower()}_wrapper.cpp" for typename in types]) - return [os.path.normpath(os.path.join(out, package, f)) for f in sources] + return [os.path.normpath(os.path.join(out, package, f)).replace("\\", "/") for f in sources] if __name__ == "__main__":