# -*- coding: utf-8 -*-
# DO NOT EDIT THIS FILE
# This file was automatically generated by Natron PyPlug exporter version 10.

# Hand-written code should be added in a separate file named PM_Card3DExt.py
# See http://natron.readthedocs.org/en/master/groups.html#adding-hand-written-code-callbacks-etc
# Note that Viewers are never exported

import NatronEngine
import sys

# Try to import the extensions file where callbacks and hand-written code should be located.
try:
    from PM_Card3DExt import *
except ImportError:
    pass

def getPluginID():
    return "natron.community.plugins.PM_Card3D"

def getLabel():
    return "PM_Card3D"

def getVersion():
    return 1

def getIconPath():
    return "PM_Card3D.png"

def getGrouping():
    return "Community/Transform"

def getPluginDescription():
    return "Create a 3D plane seen from the camera defined using the PM_Camera plugin.\n\nCHAN file :\na chan file can be provided if you need to export the plane animation.\nchan must have XYZ rotation order (no other rotation mode provided for now)\n\nZbuffer :\nAs long as the RGBA channels the pyplug generate a Z buffer. Look at the Zbuf.B channel .\nZbuf.R and Zbuf.G : UV coordinates to map the input image to.\nZbuf.B : the Z buffer if you want the plane to be integrate into another image using a Zcombine node.\nZbuf.A : the alpha of the image.\n"

def createInstance(app,group):
    # Create all nodes in the group

    # Create the parameters of the group node the same way we did for all internal nodes
    lastNode = group
    param = lastNode.getParam("onParamChanged")
    if param is not None:
        param.setValue("PM_Card3D.plane_read_chan")
        del param


    # Create the user parameters
    lastNode.Controls = lastNode.createPageParam("Controls", "Controls")
    param = lastNode.createSeparatorParam("sepa", "chan importer")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepa = param
    del param

    param = lastNode.createFileParam("chan", "chan file")
    param.setSequenceEnabled(False)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("Path of an optional .chan file to transform the plane.")
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.chan = param
    del param

    param = lastNode.createButtonParam("import_chan_file", "Import .chan file")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(False)
    param.setEvaluateOnChange(False)
    lastNode.import_chan_file = param
    del param

    param = lastNode.createSeparatorParam("sep", "image mapping")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sep = param
    del param

    param = lastNode.createChoiceParam("STMap1filter", "Filter")
    param.setDefaultValue(2)
    param.restoreDefaultValue()

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.set(0)
    lastNode.STMap1filter = param
    del param

    param = lastNode.createBooleanParam("backface", "backface culling")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.backface = param
    del param

    param = lastNode.createDouble2DParam("STMap1uvOffset", "UV Offset")
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(1, 1)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvOffset = param
    del param

    param = lastNode.createDouble2DParam("STMap1uvScale", "UV Scale")
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(100, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(100, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvScale = param
    del param

    param = lastNode.createSeparatorParam("sepb", "Motion Blur")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepb = param
    del param

    param = lastNode.createIntParam("blur_sample", "Samples")
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(0, 0)
    param.restoreDefaultValue(0)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("motion blur is calculated by accumulation of various inter-frames.\n\nThis parameter set how many frames/samples to accumulate.\n\nMore sample = more calculation")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.blur_sample = param
    del param

    param = lastNode.createDoubleParam("TimeBlur1shutter", "Shutter")
    param.setMinimum(0, 0)
    param.setMaximum(2, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(2, 0)
    param.setDefaultValue(0.5, 0)
    param.restoreDefaultValue(0)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutter = param
    del param

    param = lastNode.createDoubleParam("TimeBlur1shutterCustomOffset", "Custom Offset")
    param.setMinimum(-1, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(-1, 0)
    param.setDisplayMaximum(1, 0)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutterCustomOffset = param
    del param

    param = lastNode.createSeparatorParam("sepc", "")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepc = param
    del param

    param = lastNode.createBooleanParam("Merge1enableMask_Mask", "Mask")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.Merge1enableMask_Mask = param
    del param

    param = lastNode.createChoiceParam("Merge1maskChannel_Mask", "")
    param.setDefaultValue(4)
    param.restoreDefaultValue()

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskChannel_Mask = param
    del param

    param = lastNode.createBooleanParam("Merge1maskInvert", "Invert Mask")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskInvert = param
    del param

    param = lastNode.createDoubleParam("Merge1mix", "Mix")
    param.setMinimum(0, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.Merge1mix = param
    del param

    lastNode.transforms = lastNode.createPageParam("transforms", "Transforms")
    param = lastNode.createSeparatorParam("sepe", "Location")

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepe = param
    del param

    param = lastNode.createDoubleParam("dlocx", "X")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("X location of the plane , if you use .chan import then you may want to use this to offset the plane")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocx = param
    del param

    param = lastNode.createDoubleParam("locx", "ChanX")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("X location of the Card in 3D space, if you\'ve imported a .chan file , then these value are animated.\nUse the other X transform to offset the plane")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locx = param
    del param

    param = lastNode.createDoubleParam("dlocy", "Y")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Y location of the plane , if you use .chan import then you may want to use this to offset the plane")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocy = param
    del param

    param = lastNode.createDoubleParam("locy", "Chan Y")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Y location of the Card in 3D space, if you\'ve imported a .chan file , then these value are animated.\nUse the other X transform to offset the plane")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locy = param
    del param

    param = lastNode.createDoubleParam("dlocz", "Z")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Z location of the plane , if you use .chan import then you may want to use this to offset the plane")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocz = param
    del param

    param = lastNode.createDoubleParam("locz", "Chan Z")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Z location of the Card in 3D space, if you\'ve imported a .chan file , then these value are animated.\nUse the other X transform to offset the plane")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    param.setValue(-10, 0)
    lastNode.locz = param
    del param

    param = lastNode.createSeparatorParam("sepd", "Rotation")

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepd = param
    del param

    param = lastNode.createDoubleParam("drotx", "X")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("X rotation of the Plane, if you use the .chan import you may want to use this to offset the plane")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotx = param
    del param

    param = lastNode.createDoubleParam("rotx", "ChanX")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("X Rotation of the Card in 3D space used with the .chan import")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotx = param
    del param

    param = lastNode.createDoubleParam("droty", "Y")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Y rotation of the plane")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.droty = param
    del param

    param = lastNode.createDoubleParam("roty", "ChanY")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Y Rotation of the Card in 3D space")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.roty = param
    del param

    param = lastNode.createDoubleParam("drotz", "Z")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotz = param
    del param

    param = lastNode.createDoubleParam("rotz", "ChanZ")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Z Rotation of the Card in 3D space used with the .chan import")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotz = param
    del param

    param = lastNode.createSeparatorParam("sepf", "Scale")

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepf = param
    del param

    param = lastNode.createDouble2DParam("scale", "X / Y")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setMinimum(-2147483648, 1)
    param.setMaximum(2147483647, 1)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(10, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Dimention of the Card in 3D space.\nBest practice is to use this one to set the aspect ratio of the card, and the uniform scale to get the card the final scale.")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.setValue(1.92, 0)
    param.setValue(1.08, 1)
    lastNode.scale = param
    del param

    param = lastNode.createDoubleParam("scale_u", "Uniform")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("this is an extra scaling factor to scale both X and Y,\nUse the first to set the X and Y ratio of the card, and this one to set the global scale\n")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.scale_u = param
    del param

    # Refresh the GUI with the newly created parameters
    lastNode.setPagesOrder(['Controls', 'transforms', 'Node'])
    lastNode.refreshUserParamsGUI()
    del lastNode

    # Start of node "_Plane"
    lastNode = app.createNode("net.sf.openfx.Shadertoy", 1, group)
    lastNode.setScriptName("_Plane")
    lastNode.setLabel(" Plane")
    lastNode.setPosition(558, 465)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    group_Plane = lastNode

    param = lastNode.getParam("paramValueInt1")
    if param is not None:
        param.setValue(7, 0)
        del param

    param = lastNode.getParam("paramValueVec31")
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(-10, 2)
        del param

    param = lastNode.getParam("paramValueVec32")
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param

    param = lastNode.getParam("paramValueVec23")
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        del param

    param = lastNode.getParam("paramValueVec33")
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param

    param = lastNode.getParam("paramValueVec34")
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param

    param = lastNode.getParam("paramValueVec35")
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        param.setValue(1, 2)
        del param

    param = lastNode.getParam("imageShaderPresetDir")
    if param is not None:
        param.setValue("")
        del param

    param = lastNode.getParam("imageShaderSource")
    if param is not None:
        param.setValue("uniform bool backface = false ;\nuniform vec3 pln_loc = vec3(0.0,0.,10.0);\nuniform vec3 pln_rot = vec3(0.0);\nuniform vec3 d_loc = vec3(0.0,0.,0.0);\nuniform vec3 d_rot = vec3(0.0);\n\n// scale X Y, and the last one is the uniform scale\nuniform vec3 pln_scl = vec3(1.0); // scale\n\n\nfloat M_PI = 3.14159265359 ;\nfloat kEpsilon = 1e-8;\n//float M_PI = 3.14159265358979323846264338327950288419;\n\n\nfloat deg2rad(float deg)\n { return deg * M_PI / 180.0; }\n\nmat4 mat3to4(mat3 m){\n\treturn mat4(\n\t\tm[0][0],m[0][1],m[0][2],0,\n\t\tm[1][0],m[1][1],m[1][2],0,\n\t\tm[2][0],m[2][1],m[2][2],0,\n\t\t0,0,0,1);}\nmat3 rotx(float x){\n\treturn mat3 (\n\t\t1,     0,      0,\n\t\t0, cos(x), sin(x),\n\t\t0,-sin(x), cos(x));}\nmat3 roty(float y){\n\treturn mat3 (\n\t\tcos(y), 0,-sin(y),\n\t\t    0,  1,     0,\n\t\tsin(y), 0, cos(y));}\nmat3 rotz(float z){\n\t\treturn mat3 (\n\t   cos(z),sin(z),0,\n\t\t-sin(z),cos(z),0,\n\t    \t 0,     0, 1);}\n\nbool rayTriangleIntersect( vec3 orig, vec3 dir, vec3 v0, vec3 v1, vec3 v2, inout float t, inout float u, inout float v)\n\t{\n\t\tbool res = true ;\n\t\tvec3 v0v1 =vec3( v1 - v0);\n\t\tvec3 v0v2 =vec3( v2 - v0);\n\t\tvec3 pvec =vec3( cross(dir,v0v2));\n\t\tfloat det = dot(v0v1,pvec);\n\n\t\tfloat invDet = 1 / det;\n\n\t\tvec3 tvec =vec3( orig - v0);\n\t\tu = dot(tvec,pvec) * invDet;\n\t\tif (u < 0 || u > 1) res=false ;\n\n\t\tvec3 qvec =vec3( cross(tvec,v0v1));\n\t\tv = dot(dir,qvec) * invDet;\n\t\tif (v < 0 || u + v > 1) res =false;\n\n\t\tif (backface == true){\n\t\t\tif (det < kEpsilon){ res = false;};\n\t\t};\n\n\t\tt = dot(v0v2,qvec) * invDet;\n\n\t\t// position in z (if the plane is below the camera)\n\t\tif (t < 0 ) res=false;\n\n\t\treturn res;\n\t}\nmat4 getcam(vec2 def){\n\tmat4 cm;\n\tcm[0]=texture2D( iChannel0, vec2(8/def.x,6/def.y));\n\tcm[1]=texture2D( iChannel0, vec2(24/def.x,6/def.y));\n\tcm[2]=texture2D( iChannel0, vec2(8/def.x,20/def.y));\n\tcm[3]=texture2D( iChannel0, vec2(24/def.x,20/def.y));\n\treturn cm;\n\t}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\t\tvec2 def = iChannelResolution[0].xy/iRenderScale.xy;\n\t\tmat4 cameraToWorld = getcam(def); // camera matrix\n\t\tvec4 cam = texture2D( iChannel0, vec2(8/def.x,34/def.y)); // fov , sensor_offset , shift.xy\n\t\tfloat Px = (2*(fragCoord.x / iResolution.x)-1) * cam.x * (iResolution.x / iResolution.y) ;\n\t\tfloat Py = (2*((fragCoord.y / iResolution.y)-0.5))* cam.x ;\n\t  vec3 rayOrigin=(cameraToWorld*vec4(0.0, 0., 0.,1)).xyz;\n    vec3 rayPWorld=(cameraToWorld*vec4(Px, Py, cam.y,1)).xyz;\n\t\tvec3 rayDirection = normalize(rayPWorld-rayOrigin);\n    vec3 ploc;\n    mat4 drot;\n\n    // PLANE vertex\n    vec3 v0=vec3(-1, -1,0);\n    vec3 v1=vec3( 1, -1, 0);\n    vec3 v2=vec3( -1, 1, 0);\n    vec3 v3=vec3( 1, 1, 0);\n\n    //Plane scale\n    v0.xy*=pln_scl.xy*pln_scl.z;\n    v1.xy*=pln_scl.xy*pln_scl.z;\n    v2.xy*=pln_scl.xy*pln_scl.z;\n    v3.xy*=pln_scl.xy*pln_scl.z;\n\n    //plane first transform (delta loc / rot) to avoid gimbal or rotational conflict\n    drot=mat3to4(rotx(deg2rad(-d_rot.x)) * roty(deg2rad(-d_rot.y)) * rotz(deg2rad(-d_rot.z)));\n    ploc=vec3(d_loc.x, d_loc.y, d_loc.z );\n    v0=(vec4(v0,1)*drot).xyz+ploc;\n    v1=(vec4(v1,1)*drot).xyz+ploc;\n    v2=(vec4(v2,1)*drot).xyz+ploc;\n    v3=(vec4(v3,1)*drot).xyz+ploc;\n\n\n\t\t// plane rotation matrix XYZ\n\t\tdrot=mat3to4(rotx(deg2rad(-pln_rot.x)) * roty(deg2rad(-pln_rot.y)) * rotz(deg2rad(-pln_rot.z)));\n\t\tploc=vec3(pln_loc.x, pln_loc.y, pln_loc.z );\n\t\tv0=(vec4(v0,1)*drot).xyz+ploc;\n\t\tv1=(vec4(v1,1)*drot).xyz+ploc;\n\t\tv2=(vec4(v2,1)*drot).xyz+ploc;\n\t\tv3=(vec4(v3,1)*drot).xyz+ploc;\n\n\t\t\tfloat t; float u; float v; vec4 res=vec4(0);\n\t\t\tres.b=100000000; // zbuffer\n\n\t\t\tif (rayTriangleIntersect(rayOrigin, rayDirection, v0, v2, v1, t, u, v)==true){\n\t\t\t\tres=vec4(v,1-u,t,1);\n\t\t\t}\n\n\t\t\tif (rayTriangleIntersect(rayOrigin, rayDirection, v3, v1, v2, t, u, v)==true){\n\t\t\t\tres=vec4(1-v,u,t,1);\n\t\t\t}\n\n\tfragColor=res.rgba;\n}\n")
        del param

    param = lastNode.getParam("inputEnable1")
    if param is not None:
        param.setValue(False)
        del param

    param = lastNode.getParam("inputEnable2")
    if param is not None:
        param.setValue(False)
        del param

    param = lastNode.getParam("inputEnable3")
    if param is not None:
        param.setValue(False)
        del param

    param = lastNode.getParam("NatronParamFormatChoice")
    if param is not None:
        param.set("PC_Video 640x480")
        del param

    param = lastNode.getParam("mouseParams")
    if param is not None:
        param.setValue(False)
        del param

    param = lastNode.getParam("paramCount")
    if param is not None:
        param.setValue(6, 0)
        del param

    param = lastNode.getParam("paramType0")
    if param is not None:
        param.set("bool")
        del param

    param = lastNode.getParam("paramName0")
    if param is not None:
        param.setValue("backface")
        del param

    param = lastNode.getParam("paramLabel0")
    if param is not None:
        param.setValue("backface")
        del param

    param = lastNode.getParam("paramType1")
    if param is not None:
        param.set("vec3")
        del param

    param = lastNode.getParam("paramName1")
    if param is not None:
        param.setValue("pln_loc")
        del param

    param = lastNode.getParam("paramLabel1")
    if param is not None:
        param.setValue("pln_loc")
        del param

    param = lastNode.getParam("paramDefaultVec31")
    if param is not None:
        param.setValue(10, 2)
        del param

    param = lastNode.getParam("paramType2")
    if param is not None:
        param.set("vec3")
        del param

    param = lastNode.getParam("paramName2")
    if param is not None:
        param.setValue("pln_rot")
        del param

    param = lastNode.getParam("paramLabel2")
    if param is not None:
        param.setValue("pln_rot")
        del param

    param = lastNode.getParam("paramType3")
    if param is not None:
        param.set("vec3")
        del param

    param = lastNode.getParam("paramName3")
    if param is not None:
        param.setValue("d_loc")
        del param

    param = lastNode.getParam("paramLabel3")
    if param is not None:
        param.setValue("d_loc")
        del param

    param = lastNode.getParam("paramType4")
    if param is not None:
        param.set("vec3")
        del param

    param = lastNode.getParam("paramName4")
    if param is not None:
        param.setValue("d_rot")
        del param

    param = lastNode.getParam("paramLabel4")
    if param is not None:
        param.setValue("d_rot")
        del param

    param = lastNode.getParam("paramType5")
    if param is not None:
        param.set("vec3")
        del param

    param = lastNode.getParam("paramName5")
    if param is not None:
        param.setValue("pln_scl")
        del param

    param = lastNode.getParam("paramLabel5")
    if param is not None:
        param.setValue("scale")
        del param

    param = lastNode.getParam("paramDefaultVec35")
    if param is not None:
        param.setValue(1, 0)
        param.setValue(1, 1)
        param.setValue(1, 2)
        del param

    param = lastNode.getParam("paramType6")
    if param is not None:
        param.set("float")
        del param

    param = lastNode.getParam("paramName6")
    if param is not None:
        param.setValue("sensor")
        del param

    param = lastNode.getParam("paramLabel6")
    if param is not None:
        param.setValue("sensor")
        del param

    del lastNode
    # End of node "_Plane"

    # Start of node "STMap1"
    lastNode = app.createNode("net.sf.openfx.STMap", 2, group)
    lastNode.setScriptName("STMap1")
    lastNode.setLabel("STMap1")
    lastNode.setPosition(966, 465)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.7, 0.3, 0.1)
    groupSTMap1 = lastNode

    param = lastNode.getParam("channelUChoice")
    if param is not None:
        param.setValue("UV.r")
        del param

    param = lastNode.getParam("channelVChoice")
    if param is not None:
        param.setValue("UV.g")
        del param

    param = lastNode.getParam("channelAChoice")
    if param is not None:
        param.setValue("UV.a")
        del param

    param = lastNode.getParam("wrapU")
    if param is not None:
        param.set("Repeat")
        del param

    param = lastNode.getParam("wrapV")
    if param is not None:
        param.set("Repeat")
        del param

    param = lastNode.getParam("filter")
    if param is not None:
        param.set("Impulse")
        del param

    del lastNode
    # End of node "STMap1"

    # Start of node "TimeBlur1"
    lastNode = app.createNode("net.sf.openfx.TimeBlur", 1, group)
    lastNode.setScriptName("TimeBlur1")
    lastNode.setLabel("TimeBlur1")
    lastNode.setPosition(978, 588)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.7, 0.65, 0.35)
    groupTimeBlur1 = lastNode

    param = lastNode.getParam("division")
    if param is not None:
        param.setValue(1, 0)
        del param

    param = lastNode.getParam("shutterOffset")
    if param is not None:
        param.set("Custom")
        del param

    param = lastNode.getParam("disableNode")
    if param is not None:
        param.setValue(True)
        del param

    del lastNode
    # End of node "TimeBlur1"

    # Start of node "Camera"
    lastNode = app.createNode("fr.inria.built-in.Input", 1, group)
    lastNode.setScriptName("Camera")
    lastNode.setLabel("Camera")
    lastNode.setPosition(546, 17)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupCamera = lastNode

    del lastNode
    # End of node "Camera"

    # Start of node "Output1"
    lastNode = app.createNode("fr.inria.built-in.Output", 1, group)
    lastNode.setLabel("Output1")
    lastNode.setPosition(546, 922)
    lastNode.setSize(104, 30)
    lastNode.setColor(0.7, 0.7, 0.7)
    groupOutput1 = lastNode

    del lastNode
    # End of node "Output1"

    # Start of node "Image"
    lastNode = app.createNode("fr.inria.built-in.Input", 1, group)
    lastNode.setScriptName("Image")
    lastNode.setLabel("Image")
    lastNode.setPosition(966, 24)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupImage = lastNode

    del lastNode
    # End of node "Image"

    # Start of node "Merge1"
    lastNode = app.createNode("net.sf.openfx.MergePlugin", 1, group)
    lastNode.setScriptName("Merge1")
    lastNode.setLabel("Merge1")
    lastNode.setPosition(969, 722)
    lastNode.setSize(104, 66)
    lastNode.setColor(0.3, 0.37, 0.776)
    groupMerge1 = lastNode

    param = lastNode.getParam("userTextArea")
    if param is not None:
        param.setValue("<Natron>(over)</Natron>")
        del param

    del lastNode
    # End of node "Merge1"

    # Start of node "Mask"
    lastNode = app.createNode("fr.inria.built-in.Input", 1, group)
    lastNode.setScriptName("Mask")
    lastNode.setLabel("Mask")
    lastNode.setPosition(1197, 730)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupMask = lastNode

    param = lastNode.getParam("optional")
    if param is not None:
        param.setValue(True)
        del param

    param = lastNode.getParam("isMask")
    if param is not None:
        param.setValue(True)
        del param

    del lastNode
    # End of node "Mask"

    # Start of node "Zbuffer"
    lastNode = app.createNode("net.sf.openfx.ShufflePlugin", 2, group)
    lastNode.setScriptName("Zbuffer")
    lastNode.setLabel("Zbuffer")
    lastNode.setPosition(546, 734)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.6, 0.24, 0.39)
    lastNode.addUserPlane("Zbuf", ["R","G","B","A"])
    groupZbuffer = lastNode

    param = lastNode.getParam("outputChannels")
    if param is not None:
        param.set("Zbuf")
        del param

    param = lastNode.getParam("outputChannelsChoice")
    if param is not None:
        param.setValue("Zbuf")
        del param

    param = lastNode.getParam("outputRChoice")
    if param is not None:
        param.setValue("B.r")
        del param

    param = lastNode.getParam("outputGChoice")
    if param is not None:
        param.setValue("B.g")
        del param

    param = lastNode.getParam("outputBChoice")
    if param is not None:
        param.setValue("B.b")
        del param

    param = lastNode.getParam("outputAChoice")
    if param is not None:
        param.setValue("B.a")
        del param

    del lastNode
    # End of node "Zbuffer"

    # Now that all nodes are created we can connect them together, restore expressions
    group_Plane.connectInput(0, groupCamera)
    groupSTMap1.connectInput(0, group_Plane)
    groupSTMap1.connectInput(1, groupImage)
    groupTimeBlur1.connectInput(0, groupSTMap1)
    groupOutput1.connectInput(0, groupZbuffer)
    groupMerge1.connectInput(1, groupTimeBlur1)
    groupMerge1.connectInput(2, groupMask)
    groupZbuffer.connectInput(0, group_Plane)
    groupZbuffer.connectInput(1, groupMerge1)

    param = group_Plane.getParam("paramValueBool0")
    group.getParam("backface").setAsAlias(param)
    del param
    param = group_Plane.getParam("paramValueVec31")
    param.setExpression("thisGroup.locx.get()", False, 0)
    param.setExpression("thisGroup.locy.get()", False, 1)
    param.setExpression("thisGroup.locz.get()", False, 2)
    del param
    param = group_Plane.getParam("paramValueVec32")
    param.setExpression("thisGroup.rotx.get()", False, 0)
    param.setExpression("thisGroup.roty.get()", False, 1)
    param.setExpression("thisGroup.rotz.get()", False, 2)
    del param
    param = group_Plane.getParam("paramValueVec23")
    param.setExpression("thisGroup.scale.get().x", False, 0)
    param.setExpression("thisGroup.scale.get().y", False, 1)
    del param
    param = group_Plane.getParam("paramValueVec33")
    param.setExpression("thisGroup.dlocx.get()", False, 0)
    param.setExpression("thisGroup.dlocy.get()", False, 1)
    param.setExpression("thisGroup.dlocz.get()", False, 2)
    del param
    param = group_Plane.getParam("paramValueVec34")
    param.setExpression("thisGroup.drotx.get()", False, 0)
    param.setExpression("thisGroup.droty.get()", False, 1)
    param.setExpression("thisGroup.drotz.get()", False, 2)
    del param
    param = group_Plane.getParam("paramValueVec35")
    param.setExpression("thisGroup.scale.get().x", False, 0)
    param.setExpression("thisGroup.scale.get().y", False, 1)
    param.setExpression("thisGroup.scale_u.get()", False, 2)
    del param
    param = groupSTMap1.getParam("uvOffset")
    group.getParam("STMap1uvOffset").setAsAlias(param)
    del param
    param = groupSTMap1.getParam("uvScale")
    group.getParam("STMap1uvScale").setAsAlias(param)
    del param
    param = groupSTMap1.getParam("filter")
    group.getParam("STMap1filter").setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam("division")
    param.setExpression("thisGroup.blur_sample.get()", False, 0)
    del param
    param = groupTimeBlur1.getParam("shutter")
    group.getParam("TimeBlur1shutter").setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam("shutterCustomOffset")
    group.getParam("TimeBlur1shutterCustomOffset").setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam("disableNode")
    param.setExpression("thisGroup.blur_sample.get()==0", False, 0)
    del param
    param = groupMerge1.getParam("maskInvert")
    group.getParam("Merge1maskInvert").setAsAlias(param)
    del param
    param = groupMerge1.getParam("mix")
    group.getParam("Merge1mix").setAsAlias(param)
    del param
    param = groupMerge1.getParam("enableMask_Mask")
    group.getParam("Merge1enableMask_Mask").setAsAlias(param)
    del param
    param = groupMerge1.getParam("maskChannel_Mask")
    group.getParam("Merge1maskChannel_Mask").setAsAlias(param)
    del param

    try:
        extModule = sys.modules["PM_Card3DExt"]
    except KeyError:
        extModule = None
    if extModule is not None and hasattr(extModule ,"createInstanceExt") and hasattr(extModule.createInstanceExt,"__call__"):
        extModule.createInstanceExt(app,group)

41db9d7cd19eabba97b521cde96d62ddaddbf4d0
<mask token>


def getVersion():
    return 1


def getIconPath():
    return 'PM_Card3D.png'


def getGrouping():
    return 'Community/Transform'


def getPluginDescription():
    return """Create a 3D plane seen from the camera defined using the PM_Camera plugin.

CHAN file :
a chan file can be provided if you need to export the plane animation.
chan must have XYZ rotation order (no other rotation mode provided for now)

Zbuffer :
As long as the RGBA channels the pyplug generate a Z buffer. Look at the Zbuf.B channel .
Zbuf.R and Zbuf.G : UV coordinates to map the input image to.
Zbuf.B : the Z buffer if you want the plane to be integrate into another image using a Zcombine node.
Zbuf.A : the alpha of the image.
"""


def createInstance(app, group):
    lastNode = group
    param = lastNode.getParam('onParamChanged')
    if param is not None:
        param.setValue('PM_Card3D.plane_read_chan')
        del param
    lastNode.Controls = lastNode.createPageParam('Controls', 'Controls')
    param = lastNode.createSeparatorParam('sepa', 'chan importer')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepa = param
    del param
    param = lastNode.createFileParam('chan', 'chan file')
    param.setSequenceEnabled(False)
    lastNode.Controls.addParam(param)
    param.setHelp('Path of an optional .chan file to transform the plane.')
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.chan = param
    del param
    param = lastNode.createButtonParam('import_chan_file', 'Import .chan file')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setEvaluateOnChange(False)
    lastNode.import_chan_file = param
    del param
    param = lastNode.createSeparatorParam('sep', 'image mapping')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sep = param
    del param
    param = lastNode.createChoiceParam('STMap1filter', 'Filter')
    param.setDefaultValue(2)
    param.restoreDefaultValue()
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.set(0)
    lastNode.STMap1filter = param
    del param
    param = lastNode.createBooleanParam('backface', 'backface culling')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.backface = param
    del param
    param = lastNode.createDouble2DParam('STMap1uvOffset', 'UV Offset')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(1, 1)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvOffset = param
    del param
    param = lastNode.createDouble2DParam('STMap1uvScale', 'UV Scale')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(100, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(100, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvScale = param
    del param
    param = lastNode.createSeparatorParam('sepb', 'Motion Blur')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepb = param
    del param
    param = lastNode.createIntParam('blur_sample', 'Samples')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(0, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp(
        """motion blur is calculated by accumulation of various inter-frames.

This parameter set how many frames/samples to accumulate.

More sample = more calculation"""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.blur_sample = param
    del param
    param = lastNode.createDoubleParam('TimeBlur1shutter', 'Shutter')
    param.setMinimum(0, 0)
    param.setMaximum(2, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(2, 0)
    param.setDefaultValue(0.5, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutter = param
    del param
    param = lastNode.createDoubleParam('TimeBlur1shutterCustomOffset',
        'Custom Offset')
    param.setMinimum(-1, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(-1, 0)
    param.setDisplayMaximum(1, 0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutterCustomOffset = param
    del param
    param = lastNode.createSeparatorParam('sepc', '')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepc = param
    del param
    param = lastNode.createBooleanParam('Merge1enableMask_Mask', 'Mask')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.Merge1enableMask_Mask = param
    del param
    param = lastNode.createChoiceParam('Merge1maskChannel_Mask', '')
    param.setDefaultValue(4)
    param.restoreDefaultValue()
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskChannel_Mask = param
    del param
    param = lastNode.createBooleanParam('Merge1maskInvert', 'Invert Mask')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskInvert = param
    del param
    param = lastNode.createDoubleParam('Merge1mix', 'Mix')
    param.setMinimum(0, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.Merge1mix = param
    del param
    lastNode.transforms = lastNode.createPageParam('transforms', 'Transforms')
    param = lastNode.createSeparatorParam('sepe', 'Location')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepe = param
    del param
    param = lastNode.createDoubleParam('dlocx', 'X')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocx = param
    del param
    param = lastNode.createDoubleParam('locx', 'ChanX')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """X location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locx = param
    del param
    param = lastNode.createDoubleParam('dlocy', 'Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Y location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocy = param
    del param
    param = lastNode.createDoubleParam('locy', 'Chan Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Y location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locy = param
    del param
    param = lastNode.createDoubleParam('dlocz', 'Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Z location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocz = param
    del param
    param = lastNode.createDoubleParam('locz', 'Chan Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Z location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    param.setValue(-10, 0)
    lastNode.locz = param
    del param
    param = lastNode.createSeparatorParam('sepd', 'Rotation')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepd = param
    del param
    param = lastNode.createDoubleParam('drotx', 'X')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X rotation of the Plane, if you use the .chan import you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotx = param
    del param
    param = lastNode.createDoubleParam('rotx', 'ChanX')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X Rotation of the Card in 3D space used with the .chan import')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotx = param
    del param
    param = lastNode.createDoubleParam('droty', 'Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('Y rotation of the plane')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.droty = param
    del param
    param = lastNode.createDoubleParam('roty', 'ChanY')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('Y Rotation of the Card in 3D space')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.roty = param
    del param
    param = lastNode.createDoubleParam('drotz', 'Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotz = param
    del param
    param = lastNode.createDoubleParam('rotz', 'ChanZ')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Z Rotation of the Card in 3D space used with the .chan import')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotz = param
    del param
    param = lastNode.createSeparatorParam('sepf', 'Scale')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepf = param
    del param
    param = lastNode.createDouble2DParam('scale', 'X / Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setMinimum(-2147483648, 1)
    param.setMaximum(2147483647, 1)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(10, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Dimention of the Card in 3D space.
Best practice is to use this one to set the aspect ratio of the card, and the uniform scale to get the card the final scale."""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.setValue(1.92, 0)
    param.setValue(1.08, 1)
    lastNode.scale = param
    del param
    param = lastNode.createDoubleParam('scale_u', 'Uniform')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """this is an extra scaling factor to scale both X and Y,
Use the first to set the X and Y ratio of the card, and this one to set the global scale
"""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.scale_u = param
    del param
    lastNode.setPagesOrder(['Controls', 'transforms', 'Node'])
    lastNode.refreshUserParamsGUI()
    del lastNode
    lastNode = app.createNode('net.sf.openfx.Shadertoy', 1, group)
    lastNode.setScriptName('_Plane')
    lastNode.setLabel(' Plane')
    lastNode.setPosition(558, 465)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    group_Plane = lastNode
    param = lastNode.getParam('paramValueInt1')
    if param is not None:
        param.setValue(7, 0)
        del param
    param = lastNode.getParam('paramValueVec31')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(-10, 2)
        del param
    param = lastNode.getParam('paramValueVec32')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec23')
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        del param
    param = lastNode.getParam('paramValueVec33')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec34')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec35')
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        param.setValue(1, 2)
        del param
    param = lastNode.getParam('imageShaderPresetDir')
    if param is not None:
        param.setValue('')
        del param
    param = lastNode.getParam('imageShaderSource')
    if param is not None:
        param.setValue(
            """uniform bool backface = false ;
uniform vec3 pln_loc = vec3(0.0,0.,10.0);
uniform vec3 pln_rot = vec3(0.0);
uniform vec3 d_loc = vec3(0.0,0.,0.0);
uniform vec3 d_rot = vec3(0.0);

// scale X Y, and the last one is the uniform scale
uniform vec3 pln_scl = vec3(1.0); // scale


float M_PI = 3.14159265359 ;
float kEpsilon = 1e-8;
//float M_PI = 3.14159265358979323846264338327950288419;


float deg2rad(float deg)
 { return deg * M_PI / 180.0; }

mat4 mat3to4(mat3 m){
	return mat4(
		m[0][0],m[0][1],m[0][2],0,
		m[1][0],m[1][1],m[1][2],0,
		m[2][0],m[2][1],m[2][2],0,
		0,0,0,1);}
mat3 rotx(float x){
	return mat3 (
		1,     0,      0,
		0, cos(x), sin(x),
		0,-sin(x), cos(x));}
mat3 roty(float y){
	return mat3 (
		cos(y), 0,-sin(y),
		    0,  1,     0,
		sin(y), 0, cos(y));}
mat3 rotz(float z){
		return mat3 (
	   cos(z),sin(z),0,
		-sin(z),cos(z),0,
	    	 0,     0, 1);}

bool rayTriangleIntersect( vec3 orig, vec3 dir, vec3 v0, vec3 v1, vec3 v2, inout float t, inout float u, inout float v)
	{
		bool res = true ;
		vec3 v0v1 =vec3( v1 - v0);
		vec3 v0v2 =vec3( v2 - v0);
		vec3 pvec =vec3( cross(dir,v0v2));
		float det = dot(v0v1,pvec);

		float invDet = 1 / det;

		vec3 tvec =vec3( orig - v0);
		u = dot(tvec,pvec) * invDet;
		if (u < 0 || u > 1) res=false ;

		vec3 qvec =vec3( cross(tvec,v0v1));
		v = dot(dir,qvec) * invDet;
		if (v < 0 || u + v > 1) res =false;

		if (backface == true){
			if (det < kEpsilon){ res = false;};
		};

		t = dot(v0v2,qvec) * invDet;

		// position in z (if the plane is below the camera)
		if (t < 0 ) res=false;

		return res;
	}
mat4 getcam(vec2 def){
	mat4 cm;
	cm[0]=texture2D( iChannel0, vec2(8/def.x,6/def.y));
	cm[1]=texture2D( iChannel0, vec2(24/def.x,6/def.y));
	cm[2]=texture2D( iChannel0, vec2(8/def.x,20/def.y));
	cm[3]=texture2D( iChannel0, vec2(24/def.x,20/def.y));
	return cm;
	}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
		vec2 def = iChannelResolution[0].xy/iRenderScale.xy;
		mat4 cameraToWorld = getcam(def); // camera matrix
		vec4 cam = texture2D( iChannel0, vec2(8/def.x,34/def.y)); // fov , sensor_offset , shift.xy
		float Px = (2*(fragCoord.x / iResolution.x)-1) * cam.x * (iResolution.x / iResolution.y) ;
		float Py = (2*((fragCoord.y / iResolution.y)-0.5))* cam.x ;
	  vec3 rayOrigin=(cameraToWorld*vec4(0.0, 0., 0.,1)).xyz;
    vec3 rayPWorld=(cameraToWorld*vec4(Px, Py, cam.y,1)).xyz;
		vec3 rayDirection = normalize(rayPWorld-rayOrigin);
    vec3 ploc;
    mat4 drot;

    // PLANE vertex
    vec3 v0=vec3(-1, -1,0);
    vec3 v1=vec3( 1, -1, 0);
    vec3 v2=vec3( -1, 1, 0);
    vec3 v3=vec3( 1, 1, 0);

    //Plane scale
    v0.xy*=pln_scl.xy*pln_scl.z;
    v1.xy*=pln_scl.xy*pln_scl.z;
    v2.xy*=pln_scl.xy*pln_scl.z;
    v3.xy*=pln_scl.xy*pln_scl.z;

    //plane first transform (delta loc / rot) to avoid gimbal or rotational conflict
    drot=mat3to4(rotx(deg2rad(-d_rot.x)) * roty(deg2rad(-d_rot.y)) * rotz(deg2rad(-d_rot.z)));
    ploc=vec3(d_loc.x, d_loc.y, d_loc.z );
    v0=(vec4(v0,1)*drot).xyz+ploc;
    v1=(vec4(v1,1)*drot).xyz+ploc;
    v2=(vec4(v2,1)*drot).xyz+ploc;
    v3=(vec4(v3,1)*drot).xyz+ploc;


		// plane rotation matrix XYZ
		drot=mat3to4(rotx(deg2rad(-pln_rot.x)) * roty(deg2rad(-pln_rot.y)) * rotz(deg2rad(-pln_rot.z)));
		ploc=vec3(pln_loc.x, pln_loc.y, pln_loc.z );
		v0=(vec4(v0,1)*drot).xyz+ploc;
		v1=(vec4(v1,1)*drot).xyz+ploc;
		v2=(vec4(v2,1)*drot).xyz+ploc;
		v3=(vec4(v3,1)*drot).xyz+ploc;

			float t; float u; float v; vec4 res=vec4(0);
			res.b=100000000; // zbuffer

			if (rayTriangleIntersect(rayOrigin, rayDirection, v0, v2, v1, t, u, v)==true){
				res=vec4(v,1-u,t,1);
			}

			if (rayTriangleIntersect(rayOrigin, rayDirection, v3, v1, v2, t, u, v)==true){
				res=vec4(1-v,u,t,1);
			}

	fragColor=res.rgba;
}
"""
            )
        del param
    param = lastNode.getParam('inputEnable1')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('inputEnable2')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('inputEnable3')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('NatronParamFormatChoice')
    if param is not None:
        param.set('PC_Video 640x480')
        del param
    param = lastNode.getParam('mouseParams')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('paramCount')
    if param is not None:
        param.setValue(6, 0)
        del param
    param = lastNode.getParam('paramType0')
    if param is not None:
        param.set('bool')
        del param
    param = lastNode.getParam('paramName0')
    if param is not None:
        param.setValue('backface')
        del param
    param = lastNode.getParam('paramLabel0')
    if param is not None:
        param.setValue('backface')
        del param
    param = lastNode.getParam('paramType1')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName1')
    if param is not None:
        param.setValue('pln_loc')
        del param
    param = lastNode.getParam('paramLabel1')
    if param is not None:
        param.setValue('pln_loc')
        del param
    param = lastNode.getParam('paramDefaultVec31')
    if param is not None:
        param.setValue(10, 2)
        del param
    param = lastNode.getParam('paramType2')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName2')
    if param is not None:
        param.setValue('pln_rot')
        del param
    param = lastNode.getParam('paramLabel2')
    if param is not None:
        param.setValue('pln_rot')
        del param
    param = lastNode.getParam('paramType3')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName3')
    if param is not None:
        param.setValue('d_loc')
        del param
    param = lastNode.getParam('paramLabel3')
    if param is not None:
        param.setValue('d_loc')
        del param
    param = lastNode.getParam('paramType4')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName4')
    if param is not None:
        param.setValue('d_rot')
        del param
    param = lastNode.getParam('paramLabel4')
    if param is not None:
        param.setValue('d_rot')
        del param
    param = lastNode.getParam('paramType5')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName5')
    if param is not None:
        param.setValue('pln_scl')
        del param
    param = lastNode.getParam('paramLabel5')
    if param is not None:
        param.setValue('scale')
        del param
    param = lastNode.getParam('paramDefaultVec35')
    if param is not None:
        param.setValue(1, 0)
        param.setValue(1, 1)
        param.setValue(1, 2)
        del param
    param = lastNode.getParam('paramType6')
    if param is not None:
        param.set('float')
        del param
    param = lastNode.getParam('paramName6')
    if param is not None:
        param.setValue('sensor')
        del param
    param = lastNode.getParam('paramLabel6')
    if param is not None:
        param.setValue('sensor')
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.STMap', 2, group)
    lastNode.setScriptName('STMap1')
    lastNode.setLabel('STMap1')
    lastNode.setPosition(966, 465)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.7, 0.3, 0.1)
    groupSTMap1 = lastNode
    param = lastNode.getParam('channelUChoice')
    if param is not None:
        param.setValue('UV.r')
        del param
    param = lastNode.getParam('channelVChoice')
    if param is not None:
        param.setValue('UV.g')
        del param
    param = lastNode.getParam('channelAChoice')
    if param is not None:
        param.setValue('UV.a')
        del param
    param = lastNode.getParam('wrapU')
    if param is not None:
        param.set('Repeat')
        del param
    param = lastNode.getParam('wrapV')
    if param is not None:
        param.set('Repeat')
        del param
    param = lastNode.getParam('filter')
    if param is not None:
        param.set('Impulse')
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.TimeBlur', 1, group)
    lastNode.setScriptName('TimeBlur1')
    lastNode.setLabel('TimeBlur1')
    lastNode.setPosition(978, 588)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.7, 0.65, 0.35)
    groupTimeBlur1 = lastNode
    param = lastNode.getParam('division')
    if param is not None:
        param.setValue(1, 0)
        del param
    param = lastNode.getParam('shutterOffset')
    if param is not None:
        param.set('Custom')
        del param
    param = lastNode.getParam('disableNode')
    if param is not None:
        param.setValue(True)
        del param
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Camera')
    lastNode.setLabel('Camera')
    lastNode.setPosition(546, 17)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupCamera = lastNode
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Output', 1, group)
    lastNode.setLabel('Output1')
    lastNode.setPosition(546, 922)
    lastNode.setSize(104, 30)
    lastNode.setColor(0.7, 0.7, 0.7)
    groupOutput1 = lastNode
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Image')
    lastNode.setLabel('Image')
    lastNode.setPosition(966, 24)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupImage = lastNode
    del lastNode
    lastNode = app.createNode('net.sf.openfx.MergePlugin', 1, group)
    lastNode.setScriptName('Merge1')
    lastNode.setLabel('Merge1')
    lastNode.setPosition(969, 722)
    lastNode.setSize(104, 66)
    lastNode.setColor(0.3, 0.37, 0.776)
    groupMerge1 = lastNode
    param = lastNode.getParam('userTextArea')
    if param is not None:
        param.setValue('<Natron>(over)</Natron>')
        del param
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Mask')
    lastNode.setLabel('Mask')
    lastNode.setPosition(1197, 730)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupMask = lastNode
    param = lastNode.getParam('optional')
    if param is not None:
        param.setValue(True)
        del param
    param = lastNode.getParam('isMask')
    if param is not None:
        param.setValue(True)
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.ShufflePlugin', 2, group)
    lastNode.setScriptName('Zbuffer')
    lastNode.setLabel('Zbuffer')
    lastNode.setPosition(546, 734)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.6, 0.24, 0.39)
    lastNode.addUserPlane('Zbuf', ['R', 'G', 'B', 'A'])
    groupZbuffer = lastNode
    param = lastNode.getParam('outputChannels')
    if param is not None:
        param.set('Zbuf')
        del param
    param = lastNode.getParam('outputChannelsChoice')
    if param is not None:
        param.setValue('Zbuf')
        del param
    param = lastNode.getParam('outputRChoice')
    if param is not None:
        param.setValue('B.r')
        del param
    param = lastNode.getParam('outputGChoice')
    if param is not None:
        param.setValue('B.g')
        del param
    param = lastNode.getParam('outputBChoice')
    if param is not None:
        param.setValue('B.b')
        del param
    param = lastNode.getParam('outputAChoice')
    if param is not None:
        param.setValue('B.a')
        del param
    del lastNode
    group_Plane.connectInput(0, groupCamera)
    groupSTMap1.connectInput(0, group_Plane)
    groupSTMap1.connectInput(1, groupImage)
    groupTimeBlur1.connectInput(0, groupSTMap1)
    groupOutput1.connectInput(0, groupZbuffer)
    groupMerge1.connectInput(1, groupTimeBlur1)
    groupMerge1.connectInput(2, groupMask)
    groupZbuffer.connectInput(0, group_Plane)
    groupZbuffer.connectInput(1, groupMerge1)
    param = group_Plane.getParam('paramValueBool0')
    group.getParam('backface').setAsAlias(param)
    del param
    param = group_Plane.getParam('paramValueVec31')
    param.setExpression('thisGroup.locx.get()', False, 0)
    param.setExpression('thisGroup.locy.get()', False, 1)
    param.setExpression('thisGroup.locz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec32')
    param.setExpression('thisGroup.rotx.get()', False, 0)
    param.setExpression('thisGroup.roty.get()', False, 1)
    param.setExpression('thisGroup.rotz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec23')
    param.setExpression('thisGroup.scale.get().x', False, 0)
    param.setExpression('thisGroup.scale.get().y', False, 1)
    del param
    param = group_Plane.getParam('paramValueVec33')
    param.setExpression('thisGroup.dlocx.get()', False, 0)
    param.setExpression('thisGroup.dlocy.get()', False, 1)
    param.setExpression('thisGroup.dlocz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec34')
    param.setExpression('thisGroup.drotx.get()', False, 0)
    param.setExpression('thisGroup.droty.get()', False, 1)
    param.setExpression('thisGroup.drotz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec35')
    param.setExpression('thisGroup.scale.get().x', False, 0)
    param.setExpression('thisGroup.scale.get().y', False, 1)
    param.setExpression('thisGroup.scale_u.get()', False, 2)
    del param
    param = groupSTMap1.getParam('uvOffset')
    group.getParam('STMap1uvOffset').setAsAlias(param)
    del param
    param = groupSTMap1.getParam('uvScale')
    group.getParam('STMap1uvScale').setAsAlias(param)
    del param
    param = groupSTMap1.getParam('filter')
    group.getParam('STMap1filter').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('division')
    param.setExpression('thisGroup.blur_sample.get()', False, 0)
    del param
    param = groupTimeBlur1.getParam('shutter')
    group.getParam('TimeBlur1shutter').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('shutterCustomOffset')
    group.getParam('TimeBlur1shutterCustomOffset').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('disableNode')
    param.setExpression('thisGroup.blur_sample.get()==0', False, 0)
    del param
    param = groupMerge1.getParam('maskInvert')
    group.getParam('Merge1maskInvert').setAsAlias(param)
    del param
    param = groupMerge1.getParam('mix')
    group.getParam('Merge1mix').setAsAlias(param)
    del param
    param = groupMerge1.getParam('enableMask_Mask')
    group.getParam('Merge1enableMask_Mask').setAsAlias(param)
    del param
    param = groupMerge1.getParam('maskChannel_Mask')
    group.getParam('Merge1maskChannel_Mask').setAsAlias(param)
    del param
    try:
        extModule = sys.modules['PM_Card3DExt']
    except KeyError:
        extModule = None
    if extModule is not None and hasattr(extModule, 'createInstanceExt'
        ) and hasattr(extModule.createInstanceExt, '__call__'):
        extModule.createInstanceExt(app, group)

<mask token>


def getPluginID():
    return 'natron.community.plugins.PM_Card3D'


<mask token>


def getVersion():
    return 1


def getIconPath():
    return 'PM_Card3D.png'


def getGrouping():
    return 'Community/Transform'


def getPluginDescription():
    return """Create a 3D plane seen from the camera defined using the PM_Camera plugin.

CHAN file :
a chan file can be provided if you need to export the plane animation.
chan must have XYZ rotation order (no other rotation mode provided for now)

Zbuffer :
As long as the RGBA channels the pyplug generate a Z buffer. Look at the Zbuf.B channel .
Zbuf.R and Zbuf.G : UV coordinates to map the input image to.
Zbuf.B : the Z buffer if you want the plane to be integrate into another image using a Zcombine node.
Zbuf.A : the alpha of the image.
"""


def createInstance(app, group):
    lastNode = group
    param = lastNode.getParam('onParamChanged')
    if param is not None:
        param.setValue('PM_Card3D.plane_read_chan')
        del param
    lastNode.Controls = lastNode.createPageParam('Controls', 'Controls')
    param = lastNode.createSeparatorParam('sepa', 'chan importer')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepa = param
    del param
    param = lastNode.createFileParam('chan', 'chan file')
    param.setSequenceEnabled(False)
    lastNode.Controls.addParam(param)
    param.setHelp('Path of an optional .chan file to transform the plane.')
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.chan = param
    del param
    param = lastNode.createButtonParam('import_chan_file', 'Import .chan file')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setEvaluateOnChange(False)
    lastNode.import_chan_file = param
    del param
    param = lastNode.createSeparatorParam('sep', 'image mapping')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sep = param
    del param
    param = lastNode.createChoiceParam('STMap1filter', 'Filter')
    param.setDefaultValue(2)
    param.restoreDefaultValue()
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.set(0)
    lastNode.STMap1filter = param
    del param
    param = lastNode.createBooleanParam('backface', 'backface culling')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.backface = param
    del param
    param = lastNode.createDouble2DParam('STMap1uvOffset', 'UV Offset')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(1, 1)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvOffset = param
    del param
    param = lastNode.createDouble2DParam('STMap1uvScale', 'UV Scale')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(100, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(100, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvScale = param
    del param
    param = lastNode.createSeparatorParam('sepb', 'Motion Blur')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepb = param
    del param
    param = lastNode.createIntParam('blur_sample', 'Samples')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(0, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp(
        """motion blur is calculated by accumulation of various inter-frames.

This parameter set how many frames/samples to accumulate.

More sample = more calculation"""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.blur_sample = param
    del param
    param = lastNode.createDoubleParam('TimeBlur1shutter', 'Shutter')
    param.setMinimum(0, 0)
    param.setMaximum(2, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(2, 0)
    param.setDefaultValue(0.5, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutter = param
    del param
    param = lastNode.createDoubleParam('TimeBlur1shutterCustomOffset',
        'Custom Offset')
    param.setMinimum(-1, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(-1, 0)
    param.setDisplayMaximum(1, 0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutterCustomOffset = param
    del param
    param = lastNode.createSeparatorParam('sepc', '')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepc = param
    del param
    param = lastNode.createBooleanParam('Merge1enableMask_Mask', 'Mask')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.Merge1enableMask_Mask = param
    del param
    param = lastNode.createChoiceParam('Merge1maskChannel_Mask', '')
    param.setDefaultValue(4)
    param.restoreDefaultValue()
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskChannel_Mask = param
    del param
    param = lastNode.createBooleanParam('Merge1maskInvert', 'Invert Mask')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskInvert = param
    del param
    param = lastNode.createDoubleParam('Merge1mix', 'Mix')
    param.setMinimum(0, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.Merge1mix = param
    del param
    lastNode.transforms = lastNode.createPageParam('transforms', 'Transforms')
    param = lastNode.createSeparatorParam('sepe', 'Location')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepe = param
    del param
    param = lastNode.createDoubleParam('dlocx', 'X')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocx = param
    del param
    param = lastNode.createDoubleParam('locx', 'ChanX')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """X location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locx = param
    del param
    param = lastNode.createDoubleParam('dlocy', 'Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Y location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocy = param
    del param
    param = lastNode.createDoubleParam('locy', 'Chan Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Y location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locy = param
    del param
    param = lastNode.createDoubleParam('dlocz', 'Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Z location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocz = param
    del param
    param = lastNode.createDoubleParam('locz', 'Chan Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Z location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    param.setValue(-10, 0)
    lastNode.locz = param
    del param
    param = lastNode.createSeparatorParam('sepd', 'Rotation')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepd = param
    del param
    param = lastNode.createDoubleParam('drotx', 'X')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X rotation of the Plane, if you use the .chan import you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotx = param
    del param
    param = lastNode.createDoubleParam('rotx', 'ChanX')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X Rotation of the Card in 3D space used with the .chan import')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotx = param
    del param
    param = lastNode.createDoubleParam('droty', 'Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('Y rotation of the plane')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.droty = param
    del param
    param = lastNode.createDoubleParam('roty', 'ChanY')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('Y Rotation of the Card in 3D space')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.roty = param
    del param
    param = lastNode.createDoubleParam('drotz', 'Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotz = param
    del param
    param = lastNode.createDoubleParam('rotz', 'ChanZ')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Z Rotation of the Card in 3D space used with the .chan import')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotz = param
    del param
    param = lastNode.createSeparatorParam('sepf', 'Scale')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepf = param
    del param
    param = lastNode.createDouble2DParam('scale', 'X / Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setMinimum(-2147483648, 1)
    param.setMaximum(2147483647, 1)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(10, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Dimention of the Card in 3D space.
Best practice is to use this one to set the aspect ratio of the card, and the uniform scale to get the card the final scale."""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.setValue(1.92, 0)
    param.setValue(1.08, 1)
    lastNode.scale = param
    del param
    param = lastNode.createDoubleParam('scale_u', 'Uniform')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """this is an extra scaling factor to scale both X and Y,
Use the first to set the X and Y ratio of the card, and this one to set the global scale
"""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.scale_u = param
    del param
    lastNode.setPagesOrder(['Controls', 'transforms', 'Node'])
    lastNode.refreshUserParamsGUI()
    del lastNode
    lastNode = app.createNode('net.sf.openfx.Shadertoy', 1, group)
    lastNode.setScriptName('_Plane')
    lastNode.setLabel(' Plane')
    lastNode.setPosition(558, 465)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    group_Plane = lastNode
    param = lastNode.getParam('paramValueInt1')
    if param is not None:
        param.setValue(7, 0)
        del param
    param = lastNode.getParam('paramValueVec31')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(-10, 2)
        del param
    param = lastNode.getParam('paramValueVec32')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec23')
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        del param
    param = lastNode.getParam('paramValueVec33')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec34')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec35')
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        param.setValue(1, 2)
        del param
    param = lastNode.getParam('imageShaderPresetDir')
    if param is not None:
        param.setValue('')
        del param
    param = lastNode.getParam('imageShaderSource')
    if param is not None:
        param.setValue(
            """uniform bool backface = false ;
uniform vec3 pln_loc = vec3(0.0,0.,10.0);
uniform vec3 pln_rot = vec3(0.0);
uniform vec3 d_loc = vec3(0.0,0.,0.0);
uniform vec3 d_rot = vec3(0.0);

// scale X Y, and the last one is the uniform scale
uniform vec3 pln_scl = vec3(1.0); // scale


float M_PI = 3.14159265359 ;
float kEpsilon = 1e-8;
//float M_PI = 3.14159265358979323846264338327950288419;


float deg2rad(float deg)
 { return deg * M_PI / 180.0; }

mat4 mat3to4(mat3 m){
	return mat4(
		m[0][0],m[0][1],m[0][2],0,
		m[1][0],m[1][1],m[1][2],0,
		m[2][0],m[2][1],m[2][2],0,
		0,0,0,1);}
mat3 rotx(float x){
	return mat3 (
		1,     0,      0,
		0, cos(x), sin(x),
		0,-sin(x), cos(x));}
mat3 roty(float y){
	return mat3 (
		cos(y), 0,-sin(y),
		    0,  1,     0,
		sin(y), 0, cos(y));}
mat3 rotz(float z){
		return mat3 (
	   cos(z),sin(z),0,
		-sin(z),cos(z),0,
	    	 0,     0, 1);}

bool rayTriangleIntersect( vec3 orig, vec3 dir, vec3 v0, vec3 v1, vec3 v2, inout float t, inout float u, inout float v)
	{
		bool res = true ;
		vec3 v0v1 =vec3( v1 - v0);
		vec3 v0v2 =vec3( v2 - v0);
		vec3 pvec =vec3( cross(dir,v0v2));
		float det = dot(v0v1,pvec);

		float invDet = 1 / det;

		vec3 tvec =vec3( orig - v0);
		u = dot(tvec,pvec) * invDet;
		if (u < 0 || u > 1) res=false ;

		vec3 qvec =vec3( cross(tvec,v0v1));
		v = dot(dir,qvec) * invDet;
		if (v < 0 || u + v > 1) res =false;

		if (backface == true){
			if (det < kEpsilon){ res = false;};
		};

		t = dot(v0v2,qvec) * invDet;

		// position in z (if the plane is below the camera)
		if (t < 0 ) res=false;

		return res;
	}
mat4 getcam(vec2 def){
	mat4 cm;
	cm[0]=texture2D( iChannel0, vec2(8/def.x,6/def.y));
	cm[1]=texture2D( iChannel0, vec2(24/def.x,6/def.y));
	cm[2]=texture2D( iChannel0, vec2(8/def.x,20/def.y));
	cm[3]=texture2D( iChannel0, vec2(24/def.x,20/def.y));
	return cm;
	}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
		vec2 def = iChannelResolution[0].xy/iRenderScale.xy;
		mat4 cameraToWorld = getcam(def); // camera matrix
		vec4 cam = texture2D( iChannel0, vec2(8/def.x,34/def.y)); // fov , sensor_offset , shift.xy
		float Px = (2*(fragCoord.x / iResolution.x)-1) * cam.x * (iResolution.x / iResolution.y) ;
		float Py = (2*((fragCoord.y / iResolution.y)-0.5))* cam.x ;
	  vec3 rayOrigin=(cameraToWorld*vec4(0.0, 0., 0.,1)).xyz;
    vec3 rayPWorld=(cameraToWorld*vec4(Px, Py, cam.y,1)).xyz;
		vec3 rayDirection = normalize(rayPWorld-rayOrigin);
    vec3 ploc;
    mat4 drot;

    // PLANE vertex
    vec3 v0=vec3(-1, -1,0);
    vec3 v1=vec3( 1, -1, 0);
    vec3 v2=vec3( -1, 1, 0);
    vec3 v3=vec3( 1, 1, 0);

    //Plane scale
    v0.xy*=pln_scl.xy*pln_scl.z;
    v1.xy*=pln_scl.xy*pln_scl.z;
    v2.xy*=pln_scl.xy*pln_scl.z;
    v3.xy*=pln_scl.xy*pln_scl.z;

    //plane first transform (delta loc / rot) to avoid gimbal or rotational conflict
    drot=mat3to4(rotx(deg2rad(-d_rot.x)) * roty(deg2rad(-d_rot.y)) * rotz(deg2rad(-d_rot.z)));
    ploc=vec3(d_loc.x, d_loc.y, d_loc.z );
    v0=(vec4(v0,1)*drot).xyz+ploc;
    v1=(vec4(v1,1)*drot).xyz+ploc;
    v2=(vec4(v2,1)*drot).xyz+ploc;
    v3=(vec4(v3,1)*drot).xyz+ploc;


		// plane rotation matrix XYZ
		drot=mat3to4(rotx(deg2rad(-pln_rot.x)) * roty(deg2rad(-pln_rot.y)) * rotz(deg2rad(-pln_rot.z)));
		ploc=vec3(pln_loc.x, pln_loc.y, pln_loc.z );
		v0=(vec4(v0,1)*drot).xyz+ploc;
		v1=(vec4(v1,1)*drot).xyz+ploc;
		v2=(vec4(v2,1)*drot).xyz+ploc;
		v3=(vec4(v3,1)*drot).xyz+ploc;

			float t; float u; float v; vec4 res=vec4(0);
			res.b=100000000; // zbuffer

			if (rayTriangleIntersect(rayOrigin, rayDirection, v0, v2, v1, t, u, v)==true){
				res=vec4(v,1-u,t,1);
			}

			if (rayTriangleIntersect(rayOrigin, rayDirection, v3, v1, v2, t, u, v)==true){
				res=vec4(1-v,u,t,1);
			}

	fragColor=res.rgba;
}
"""
            )
        del param
    param = lastNode.getParam('inputEnable1')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('inputEnable2')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('inputEnable3')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('NatronParamFormatChoice')
    if param is not None:
        param.set('PC_Video 640x480')
        del param
    param = lastNode.getParam('mouseParams')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('paramCount')
    if param is not None:
        param.setValue(6, 0)
        del param
    param = lastNode.getParam('paramType0')
    if param is not None:
        param.set('bool')
        del param
    param = lastNode.getParam('paramName0')
    if param is not None:
        param.setValue('backface')
        del param
    param = lastNode.getParam('paramLabel0')
    if param is not None:
        param.setValue('backface')
        del param
    param = lastNode.getParam('paramType1')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName1')
    if param is not None:
        param.setValue('pln_loc')
        del param
    param = lastNode.getParam('paramLabel1')
    if param is not None:
        param.setValue('pln_loc')
        del param
    param = lastNode.getParam('paramDefaultVec31')
    if param is not None:
        param.setValue(10, 2)
        del param
    param = lastNode.getParam('paramType2')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName2')
    if param is not None:
        param.setValue('pln_rot')
        del param
    param = lastNode.getParam('paramLabel2')
    if param is not None:
        param.setValue('pln_rot')
        del param
    param = lastNode.getParam('paramType3')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName3')
    if param is not None:
        param.setValue('d_loc')
        del param
    param = lastNode.getParam('paramLabel3')
    if param is not None:
        param.setValue('d_loc')
        del param
    param = lastNode.getParam('paramType4')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName4')
    if param is not None:
        param.setValue('d_rot')
        del param
    param = lastNode.getParam('paramLabel4')
    if param is not None:
        param.setValue('d_rot')
        del param
    param = lastNode.getParam('paramType5')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName5')
    if param is not None:
        param.setValue('pln_scl')
        del param
    param = lastNode.getParam('paramLabel5')
    if param is not None:
        param.setValue('scale')
        del param
    param = lastNode.getParam('paramDefaultVec35')
    if param is not None:
        param.setValue(1, 0)
        param.setValue(1, 1)
        param.setValue(1, 2)
        del param
    param = lastNode.getParam('paramType6')
    if param is not None:
        param.set('float')
        del param
    param = lastNode.getParam('paramName6')
    if param is not None:
        param.setValue('sensor')
        del param
    param = lastNode.getParam('paramLabel6')
    if param is not None:
        param.setValue('sensor')
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.STMap', 2, group)
    lastNode.setScriptName('STMap1')
    lastNode.setLabel('STMap1')
    lastNode.setPosition(966, 465)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.7, 0.3, 0.1)
    groupSTMap1 = lastNode
    param = lastNode.getParam('channelUChoice')
    if param is not None:
        param.setValue('UV.r')
        del param
    param = lastNode.getParam('channelVChoice')
    if param is not None:
        param.setValue('UV.g')
        del param
    param = lastNode.getParam('channelAChoice')
    if param is not None:
        param.setValue('UV.a')
        del param
    param = lastNode.getParam('wrapU')
    if param is not None:
        param.set('Repeat')
        del param
    param = lastNode.getParam('wrapV')
    if param is not None:
        param.set('Repeat')
        del param
    param = lastNode.getParam('filter')
    if param is not None:
        param.set('Impulse')
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.TimeBlur', 1, group)
    lastNode.setScriptName('TimeBlur1')
    lastNode.setLabel('TimeBlur1')
    lastNode.setPosition(978, 588)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.7, 0.65, 0.35)
    groupTimeBlur1 = lastNode
    param = lastNode.getParam('division')
    if param is not None:
        param.setValue(1, 0)
        del param
    param = lastNode.getParam('shutterOffset')
    if param is not None:
        param.set('Custom')
        del param
    param = lastNode.getParam('disableNode')
    if param is not None:
        param.setValue(True)
        del param
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Camera')
    lastNode.setLabel('Camera')
    lastNode.setPosition(546, 17)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupCamera = lastNode
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Output', 1, group)
    lastNode.setLabel('Output1')
    lastNode.setPosition(546, 922)
    lastNode.setSize(104, 30)
    lastNode.setColor(0.7, 0.7, 0.7)
    groupOutput1 = lastNode
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Image')
    lastNode.setLabel('Image')
    lastNode.setPosition(966, 24)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupImage = lastNode
    del lastNode
    lastNode = app.createNode('net.sf.openfx.MergePlugin', 1, group)
    lastNode.setScriptName('Merge1')
    lastNode.setLabel('Merge1')
    lastNode.setPosition(969, 722)
    lastNode.setSize(104, 66)
    lastNode.setColor(0.3, 0.37, 0.776)
    groupMerge1 = lastNode
    param = lastNode.getParam('userTextArea')
    if param is not None:
        param.setValue('<Natron>(over)</Natron>')
        del param
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Mask')
    lastNode.setLabel('Mask')
    lastNode.setPosition(1197, 730)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupMask = lastNode
    param = lastNode.getParam('optional')
    if param is not None:
        param.setValue(True)
        del param
    param = lastNode.getParam('isMask')
    if param is not None:
        param.setValue(True)
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.ShufflePlugin', 2, group)
    lastNode.setScriptName('Zbuffer')
    lastNode.setLabel('Zbuffer')
    lastNode.setPosition(546, 734)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.6, 0.24, 0.39)
    lastNode.addUserPlane('Zbuf', ['R', 'G', 'B', 'A'])
    groupZbuffer = lastNode
    param = lastNode.getParam('outputChannels')
    if param is not None:
        param.set('Zbuf')
        del param
    param = lastNode.getParam('outputChannelsChoice')
    if param is not None:
        param.setValue('Zbuf')
        del param
    param = lastNode.getParam('outputRChoice')
    if param is not None:
        param.setValue('B.r')
        del param
    param = lastNode.getParam('outputGChoice')
    if param is not None:
        param.setValue('B.g')
        del param
    param = lastNode.getParam('outputBChoice')
    if param is not None:
        param.setValue('B.b')
        del param
    param = lastNode.getParam('outputAChoice')
    if param is not None:
        param.setValue('B.a')
        del param
    del lastNode
    group_Plane.connectInput(0, groupCamera)
    groupSTMap1.connectInput(0, group_Plane)
    groupSTMap1.connectInput(1, groupImage)
    groupTimeBlur1.connectInput(0, groupSTMap1)
    groupOutput1.connectInput(0, groupZbuffer)
    groupMerge1.connectInput(1, groupTimeBlur1)
    groupMerge1.connectInput(2, groupMask)
    groupZbuffer.connectInput(0, group_Plane)
    groupZbuffer.connectInput(1, groupMerge1)
    param = group_Plane.getParam('paramValueBool0')
    group.getParam('backface').setAsAlias(param)
    del param
    param = group_Plane.getParam('paramValueVec31')
    param.setExpression('thisGroup.locx.get()', False, 0)
    param.setExpression('thisGroup.locy.get()', False, 1)
    param.setExpression('thisGroup.locz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec32')
    param.setExpression('thisGroup.rotx.get()', False, 0)
    param.setExpression('thisGroup.roty.get()', False, 1)
    param.setExpression('thisGroup.rotz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec23')
    param.setExpression('thisGroup.scale.get().x', False, 0)
    param.setExpression('thisGroup.scale.get().y', False, 1)
    del param
    param = group_Plane.getParam('paramValueVec33')
    param.setExpression('thisGroup.dlocx.get()', False, 0)
    param.setExpression('thisGroup.dlocy.get()', False, 1)
    param.setExpression('thisGroup.dlocz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec34')
    param.setExpression('thisGroup.drotx.get()', False, 0)
    param.setExpression('thisGroup.droty.get()', False, 1)
    param.setExpression('thisGroup.drotz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec35')
    param.setExpression('thisGroup.scale.get().x', False, 0)
    param.setExpression('thisGroup.scale.get().y', False, 1)
    param.setExpression('thisGroup.scale_u.get()', False, 2)
    del param
    param = groupSTMap1.getParam('uvOffset')
    group.getParam('STMap1uvOffset').setAsAlias(param)
    del param
    param = groupSTMap1.getParam('uvScale')
    group.getParam('STMap1uvScale').setAsAlias(param)
    del param
    param = groupSTMap1.getParam('filter')
    group.getParam('STMap1filter').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('division')
    param.setExpression('thisGroup.blur_sample.get()', False, 0)
    del param
    param = groupTimeBlur1.getParam('shutter')
    group.getParam('TimeBlur1shutter').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('shutterCustomOffset')
    group.getParam('TimeBlur1shutterCustomOffset').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('disableNode')
    param.setExpression('thisGroup.blur_sample.get()==0', False, 0)
    del param
    param = groupMerge1.getParam('maskInvert')
    group.getParam('Merge1maskInvert').setAsAlias(param)
    del param
    param = groupMerge1.getParam('mix')
    group.getParam('Merge1mix').setAsAlias(param)
    del param
    param = groupMerge1.getParam('enableMask_Mask')
    group.getParam('Merge1enableMask_Mask').setAsAlias(param)
    del param
    param = groupMerge1.getParam('maskChannel_Mask')
    group.getParam('Merge1maskChannel_Mask').setAsAlias(param)
    del param
    try:
        extModule = sys.modules['PM_Card3DExt']
    except KeyError:
        extModule = None
    if extModule is not None and hasattr(extModule, 'createInstanceExt'
        ) and hasattr(extModule.createInstanceExt, '__call__'):
        extModule.createInstanceExt(app, group)

<mask token>


def getPluginID():
    return 'natron.community.plugins.PM_Card3D'


def getLabel():
    return 'PM_Card3D'


def getVersion():
    return 1


def getIconPath():
    return 'PM_Card3D.png'


def getGrouping():
    return 'Community/Transform'


def getPluginDescription():
    return """Create a 3D plane seen from the camera defined using the PM_Camera plugin.

CHAN file :
a chan file can be provided if you need to export the plane animation.
chan must have XYZ rotation order (no other rotation mode provided for now)

Zbuffer :
As long as the RGBA channels the pyplug generate a Z buffer. Look at the Zbuf.B channel .
Zbuf.R and Zbuf.G : UV coordinates to map the input image to.
Zbuf.B : the Z buffer if you want the plane to be integrate into another image using a Zcombine node.
Zbuf.A : the alpha of the image.
"""


def createInstance(app, group):
    lastNode = group
    param = lastNode.getParam('onParamChanged')
    if param is not None:
        param.setValue('PM_Card3D.plane_read_chan')
        del param
    lastNode.Controls = lastNode.createPageParam('Controls', 'Controls')
    param = lastNode.createSeparatorParam('sepa', 'chan importer')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepa = param
    del param
    param = lastNode.createFileParam('chan', 'chan file')
    param.setSequenceEnabled(False)
    lastNode.Controls.addParam(param)
    param.setHelp('Path of an optional .chan file to transform the plane.')
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.chan = param
    del param
    param = lastNode.createButtonParam('import_chan_file', 'Import .chan file')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setEvaluateOnChange(False)
    lastNode.import_chan_file = param
    del param
    param = lastNode.createSeparatorParam('sep', 'image mapping')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sep = param
    del param
    param = lastNode.createChoiceParam('STMap1filter', 'Filter')
    param.setDefaultValue(2)
    param.restoreDefaultValue()
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.set(0)
    lastNode.STMap1filter = param
    del param
    param = lastNode.createBooleanParam('backface', 'backface culling')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.backface = param
    del param
    param = lastNode.createDouble2DParam('STMap1uvOffset', 'UV Offset')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(1, 1)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvOffset = param
    del param
    param = lastNode.createDouble2DParam('STMap1uvScale', 'UV Scale')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(100, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(100, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvScale = param
    del param
    param = lastNode.createSeparatorParam('sepb', 'Motion Blur')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepb = param
    del param
    param = lastNode.createIntParam('blur_sample', 'Samples')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(0, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp(
        """motion blur is calculated by accumulation of various inter-frames.

This parameter set how many frames/samples to accumulate.

More sample = more calculation"""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.blur_sample = param
    del param
    param = lastNode.createDoubleParam('TimeBlur1shutter', 'Shutter')
    param.setMinimum(0, 0)
    param.setMaximum(2, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(2, 0)
    param.setDefaultValue(0.5, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutter = param
    del param
    param = lastNode.createDoubleParam('TimeBlur1shutterCustomOffset',
        'Custom Offset')
    param.setMinimum(-1, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(-1, 0)
    param.setDisplayMaximum(1, 0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutterCustomOffset = param
    del param
    param = lastNode.createSeparatorParam('sepc', '')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepc = param
    del param
    param = lastNode.createBooleanParam('Merge1enableMask_Mask', 'Mask')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.Merge1enableMask_Mask = param
    del param
    param = lastNode.createChoiceParam('Merge1maskChannel_Mask', '')
    param.setDefaultValue(4)
    param.restoreDefaultValue()
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskChannel_Mask = param
    del param
    param = lastNode.createBooleanParam('Merge1maskInvert', 'Invert Mask')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskInvert = param
    del param
    param = lastNode.createDoubleParam('Merge1mix', 'Mix')
    param.setMinimum(0, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.Merge1mix = param
    del param
    lastNode.transforms = lastNode.createPageParam('transforms', 'Transforms')
    param = lastNode.createSeparatorParam('sepe', 'Location')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepe = param
    del param
    param = lastNode.createDoubleParam('dlocx', 'X')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocx = param
    del param
    param = lastNode.createDoubleParam('locx', 'ChanX')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """X location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locx = param
    del param
    param = lastNode.createDoubleParam('dlocy', 'Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Y location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocy = param
    del param
    param = lastNode.createDoubleParam('locy', 'Chan Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Y location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locy = param
    del param
    param = lastNode.createDoubleParam('dlocz', 'Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Z location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocz = param
    del param
    param = lastNode.createDoubleParam('locz', 'Chan Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Z location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    param.setValue(-10, 0)
    lastNode.locz = param
    del param
    param = lastNode.createSeparatorParam('sepd', 'Rotation')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepd = param
    del param
    param = lastNode.createDoubleParam('drotx', 'X')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X rotation of the Plane, if you use the .chan import you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotx = param
    del param
    param = lastNode.createDoubleParam('rotx', 'ChanX')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X Rotation of the Card in 3D space used with the .chan import')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotx = param
    del param
    param = lastNode.createDoubleParam('droty', 'Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('Y rotation of the plane')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.droty = param
    del param
    param = lastNode.createDoubleParam('roty', 'ChanY')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('Y Rotation of the Card in 3D space')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.roty = param
    del param
    param = lastNode.createDoubleParam('drotz', 'Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotz = param
    del param
    param = lastNode.createDoubleParam('rotz', 'ChanZ')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Z Rotation of the Card in 3D space used with the .chan import')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotz = param
    del param
    param = lastNode.createSeparatorParam('sepf', 'Scale')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepf = param
    del param
    param = lastNode.createDouble2DParam('scale', 'X / Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setMinimum(-2147483648, 1)
    param.setMaximum(2147483647, 1)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(10, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Dimention of the Card in 3D space.
Best practice is to use this one to set the aspect ratio of the card, and the uniform scale to get the card the final scale."""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.setValue(1.92, 0)
    param.setValue(1.08, 1)
    lastNode.scale = param
    del param
    param = lastNode.createDoubleParam('scale_u', 'Uniform')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """this is an extra scaling factor to scale both X and Y,
Use the first to set the X and Y ratio of the card, and this one to set the global scale
"""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.scale_u = param
    del param
    lastNode.setPagesOrder(['Controls', 'transforms', 'Node'])
    lastNode.refreshUserParamsGUI()
    del lastNode
    lastNode = app.createNode('net.sf.openfx.Shadertoy', 1, group)
    lastNode.setScriptName('_Plane')
    lastNode.setLabel(' Plane')
    lastNode.setPosition(558, 465)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    group_Plane = lastNode
    param = lastNode.getParam('paramValueInt1')
    if param is not None:
        param.setValue(7, 0)
        del param
    param = lastNode.getParam('paramValueVec31')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(-10, 2)
        del param
    param = lastNode.getParam('paramValueVec32')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec23')
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        del param
    param = lastNode.getParam('paramValueVec33')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec34')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec35')
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        param.setValue(1, 2)
        del param
    param = lastNode.getParam('imageShaderPresetDir')
    if param is not None:
        param.setValue('')
        del param
    param = lastNode.getParam('imageShaderSource')
    if param is not None:
        param.setValue(
            """uniform bool backface = false ;
uniform vec3 pln_loc = vec3(0.0,0.,10.0);
uniform vec3 pln_rot = vec3(0.0);
uniform vec3 d_loc = vec3(0.0,0.,0.0);
uniform vec3 d_rot = vec3(0.0);

// scale X Y, and the last one is the uniform scale
uniform vec3 pln_scl = vec3(1.0); // scale


float M_PI = 3.14159265359 ;
float kEpsilon = 1e-8;
//float M_PI = 3.14159265358979323846264338327950288419;


float deg2rad(float deg)
 { return deg * M_PI / 180.0; }

mat4 mat3to4(mat3 m){
	return mat4(
		m[0][0],m[0][1],m[0][2],0,
		m[1][0],m[1][1],m[1][2],0,
		m[2][0],m[2][1],m[2][2],0,
		0,0,0,1);}
mat3 rotx(float x){
	return mat3 (
		1,     0,      0,
		0, cos(x), sin(x),
		0,-sin(x), cos(x));}
mat3 roty(float y){
	return mat3 (
		cos(y), 0,-sin(y),
		    0,  1,     0,
		sin(y), 0, cos(y));}
mat3 rotz(float z){
		return mat3 (
	   cos(z),sin(z),0,
		-sin(z),cos(z),0,
	    	 0,     0, 1);}

bool rayTriangleIntersect( vec3 orig, vec3 dir, vec3 v0, vec3 v1, vec3 v2, inout float t, inout float u, inout float v)
	{
		bool res = true ;
		vec3 v0v1 =vec3( v1 - v0);
		vec3 v0v2 =vec3( v2 - v0);
		vec3 pvec =vec3( cross(dir,v0v2));
		float det = dot(v0v1,pvec);

		float invDet = 1 / det;

		vec3 tvec =vec3( orig - v0);
		u = dot(tvec,pvec) * invDet;
		if (u < 0 || u > 1) res=false ;

		vec3 qvec =vec3( cross(tvec,v0v1));
		v = dot(dir,qvec) * invDet;
		if (v < 0 || u + v > 1) res =false;

		if (backface == true){
			if (det < kEpsilon){ res = false;};
		};

		t = dot(v0v2,qvec) * invDet;

		// position in z (if the plane is below the camera)
		if (t < 0 ) res=false;

		return res;
	}
mat4 getcam(vec2 def){
	mat4 cm;
	cm[0]=texture2D( iChannel0, vec2(8/def.x,6/def.y));
	cm[1]=texture2D( iChannel0, vec2(24/def.x,6/def.y));
	cm[2]=texture2D( iChannel0, vec2(8/def.x,20/def.y));
	cm[3]=texture2D( iChannel0, vec2(24/def.x,20/def.y));
	return cm;
	}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
		vec2 def = iChannelResolution[0].xy/iRenderScale.xy;
		mat4 cameraToWorld = getcam(def); // camera matrix
		vec4 cam = texture2D( iChannel0, vec2(8/def.x,34/def.y)); // fov , sensor_offset , shift.xy
		float Px = (2*(fragCoord.x / iResolution.x)-1) * cam.x * (iResolution.x / iResolution.y) ;
		float Py = (2*((fragCoord.y / iResolution.y)-0.5))* cam.x ;
	  vec3 rayOrigin=(cameraToWorld*vec4(0.0, 0., 0.,1)).xyz;
    vec3 rayPWorld=(cameraToWorld*vec4(Px, Py, cam.y,1)).xyz;
		vec3 rayDirection = normalize(rayPWorld-rayOrigin);
    vec3 ploc;
    mat4 drot;

    // PLANE vertex
    vec3 v0=vec3(-1, -1,0);
    vec3 v1=vec3( 1, -1, 0);
    vec3 v2=vec3( -1, 1, 0);
    vec3 v3=vec3( 1, 1, 0);

    //Plane scale
    v0.xy*=pln_scl.xy*pln_scl.z;
    v1.xy*=pln_scl.xy*pln_scl.z;
    v2.xy*=pln_scl.xy*pln_scl.z;
    v3.xy*=pln_scl.xy*pln_scl.z;

    //plane first transform (delta loc / rot) to avoid gimbal or rotational conflict
    drot=mat3to4(rotx(deg2rad(-d_rot.x)) * roty(deg2rad(-d_rot.y)) * rotz(deg2rad(-d_rot.z)));
    ploc=vec3(d_loc.x, d_loc.y, d_loc.z );
    v0=(vec4(v0,1)*drot).xyz+ploc;
    v1=(vec4(v1,1)*drot).xyz+ploc;
    v2=(vec4(v2,1)*drot).xyz+ploc;
    v3=(vec4(v3,1)*drot).xyz+ploc;


		// plane rotation matrix XYZ
		drot=mat3to4(rotx(deg2rad(-pln_rot.x)) * roty(deg2rad(-pln_rot.y)) * rotz(deg2rad(-pln_rot.z)));
		ploc=vec3(pln_loc.x, pln_loc.y, pln_loc.z );
		v0=(vec4(v0,1)*drot).xyz+ploc;
		v1=(vec4(v1,1)*drot).xyz+ploc;
		v2=(vec4(v2,1)*drot).xyz+ploc;
		v3=(vec4(v3,1)*drot).xyz+ploc;

			float t; float u; float v; vec4 res=vec4(0);
			res.b=100000000; // zbuffer

			if (rayTriangleIntersect(rayOrigin, rayDirection, v0, v2, v1, t, u, v)==true){
				res=vec4(v,1-u,t,1);
			}

			if (rayTriangleIntersect(rayOrigin, rayDirection, v3, v1, v2, t, u, v)==true){
				res=vec4(1-v,u,t,1);
			}

	fragColor=res.rgba;
}
"""
            )
        del param
    param = lastNode.getParam('inputEnable1')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('inputEnable2')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('inputEnable3')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('NatronParamFormatChoice')
    if param is not None:
        param.set('PC_Video 640x480')
        del param
    param = lastNode.getParam('mouseParams')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('paramCount')
    if param is not None:
        param.setValue(6, 0)
        del param
    param = lastNode.getParam('paramType0')
    if param is not None:
        param.set('bool')
        del param
    param = lastNode.getParam('paramName0')
    if param is not None:
        param.setValue('backface')
        del param
    param = lastNode.getParam('paramLabel0')
    if param is not None:
        param.setValue('backface')
        del param
    param = lastNode.getParam('paramType1')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName1')
    if param is not None:
        param.setValue('pln_loc')
        del param
    param = lastNode.getParam('paramLabel1')
    if param is not None:
        param.setValue('pln_loc')
        del param
    param = lastNode.getParam('paramDefaultVec31')
    if param is not None:
        param.setValue(10, 2)
        del param
    param = lastNode.getParam('paramType2')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName2')
    if param is not None:
        param.setValue('pln_rot')
        del param
    param = lastNode.getParam('paramLabel2')
    if param is not None:
        param.setValue('pln_rot')
        del param
    param = lastNode.getParam('paramType3')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName3')
    if param is not None:
        param.setValue('d_loc')
        del param
    param = lastNode.getParam('paramLabel3')
    if param is not None:
        param.setValue('d_loc')
        del param
    param = lastNode.getParam('paramType4')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName4')
    if param is not None:
        param.setValue('d_rot')
        del param
    param = lastNode.getParam('paramLabel4')
    if param is not None:
        param.setValue('d_rot')
        del param
    param = lastNode.getParam('paramType5')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName5')
    if param is not None:
        param.setValue('pln_scl')
        del param
    param = lastNode.getParam('paramLabel5')
    if param is not None:
        param.setValue('scale')
        del param
    param = lastNode.getParam('paramDefaultVec35')
    if param is not None:
        param.setValue(1, 0)
        param.setValue(1, 1)
        param.setValue(1, 2)
        del param
    param = lastNode.getParam('paramType6')
    if param is not None:
        param.set('float')
        del param
    param = lastNode.getParam('paramName6')
    if param is not None:
        param.setValue('sensor')
        del param
    param = lastNode.getParam('paramLabel6')
    if param is not None:
        param.setValue('sensor')
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.STMap', 2, group)
    lastNode.setScriptName('STMap1')
    lastNode.setLabel('STMap1')
    lastNode.setPosition(966, 465)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.7, 0.3, 0.1)
    groupSTMap1 = lastNode
    param = lastNode.getParam('channelUChoice')
    if param is not None:
        param.setValue('UV.r')
        del param
    param = lastNode.getParam('channelVChoice')
    if param is not None:
        param.setValue('UV.g')
        del param
    param = lastNode.getParam('channelAChoice')
    if param is not None:
        param.setValue('UV.a')
        del param
    param = lastNode.getParam('wrapU')
    if param is not None:
        param.set('Repeat')
        del param
    param = lastNode.getParam('wrapV')
    if param is not None:
        param.set('Repeat')
        del param
    param = lastNode.getParam('filter')
    if param is not None:
        param.set('Impulse')
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.TimeBlur', 1, group)
    lastNode.setScriptName('TimeBlur1')
    lastNode.setLabel('TimeBlur1')
    lastNode.setPosition(978, 588)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.7, 0.65, 0.35)
    groupTimeBlur1 = lastNode
    param = lastNode.getParam('division')
    if param is not None:
        param.setValue(1, 0)
        del param
    param = lastNode.getParam('shutterOffset')
    if param is not None:
        param.set('Custom')
        del param
    param = lastNode.getParam('disableNode')
    if param is not None:
        param.setValue(True)
        del param
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Camera')
    lastNode.setLabel('Camera')
    lastNode.setPosition(546, 17)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupCamera = lastNode
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Output', 1, group)
    lastNode.setLabel('Output1')
    lastNode.setPosition(546, 922)
    lastNode.setSize(104, 30)
    lastNode.setColor(0.7, 0.7, 0.7)
    groupOutput1 = lastNode
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Image')
    lastNode.setLabel('Image')
    lastNode.setPosition(966, 24)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupImage = lastNode
    del lastNode
    lastNode = app.createNode('net.sf.openfx.MergePlugin', 1, group)
    lastNode.setScriptName('Merge1')
    lastNode.setLabel('Merge1')
    lastNode.setPosition(969, 722)
    lastNode.setSize(104, 66)
    lastNode.setColor(0.3, 0.37, 0.776)
    groupMerge1 = lastNode
    param = lastNode.getParam('userTextArea')
    if param is not None:
        param.setValue('<Natron>(over)</Natron>')
        del param
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Mask')
    lastNode.setLabel('Mask')
    lastNode.setPosition(1197, 730)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupMask = lastNode
    param = lastNode.getParam('optional')
    if param is not None:
        param.setValue(True)
        del param
    param = lastNode.getParam('isMask')
    if param is not None:
        param.setValue(True)
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.ShufflePlugin', 2, group)
    lastNode.setScriptName('Zbuffer')
    lastNode.setLabel('Zbuffer')
    lastNode.setPosition(546, 734)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.6, 0.24, 0.39)
    lastNode.addUserPlane('Zbuf', ['R', 'G', 'B', 'A'])
    groupZbuffer = lastNode
    param = lastNode.getParam('outputChannels')
    if param is not None:
        param.set('Zbuf')
        del param
    param = lastNode.getParam('outputChannelsChoice')
    if param is not None:
        param.setValue('Zbuf')
        del param
    param = lastNode.getParam('outputRChoice')
    if param is not None:
        param.setValue('B.r')
        del param
    param = lastNode.getParam('outputGChoice')
    if param is not None:
        param.setValue('B.g')
        del param
    param = lastNode.getParam('outputBChoice')
    if param is not None:
        param.setValue('B.b')
        del param
    param = lastNode.getParam('outputAChoice')
    if param is not None:
        param.setValue('B.a')
        del param
    del lastNode
    group_Plane.connectInput(0, groupCamera)
    groupSTMap1.connectInput(0, group_Plane)
    groupSTMap1.connectInput(1, groupImage)
    groupTimeBlur1.connectInput(0, groupSTMap1)
    groupOutput1.connectInput(0, groupZbuffer)
    groupMerge1.connectInput(1, groupTimeBlur1)
    groupMerge1.connectInput(2, groupMask)
    groupZbuffer.connectInput(0, group_Plane)
    groupZbuffer.connectInput(1, groupMerge1)
    param = group_Plane.getParam('paramValueBool0')
    group.getParam('backface').setAsAlias(param)
    del param
    param = group_Plane.getParam('paramValueVec31')
    param.setExpression('thisGroup.locx.get()', False, 0)
    param.setExpression('thisGroup.locy.get()', False, 1)
    param.setExpression('thisGroup.locz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec32')
    param.setExpression('thisGroup.rotx.get()', False, 0)
    param.setExpression('thisGroup.roty.get()', False, 1)
    param.setExpression('thisGroup.rotz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec23')
    param.setExpression('thisGroup.scale.get().x', False, 0)
    param.setExpression('thisGroup.scale.get().y', False, 1)
    del param
    param = group_Plane.getParam('paramValueVec33')
    param.setExpression('thisGroup.dlocx.get()', False, 0)
    param.setExpression('thisGroup.dlocy.get()', False, 1)
    param.setExpression('thisGroup.dlocz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec34')
    param.setExpression('thisGroup.drotx.get()', False, 0)
    param.setExpression('thisGroup.droty.get()', False, 1)
    param.setExpression('thisGroup.drotz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec35')
    param.setExpression('thisGroup.scale.get().x', False, 0)
    param.setExpression('thisGroup.scale.get().y', False, 1)
    param.setExpression('thisGroup.scale_u.get()', False, 2)
    del param
    param = groupSTMap1.getParam('uvOffset')
    group.getParam('STMap1uvOffset').setAsAlias(param)
    del param
    param = groupSTMap1.getParam('uvScale')
    group.getParam('STMap1uvScale').setAsAlias(param)
    del param
    param = groupSTMap1.getParam('filter')
    group.getParam('STMap1filter').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('division')
    param.setExpression('thisGroup.blur_sample.get()', False, 0)
    del param
    param = groupTimeBlur1.getParam('shutter')
    group.getParam('TimeBlur1shutter').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('shutterCustomOffset')
    group.getParam('TimeBlur1shutterCustomOffset').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('disableNode')
    param.setExpression('thisGroup.blur_sample.get()==0', False, 0)
    del param
    param = groupMerge1.getParam('maskInvert')
    group.getParam('Merge1maskInvert').setAsAlias(param)
    del param
    param = groupMerge1.getParam('mix')
    group.getParam('Merge1mix').setAsAlias(param)
    del param
    param = groupMerge1.getParam('enableMask_Mask')
    group.getParam('Merge1enableMask_Mask').setAsAlias(param)
    del param
    param = groupMerge1.getParam('maskChannel_Mask')
    group.getParam('Merge1maskChannel_Mask').setAsAlias(param)
    del param
    try:
        extModule = sys.modules['PM_Card3DExt']
    except KeyError:
        extModule = None
    if extModule is not None and hasattr(extModule, 'createInstanceExt'
        ) and hasattr(extModule.createInstanceExt, '__call__'):
        extModule.createInstanceExt(app, group)

<mask token>
try:
    from PM_Card3DExt import *
except ImportError:
    pass


def getPluginID():
    return 'natron.community.plugins.PM_Card3D'


def getLabel():
    return 'PM_Card3D'


def getVersion():
    return 1


def getIconPath():
    return 'PM_Card3D.png'


def getGrouping():
    return 'Community/Transform'


def getPluginDescription():
    return """Create a 3D plane seen from the camera defined using the PM_Camera plugin.

CHAN file :
a chan file can be provided if you need to export the plane animation.
chan must have XYZ rotation order (no other rotation mode provided for now)

Zbuffer :
As long as the RGBA channels the pyplug generate a Z buffer. Look at the Zbuf.B channel .
Zbuf.R and Zbuf.G : UV coordinates to map the input image to.
Zbuf.B : the Z buffer if you want the plane to be integrate into another image using a Zcombine node.
Zbuf.A : the alpha of the image.
"""


def createInstance(app, group):
    lastNode = group
    param = lastNode.getParam('onParamChanged')
    if param is not None:
        param.setValue('PM_Card3D.plane_read_chan')
        del param
    lastNode.Controls = lastNode.createPageParam('Controls', 'Controls')
    param = lastNode.createSeparatorParam('sepa', 'chan importer')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepa = param
    del param
    param = lastNode.createFileParam('chan', 'chan file')
    param.setSequenceEnabled(False)
    lastNode.Controls.addParam(param)
    param.setHelp('Path of an optional .chan file to transform the plane.')
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.chan = param
    del param
    param = lastNode.createButtonParam('import_chan_file', 'Import .chan file')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setEvaluateOnChange(False)
    lastNode.import_chan_file = param
    del param
    param = lastNode.createSeparatorParam('sep', 'image mapping')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sep = param
    del param
    param = lastNode.createChoiceParam('STMap1filter', 'Filter')
    param.setDefaultValue(2)
    param.restoreDefaultValue()
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.set(0)
    lastNode.STMap1filter = param
    del param
    param = lastNode.createBooleanParam('backface', 'backface culling')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.backface = param
    del param
    param = lastNode.createDouble2DParam('STMap1uvOffset', 'UV Offset')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(1, 1)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvOffset = param
    del param
    param = lastNode.createDouble2DParam('STMap1uvScale', 'UV Scale')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(100, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(100, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvScale = param
    del param
    param = lastNode.createSeparatorParam('sepb', 'Motion Blur')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepb = param
    del param
    param = lastNode.createIntParam('blur_sample', 'Samples')
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(0, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp(
        """motion blur is calculated by accumulation of various inter-frames.

This parameter set how many frames/samples to accumulate.

More sample = more calculation"""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.blur_sample = param
    del param
    param = lastNode.createDoubleParam('TimeBlur1shutter', 'Shutter')
    param.setMinimum(0, 0)
    param.setMaximum(2, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(2, 0)
    param.setDefaultValue(0.5, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutter = param
    del param
    param = lastNode.createDoubleParam('TimeBlur1shutterCustomOffset',
        'Custom Offset')
    param.setMinimum(-1, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(-1, 0)
    param.setDisplayMaximum(1, 0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutterCustomOffset = param
    del param
    param = lastNode.createSeparatorParam('sepc', '')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepc = param
    del param
    param = lastNode.createBooleanParam('Merge1enableMask_Mask', 'Mask')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.Merge1enableMask_Mask = param
    del param
    param = lastNode.createChoiceParam('Merge1maskChannel_Mask', '')
    param.setDefaultValue(4)
    param.restoreDefaultValue()
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskChannel_Mask = param
    del param
    param = lastNode.createBooleanParam('Merge1maskInvert', 'Invert Mask')
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskInvert = param
    del param
    param = lastNode.createDoubleParam('Merge1mix', 'Mix')
    param.setMinimum(0, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    lastNode.Controls.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.Merge1mix = param
    del param
    lastNode.transforms = lastNode.createPageParam('transforms', 'Transforms')
    param = lastNode.createSeparatorParam('sepe', 'Location')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepe = param
    del param
    param = lastNode.createDoubleParam('dlocx', 'X')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocx = param
    del param
    param = lastNode.createDoubleParam('locx', 'ChanX')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """X location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locx = param
    del param
    param = lastNode.createDoubleParam('dlocy', 'Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Y location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocy = param
    del param
    param = lastNode.createDoubleParam('locy', 'Chan Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Y location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locy = param
    del param
    param = lastNode.createDoubleParam('dlocz', 'Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Z location of the plane , if you use .chan import then you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocz = param
    del param
    param = lastNode.createDoubleParam('locz', 'Chan Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Z location of the Card in 3D space, if you've imported a .chan file , then these value are animated.
Use the other X transform to offset the plane"""
        )
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    param.setValue(-10, 0)
    lastNode.locz = param
    del param
    param = lastNode.createSeparatorParam('sepd', 'Rotation')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepd = param
    del param
    param = lastNode.createDoubleParam('drotx', 'X')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X rotation of the Plane, if you use the .chan import you may want to use this to offset the plane'
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotx = param
    del param
    param = lastNode.createDoubleParam('rotx', 'ChanX')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'X Rotation of the Card in 3D space used with the .chan import')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotx = param
    del param
    param = lastNode.createDoubleParam('droty', 'Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('Y rotation of the plane')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.droty = param
    del param
    param = lastNode.createDoubleParam('roty', 'ChanY')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('Y Rotation of the Card in 3D space')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.roty = param
    del param
    param = lastNode.createDoubleParam('drotz', 'Z')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotz = param
    del param
    param = lastNode.createDoubleParam('rotz', 'ChanZ')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        'Z Rotation of the Card in 3D space used with the .chan import')
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotz = param
    del param
    param = lastNode.createSeparatorParam('sepf', 'Scale')
    lastNode.transforms.addParam(param)
    param.setHelp('')
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepf = param
    del param
    param = lastNode.createDouble2DParam('scale', 'X / Y')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setMinimum(-2147483648, 1)
    param.setMaximum(2147483647, 1)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(10, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """Dimention of the Card in 3D space.
Best practice is to use this one to set the aspect ratio of the card, and the uniform scale to get the card the final scale."""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.setValue(1.92, 0)
    param.setValue(1.08, 1)
    lastNode.scale = param
    del param
    param = lastNode.createDoubleParam('scale_u', 'Uniform')
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    lastNode.transforms.addParam(param)
    param.setHelp(
        """this is an extra scaling factor to scale both X and Y,
Use the first to set the X and Y ratio of the card, and this one to set the global scale
"""
        )
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.scale_u = param
    del param
    lastNode.setPagesOrder(['Controls', 'transforms', 'Node'])
    lastNode.refreshUserParamsGUI()
    del lastNode
    lastNode = app.createNode('net.sf.openfx.Shadertoy', 1, group)
    lastNode.setScriptName('_Plane')
    lastNode.setLabel(' Plane')
    lastNode.setPosition(558, 465)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    group_Plane = lastNode
    param = lastNode.getParam('paramValueInt1')
    if param is not None:
        param.setValue(7, 0)
        del param
    param = lastNode.getParam('paramValueVec31')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(-10, 2)
        del param
    param = lastNode.getParam('paramValueVec32')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec23')
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        del param
    param = lastNode.getParam('paramValueVec33')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec34')
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param
    param = lastNode.getParam('paramValueVec35')
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        param.setValue(1, 2)
        del param
    param = lastNode.getParam('imageShaderPresetDir')
    if param is not None:
        param.setValue('')
        del param
    param = lastNode.getParam('imageShaderSource')
    if param is not None:
        param.setValue(
            """uniform bool backface = false ;
uniform vec3 pln_loc = vec3(0.0,0.,10.0);
uniform vec3 pln_rot = vec3(0.0);
uniform vec3 d_loc = vec3(0.0,0.,0.0);
uniform vec3 d_rot = vec3(0.0);

// scale X Y, and the last one is the uniform scale
uniform vec3 pln_scl = vec3(1.0); // scale


float M_PI = 3.14159265359 ;
float kEpsilon = 1e-8;
//float M_PI = 3.14159265358979323846264338327950288419;


float deg2rad(float deg)
 { return deg * M_PI / 180.0; }

mat4 mat3to4(mat3 m){
	return mat4(
		m[0][0],m[0][1],m[0][2],0,
		m[1][0],m[1][1],m[1][2],0,
		m[2][0],m[2][1],m[2][2],0,
		0,0,0,1);}
mat3 rotx(float x){
	return mat3 (
		1,     0,      0,
		0, cos(x), sin(x),
		0,-sin(x), cos(x));}
mat3 roty(float y){
	return mat3 (
		cos(y), 0,-sin(y),
		    0,  1,     0,
		sin(y), 0, cos(y));}
mat3 rotz(float z){
		return mat3 (
	   cos(z),sin(z),0,
		-sin(z),cos(z),0,
	    	 0,     0, 1);}

bool rayTriangleIntersect( vec3 orig, vec3 dir, vec3 v0, vec3 v1, vec3 v2, inout float t, inout float u, inout float v)
	{
		bool res = true ;
		vec3 v0v1 =vec3( v1 - v0);
		vec3 v0v2 =vec3( v2 - v0);
		vec3 pvec =vec3( cross(dir,v0v2));
		float det = dot(v0v1,pvec);

		float invDet = 1 / det;

		vec3 tvec =vec3( orig - v0);
		u = dot(tvec,pvec) * invDet;
		if (u < 0 || u > 1) res=false ;

		vec3 qvec =vec3( cross(tvec,v0v1));
		v = dot(dir,qvec) * invDet;
		if (v < 0 || u + v > 1) res =false;

		if (backface == true){
			if (det < kEpsilon){ res = false;};
		};

		t = dot(v0v2,qvec) * invDet;

		// position in z (if the plane is below the camera)
		if (t < 0 ) res=false;

		return res;
	}
mat4 getcam(vec2 def){
	mat4 cm;
	cm[0]=texture2D( iChannel0, vec2(8/def.x,6/def.y));
	cm[1]=texture2D( iChannel0, vec2(24/def.x,6/def.y));
	cm[2]=texture2D( iChannel0, vec2(8/def.x,20/def.y));
	cm[3]=texture2D( iChannel0, vec2(24/def.x,20/def.y));
	return cm;
	}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
		vec2 def = iChannelResolution[0].xy/iRenderScale.xy;
		mat4 cameraToWorld = getcam(def); // camera matrix
		vec4 cam = texture2D( iChannel0, vec2(8/def.x,34/def.y)); // fov , sensor_offset , shift.xy
		float Px = (2*(fragCoord.x / iResolution.x)-1) * cam.x * (iResolution.x / iResolution.y) ;
		float Py = (2*((fragCoord.y / iResolution.y)-0.5))* cam.x ;
	  vec3 rayOrigin=(cameraToWorld*vec4(0.0, 0., 0.,1)).xyz;
    vec3 rayPWorld=(cameraToWorld*vec4(Px, Py, cam.y,1)).xyz;
		vec3 rayDirection = normalize(rayPWorld-rayOrigin);
    vec3 ploc;
    mat4 drot;

    // PLANE vertex
    vec3 v0=vec3(-1, -1,0);
    vec3 v1=vec3( 1, -1, 0);
    vec3 v2=vec3( -1, 1, 0);
    vec3 v3=vec3( 1, 1, 0);

    //Plane scale
    v0.xy*=pln_scl.xy*pln_scl.z;
    v1.xy*=pln_scl.xy*pln_scl.z;
    v2.xy*=pln_scl.xy*pln_scl.z;
    v3.xy*=pln_scl.xy*pln_scl.z;

    //plane first transform (delta loc / rot) to avoid gimbal or rotational conflict
    drot=mat3to4(rotx(deg2rad(-d_rot.x)) * roty(deg2rad(-d_rot.y)) * rotz(deg2rad(-d_rot.z)));
    ploc=vec3(d_loc.x, d_loc.y, d_loc.z );
    v0=(vec4(v0,1)*drot).xyz+ploc;
    v1=(vec4(v1,1)*drot).xyz+ploc;
    v2=(vec4(v2,1)*drot).xyz+ploc;
    v3=(vec4(v3,1)*drot).xyz+ploc;


		// plane rotation matrix XYZ
		drot=mat3to4(rotx(deg2rad(-pln_rot.x)) * roty(deg2rad(-pln_rot.y)) * rotz(deg2rad(-pln_rot.z)));
		ploc=vec3(pln_loc.x, pln_loc.y, pln_loc.z );
		v0=(vec4(v0,1)*drot).xyz+ploc;
		v1=(vec4(v1,1)*drot).xyz+ploc;
		v2=(vec4(v2,1)*drot).xyz+ploc;
		v3=(vec4(v3,1)*drot).xyz+ploc;

			float t; float u; float v; vec4 res=vec4(0);
			res.b=100000000; // zbuffer

			if (rayTriangleIntersect(rayOrigin, rayDirection, v0, v2, v1, t, u, v)==true){
				res=vec4(v,1-u,t,1);
			}

			if (rayTriangleIntersect(rayOrigin, rayDirection, v3, v1, v2, t, u, v)==true){
				res=vec4(1-v,u,t,1);
			}

	fragColor=res.rgba;
}
"""
            )
        del param
    param = lastNode.getParam('inputEnable1')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('inputEnable2')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('inputEnable3')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('NatronParamFormatChoice')
    if param is not None:
        param.set('PC_Video 640x480')
        del param
    param = lastNode.getParam('mouseParams')
    if param is not None:
        param.setValue(False)
        del param
    param = lastNode.getParam('paramCount')
    if param is not None:
        param.setValue(6, 0)
        del param
    param = lastNode.getParam('paramType0')
    if param is not None:
        param.set('bool')
        del param
    param = lastNode.getParam('paramName0')
    if param is not None:
        param.setValue('backface')
        del param
    param = lastNode.getParam('paramLabel0')
    if param is not None:
        param.setValue('backface')
        del param
    param = lastNode.getParam('paramType1')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName1')
    if param is not None:
        param.setValue('pln_loc')
        del param
    param = lastNode.getParam('paramLabel1')
    if param is not None:
        param.setValue('pln_loc')
        del param
    param = lastNode.getParam('paramDefaultVec31')
    if param is not None:
        param.setValue(10, 2)
        del param
    param = lastNode.getParam('paramType2')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName2')
    if param is not None:
        param.setValue('pln_rot')
        del param
    param = lastNode.getParam('paramLabel2')
    if param is not None:
        param.setValue('pln_rot')
        del param
    param = lastNode.getParam('paramType3')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName3')
    if param is not None:
        param.setValue('d_loc')
        del param
    param = lastNode.getParam('paramLabel3')
    if param is not None:
        param.setValue('d_loc')
        del param
    param = lastNode.getParam('paramType4')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName4')
    if param is not None:
        param.setValue('d_rot')
        del param
    param = lastNode.getParam('paramLabel4')
    if param is not None:
        param.setValue('d_rot')
        del param
    param = lastNode.getParam('paramType5')
    if param is not None:
        param.set('vec3')
        del param
    param = lastNode.getParam('paramName5')
    if param is not None:
        param.setValue('pln_scl')
        del param
    param = lastNode.getParam('paramLabel5')
    if param is not None:
        param.setValue('scale')
        del param
    param = lastNode.getParam('paramDefaultVec35')
    if param is not None:
        param.setValue(1, 0)
        param.setValue(1, 1)
        param.setValue(1, 2)
        del param
    param = lastNode.getParam('paramType6')
    if param is not None:
        param.set('float')
        del param
    param = lastNode.getParam('paramName6')
    if param is not None:
        param.setValue('sensor')
        del param
    param = lastNode.getParam('paramLabel6')
    if param is not None:
        param.setValue('sensor')
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.STMap', 2, group)
    lastNode.setScriptName('STMap1')
    lastNode.setLabel('STMap1')
    lastNode.setPosition(966, 465)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.7, 0.3, 0.1)
    groupSTMap1 = lastNode
    param = lastNode.getParam('channelUChoice')
    if param is not None:
        param.setValue('UV.r')
        del param
    param = lastNode.getParam('channelVChoice')
    if param is not None:
        param.setValue('UV.g')
        del param
    param = lastNode.getParam('channelAChoice')
    if param is not None:
        param.setValue('UV.a')
        del param
    param = lastNode.getParam('wrapU')
    if param is not None:
        param.set('Repeat')
        del param
    param = lastNode.getParam('wrapV')
    if param is not None:
        param.set('Repeat')
        del param
    param = lastNode.getParam('filter')
    if param is not None:
        param.set('Impulse')
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.TimeBlur', 1, group)
    lastNode.setScriptName('TimeBlur1')
    lastNode.setLabel('TimeBlur1')
    lastNode.setPosition(978, 588)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.7, 0.65, 0.35)
    groupTimeBlur1 = lastNode
    param = lastNode.getParam('division')
    if param is not None:
        param.setValue(1, 0)
        del param
    param = lastNode.getParam('shutterOffset')
    if param is not None:
        param.set('Custom')
        del param
    param = lastNode.getParam('disableNode')
    if param is not None:
        param.setValue(True)
        del param
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Camera')
    lastNode.setLabel('Camera')
    lastNode.setPosition(546, 17)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupCamera = lastNode
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Output', 1, group)
    lastNode.setLabel('Output1')
    lastNode.setPosition(546, 922)
    lastNode.setSize(104, 30)
    lastNode.setColor(0.7, 0.7, 0.7)
    groupOutput1 = lastNode
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Image')
    lastNode.setLabel('Image')
    lastNode.setPosition(966, 24)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupImage = lastNode
    del lastNode
    lastNode = app.createNode('net.sf.openfx.MergePlugin', 1, group)
    lastNode.setScriptName('Merge1')
    lastNode.setLabel('Merge1')
    lastNode.setPosition(969, 722)
    lastNode.setSize(104, 66)
    lastNode.setColor(0.3, 0.37, 0.776)
    groupMerge1 = lastNode
    param = lastNode.getParam('userTextArea')
    if param is not None:
        param.setValue('<Natron>(over)</Natron>')
        del param
    del lastNode
    lastNode = app.createNode('fr.inria.built-in.Input', 1, group)
    lastNode.setScriptName('Mask')
    lastNode.setLabel('Mask')
    lastNode.setPosition(1197, 730)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupMask = lastNode
    param = lastNode.getParam('optional')
    if param is not None:
        param.setValue(True)
        del param
    param = lastNode.getParam('isMask')
    if param is not None:
        param.setValue(True)
        del param
    del lastNode
    lastNode = app.createNode('net.sf.openfx.ShufflePlugin', 2, group)
    lastNode.setScriptName('Zbuffer')
    lastNode.setLabel('Zbuffer')
    lastNode.setPosition(546, 734)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.6, 0.24, 0.39)
    lastNode.addUserPlane('Zbuf', ['R', 'G', 'B', 'A'])
    groupZbuffer = lastNode
    param = lastNode.getParam('outputChannels')
    if param is not None:
        param.set('Zbuf')
        del param
    param = lastNode.getParam('outputChannelsChoice')
    if param is not None:
        param.setValue('Zbuf')
        del param
    param = lastNode.getParam('outputRChoice')
    if param is not None:
        param.setValue('B.r')
        del param
    param = lastNode.getParam('outputGChoice')
    if param is not None:
        param.setValue('B.g')
        del param
    param = lastNode.getParam('outputBChoice')
    if param is not None:
        param.setValue('B.b')
        del param
    param = lastNode.getParam('outputAChoice')
    if param is not None:
        param.setValue('B.a')
        del param
    del lastNode
    group_Plane.connectInput(0, groupCamera)
    groupSTMap1.connectInput(0, group_Plane)
    groupSTMap1.connectInput(1, groupImage)
    groupTimeBlur1.connectInput(0, groupSTMap1)
    groupOutput1.connectInput(0, groupZbuffer)
    groupMerge1.connectInput(1, groupTimeBlur1)
    groupMerge1.connectInput(2, groupMask)
    groupZbuffer.connectInput(0, group_Plane)
    groupZbuffer.connectInput(1, groupMerge1)
    param = group_Plane.getParam('paramValueBool0')
    group.getParam('backface').setAsAlias(param)
    del param
    param = group_Plane.getParam('paramValueVec31')
    param.setExpression('thisGroup.locx.get()', False, 0)
    param.setExpression('thisGroup.locy.get()', False, 1)
    param.setExpression('thisGroup.locz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec32')
    param.setExpression('thisGroup.rotx.get()', False, 0)
    param.setExpression('thisGroup.roty.get()', False, 1)
    param.setExpression('thisGroup.rotz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec23')
    param.setExpression('thisGroup.scale.get().x', False, 0)
    param.setExpression('thisGroup.scale.get().y', False, 1)
    del param
    param = group_Plane.getParam('paramValueVec33')
    param.setExpression('thisGroup.dlocx.get()', False, 0)
    param.setExpression('thisGroup.dlocy.get()', False, 1)
    param.setExpression('thisGroup.dlocz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec34')
    param.setExpression('thisGroup.drotx.get()', False, 0)
    param.setExpression('thisGroup.droty.get()', False, 1)
    param.setExpression('thisGroup.drotz.get()', False, 2)
    del param
    param = group_Plane.getParam('paramValueVec35')
    param.setExpression('thisGroup.scale.get().x', False, 0)
    param.setExpression('thisGroup.scale.get().y', False, 1)
    param.setExpression('thisGroup.scale_u.get()', False, 2)
    del param
    param = groupSTMap1.getParam('uvOffset')
    group.getParam('STMap1uvOffset').setAsAlias(param)
    del param
    param = groupSTMap1.getParam('uvScale')
    group.getParam('STMap1uvScale').setAsAlias(param)
    del param
    param = groupSTMap1.getParam('filter')
    group.getParam('STMap1filter').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('division')
    param.setExpression('thisGroup.blur_sample.get()', False, 0)
    del param
    param = groupTimeBlur1.getParam('shutter')
    group.getParam('TimeBlur1shutter').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('shutterCustomOffset')
    group.getParam('TimeBlur1shutterCustomOffset').setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam('disableNode')
    param.setExpression('thisGroup.blur_sample.get()==0', False, 0)
    del param
    param = groupMerge1.getParam('maskInvert')
    group.getParam('Merge1maskInvert').setAsAlias(param)
    del param
    param = groupMerge1.getParam('mix')
    group.getParam('Merge1mix').setAsAlias(param)
    del param
    param = groupMerge1.getParam('enableMask_Mask')
    group.getParam('Merge1enableMask_Mask').setAsAlias(param)
    del param
    param = groupMerge1.getParam('maskChannel_Mask')
    group.getParam('Merge1maskChannel_Mask').setAsAlias(param)
    del param
    try:
        extModule = sys.modules['PM_Card3DExt']
    except KeyError:
        extModule = None
    if extModule is not None and hasattr(extModule, 'createInstanceExt'
        ) and hasattr(extModule.createInstanceExt, '__call__'):
        extModule.createInstanceExt(app, group)

# -*- coding: utf-8 -*-
# DO NOT EDIT THIS FILE
# This file was automatically generated by Natron PyPlug exporter version 10.

# Hand-written code should be added in a separate file named PM_Card3DExt.py
# See http://natron.readthedocs.org/en/master/groups.html#adding-hand-written-code-callbacks-etc
# Note that Viewers are never exported

import NatronEngine
import sys

# Try to import the extensions file where callbacks and hand-written code should be located.
try:
    from PM_Card3DExt import *
except ImportError:
    pass

def getPluginID():
    return "natron.community.plugins.PM_Card3D"

def getLabel():
    return "PM_Card3D"

def getVersion():
    return 1

def getIconPath():
    return "PM_Card3D.png"

def getGrouping():
    return "Community/Transform"

def getPluginDescription():
    return "Create a 3D plane seen from the camera defined using the PM_Camera plugin.\n\nCHAN file :\na chan file can be provided if you need to export the plane animation.\nchan must have XYZ rotation order (no other rotation mode provided for now)\n\nZbuffer :\nAs long as the RGBA channels the pyplug generate a Z buffer. Look at the Zbuf.B channel .\nZbuf.R and Zbuf.G : UV coordinates to map the input image to.\nZbuf.B : the Z buffer if you want the plane to be integrate into another image using a Zcombine node.\nZbuf.A : the alpha of the image.\n"

def createInstance(app,group):
    # Create all nodes in the group

    # Create the parameters of the group node the same way we did for all internal nodes
    lastNode = group
    param = lastNode.getParam("onParamChanged")
    if param is not None:
        param.setValue("PM_Card3D.plane_read_chan")
        del param


    # Create the user parameters
    lastNode.Controls = lastNode.createPageParam("Controls", "Controls")
    param = lastNode.createSeparatorParam("sepa", "chan importer")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepa = param
    del param

    param = lastNode.createFileParam("chan", "chan file")
    param.setSequenceEnabled(False)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("Path of an optional .chan file to transform the plane.")
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.chan = param
    del param

    param = lastNode.createButtonParam("import_chan_file", "Import .chan file")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(False)
    param.setEvaluateOnChange(False)
    lastNode.import_chan_file = param
    del param

    param = lastNode.createSeparatorParam("sep", "image mapping")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sep = param
    del param

    param = lastNode.createChoiceParam("STMap1filter", "Filter")
    param.setDefaultValue(2)
    param.restoreDefaultValue()

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.set(0)
    lastNode.STMap1filter = param
    del param

    param = lastNode.createBooleanParam("backface", "backface culling")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.backface = param
    del param

    param = lastNode.createDouble2DParam("STMap1uvOffset", "UV Offset")
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(1, 1)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvOffset = param
    del param

    param = lastNode.createDouble2DParam("STMap1uvScale", "UV Scale")
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(100, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(100, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.STMap1uvScale = param
    del param

    param = lastNode.createSeparatorParam("sepb", "Motion Blur")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepb = param
    del param

    param = lastNode.createIntParam("blur_sample", "Samples")
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(0, 0)
    param.restoreDefaultValue(0)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("motion blur is calculated by accumulation of various inter-frames.\n\nThis parameter set how many frames/samples to accumulate.\n\nMore sample = more calculation")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.blur_sample = param
    del param

    param = lastNode.createDoubleParam("TimeBlur1shutter", "Shutter")
    param.setMinimum(0, 0)
    param.setMaximum(2, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(2, 0)
    param.setDefaultValue(0.5, 0)
    param.restoreDefaultValue(0)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutter = param
    del param

    param = lastNode.createDoubleParam("TimeBlur1shutterCustomOffset", "Custom Offset")
    param.setMinimum(-1, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(-1, 0)
    param.setDisplayMaximum(1, 0)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.TimeBlur1shutterCustomOffset = param
    del param

    param = lastNode.createSeparatorParam("sepc", "")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepc = param
    del param

    param = lastNode.createBooleanParam("Merge1enableMask_Mask", "Mask")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(False)
    lastNode.Merge1enableMask_Mask = param
    del param

    param = lastNode.createChoiceParam("Merge1maskChannel_Mask", "")
    param.setDefaultValue(4)
    param.restoreDefaultValue()

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskChannel_Mask = param
    del param

    param = lastNode.createBooleanParam("Merge1maskInvert", "Invert Mask")

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(False)
    param.setAnimationEnabled(False)
    lastNode.Merge1maskInvert = param
    del param

    param = lastNode.createDoubleParam("Merge1mix", "Mix")
    param.setMinimum(0, 0)
    param.setMaximum(1, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(1, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)

    # Add the param to the page
    lastNode.Controls.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.Merge1mix = param
    del param

    lastNode.transforms = lastNode.createPageParam("transforms", "Transforms")
    param = lastNode.createSeparatorParam("sepe", "Location")

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepe = param
    del param

    param = lastNode.createDoubleParam("dlocx", "X")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("X location of the plane , if you use .chan import then you may want to use this to offset the plane")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocx = param
    del param

    param = lastNode.createDoubleParam("locx", "ChanX")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("X location of the Card in 3D space, if you\'ve imported a .chan file , then these value are animated.\nUse the other X transform to offset the plane")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locx = param
    del param

    param = lastNode.createDoubleParam("dlocy", "Y")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Y location of the plane , if you use .chan import then you may want to use this to offset the plane")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocy = param
    del param

    param = lastNode.createDoubleParam("locy", "Chan Y")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Y location of the Card in 3D space, if you\'ve imported a .chan file , then these value are animated.\nUse the other X transform to offset the plane")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.locy = param
    del param

    param = lastNode.createDoubleParam("dlocz", "Z")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Z location of the plane , if you use .chan import then you may want to use this to offset the plane")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.dlocz = param
    del param

    param = lastNode.createDoubleParam("locz", "Chan Z")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-100, 0)
    param.setDisplayMaximum(100, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Z location of the Card in 3D space, if you\'ve imported a .chan file , then these value are animated.\nUse the other X transform to offset the plane")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    param.setValue(-10, 0)
    lastNode.locz = param
    del param

    param = lastNode.createSeparatorParam("sepd", "Rotation")

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepd = param
    del param

    param = lastNode.createDoubleParam("drotx", "X")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("X rotation of the Plane, if you use the .chan import you may want to use this to offset the plane")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotx = param
    del param

    param = lastNode.createDoubleParam("rotx", "ChanX")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("X Rotation of the Card in 3D space used with the .chan import")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotx = param
    del param

    param = lastNode.createDoubleParam("droty", "Y")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Y rotation of the plane")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.droty = param
    del param

    param = lastNode.createDoubleParam("roty", "ChanY")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Y Rotation of the Card in 3D space")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.roty = param
    del param

    param = lastNode.createDoubleParam("drotz", "Z")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.drotz = param
    del param

    param = lastNode.createDoubleParam("rotz", "ChanZ")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(-180, 0)
    param.setDisplayMaximum(180, 0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Z Rotation of the Card in 3D space used with the .chan import")
    param.setAddNewLine(False)
    param.setAnimationEnabled(True)
    lastNode.rotz = param
    del param

    param = lastNode.createSeparatorParam("sepf", "Scale")

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("")
    param.setAddNewLine(True)
    param.setPersistent(False)
    param.setEvaluateOnChange(False)
    lastNode.sepf = param
    del param

    param = lastNode.createDouble2DParam("scale", "X / Y")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)
    param.setMinimum(-2147483648, 1)
    param.setMaximum(2147483647, 1)
    param.setDisplayMinimum(0, 1)
    param.setDisplayMaximum(10, 1)
    param.setDefaultValue(1, 1)
    param.restoreDefaultValue(1)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("Dimention of the Card in 3D space.\nBest practice is to use this one to set the aspect ratio of the card, and the uniform scale to get the card the final scale.")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    param.setValue(1.92, 0)
    param.setValue(1.08, 1)
    lastNode.scale = param
    del param

    param = lastNode.createDoubleParam("scale_u", "Uniform")
    param.setMinimum(-2147483648, 0)
    param.setMaximum(2147483647, 0)
    param.setDisplayMinimum(0, 0)
    param.setDisplayMaximum(10, 0)
    param.setDefaultValue(1, 0)
    param.restoreDefaultValue(0)

    # Add the param to the page
    lastNode.transforms.addParam(param)

    # Set param properties
    param.setHelp("this is an extra scaling factor to scale both X and Y,\nUse the first to set the X and Y ratio of the card, and this one to set the global scale\n")
    param.setAddNewLine(True)
    param.setAnimationEnabled(True)
    lastNode.scale_u = param
    del param

    # Refresh the GUI with the newly created parameters
    lastNode.setPagesOrder(['Controls', 'transforms', 'Node'])
    lastNode.refreshUserParamsGUI()
    del lastNode

    # Start of node "_Plane"
    lastNode = app.createNode("net.sf.openfx.Shadertoy", 1, group)
    lastNode.setScriptName("_Plane")
    lastNode.setLabel(" Plane")
    lastNode.setPosition(558, 465)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    group_Plane = lastNode

    param = lastNode.getParam("paramValueInt1")
    if param is not None:
        param.setValue(7, 0)
        del param

    param = lastNode.getParam("paramValueVec31")
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(-10, 2)
        del param

    param = lastNode.getParam("paramValueVec32")
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param

    param = lastNode.getParam("paramValueVec23")
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        del param

    param = lastNode.getParam("paramValueVec33")
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param

    param = lastNode.getParam("paramValueVec34")
    if param is not None:
        param.setValue(0, 0)
        param.setValue(0, 1)
        param.setValue(0, 2)
        del param

    param = lastNode.getParam("paramValueVec35")
    if param is not None:
        param.setValue(1.92, 0)
        param.setValue(1.08, 1)
        param.setValue(1, 2)
        del param

    param = lastNode.getParam("imageShaderPresetDir")
    if param is not None:
        param.setValue("")
        del param

    param = lastNode.getParam("imageShaderSource")
    if param is not None:
        param.setValue("uniform bool backface = false ;\nuniform vec3 pln_loc = vec3(0.0,0.,10.0);\nuniform vec3 pln_rot = vec3(0.0);\nuniform vec3 d_loc = vec3(0.0,0.,0.0);\nuniform vec3 d_rot = vec3(0.0);\n\n// scale X Y, and the last one is the uniform scale\nuniform vec3 pln_scl = vec3(1.0); // scale\n\n\nfloat M_PI = 3.14159265359 ;\nfloat kEpsilon = 1e-8;\n//float M_PI = 3.14159265358979323846264338327950288419;\n\n\nfloat deg2rad(float deg)\n { return deg * M_PI / 180.0; }\n\nmat4 mat3to4(mat3 m){\n\treturn mat4(\n\t\tm[0][0],m[0][1],m[0][2],0,\n\t\tm[1][0],m[1][1],m[1][2],0,\n\t\tm[2][0],m[2][1],m[2][2],0,\n\t\t0,0,0,1);}\nmat3 rotx(float x){\n\treturn mat3 (\n\t\t1,     0,      0,\n\t\t0, cos(x), sin(x),\n\t\t0,-sin(x), cos(x));}\nmat3 roty(float y){\n\treturn mat3 (\n\t\tcos(y), 0,-sin(y),\n\t\t    0,  1,     0,\n\t\tsin(y), 0, cos(y));}\nmat3 rotz(float z){\n\t\treturn mat3 (\n\t   cos(z),sin(z),0,\n\t\t-sin(z),cos(z),0,\n\t    \t 0,     0, 1);}\n\nbool rayTriangleIntersect( vec3 orig, vec3 dir, vec3 v0, vec3 v1, vec3 v2, inout float t, inout float u, inout float v)\n\t{\n\t\tbool res = true ;\n\t\tvec3 v0v1 =vec3( v1 - v0);\n\t\tvec3 v0v2 =vec3( v2 - v0);\n\t\tvec3 pvec =vec3( cross(dir,v0v2));\n\t\tfloat det = dot(v0v1,pvec);\n\n\t\tfloat invDet = 1 / det;\n\n\t\tvec3 tvec =vec3( orig - v0);\n\t\tu = dot(tvec,pvec) * invDet;\n\t\tif (u < 0 || u > 1) res=false ;\n\n\t\tvec3 qvec =vec3( cross(tvec,v0v1));\n\t\tv = dot(dir,qvec) * invDet;\n\t\tif (v < 0 || u + v > 1) res =false;\n\n\t\tif (backface == true){\n\t\t\tif (det < kEpsilon){ res = false;};\n\t\t};\n\n\t\tt = dot(v0v2,qvec) * invDet;\n\n\t\t// position in z (if the plane is below the camera)\n\t\tif (t < 0 ) res=false;\n\n\t\treturn res;\n\t}\nmat4 getcam(vec2 def){\n\tmat4 cm;\n\tcm[0]=texture2D( iChannel0, vec2(8/def.x,6/def.y));\n\tcm[1]=texture2D( iChannel0, vec2(24/def.x,6/def.y));\n\tcm[2]=texture2D( iChannel0, vec2(8/def.x,20/def.y));\n\tcm[3]=texture2D( iChannel0, vec2(24/def.x,20/def.y));\n\treturn cm;\n\t}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\t\tvec2 def = iChannelResolution[0].xy/iRenderScale.xy;\n\t\tmat4 cameraToWorld = getcam(def); // camera matrix\n\t\tvec4 cam = texture2D( iChannel0, vec2(8/def.x,34/def.y)); // fov , sensor_offset , shift.xy\n\t\tfloat Px = (2*(fragCoord.x / iResolution.x)-1) * cam.x * (iResolution.x / iResolution.y) ;\n\t\tfloat Py = (2*((fragCoord.y / iResolution.y)-0.5))* cam.x ;\n\t  vec3 rayOrigin=(cameraToWorld*vec4(0.0, 0., 0.,1)).xyz;\n    vec3 rayPWorld=(cameraToWorld*vec4(Px, Py, cam.y,1)).xyz;\n\t\tvec3 rayDirection = normalize(rayPWorld-rayOrigin);\n    vec3 ploc;\n    mat4 drot;\n\n    // PLANE vertex\n    vec3 v0=vec3(-1, -1,0);\n    vec3 v1=vec3( 1, -1, 0);\n    vec3 v2=vec3( -1, 1, 0);\n    vec3 v3=vec3( 1, 1, 0);\n\n    //Plane scale\n    v0.xy*=pln_scl.xy*pln_scl.z;\n    v1.xy*=pln_scl.xy*pln_scl.z;\n    v2.xy*=pln_scl.xy*pln_scl.z;\n    v3.xy*=pln_scl.xy*pln_scl.z;\n\n    //plane first transform (delta loc / rot) to avoid gimbal or rotational conflict\n    drot=mat3to4(rotx(deg2rad(-d_rot.x)) * roty(deg2rad(-d_rot.y)) * rotz(deg2rad(-d_rot.z)));\n    ploc=vec3(d_loc.x, d_loc.y, d_loc.z );\n    v0=(vec4(v0,1)*drot).xyz+ploc;\n    v1=(vec4(v1,1)*drot).xyz+ploc;\n    v2=(vec4(v2,1)*drot).xyz+ploc;\n    v3=(vec4(v3,1)*drot).xyz+ploc;\n\n\n\t\t// plane rotation matrix XYZ\n\t\tdrot=mat3to4(rotx(deg2rad(-pln_rot.x)) * roty(deg2rad(-pln_rot.y)) * rotz(deg2rad(-pln_rot.z)));\n\t\tploc=vec3(pln_loc.x, pln_loc.y, pln_loc.z );\n\t\tv0=(vec4(v0,1)*drot).xyz+ploc;\n\t\tv1=(vec4(v1,1)*drot).xyz+ploc;\n\t\tv2=(vec4(v2,1)*drot).xyz+ploc;\n\t\tv3=(vec4(v3,1)*drot).xyz+ploc;\n\n\t\t\tfloat t; float u; float v; vec4 res=vec4(0);\n\t\t\tres.b=100000000; // zbuffer\n\n\t\t\tif (rayTriangleIntersect(rayOrigin, rayDirection, v0, v2, v1, t, u, v)==true){\n\t\t\t\tres=vec4(v,1-u,t,1);\n\t\t\t}\n\n\t\t\tif (rayTriangleIntersect(rayOrigin, rayDirection, v3, v1, v2, t, u, v)==true){\n\t\t\t\tres=vec4(1-v,u,t,1);\n\t\t\t}\n\n\tfragColor=res.rgba;\n}\n")
        del param

    param = lastNode.getParam("inputEnable1")
    if param is not None:
        param.setValue(False)
        del param

    param = lastNode.getParam("inputEnable2")
    if param is not None:
        param.setValue(False)
        del param

    param = lastNode.getParam("inputEnable3")
    if param is not None:
        param.setValue(False)
        del param

    param = lastNode.getParam("NatronParamFormatChoice")
    if param is not None:
        param.set("PC_Video 640x480")
        del param

    param = lastNode.getParam("mouseParams")
    if param is not None:
        param.setValue(False)
        del param

    param = lastNode.getParam("paramCount")
    if param is not None:
        param.setValue(6, 0)
        del param

    param = lastNode.getParam("paramType0")
    if param is not None:
        param.set("bool")
        del param

    param = lastNode.getParam("paramName0")
    if param is not None:
        param.setValue("backface")
        del param

    param = lastNode.getParam("paramLabel0")
    if param is not None:
        param.setValue("backface")
        del param

    param = lastNode.getParam("paramType1")
    if param is not None:
        param.set("vec3")
        del param

    param = lastNode.getParam("paramName1")
    if param is not None:
        param.setValue("pln_loc")
        del param

    param = lastNode.getParam("paramLabel1")
    if param is not None:
        param.setValue("pln_loc")
        del param

    param = lastNode.getParam("paramDefaultVec31")
    if param is not None:
        param.setValue(10, 2)
        del param

    param = lastNode.getParam("paramType2")
    if param is not None:
        param.set("vec3")
        del param

    param = lastNode.getParam("paramName2")
    if param is not None:
        param.setValue("pln_rot")
        del param

    param = lastNode.getParam("paramLabel2")
    if param is not None:
        param.setValue("pln_rot")
        del param

    param = lastNode.getParam("paramType3")
    if param is not None:
        param.set("vec3")
        del param

    param = lastNode.getParam("paramName3")
    if param is not None:
        param.setValue("d_loc")
        del param

    param = lastNode.getParam("paramLabel3")
    if param is not None:
        param.setValue("d_loc")
        del param

    param = lastNode.getParam("paramType4")
    if param is not None:
        param.set("vec3")
        del param

    param = lastNode.getParam("paramName4")
    if param is not None:
        param.setValue("d_rot")
        del param

    param = lastNode.getParam("paramLabel4")
    if param is not None:
        param.setValue("d_rot")
        del param

    param = lastNode.getParam("paramType5")
    if param is not None:
        param.set("vec3")
        del param

    param = lastNode.getParam("paramName5")
    if param is not None:
        param.setValue("pln_scl")
        del param

    param = lastNode.getParam("paramLabel5")
    if param is not None:
        param.setValue("scale")
        del param

    param = lastNode.getParam("paramDefaultVec35")
    if param is not None:
        param.setValue(1, 0)
        param.setValue(1, 1)
        param.setValue(1, 2)
        del param

    param = lastNode.getParam("paramType6")
    if param is not None:
        param.set("float")
        del param

    param = lastNode.getParam("paramName6")
    if param is not None:
        param.setValue("sensor")
        del param

    param = lastNode.getParam("paramLabel6")
    if param is not None:
        param.setValue("sensor")
        del param

    del lastNode
    # End of node "_Plane"

    # Start of node "STMap1"
    lastNode = app.createNode("net.sf.openfx.STMap", 2, group)
    lastNode.setScriptName("STMap1")
    lastNode.setLabel("STMap1")
    lastNode.setPosition(966, 465)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.7, 0.3, 0.1)
    groupSTMap1 = lastNode

    param = lastNode.getParam("channelUChoice")
    if param is not None:
        param.setValue("UV.r")
        del param

    param = lastNode.getParam("channelVChoice")
    if param is not None:
        param.setValue("UV.g")
        del param

    param = lastNode.getParam("channelAChoice")
    if param is not None:
        param.setValue("UV.a")
        del param

    param = lastNode.getParam("wrapU")
    if param is not None:
        param.set("Repeat")
        del param

    param = lastNode.getParam("wrapV")
    if param is not None:
        param.set("Repeat")
        del param

    param = lastNode.getParam("filter")
    if param is not None:
        param.set("Impulse")
        del param

    del lastNode
    # End of node "STMap1"

    # Start of node "TimeBlur1"
    lastNode = app.createNode("net.sf.openfx.TimeBlur", 1, group)
    lastNode.setScriptName("TimeBlur1")
    lastNode.setLabel("TimeBlur1")
    lastNode.setPosition(978, 588)
    lastNode.setSize(80, 43)
    lastNode.setColor(0.7, 0.65, 0.35)
    groupTimeBlur1 = lastNode

    param = lastNode.getParam("division")
    if param is not None:
        param.setValue(1, 0)
        del param

    param = lastNode.getParam("shutterOffset")
    if param is not None:
        param.set("Custom")
        del param

    param = lastNode.getParam("disableNode")
    if param is not None:
        param.setValue(True)
        del param

    del lastNode
    # End of node "TimeBlur1"

    # Start of node "Camera"
    lastNode = app.createNode("fr.inria.built-in.Input", 1, group)
    lastNode.setScriptName("Camera")
    lastNode.setLabel("Camera")
    lastNode.setPosition(546, 17)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupCamera = lastNode

    del lastNode
    # End of node "Camera"

    # Start of node "Output1"
    lastNode = app.createNode("fr.inria.built-in.Output", 1, group)
    lastNode.setLabel("Output1")
    lastNode.setPosition(546, 922)
    lastNode.setSize(104, 30)
    lastNode.setColor(0.7, 0.7, 0.7)
    groupOutput1 = lastNode

    del lastNode
    # End of node "Output1"

    # Start of node "Image"
    lastNode = app.createNode("fr.inria.built-in.Input", 1, group)
    lastNode.setScriptName("Image")
    lastNode.setLabel("Image")
    lastNode.setPosition(966, 24)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupImage = lastNode

    del lastNode
    # End of node "Image"

    # Start of node "Merge1"
    lastNode = app.createNode("net.sf.openfx.MergePlugin", 1, group)
    lastNode.setScriptName("Merge1")
    lastNode.setLabel("Merge1")
    lastNode.setPosition(969, 722)
    lastNode.setSize(104, 66)
    lastNode.setColor(0.3, 0.37, 0.776)
    groupMerge1 = lastNode

    param = lastNode.getParam("userTextArea")
    if param is not None:
        param.setValue("<Natron>(over)</Natron>")
        del param

    del lastNode
    # End of node "Merge1"

    # Start of node "Mask"
    lastNode = app.createNode("fr.inria.built-in.Input", 1, group)
    lastNode.setScriptName("Mask")
    lastNode.setLabel("Mask")
    lastNode.setPosition(1197, 730)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.3, 0.5, 0.2)
    groupMask = lastNode

    param = lastNode.getParam("optional")
    if param is not None:
        param.setValue(True)
        del param

    param = lastNode.getParam("isMask")
    if param is not None:
        param.setValue(True)
        del param

    del lastNode
    # End of node "Mask"

    # Start of node "Zbuffer"
    lastNode = app.createNode("net.sf.openfx.ShufflePlugin", 2, group)
    lastNode.setScriptName("Zbuffer")
    lastNode.setLabel("Zbuffer")
    lastNode.setPosition(546, 734)
    lastNode.setSize(104, 43)
    lastNode.setColor(0.6, 0.24, 0.39)
    lastNode.addUserPlane("Zbuf", ["R","G","B","A"])
    groupZbuffer = lastNode

    param = lastNode.getParam("outputChannels")
    if param is not None:
        param.set("Zbuf")
        del param

    param = lastNode.getParam("outputChannelsChoice")
    if param is not None:
        param.setValue("Zbuf")
        del param

    param = lastNode.getParam("outputRChoice")
    if param is not None:
        param.setValue("B.r")
        del param

    param = lastNode.getParam("outputGChoice")
    if param is not None:
        param.setValue("B.g")
        del param

    param = lastNode.getParam("outputBChoice")
    if param is not None:
        param.setValue("B.b")
        del param

    param = lastNode.getParam("outputAChoice")
    if param is not None:
        param.setValue("B.a")
        del param

    del lastNode
    # End of node "Zbuffer"

    # Now that all nodes are created we can connect them together, restore expressions
    group_Plane.connectInput(0, groupCamera)
    groupSTMap1.connectInput(0, group_Plane)
    groupSTMap1.connectInput(1, groupImage)
    groupTimeBlur1.connectInput(0, groupSTMap1)
    groupOutput1.connectInput(0, groupZbuffer)
    groupMerge1.connectInput(1, groupTimeBlur1)
    groupMerge1.connectInput(2, groupMask)
    groupZbuffer.connectInput(0, group_Plane)
    groupZbuffer.connectInput(1, groupMerge1)

    param = group_Plane.getParam("paramValueBool0")
    group.getParam("backface").setAsAlias(param)
    del param
    param = group_Plane.getParam("paramValueVec31")
    param.setExpression("thisGroup.locx.get()", False, 0)
    param.setExpression("thisGroup.locy.get()", False, 1)
    param.setExpression("thisGroup.locz.get()", False, 2)
    del param
    param = group_Plane.getParam("paramValueVec32")
    param.setExpression("thisGroup.rotx.get()", False, 0)
    param.setExpression("thisGroup.roty.get()", False, 1)
    param.setExpression("thisGroup.rotz.get()", False, 2)
    del param
    param = group_Plane.getParam("paramValueVec23")
    param.setExpression("thisGroup.scale.get().x", False, 0)
    param.setExpression("thisGroup.scale.get().y", False, 1)
    del param
    param = group_Plane.getParam("paramValueVec33")
    param.setExpression("thisGroup.dlocx.get()", False, 0)
    param.setExpression("thisGroup.dlocy.get()", False, 1)
    param.setExpression("thisGroup.dlocz.get()", False, 2)
    del param
    param = group_Plane.getParam("paramValueVec34")
    param.setExpression("thisGroup.drotx.get()", False, 0)
    param.setExpression("thisGroup.droty.get()", False, 1)
    param.setExpression("thisGroup.drotz.get()", False, 2)
    del param
    param = group_Plane.getParam("paramValueVec35")
    param.setExpression("thisGroup.scale.get().x", False, 0)
    param.setExpression("thisGroup.scale.get().y", False, 1)
    param.setExpression("thisGroup.scale_u.get()", False, 2)
    del param
    param = groupSTMap1.getParam("uvOffset")
    group.getParam("STMap1uvOffset").setAsAlias(param)
    del param
    param = groupSTMap1.getParam("uvScale")
    group.getParam("STMap1uvScale").setAsAlias(param)
    del param
    param = groupSTMap1.getParam("filter")
    group.getParam("STMap1filter").setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam("division")
    param.setExpression("thisGroup.blur_sample.get()", False, 0)
    del param
    param = groupTimeBlur1.getParam("shutter")
    group.getParam("TimeBlur1shutter").setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam("shutterCustomOffset")
    group.getParam("TimeBlur1shutterCustomOffset").setAsAlias(param)
    del param
    param = groupTimeBlur1.getParam("disableNode")
    param.setExpression("thisGroup.blur_sample.get()==0", False, 0)
    del param
    param = groupMerge1.getParam("maskInvert")
    group.getParam("Merge1maskInvert").setAsAlias(param)
    del param
    param = groupMerge1.getParam("mix")
    group.getParam("Merge1mix").setAsAlias(param)
    del param
    param = groupMerge1.getParam("enableMask_Mask")
    group.getParam("Merge1enableMask_Mask").setAsAlias(param)
    del param
    param = groupMerge1.getParam("maskChannel_Mask")
    group.getParam("Merge1maskChannel_Mask").setAsAlias(param)
    del param

    try:
        extModule = sys.modules["PM_Card3DExt"]
    except KeyError:
        extModule = None
    if extModule is not None and hasattr(extModule ,"createInstanceExt") and hasattr(extModule.createInstanceExt,"__call__"):
        extModule.createInstanceExt(app,group)
