Skip to content

Commit 410dae8

Browse files
SG-37377: Add Compare to Live Review (#738)
### [SG-37377](https://jira.autodesk.com/browse/SG-37377): Add Compare to Live Review ### Summarize your change. - [X] Add Compare OTIO schema and hook - [X] Add Opacity Compare mode in IPGraph and in OTIO compare hook - [X] Add Wipe (angular mask) mode in IPGraph and in OTIO compare hook - [X] Add Reverse Wipe shader to handle swapping versions - [X] Update requirements.txt to use the main branch of the OTIO Github repo to get the latest fixes for OTIO V2d before the next release is available - [X] `read_otio_string` was removed since the parsing of the OTIO Timeline is now down directly in the Live Review plugin - [X] Handle OTIO GeneratorReference to use clips with plain coloured background in OTIO tests ### Describe the reason for the change. In the web app, users can use four different compare modes when they are analyzing two versions. Since some of those compare modes were not, or only partially, present in RV, these PR contains all the changes required to add them. Opacity and Compare implementations are based on what is in [Create](https://git.autodesk.com/media-and-entertainment/shotgun-rv/pull/193). Note that Side by Side is entirely in the Live Review plugin in [this PR](https://git.autodesk.com/media-and-entertainment/rv/pull/342). The difference mode will need to be added in a following PR since some investigations need to be done to identify why the web app and RV have such different ways of implementing this mode. ### Describe what you have tested and on which operating system. The changes were tested on macOS during a Live Session between RV and the web app on [https://sg-create-prod.shotgunstudio.com/](https://sg-create-prod.shotgunstudio.com/). --------- Signed-off-by: Éloïse Brosseau <eloise.brosseau@autodesk.com>
1 parent 65133b3 commit 410dae8

22 files changed

+1721
-1089
lines changed

.clang-tidy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Checks: >
1414
-modernize-use-trailing-return-type,
1515
performance-*,
1616
readability-*,
17+
-readability-uppercase-literal-suffix,
1718
WarningsAsErrors: ''
1819
FormatStyle: 'file'
1920
...

src/build/requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
pip # License: MIT License (MIT)
44
setuptools # License: MIT License
5-
OpenTimelineIO==0.16 # License: Other/Proprietary License (Modified Apache 2.0 License)
5+
# We need to use the main branch of the OTIO Github repo since the latest release available as a Pypi package is missing some features we need for Live Review
6+
git+https://github.com/AcademySoftwareFoundation/OpenTimelineIO@main#egg=OpenTimelineIO # License: Other/Proprietary License (Modified Apache 2.0 License)
67
PyOpenGL # License: BSD License (BSD)
78
# PyOpenGL_accelerate as issue with native arm64 build on MacOS.
89
# Use PyOpenGL_accelerate only on x86_64 platform.

src/lib/ip/IPBaseNodes/IPBaseNodes/SequenceIPNode.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,13 @@ namespace IPCore
144144
IntProperty* m_outputSize;
145145
IntProperty* m_interactiveSize;
146146
StringProperty* m_inputsBlendingModes;
147+
FloatProperty* m_inputsOpacities;
147148
IntProperty* m_supportReversedOrderBlending;
149+
FloatProperty* m_inputsAngularMaskPivotX;
150+
FloatProperty* m_inputsAngularMaskPivotY;
151+
FloatProperty* m_inputsAngularMaskAngleInRadians;
152+
IntProperty* m_inputsAngularMaskActive;
153+
IntProperty* m_inputsReverseAngularMask;
148154

149155
/// this signal is called before all state change
150156
VoidSignal m_changingSignal;

src/lib/ip/IPBaseNodes/SequenceIPNode.cpp

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <IPCore/IPGraph.h>
1414
#include <IPCore/ShaderUtil.h>
1515
#include <IPCore/GroupIPNode.h>
16+
#include <IPCore/ShaderCommon.h>
17+
#include <TwkMath/Vec2.h>
1618
#include <TwkFB/FrameBuffer.h>
1719
#include <TwkFB/Operations.h>
1820
#include <iostream>
@@ -85,9 +87,30 @@ namespace IPCore
8587
// just like any other per-input EDL information.
8688
m_inputsBlendingModes = declareProperty<StringProperty>(
8789
"composite.inputBlendModes", "", 0, false);
88-
// since it is per input, make sure the property contains is emptied at
89-
// creation time
90+
91+
m_inputsOpacities = declareProperty<FloatProperty>(
92+
"composite.inputOpacities", 1.0f, nullptr, false);
93+
94+
m_inputsAngularMaskPivotX = declareProperty<FloatProperty>(
95+
"composite.inputAngularMaskPivotX", 0.0f, nullptr, false);
96+
m_inputsAngularMaskPivotY = declareProperty<FloatProperty>(
97+
"composite.inputAngularMaskPivotY", 0.0f, nullptr, false);
98+
m_inputsAngularMaskAngleInRadians = declareProperty<FloatProperty>(
99+
"composite.inputAngularMaskAngleInRadians", 0.0f, nullptr, false);
100+
m_inputsAngularMaskActive =
101+
declareProperty<IntProperty>("composite.inputAngularMaskActive", 1);
102+
m_inputsReverseAngularMask =
103+
declareProperty<IntProperty>("composite.swapAngularMaskInput", 1);
104+
105+
// since they are per input, make sure the property containers are
106+
// emptied at creation time
90107
m_inputsBlendingModes->erase(0, 1);
108+
m_inputsOpacities->erase(0, 1);
109+
m_inputsAngularMaskPivotX->erase(0, 1);
110+
m_inputsAngularMaskPivotY->erase(0, 1);
111+
m_inputsAngularMaskAngleInRadians->erase(0, 1);
112+
m_inputsAngularMaskActive->erase(0, 1);
113+
m_inputsReverseAngularMask->erase(0, 1);
91114

92115
// By default, the output of this node support reverse-order blending.
93116
// this is mainly kept for backward compatibility reason.
@@ -370,6 +393,34 @@ namespace IPCore
370393

371394
// Shader::installAdaptiveBoxResizeRecursive(root);
372395

396+
// If we have per-input opacities, now is the time to use them
397+
if (source >= 0 && source < m_inputsOpacities->size()
398+
&& child->shaderExpr != nullptr)
399+
{
400+
child->shaderExpr = Shader::newOpacity(
401+
child, child->shaderExpr, (*m_inputsOpacities)[source]);
402+
}
403+
404+
const bool isSourceValid =
405+
source >= 0 && source < m_inputsAngularMaskPivotX->size()
406+
&& source < m_inputsAngularMaskPivotY->size()
407+
&& source < m_inputsAngularMaskAngleInRadians->size()
408+
&& source < m_inputsAngularMaskActive->size()
409+
&& source < m_inputsReverseAngularMask->size();
410+
411+
if (isSourceValid && ((*m_inputsAngularMaskActive)[source] != 0))
412+
{
413+
414+
const float pivotX = (*m_inputsAngularMaskPivotX)[source];
415+
const float pivotY = (*m_inputsAngularMaskPivotY)[source];
416+
const float angleInRadians =
417+
(*m_inputsAngularMaskAngleInRadians)[source];
418+
419+
child->shaderExpr = Shader::newAngularMask(
420+
child, child->shaderExpr, Vec2f(pivotX, pivotY), angleInRadians,
421+
(*m_inputsReverseAngularMask)[source] != 0);
422+
}
423+
373424
root->appendChild(child);
374425

375426
if (m_clipCaching && context.thread == CacheEvalThread

src/lib/ip/IPCore/CMakeLists.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ SET(_shaders
126126
StereoChecker
127127
StereoAnaglyph
128128
StereoLumAnaglyph
129+
AngularMask
130+
ReverseAngularMask
131+
Opacity
129132
Over2
130133
Over3
131134
Over4
@@ -259,9 +262,7 @@ ELSEIF(RV_TARGET_DARWIN)
259262
PUBLIC OpenCL::OpenCL
260263
)
261264
ELSE()
262-
TARGET_LINK_LIBRARIES(
263-
${_target}
264-
)
265+
TARGET_LINK_LIBRARIES(${_target})
265266
ENDIF()
266267

267268
RV_STAGE(TYPE "LIBRARY" TARGET ${_target})

src/lib/ip/IPCore/IPCore/ShaderCommon.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
//
88
#ifndef __IPCore__ShaderCommon__h__
99
#define __IPCore__ShaderCommon__h__
10-
#include <iostream>
1110
#include <IPCore/ShaderExpression.h>
1211
#include <IPCore/IPImage.h>
1312
#include <TwkMath/Mat44.h>
13+
#include <TwkMath/Vec2.h>
1414

1515
namespace IPCore
1616
{
@@ -252,6 +252,14 @@ namespace IPCore
252252
const TwkMath::Vec2f& center, const TwkMath::Vec2f& f,
253253
const TwkMath::Vec2f& cropRatio);
254254

255+
Expression* newOpacity(const IPImage* image, Expression* expr,
256+
float opacity);
257+
258+
Expression* newAngularMask(const IPImage* image, Expression* expr,
259+
const TwkMath::Vec2f& pivot,
260+
float angleInRadians,
261+
bool isReverseAngularMask);
262+
255263
//
256264
// ICC profile shaders
257265
//

src/lib/ip/IPCore/IPCore/ShaderFunction.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ namespace IPCore
210210

211211
bool usesOutputST() const { return m_usesOutputST; }
212212

213+
bool usesFragmentPosition() const { return m_usesFragmentPosition; }
214+
213215
void releaseCompiledState() const;
214216
const Symbol::Type returnType() const;
215217

@@ -280,8 +282,9 @@ namespace IPCore
280282
std::string m_hashString;
281283
ResourceUsage m_resourceUsage;
282284
bool m_inline;
283-
bool m_usesOutputSize;
284-
bool m_usesOutputST;
285+
bool m_usesOutputSize{false};
286+
bool m_usesOutputST{false};
287+
bool m_usesFragmentPosition{false};
285288
bool m_usesSampling;
286289

287290
friend class Program;

src/lib/ip/IPCore/IPCore/ShaderProgram.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ namespace IPCore
188188
// output uniform variables needed in case of uncropped images
189189
void outputUncropUniforms(std::ostream&, const Expression*);
190190

191-
private:
192191
Expression* m_expr;
193192
GraphIDSet m_outputSTSet;
194193
GraphIDSet m_outputSizeSet;
@@ -203,8 +202,9 @@ namespace IPCore
203202
size_t m_totalST;
204203
Function* m_main;
205204
std::string m_vertexCode;
206-
bool m_needOutputSize;
207-
bool m_needOutputST;
205+
bool m_needOutputSize{false};
206+
bool m_needOutputST{false};
207+
bool m_needFragmentPosition{false};
208208
};
209209

210210
class ProgramCache

src/lib/ip/IPCore/IPCore/ShaderSymbol.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ namespace IPCore
145145
Coord2DRectType,
146146
InputImageType,
147147
OutputImageType,
148+
FragmentPositionType,
148149
};
149150

150151
Symbol(Qualifier c, const std::string& name, Type t,
@@ -189,6 +190,11 @@ namespace IPCore
189190

190191
bool isInputImage() const { return m_type == InputImageType; }
191192

193+
[[nodiscard]] bool isFragmentPositon() const
194+
{
195+
return m_type == FragmentPositionType;
196+
}
197+
192198
bool operator==(const Symbol& s) const
193199
{
194200
return s.m_name == m_name && s.m_qualifier == m_qualifier

src/lib/ip/IPCore/ImageRenderer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2705,8 +2705,8 @@ namespace IPCore
27052705
case IPImage::Dissolve:
27062706
glEnable(GL_BLEND);
27072707
glBlendEquation(GL_FUNC_ADD);
2708-
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE,
2709-
GL_ONE_MINUS_SRC_ALPHA);
2708+
// src is assumed premultiplied
2709+
glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
27102710
break;
27112711
case IPImage::Add:
27122712
glEnable(GL_BLEND);

src/lib/ip/IPCore/ShaderCommon.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@
77
//
88
#include <IPCore/ShaderCommon.h>
99
#include <IPCore/ShaderState.h>
10+
#include <IPCore/ShaderExpression.h>
11+
#include <IPCore/ShaderFunction.h>
12+
#include <IPCore/ShaderSymbol.h>
13+
#include <IPCore/IPImage.h>
1014
#include <TwkGLF/GL.h>
1115
#include <TwkFB/Operations.h>
1216
#include <TwkMath/MatrixColor.h>
17+
#include <TwkMath/Vec2.h>
1318
#include <boost/thread/mutex.hpp>
1419
#include <boost/functional/hash.hpp>
1520

@@ -115,6 +120,9 @@ extern const char* StereoScanline_glsl;
115120
extern const char* StereoChecker_glsl;
116121
extern const char* StereoAnaglyph_glsl;
117122
extern const char* StereoLumAnaglyph_glsl;
123+
extern const char* AngularMask_glsl;
124+
extern const char* ReverseAngularMask_glsl;
125+
extern const char* Opacity_glsl;
118126
extern const char* Over2_glsl;
119127
extern const char* Over3_glsl;
120128
extern const char* Over4_glsl;
@@ -314,6 +322,9 @@ namespace IPCore
314322
static Function* Shader_StereoChecker = 0;
315323
static Function* Shader_StereoAnaglyph = 0;
316324
static Function* Shader_StereoLumAnaglyph = 0;
325+
static Function* Shader_AngularMask = 0;
326+
static Function* Shader_ReverseAngularMask = 0;
327+
static Function* Shader_Opacity = 0;
317328
static Function* Shader_Over = 0;
318329
static Function* Shader_Add = 0;
319330
static Function* Shader_Difference = 0;
@@ -2587,6 +2598,40 @@ namespace IPCore
25872598
return Shader_LensWarp3DE4AnamorphicDegree6;
25882599
}
25892600

2601+
Function* Opacity()
2602+
{
2603+
if (Shader_Opacity == nullptr)
2604+
{
2605+
Shader_Opacity = new Shader::Function("Opacity", Opacity_glsl,
2606+
Shader::Function::Color);
2607+
}
2608+
2609+
return Shader_Opacity;
2610+
}
2611+
2612+
Function* AngularMask()
2613+
{
2614+
if (Shader_AngularMask == nullptr)
2615+
{
2616+
Shader_AngularMask = new Shader::Function(
2617+
"AngularMask", AngularMask_glsl, Shader::Function::Filter);
2618+
}
2619+
2620+
return Shader_AngularMask;
2621+
}
2622+
2623+
Function* ReverseAngularMask()
2624+
{
2625+
if (Shader_ReverseAngularMask == nullptr)
2626+
{
2627+
Shader_ReverseAngularMask = new Shader::Function(
2628+
"ReverseAngularMask", ReverseAngularMask_glsl,
2629+
Shader::Function::Filter);
2630+
}
2631+
2632+
return Shader_ReverseAngularMask;
2633+
}
2634+
25902635
//--
25912636

25922637
Expression* newDither(const IPImage* image, Expression* A,
@@ -5626,6 +5671,41 @@ namespace IPCore
56265671
return new Expression(F, args, image);
56275672
}
56285673

5674+
Expression* newOpacity(const IPImage* image, Expression* expr,
5675+
const float opacity)
5676+
{
5677+
const Function* F = Opacity();
5678+
ArgumentVector args(F->parameters().size());
5679+
size_t i = 0;
5680+
args[i] = new BoundExpression(F->parameters()[i], expr);
5681+
i++;
5682+
args[i] = new BoundFloat(F->parameters()[i], opacity);
5683+
i++;
5684+
5685+
return new Expression(F, args, image);
5686+
}
5687+
5688+
Expression* newAngularMask(const IPImage* image, Expression* expr,
5689+
const TwkMath::Vec2f& pivot,
5690+
const float angleInRadians,
5691+
bool isReverseAngularMask)
5692+
{
5693+
const Function* F =
5694+
isReverseAngularMask ? ReverseAngularMask() : AngularMask();
5695+
ArgumentVector args(F->parameters().size());
5696+
size_t i = 0;
5697+
args[i] = new BoundExpression(F->parameters()[i], expr);
5698+
i++;
5699+
args[i] = new BoundVec2f(F->parameters()[i], pivot);
5700+
i++;
5701+
args[i] = new BoundFloat(F->parameters()[i], angleInRadians);
5702+
i++;
5703+
args[i] = new BoundVec2f(F->parameters()[i], Vec2f(0.0f));
5704+
i++;
5705+
5706+
return new Expression(F, args, image);
5707+
}
5708+
56295709
//--
56305710

56315711
Expression* sourceAssemblyShader(IPImage* image, bool bgra, bool force)

0 commit comments

Comments
 (0)