1022 lines
52 KiB
Python
1022 lines
52 KiB
Python
#!/usr/bin/env python
|
|
'''
|
|
Generate MDL implementation directory based on MaterialX nodedefs
|
|
'''
|
|
|
|
import os
|
|
import sys
|
|
|
|
os.environ['PYTHONIOENCODING'] = 'utf-8'
|
|
|
|
import MaterialX as mx
|
|
|
|
def usage():
|
|
print ('genmdl.py: Generate implementation directory for mdl based on existing MaterialX nodedefs in stdlib')
|
|
print ('Usage: genmdl.py <library search path> [<module name> <version>]')
|
|
print ('- A new directory called "library/stdlib/genmdl/materialx" will be created with two files added:')
|
|
print (' - <module_name>.ref_mdl: Module with signature stubs for each MaterialX nodedef')
|
|
print (' - <module_name>_genmdl_impl.ref_mtlx: MaterialX nodedef implementation mapping file')
|
|
print ('- By default <module_name>="mymodule" and <version>="1.6"')
|
|
|
|
def _getSubDirectories(libraryPath):
|
|
return [name for name in os.listdir(libraryPath)
|
|
if os.path.isdir(os.path.join(libraryPath, name))]
|
|
|
|
def _getMTLXFilesInDirectory(path):
|
|
for file in os.listdir(path):
|
|
if file.endswith('.mtlx'):
|
|
yield file
|
|
|
|
def _loadLibrary(file, doc):
|
|
libDoc = mx.createDocument()
|
|
mx.readFromXmlFile(libDoc, file)
|
|
libDoc.setSourceUri(file)
|
|
doc.importLibrary(libDoc)
|
|
|
|
def _loadLibraries(doc, searchPath, libraryPath):
|
|
librarySubPaths = _getSubDirectories(libraryPath)
|
|
librarySubPaths.append(libraryPath)
|
|
for path in librarySubPaths:
|
|
filenames = _getMTLXFilesInDirectory(os.path.join(libraryPath, path))
|
|
for filename in filenames:
|
|
filePath = os.path.join(libraryPath, os.path.join(path, filename))
|
|
_loadLibrary(filePath, doc)
|
|
|
|
def _writeHeader(file, version):
|
|
file.write('mdl ' + version + ';\n')
|
|
file.write('using core import *;\n')
|
|
IMPORT_LIST = { '::anno::*', '::base::*', '.::swizzle::*', '.::cm::*', '::math::*', '::state::*', '::tex::*', '::state::*', '.::vectormatrix::*', '.::hsv::*', '.::noise::*'}
|
|
# To verify what are the minimal imports required
|
|
for i in IMPORT_LIST:
|
|
file.write('import' + i + ';\n')
|
|
file.write('\n\n')
|
|
file.write('// Helper function mapping texture node addressmodes to MDL wrap modes\n')
|
|
file.write('::tex::wrap_mode map_addressmode( mx_addressmode_type value ) {\n')
|
|
file.write(' switch (value) {\n')
|
|
file.write(' case mx_addressmode_type_clamp:\n')
|
|
file.write(' return ::tex::wrap_clamp;\n')
|
|
file.write(' case mx_addressmode_type_mirror:\n')
|
|
file.write(' return ::tex::wrap_mirrored_repeat;\n')
|
|
file.write(' default:\n')
|
|
file.write( ' return ::tex::wrap_repeat;\n')
|
|
file.write(' }\n')
|
|
file.write('}\n\n')
|
|
|
|
def _mapGeomProp(geomprop):
|
|
outputValue = ''
|
|
if len(geomprop):
|
|
if geomprop.find('UV') >= 0:
|
|
outputValue = 'swizzle::xy(::state::texture_coordinate(0))'
|
|
elif geomprop.find('Pobject') >= 0:
|
|
outputValue = '::state::transform_point(::state::coordinate_internal,::state::coordinate_object,::state::position())'
|
|
elif geomprop.find('PWorld') >= 0:
|
|
outputValue = '::state::transform_point(::state::coordinate_internal,::state::coordinate_world,::state::position())'
|
|
elif geomprop.find('Nobject') >= 0:
|
|
outputValue = '::state::transform_normal(::state::coordinate_internal,::state::coordinate_object,::state::normal())'
|
|
elif geomprop.find('Nworld') >= 0:
|
|
outputValue = '::state::transform_normal(::state::coordinate_internal,::state::coordinate_world,::state::normal())'
|
|
elif geomprop.find('Tobject') >= 0:
|
|
outputValue = '::state::transform_vector(::state::coordinate_internal,::state::coordinate_object,::state::texture_tangent_u(0))'
|
|
elif geomprop.find('Tworld') >= 0:
|
|
outputValue = 'state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_u(0))'
|
|
elif geomprop.find('Bobject') >= 0:
|
|
outputValue = 'state::transform_vector(::state::coordinate_internal,::state::coordinate_object,::state::texture_tangent_v(0))'
|
|
elif geomprop.find('Bworld') >= 0:
|
|
outputValue = '::state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_v(0))'
|
|
return outputValue
|
|
|
|
def _writeValueAssignment(file, outputValue, outputType, writeEmptyValues):
|
|
# Mapping of types to initializers
|
|
assignMap = dict()
|
|
assignMap['float2[<N>]'] = 'float2[]'
|
|
|
|
if outputType == 'color4':
|
|
outputType = 'mk_color4'
|
|
|
|
elif outputType in assignMap:
|
|
outputType = assignMap[outputType]
|
|
writeEmptyValues = True
|
|
|
|
if len(outputValue) or writeEmptyValues:
|
|
file.write(' = ')
|
|
if outputType:
|
|
file.write(outputType + '(')
|
|
if outputType == 'string':
|
|
file.write('"')
|
|
file.write(outputValue)
|
|
if outputType == 'string':
|
|
file.write('"')
|
|
if outputType:
|
|
file.write(')')
|
|
|
|
def _mapType(typeName, typeMap, functionName):
|
|
if 'mx_constant_filename' == functionName:
|
|
return 'string'
|
|
elif ('transformpoint' in functionName) or ('transformvector' in functionName) or ('transformnormal' in functionName):
|
|
if typeName == 'string':
|
|
return 'mx_coordinatespace_type'
|
|
if typeName in typeMap:
|
|
return typeMap[typeName]
|
|
return typeName
|
|
|
|
INDENT = '\t'
|
|
SPACE = ' '
|
|
QUOTE = '"'
|
|
FUNCTION_PREFIX = 'mx_'
|
|
FUNCTION_PARAMETER_PREFIX = 'mxp_'
|
|
|
|
# Basic template for writing out logic for "image" node definition
|
|
def _writeImageImplementation(file, outputType):
|
|
file.write(INDENT + 'if ( mxp_uaddressmode == mx_addressmode_type_constant\n')
|
|
file.write(INDENT + ' && ( mxp_texcoord.x < 0.0 || mxp_texcoord.x > 1.0))\n')
|
|
file.write(INDENT + INDENT + 'return mxp_default;\n')
|
|
file.write(INDENT + 'if ( mxp_vaddressmode == mx_addressmode_type_constant\n')
|
|
file.write(INDENT + ' && ( mxp_texcoord.y < 0.0 || mxp_texcoord.y > 1.0))\n')
|
|
file.write(INDENT + INDENT + 'return mxp_default;\n\n')
|
|
|
|
file.write(INDENT + outputType + ' returnValue')
|
|
isColor4 = (outputType == 'color4')
|
|
if isColor4:
|
|
outputType = 'float4'
|
|
outputType = 'mk_color4( ::tex::lookup_' + outputType
|
|
else:
|
|
outputType = '::tex::lookup_' + outputType
|
|
outputValue = 'tex: mxp_file, \n' \
|
|
+ INDENT*6 + 'coord: mxp_texcoord,\n' \
|
|
+ INDENT*6 + 'wrap_u: map_addressmode(mxp_uaddressmode),\n' \
|
|
+ INDENT*6 + 'wrap_v: map_addressmode(mxp_vaddressmode)'
|
|
_writeValueAssignment(file, outputValue, outputType, True)
|
|
if isColor4:
|
|
file.write(')')
|
|
file.write(';\n')
|
|
file.write(INDENT + 'return returnValue;\n')
|
|
|
|
def _writeOneArgumentFunc(file, outputType, functionName):
|
|
if outputType == 'color4':
|
|
file.write(INDENT + 'return mk_color4(' + functionName + '(mk_float4(mxp_in)));\n')
|
|
elif outputType == 'color':
|
|
file.write(INDENT + 'return color(' + functionName + '(mk_float3(mxp_in)));\n')
|
|
else:
|
|
file.write(INDENT + 'return ' + functionName + '(mxp_in);\n')
|
|
|
|
def _writeOperatorFunc(file, outputType, arg1, functionName, arg2):
|
|
if outputType == 'color4':
|
|
file.write(INDENT + 'return mk_color4(mk_float4(' + arg1 +') ' + functionName + ' mk_float4(' + arg2 + '));\n')
|
|
elif outputType == 'float3x3' or outputType == 'float4x4':
|
|
file.write(INDENT + 'return ' + outputType + '(' + arg1 + ') ' + functionName + ' ' + outputType + '(' + arg2 + ');\n')
|
|
else:
|
|
file.write(INDENT + 'return ' + arg1 + ' ' + functionName + ' ' + arg2 + ';\n')
|
|
|
|
def _writeTwoArgumentFunc(file, outputType, functionName):
|
|
if outputType == 'color4':
|
|
file.write(INDENT + 'return mk_color4(' + functionName + '(mk_float4(mxp_in1), mk_float4(mxp_in2)));\n')
|
|
elif outputType == 'color':
|
|
file.write(INDENT + 'return color(' + functionName + '(float3(mxp_in1), float3(mxp_in2)));\n')
|
|
else:
|
|
file.write(INDENT + 'return ' + functionName + '(mxp_in1, mxp_in2);\n')
|
|
|
|
def _writeThreeArgumentFunc(file, outputType, functionName, arg1, arg2, arg3):
|
|
if outputType == 'color4':
|
|
file.write(INDENT + 'return mk_color4(' + functionName + '(mk_float4(' + arg1 + '), mk_float4(' + arg2 + '), mk_float4(' + arg3 + ')));\n')
|
|
elif outputType == 'color':
|
|
file.write(INDENT + 'return color(' + functionName + '(float3(' + arg1 + '), float3(' + arg2 + '), float3(' + arg3 + ')));\n')
|
|
else:
|
|
file.write(INDENT + 'return ' + functionName + '(' + outputType + '(' + arg1 + '),' + outputType + '(' + arg2 + '),' + outputType+ '(' + arg3 + '));\n')
|
|
|
|
def _writeTransformMatrix(file, nodeName):
|
|
if nodeName.find('vector3M4') >= 0:
|
|
file.write(INDENT + 'float4 returnValue = mxp_mat * float4(mxp_in.x, mxp_in.y, mxp_in.z, 1.0);\n')
|
|
file.write(INDENT + 'return float3(returnValue.x, returnValue.y, returnValue.z);\n')
|
|
elif nodeName.find('vector2M3') >= 0:
|
|
file.write(INDENT + 'float3 returnValue = mxp_mat * float3(mxp_in.x, mxp_in.y, 1.0);\n')
|
|
file.write(INDENT + 'return float2(returnValue.x, returnValue.y);\n')
|
|
else:
|
|
file.write(INDENT + 'return mxp_mat * mxp_in;\n')
|
|
|
|
def _writeTwoArgumentCombine(file, outputType):
|
|
if outputType == 'color':
|
|
outputType = 'color3';
|
|
file.write(INDENT + 'return mk_' + outputType + '(mxp_in1, mxp_in2);\n')
|
|
|
|
def _writeThreeArgumentCombine(file, outputType):
|
|
if outputType == 'color':
|
|
file.write(INDENT + 'return ' + outputType + '(mxp_in1, mxp_in2, mxp_in3);\n')
|
|
else:
|
|
file.write(INDENT + 'return mk_' + outputType + '(mxp_in1, mxp_in2, mxp_in3);\n')
|
|
|
|
def _writeFourArgumentCombine(file, outputType):
|
|
if outputType == 'color':
|
|
outputType = 'color3';
|
|
file.write(INDENT + 'return mk_' + outputType + '(mxp_in1, mxp_in2, mxp_in3, mxp_in4);\n')
|
|
|
|
def _writeIfGreater(file, comparitor):
|
|
file.write(INDENT + 'if (mxp_value1 ' + comparitor + ' mxp_value2) { return mxp_in1; } return mxp_in2;\n' )
|
|
|
|
def _writeTranformSpace(file, outputType, functionName, input, fromspace, tospace):
|
|
file.write(INDENT + 'state::coordinate_space fromSpace = ::mx_map_space(' + fromspace + ');\n')
|
|
file.write(INDENT + 'state::coordinate_space toSpace = ::mx_map_space(' + tospace + ');\n')
|
|
file.write(INDENT + 'return mk_' + outputType + '( state::' + functionName + '(fromSpace, toSpace, ' + input + '));\n')
|
|
|
|
def writeNormalMap(file):
|
|
file.write(INDENT + 'if (mxp_space == "tangent")\n')
|
|
file.write(INDENT + '{\n')
|
|
file.write(INDENT + ' float3 v = mxp_in * 2.0 - 1.0;\n')
|
|
file.write(INDENT + ' float3 B = ::math::normalize(::math::cross(mxp_normal, mxp_tangent));\n')
|
|
file.write(INDENT + ' return ::math::normalize(mxp_tangent * v.x * mxp_scale + B * v.y * mxp_scale + mxp_normal * v.z);\n')
|
|
file.write(INDENT + '}\n')
|
|
file.write(INDENT + 'else\n')
|
|
file.write(INDENT + '{\n')
|
|
file.write(INDENT + ' float3 n = mxp_in * 2.0 - 1.0;\n')
|
|
file.write(INDENT + ' return ::math::normalize(n);\n')
|
|
file.write(INDENT + '}\n')
|
|
|
|
def _writeRemap(file, outputType):
|
|
if outputType == 'color4':
|
|
file.write(INDENT + 'color4 val = mk_color4(mxp_outlow);\n')
|
|
file.write(INDENT + 'color4 val2 = mx_add(val, mx_subtract(mk_color4(mxp_in), mk_color4(mxp_inlow)));\n')
|
|
file.write(INDENT + 'color4 val3 = mx_multiply(val2, mx_subtract(mk_color4(mxp_outhigh), mk_color4(mxp_outlow)));\n')
|
|
file.write(INDENT + 'return mx_divide(val3, mx_subtract(mk_color4(mxp_inhigh), mk_color4(mxp_inlow)));\n')
|
|
else:
|
|
file.write(INDENT + 'return mxp_outlow + (mxp_in - mxp_inlow) * (mxp_outhigh - mxp_outlow) / (mxp_inhigh - mxp_inlow);\n')
|
|
|
|
def _writeSwitch(file, outputType):
|
|
file.write(INDENT + outputType + ' returnValue;\n')
|
|
file.write(INDENT + 'switch (int(mxp_which)) {\n')
|
|
file.write(INDENT*2 + 'case 0: returnValue=mxp_in1; break;\n')
|
|
file.write(INDENT*2 + 'case 1: returnValue=mxp_in2; break;\n')
|
|
file.write(INDENT*2 + 'case 2: returnValue=mxp_in3; break;\n')
|
|
file.write(INDENT*2 + 'case 3: returnValue=mxp_in4; break;\n')
|
|
file.write(INDENT*2 + 'case 4: returnValue=mxp_in5; break;\n')
|
|
file.write(INDENT*2 + 'default: returnValue=mxp_in1; break;\n')
|
|
file.write(INDENT + '}\n')
|
|
file.write(INDENT + 'return returnValue;\n')
|
|
|
|
def _writeOverlay(file, outputType):
|
|
if outputType == 'color4':
|
|
file.write(INDENT + 'color4 upper, lower;\n')
|
|
file.write(INDENT + 'color4 fg_ = color4(mxp_fg);\n')
|
|
file.write(INDENT + 'color4 bg_ = color4(mxp_bg);\n')
|
|
file.write(INDENT + 'upper = mx_multiply(mx_multiply(mk_color4(2.0),bg_),fg_);\n')
|
|
file.write(INDENT + 'lower = mx_subtract(mx_add(bg_,fg_),mx_multiply(bg_,fg_));\n')
|
|
file.write(INDENT + 'color maskRGB = color(::math::step(float3(.5), float3(fg_.rgb)));\n')
|
|
file.write(INDENT + 'float maskA = ::math::step(.5, fg_.a);\n')
|
|
file.write(INDENT + 'color overlayvalRGB = ::math::lerp(lower.rgb, upper.rgb, maskRGB);\n')
|
|
file.write(INDENT + 'float overlayvalA = ::math::lerp(lower.a, upper.a, maskA);\n')
|
|
file.write(INDENT + 'color returnRGB = ::math::lerp(mxp_bg.rgb, overlayvalRGB, color(mxp_mix));\n')
|
|
file.write(INDENT + 'float returnA = ::math::lerp(mxp_bg.a, overlayvalA, mxp_mix);\n')
|
|
file.write(INDENT + 'return color4(returnRGB, returnA);\n')
|
|
else:
|
|
file.write(INDENT + outputType + ' upper, lower, mask, overlayval;\n')
|
|
file.write(INDENT + outputType + ' fg_ = ' + outputType + '(mxp_fg);\n')
|
|
file.write(INDENT + outputType + ' bg_ = ' + outputType + '(mxp_bg);\n')
|
|
file.write(INDENT + 'upper = 2.0*bg_*fg_;\n')
|
|
file.write(INDENT + 'lower = bg_+fg_-bg_*fg_;\n')
|
|
if outputType == 'color':
|
|
file.write(INDENT + 'mask = color(::math::step(float3(.5), float3(fg_)));\n')
|
|
else:
|
|
file.write(INDENT + 'mask = ::math::step(' + outputType + '(.5), fg_);\n')
|
|
file.write(INDENT + 'overlayval = ::math::lerp(lower, upper, mask);\n')
|
|
file.write(INDENT + 'return ' + outputType + '(::math::lerp(mxp_bg, overlayval, mxp_mix));\n')
|
|
|
|
def _writeDisjointOver(file, outputType):
|
|
if outputType == 'float2':
|
|
file.write(INDENT + 'float2 result;\n')
|
|
file.write(INDENT + 'float summedAlpha = mxp_fg.y + mxp_bg.y;\n')
|
|
file.write(INDENT + 'if (summedAlpha <= 1)\n')
|
|
file.write(INDENT + '{\n')
|
|
file.write(INDENT + ' result.x = mxp_fg.x + mxp_bg.x;\n')
|
|
file.write(INDENT + '}\n')
|
|
file.write(INDENT + 'else\n')
|
|
file.write(INDENT + '{\n')
|
|
file.write(INDENT + ' if (::math::abs(mxp_bg.y) < FLOAT_EPS)\n')
|
|
file.write(INDENT + ' {\n')
|
|
file.write(INDENT + ' result.x = 0.0;\n')
|
|
file.write(INDENT + ' }\n')
|
|
file.write(INDENT + ' else\n')
|
|
file.write(INDENT + ' {\n')
|
|
file.write(INDENT + ' result.x = mxp_fg.x + ((mxp_bg.x * (1-mxp_fg.y)) / mxp_bg.y);\n')
|
|
file.write(INDENT + ' }\n')
|
|
file.write(INDENT + '}\n')
|
|
file.write(INDENT + 'result.y = ::math::min(summedAlpha, 1.0);\n')
|
|
file.write(INDENT + 'result.x = result.x * mxp_mix + (1.0 - mxp_mix) * mxp_bg.x;\n')
|
|
file.write(INDENT + 'result.y = result.y * mxp_mix + (1.0 - mxp_mix) * mxp_bg.y;\n')
|
|
file.write(INDENT + 'return result;\n')
|
|
else:
|
|
file.write(INDENT + 'color4 result;\n')
|
|
file.write(INDENT + 'float summedAlpha = mxp_fg.a + mxp_bg.a;\n')
|
|
file.write(INDENT + 'if (summedAlpha <= 1)\n')
|
|
file.write(INDENT + '{\n')
|
|
file.write(INDENT + ' result.rgb = mxp_fg.rgb + mxp_bg.rgb;\n')
|
|
file.write(INDENT + '}\n')
|
|
file.write(INDENT + 'else\n')
|
|
file.write(INDENT + '{\n')
|
|
file.write(INDENT + ' if (::math::abs(mxp_bg.a) < FLOAT_EPS)\n')
|
|
file.write(INDENT + ' {\n')
|
|
file.write(INDENT + ' result.rgb = color(0.0,0.0,0.0);\n')
|
|
file.write(INDENT + ' }\n')
|
|
file.write(INDENT + ' else\n')
|
|
file.write(INDENT + ' {\n')
|
|
file.write(INDENT + ' result.rgb = mxp_fg.rgb + ((mxp_bg.rgb * (1-mxp_fg.a)) / mxp_bg.a);\n')
|
|
file.write(INDENT + ' }\n')
|
|
file.write(INDENT + '}\n')
|
|
file.write(INDENT + 'result.a = ::math::min(summedAlpha, 1.0);\n')
|
|
file.write(INDENT + 'result.rgb = result.rgb * mxp_mix + (1.0 - mxp_mix) * mxp_bg.rgb;\n')
|
|
file.write(INDENT + 'result.a = result.a * mxp_mix + (1.0 - mxp_mix) * mxp_bg.a;\n')
|
|
file.write(INDENT + 'return result;\n')
|
|
|
|
def main():
|
|
|
|
if len(sys.argv) < 2:
|
|
usage()
|
|
sys.exit(0)
|
|
|
|
_startPath = os.path.abspath(sys.argv[1])
|
|
if os.path.exists(_startPath) == False:
|
|
print('Start path does not exist: ' + _startPath + '. Using current directory.\n')
|
|
_startPath = os.path.abspath(os.getcwd())
|
|
|
|
moduleName = 'mymodule'
|
|
if len(sys.argv) > 2:
|
|
moduleName = sys.argv[2]
|
|
|
|
version = '1.6'
|
|
if len(sys.argv) > 3:
|
|
version = sys.argv[3]
|
|
|
|
LIBRARY = 'stdlib'
|
|
|
|
doc = mx.createDocument()
|
|
searchPath = os.path.join(_startPath, 'libraries')
|
|
libraryPath = os.path.join(searchPath, LIBRARY)
|
|
_loadLibraries(doc, searchPath, libraryPath)
|
|
|
|
DEFINITION_PREFIX = 'ND_'
|
|
IMPLEMENTATION_PREFIX = 'IM_'
|
|
IMPLEMENTATION_STRING = 'impl'
|
|
GENMDL = 'genmdl'
|
|
DESINATION_FOLDER = 'genmdl/materialx'
|
|
|
|
# Create target directory if don't exist
|
|
impl_outputPath = os.path.join(libraryPath, GENMDL)
|
|
if not os.path.exists(impl_outputPath):
|
|
os.mkdir(impl_outputPath)
|
|
outputPath = os.path.join(libraryPath, DESINATION_FOLDER)
|
|
if not os.path.exists(outputPath):
|
|
os.mkdir(outputPath)
|
|
|
|
file = None
|
|
|
|
# Write to single file if module name specified
|
|
if len(moduleName):
|
|
file = open(outputPath + '/' + moduleName + '_ref.mdl', 'w+')
|
|
_writeHeader(file, version)
|
|
|
|
# Dictionary to map from MaterialX type declarations
|
|
# to MDL type declarations
|
|
typeMap = dict()
|
|
typeMap['boolean'] = 'bool'
|
|
typeMap['integer'] = 'int'
|
|
typeMap['color2'] = 'float2'
|
|
typeMap['color3'] = 'color'
|
|
typeMap['color4'] = 'color4'
|
|
typeMap['vector2'] = 'float2'
|
|
typeMap['vector3'] = 'float3'
|
|
typeMap['vector4'] = 'float4'
|
|
typeMap['matrix33'] = 'float3x3'
|
|
typeMap['matrix44'] = 'float4x4'
|
|
typeMap['filename'] = 'texture_2d' # Assume all file textures are 2d for now
|
|
typeMap['geomname'] = 'string'
|
|
typeMap['floatarray'] = 'float[<N>]'
|
|
typeMap['integerarray'] = 'int[<N>]'
|
|
typeMap['color2array'] = 'float2[<N>]'
|
|
typeMap['color3array'] = 'color[<N>]'
|
|
typeMap['color4array'] = 'float4[<N>]'
|
|
typeMap['vector2array'] = 'float2[<N>]'
|
|
typeMap['vector3array'] = 'float3[<N>]'
|
|
typeMap['vector4array'] = 'float4[<N>]'
|
|
typeMap['stringarray'] = 'string[<N>]'
|
|
typeMap['geomnamearray'] = 'string[<N>]'
|
|
typeMap['surfaceshader'] = 'material'
|
|
typeMap['volumeshader'] = 'material'
|
|
typeMap['displacementshader'] = 'material'
|
|
typeMap['lightshader'] = 'material'
|
|
|
|
functionTypeMap = dict()
|
|
functionTypeMap['mx_separate2_color2'] = 'mx_separate2_color2_type'
|
|
functionTypeMap['mx_separate3_color3'] = 'mx_separate3_color3_type'
|
|
functionTypeMap['mx_separate4_color4'] = 'mx_separate4_color4_type'
|
|
functionTypeMap['mx_separate2_vector2'] = 'mx_separate2_vector2_type'
|
|
functionTypeMap['mx_separate3_vector3'] = 'mx_separate3_vector3_type'
|
|
functionTypeMap['mx_separate4_vector4'] = 'mx_separate4_vector4_type'
|
|
|
|
# Create an implementation per nodedef
|
|
#
|
|
implDoc = mx.createDocument()
|
|
nodedefs = doc.getNodeDefs()
|
|
nodeGraphs = doc.getNodeGraphs()
|
|
implementedCont = 0;
|
|
totalCount = 0;
|
|
for nodedef in nodedefs:
|
|
|
|
# Skip any node definitions which are implemented as node graphs
|
|
nodeDefName = nodedef.getName()
|
|
#print(nodeDef)
|
|
implementationIsGraph = False
|
|
for nodeGraph in nodeGraphs:
|
|
graphName = nodeGraph.getName()
|
|
#print('Scane nodegraph: ' + nodeGraph.getName() + '\n')
|
|
if nodeGraph.getAttribute('nodedef') == nodeDefName:
|
|
file.write('// Nodedef: ' + nodeDefName + ' is represented by a nodegraph: ' + graphName + '\n')
|
|
implementationIsGraph = True
|
|
break
|
|
if implementationIsGraph:
|
|
continue
|
|
|
|
# These definitions are for organization only
|
|
nodeGroup = nodedef.getAttribute('nodegroup')
|
|
if nodeGroup == 'organization':
|
|
continue
|
|
|
|
# TODO: Skip array definitions for now
|
|
nodeCategory = nodedef.getAttribute('node')
|
|
if nodeCategory == 'arrayappend':
|
|
print('Skip ' + nodeDefName + ' implementation. Not supported yet')
|
|
continue
|
|
if nodeCategory == 'curveadjust':
|
|
print('Skip ' + nodeDefName + ' implementation. Not supported yet')
|
|
#continue
|
|
elif nodeCategory == 'geomcolor':
|
|
print('Skip ' + nodeDefName + ' implementation. Not supported in MDL')
|
|
#continue
|
|
elif nodeCategory == 'geomattrvalue':
|
|
print('Skip ' + nodeDefName + ' implementation. Not supported in MDL')
|
|
#continue
|
|
elif nodeCategory == 'geompropvalue':
|
|
print('Skip ' + nodeDefName + ' implementation. Not supported in MDL')
|
|
#continue
|
|
|
|
if len(nodedef.getActiveOutputs()) == 0:
|
|
continue
|
|
|
|
totalCount += 1
|
|
|
|
outputValue = ''
|
|
outputType = ''
|
|
|
|
# String out definition prefix
|
|
nodeName = nodedef.getName()
|
|
if len(nodeName) > 3:
|
|
if (nodeName[0:3] == DEFINITION_PREFIX):
|
|
nodeName = nodeName[3:]
|
|
|
|
filename = nodeName + '.ref_mdl'
|
|
|
|
implname = IMPLEMENTATION_PREFIX + nodeName + '_' + GENMDL
|
|
impl = implDoc.addImplementation(implname)
|
|
impl.setNodeDef(nodedef)
|
|
if len(moduleName):
|
|
impl.setFile('stdlib/' + DESINATION_FOLDER + '/' + moduleName + '.ref_mdl')
|
|
else:
|
|
impl.setFile('stdlib/' + DESINATION_FOLDER + '/' + filename)
|
|
|
|
functionName = FUNCTION_PREFIX + nodeName
|
|
functionCallName = functionName
|
|
if len(moduleName):
|
|
functionCallName = functionName
|
|
impl.setFunction(functionCallName)
|
|
impl.setLanguage(GENMDL)
|
|
|
|
# If no module name, create a new mdl file per nodedef
|
|
if len(moduleName) == 0:
|
|
file = open(outputPath + '/materialx/' + filename, 'w+')
|
|
_writeHeader(file, version)
|
|
|
|
outType = nodedef.getType()
|
|
routeInputToOutput = False
|
|
|
|
# TODO: Skip multioutput nodes for now
|
|
#if outType == 'multioutput':
|
|
# continue
|
|
|
|
# Create a signature for the nodedef
|
|
file.write('export ')
|
|
# Add output argument
|
|
if functionName in functionTypeMap:
|
|
outType = functionTypeMap[functionName]
|
|
else:
|
|
outType = _mapType(outType, typeMap, functionName)
|
|
|
|
file.write(outType + SPACE)
|
|
file.write(functionName + '(\n')
|
|
|
|
# Add input arguments
|
|
#
|
|
elems = nodedef.getActiveValueElements()
|
|
lastComma = len(elems) - len(nodedef.getActiveOutputs())
|
|
i = 0
|
|
channelString = ''
|
|
for elem in elems:
|
|
|
|
dataType = ''
|
|
defaultgeomprop = ''
|
|
|
|
# Skip output elements
|
|
if isinstance(elem, mx.Output):
|
|
outputValue = elem.getAttribute('default')
|
|
if outputValue == '[]':
|
|
outputValue = ''
|
|
if not outputValue:
|
|
outputValue = elem.getAttribute('defaultinput')
|
|
if outputValue:
|
|
outputValue = FUNCTION_PARAMETER_PREFIX + outputValue
|
|
routeInputToOutput = True
|
|
outputType = elem.getType()
|
|
outputType = _mapType(outputType, typeMap, functionName)
|
|
continue
|
|
|
|
# Parameters map to uniforms
|
|
elif isinstance(elem, mx.Parameter):
|
|
dataType = 'uniform '
|
|
# Inputs map to varyings
|
|
elif isinstance(elem, mx.Input):
|
|
dataType = ''
|
|
defaultgeomprop = elem.getAttribute('defaultgeomprop')
|
|
|
|
# Determine type
|
|
typeString = elem.getType()
|
|
isFileTexture = (typeString == 'filename')
|
|
typeString = _mapType(typeString , typeMap, functionName)
|
|
isString = (typeString == 'string')
|
|
|
|
# Determine value
|
|
isGeometryInput = len(defaultgeomprop) > 0
|
|
if isGeometryInput:
|
|
valueString = _mapGeomProp(defaultgeomprop)
|
|
else:
|
|
valueString = elem.getValueString()
|
|
|
|
parameterName = FUNCTION_PARAMETER_PREFIX + elem.getName();
|
|
isEnumeration = len(elem.getAttribute('enum')) > 0
|
|
# Remap enumerations.
|
|
# Note: This is hard-coded since there are no type enumerations in MaterialX to map from
|
|
if isEnumeration and not isGeometryInput:
|
|
ADDRESS_MODE = { 'constant', 'clamp', 'periodic', 'mirror'}
|
|
FILTER_LOOKUP = { 'closest', 'linear', 'cubic' }
|
|
COORDINATE_SPACES = { 'model', 'object' , 'world' }
|
|
FILTER_TYPE = { 'box', 'gaussian' }
|
|
if valueString in ADDRESS_MODE:
|
|
typeString = 'mx_addressmode_type'
|
|
valueString = typeString + '_' + valueString
|
|
elif valueString in FILTER_LOOKUP:
|
|
typeString = 'mx_filterlookup_type'
|
|
valueString = typeString + '_' + valueString
|
|
elif valueString in COORDINATE_SPACES:
|
|
typeString = 'mx_coordinatespace_type'
|
|
valueString = typeString + '_' + valueString
|
|
elif valueString in FILTER_TYPE:
|
|
typeString = 'mx_filter_type'
|
|
valueString = typeString + '_' + valueString
|
|
|
|
if typeString == 'mx_coordinatespace_type' and valueString == '':
|
|
valueString = 'mx_coordinatespace_type_model'
|
|
file.write(INDENT + dataType + typeString + SPACE + parameterName)
|
|
_writeValueAssignment(file, valueString, typeString, isFileTexture or isString)
|
|
|
|
if nodeCategory == 'swizzle' and parameterName == 'mxp_channels':
|
|
channelString = valueString
|
|
|
|
# Add annotations if any
|
|
description = elem.getAttribute('doc')
|
|
if len(elem.getAttribute('enum')):
|
|
description = description + 'Enumeration {' + elem.getAttribute('enum') + '}.'
|
|
if len(elem.getAttribute('unittype')):
|
|
description = description + 'Unit Type:' + elem.getAttribute('unittype') + '.'
|
|
if len(elem.getAttribute('unit')):
|
|
description = description + ' Unit:' + elem.getAttribute('unit') + "."
|
|
uiname = elem.getAttribute('uiname')
|
|
uigroup = elem.getAttribute('uifolder')
|
|
if len(description) or len(uiname) or len(uigroup):
|
|
file.write(INDENT + '\n' + INDENT + '[[')
|
|
count = 0
|
|
if len(description):
|
|
file.write("\n" + INDENT + INDENT + 'anno::description("' + description + '")')
|
|
count = count + 1
|
|
if len(uiname):
|
|
if count > 0:
|
|
file.write(',')
|
|
file.write("\n" + INDENT + INDENT + 'anno::display_name("' + uiname + '")')
|
|
count = count + 1
|
|
if len(uigroup):
|
|
if count > 0:
|
|
file.write(',')
|
|
file.write("\n" + INDENT + INDENT + 'anno::in_group("' + uigroup + '")')
|
|
file.write('\n' + INDENT + ']]')
|
|
|
|
i = i + 1
|
|
if i < lastComma:
|
|
file.write(',')
|
|
file.write('\n')
|
|
|
|
file.write(')\n')
|
|
nodegroup = nodedef.getAttribute('nodegroup')
|
|
if len(nodegroup):
|
|
file.write(INDENT + '[[\n')
|
|
file.write(INDENT + INDENT + 'anno::description("Node Group: ' + nodegroup + '")\n')
|
|
file.write(INDENT + ']]\n')
|
|
if outputType == 'material':
|
|
if outputValue:
|
|
file.write('= ' + outputValue + '; // TODO \n\n')
|
|
else:
|
|
file.write('= material(); // TODO \n\n')
|
|
else:
|
|
file.write('{\n')
|
|
if functionName in functionTypeMap:
|
|
file.write(INDENT + '// No-op. Return default value for now\n')
|
|
file.write(INDENT + 'return ' + functionTypeMap[functionName] + '();\n')
|
|
else:
|
|
wroteImplementation = False
|
|
if nodeCategory == 'constant':
|
|
file.write(INDENT + 'return mxp_value;\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'absval':
|
|
_writeOneArgumentFunc(file, outputType, '::math::abs')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'ceil':
|
|
_writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'round':
|
|
_writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'floor':
|
|
_writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'sin':
|
|
_writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'asin':
|
|
_writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'cos':
|
|
_writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'acos':
|
|
_writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'tan':
|
|
_writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'atan2':
|
|
_writeTwoArgumentFunc(file, outputType, '::math::'+nodeCategory)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'sqrt':
|
|
_writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'ln':
|
|
_writeOneArgumentFunc(file, outputType, '::math::log')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'exp':
|
|
_writeOneArgumentFunc(file, outputType, '::math::exp')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'sign':
|
|
_writeOneArgumentFunc(file, outputType, '::math::sign')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'max':
|
|
_writeTwoArgumentFunc(file, outputType, '::math::max')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'min':
|
|
_writeTwoArgumentFunc(file, outputType, '::math::min')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'add':
|
|
_writeOperatorFunc(file, outputType, 'mxp_in1', '+', 'mxp_in2')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'subtract':
|
|
_writeOperatorFunc(file, outputType, 'mxp_in1', '-', 'mxp_in2')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'invert':
|
|
_writeOperatorFunc(file, outputType, 'mxp_amount', '-', 'mxp_in')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'multiply':
|
|
_writeOperatorFunc(file, outputType, 'mxp_in1', '*', 'mxp_in2')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'divide':
|
|
if outputType == 'color4':
|
|
file.write(INDENT + 'return mk_color4(mk_float4(mxp_in1) / mk_float4(mxp_in2));')
|
|
wroteImplementation = True
|
|
elif outputType == 'float3x3' or outputType == 'float4x4':
|
|
file.write(INDENT + 'return vectormatrix::mx_divide(mxp_in1, mxp_in2);\n')
|
|
wroteImplementation = True
|
|
else:
|
|
file.write(INDENT + 'return mxp_in1 / mxp_in2;\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'modulo':
|
|
_writeTwoArgumentFunc(file, outputType, 'mx_mod')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'power':
|
|
_writeTwoArgumentFunc(file, outputType, '::math::pow')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'clamp':
|
|
_writeThreeArgumentFunc(file, outputType, '::math::clamp', 'mxp_in', 'mxp_low', 'mxp_high')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'normalize':
|
|
_writeOneArgumentFunc(file, outputType, '::math::normalize')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'magnitude':
|
|
_writeOneArgumentFunc(file, outputType, '::math::length')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'dotproduct':
|
|
_writeTwoArgumentFunc(file, outputType, '::math::dot')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'crossproduct':
|
|
_writeTwoArgumentFunc(file, outputType, '::math::cross')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'image':
|
|
_writeImageImplementation(file, outputType)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'transformmatrix':
|
|
_writeTransformMatrix(file, nodeName)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'determinant':
|
|
_writeOneArgumentFunc(file, outputType, 'vectormatrix::mx_determinant')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'smoothstep':
|
|
_writeThreeArgumentFunc(file, outputType, '::math::smoothstep', 'mxp_in', 'mxp_low', 'mxp_high')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'luminance':
|
|
if nodeName.find('color4') > 0:
|
|
file.write(INDENT + 'color rgb = color(mxp_in.rgb);\n')
|
|
file.write(INDENT + 'color4 returnValue = mk_color4(::math::luminance(rgb));\n')
|
|
file.write(INDENT + 'returnValue.a = mxp_in.a;\n')
|
|
file.write(INDENT + 'return returnValue;\n')
|
|
else:
|
|
_writeOneArgumentFunc(file, outputType, '::math::luminance')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'plus':
|
|
if outputType != 'color4':
|
|
_writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_fg', '(mxp_bg+mxp_fg)', 'mxp_mix')
|
|
else:
|
|
file.write(INDENT + 'color rgb = ::math::lerp(mxp_fg.rgb, mxp_bg.rgb+mxp_fg.rgb, color(mxp_mix));\n')
|
|
file.write(INDENT + 'float a = ::math::lerp(mxp_fg.a, mxp_bg.a+mxp_fg.a, mxp_mix);\n')
|
|
file.write(INDENT + 'return color4(rgb,a);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'minus':
|
|
if outputType != 'color4':
|
|
_writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', '(mxp_bg-mxp_fg)', 'mxp_mix')
|
|
else:
|
|
file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb, mxp_bg.rgb-mxp_fg.rgb, color(mxp_mix));\n')
|
|
file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, mxp_bg.a-mxp_fg.a, mxp_mix);\n')
|
|
file.write(INDENT + 'return color4(rgb,a);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'difference':
|
|
if outputType != 'color4':
|
|
_writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', 'math::abs(mxp_bg-mxp_fg)', 'mxp_mix')
|
|
else:
|
|
file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb, math::abs(mxp_bg.rgb-mxp_fg.rgb), color(mxp_mix));\n')
|
|
file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, math::abs(mxp_bg.a-mxp_fg.a), mxp_mix);\n')
|
|
file.write(INDENT + 'return color4(rgb,a);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'burn':
|
|
if outputType != 'color4':
|
|
burnString = outputType + '(1.0)-(' + outputType + '(1.0)-mxp_bg)/mxp_fg'
|
|
_writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', burnString, 'mxp_mix')
|
|
else:
|
|
dodgeStringRGB = 'color(1.0)-(color(1.0)-mxp_bg.rgb)/mxp_fg.rgb'
|
|
dodgeStringA = '1.0-(1.0-mxp_bg.a)/mxp_fg.a'
|
|
file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb,'+ dodgeStringRGB + ', color(mxp_mix));\n')
|
|
file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, '+ dodgeStringA + ', mxp_mix);\n')
|
|
file.write(INDENT + 'return color4(rgb,a);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'dodge':
|
|
if outputType != 'color4':
|
|
dodgeString = 'mxp_bg/(' + outputType + '(1.0)-mxp_fg)'
|
|
_writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', dodgeString, 'mxp_mix')
|
|
else:
|
|
dodgeStringRGB = 'mxp_bg.rgb/(color(1.0)-mxp_fg.rgb)'
|
|
dodgeStringA = 'mxp_bg.a/(1.0-mxp_fg.a)'
|
|
file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb,'+ dodgeStringRGB + ', color(mxp_mix));\n')
|
|
file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, '+ dodgeStringA + ', mxp_mix);\n')
|
|
file.write(INDENT + 'return color4(rgb,a);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'screen':
|
|
if outputType != 'color4':
|
|
_writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', 'mxp_bg+mxp_fg-mxp_bg*mxp_fg', 'mxp_mix')
|
|
else:
|
|
file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb, mxp_bg.rgb+mxp_fg.rgb-mxp_bg.rgb*mxp_fg.rgb, color(mxp_mix));\n')
|
|
file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, mxp_bg.a+mxp_fg.a-mxp_bg.a*mxp_fg.a, mxp_mix);\n')
|
|
file.write(INDENT + 'return color4(rgb,a);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'inside':
|
|
_writeOperatorFunc(file, outputType, 'mxp_in', '*', 'mxp_mask')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'outside':
|
|
_writeOperatorFunc(file, outputType, 'mxp_in', '*', '(1.0 - mxp_mask)')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'in':
|
|
if outputType == 'float2':
|
|
_writeOperatorFunc(file, outputType, 'mxp_fg', '*', 'mxp_bg*(1.0-mxp_fg.y)')
|
|
else:
|
|
_writeOperatorFunc(file, outputType, 'mxp_fg', '*', 'mx_multiply_color4FA(mxp_bg, 1.0-mxp_fg.a)')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'mix':
|
|
_writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', 'mxp_fg', 'mxp_mix')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'swizzle':
|
|
_writeOneArgumentFunc(file, outputType, 'swizzle::' + channelString)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'combine2':
|
|
_writeTwoArgumentCombine(file, outputType)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'combine3':
|
|
_writeThreeArgumentCombine(file, outputType)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'combine4':
|
|
_writeFourArgumentCombine(file, outputType)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'ifgreater':
|
|
_writeIfGreater(file, '>')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'ifgreatereq':
|
|
_writeIfGreater(file, '>=')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'ifequal':
|
|
_writeIfGreater(file, '==')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'convert':
|
|
if outputType == 'float':
|
|
file.write(INDENT + 'return ' + outputType + '(mxp_in);\n')
|
|
elif outputType == 'color':
|
|
file.write(INDENT + 'return mk_color3(mxp_in);\n')
|
|
else:
|
|
file.write(INDENT + 'return mk_' + outputType + '(mxp_in);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'ramplr':
|
|
if outputType == 'color4':
|
|
file.write(INDENT + 'color rgb = math::lerp(mxp_valuel.rgb, mxp_valuer.rgb, math::clamp(mxp_texcoord.x, 0.0, 1.0));\n')
|
|
file.write(INDENT + 'float a = math::lerp(mxp_valuel.a, mxp_valuer.a, math::clamp(mxp_texcoord.x, 0.0, 1.0));\n')
|
|
file.write(INDENT + 'return color4(rgb, a);')
|
|
else:
|
|
file.write(INDENT + 'return math::lerp(mxp_valuel, mxp_valuer, math::clamp(mxp_texcoord.x, 0.0, 1.0));\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'ramptb':
|
|
if outputType == 'color4':
|
|
file.write(INDENT + 'color rgb = math::lerp(mxp_valuet.rgb, mxp_valueb.rgb, math::clamp(mxp_texcoord.y, 0.0, 1.0));\n')
|
|
file.write(INDENT + 'float a = math::lerp(mxp_valuet.a, mxp_valueb.a, math::clamp(mxp_texcoord.y, 0.0, 1.0));\n')
|
|
file.write(INDENT + 'return color4(rgb, a);')
|
|
else:
|
|
file.write(INDENT + 'return math::lerp(mxp_valuet, mxp_valueb, math::clamp(mxp_texcoord.y, 0.0, 1.0));\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'splitlr':
|
|
if outputType == 'color4':
|
|
file.write(INDENT + 'color rgb = math::lerp(mxp_valuel.rgb, mxp_valuer.rgb, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));')
|
|
file.write(INDENT + 'float a = math::lerp(mxp_valuel.a, mxp_valuer.a, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));')
|
|
file.write(INDENT + 'return color4(rgb, a);')
|
|
else:
|
|
file.write(INDENT + 'return math::lerp(mxp_valuel, mxp_valuer, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'splittb':
|
|
if outputType == 'color4':
|
|
file.write(INDENT + 'color rgb = math::lerp(mxp_valuet.rgb, mxp_valueb.rgb, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));')
|
|
file.write(INDENT + 'float a = math::lerp(mxp_valuet.a, mxp_valueb.a, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));')
|
|
file.write(INDENT + 'return color4(rgb, a);')
|
|
else:
|
|
file.write(INDENT + 'return math::lerp(mxp_valuet, mxp_valueb, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'transformvector':
|
|
_writeTranformSpace(file, outputType, 'transform_vector', 'mxp_in', 'mxp_fromspace', 'mxp_tospace')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'transformpoint':
|
|
_writeTranformSpace(file, outputType, 'transform_point', 'mxp_in', 'mxp_fromspace', 'mxp_tospace')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'transformnormal':
|
|
_writeTranformSpace(file, outputType, 'transform_normal', 'mxp_in', 'mxp_fromspace', 'mxp_tospace')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'position':
|
|
_writeTranformSpace(file, outputType, 'transform_point', 'state::position()', 'mx_coordinatespace_type_model', 'mxp_space')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'normal':
|
|
_writeTranformSpace(file, outputType, 'transform_normal', 'state::normal()', 'mx_coordinatespace_type_model', 'mxp_space')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'tangent':
|
|
_writeTranformSpace(file, outputType, 'transform_vector', 'state::texture_tangent_u(mxp_index)', 'mx_coordinatespace_type_model', 'mxp_space')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'bitangent':
|
|
_writeTranformSpace(file, outputType, 'transform_vector', 'state::texture_tangent_v(mxp_index)', 'mx_coordinatespace_type_model', 'mxp_space')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'texcoord':
|
|
file.write(INDENT + 'return mk_' + outputType + '(state::texture_coordinate(mxp_index));\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'transpose':
|
|
file.write(INDENT + 'return ::math::transpose(mxp_in);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'determinant':
|
|
file.write(INDENT + 'return vectormatrix::mx_determinant(mxp_in);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'rotate2d':
|
|
file.write(INDENT + 'return vectormatrix::mx_rotate(mxp_in, mxp_amount);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'rotate3d':
|
|
file.write(INDENT + 'return vectormatrix::mx_rotate(mxp_in, mxp_amount, mxp_axis);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'remap':
|
|
_writeRemap(file, outputType)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'time':
|
|
file.write(INDENT + 'return ::state::animation_time();\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'hsvtorgb':
|
|
file.write(INDENT + 'return ::hsv::mx_hsvtorgb(mxp_in);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'rgbtohsv':
|
|
file.write(INDENT + 'return ::hsv::mx_rgbtohsv(mxp_in);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'switch':
|
|
_writeSwitch(file, outputType)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'overlay':
|
|
_writeOverlay(file, outputType)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'normalmap':
|
|
writeNormalMap(file)
|
|
wroteImplementation = True
|
|
|
|
elif nodeCategory == 'premult':
|
|
if outputType == 'float2':
|
|
file.write(INDENT + 'return float2(mxp_in.x * mxp_in.y, mxp_in.y);\n')
|
|
elif outputType == 'color4':
|
|
file.write(INDENT + 'return mk_color4(mxp_in.rgb * mxp_in.a, mxp_in.a);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'unpremult':
|
|
if outputType == 'float2':
|
|
file.write(INDENT + 'return float2(mxp_in.x / mxp_in.y, mxp_in.y);\n')
|
|
elif outputType == 'color4':
|
|
file.write(INDENT + 'return mk_color4(mxp_in.rgb / mxp_in.a, mxp_in.a);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'disjointover':
|
|
_writeDisjointOver(file, outputType)
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'mask':
|
|
if outputType == 'float2':
|
|
file.write(INDENT + 'return (mxp_bg * mxp_fg.y * mxp_mix) + mxp_bg*(1.0-mxp_mix);\n')
|
|
elif outputType == 'color4':
|
|
file.write(INDENT + 'return mx_add(' +
|
|
'mx_multiply_color4FA(mxp_bg,mxp_fg.a*mxp_mix),' +
|
|
'mx_multiply_color4FA(mxp_bg, (1.0-mxp_mix)) );\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'matte':
|
|
if outputType == 'float2':
|
|
file.write(INDENT + 'return ' +
|
|
'float2( mxp_fg.x*mxp_fg.y + mxp_bg.x*(1.0-mxp_fg.y), mxp_fg.y + (mxp_bg.y*(1.0-mxp_fg.y)) ) ' +
|
|
'* mxp_mix + (mxp_bg * (1.0-mxp_mix));\n')
|
|
elif outputType == 'color4':
|
|
file.write(INDENT + 'color4 ls = mk_color4(\n')
|
|
file.write(INDENT + ' mx_multiply_color3FA(mxp_fg.rgb,mxp_fg.a) +\n')
|
|
file.write(INDENT + ' mx_multiply_color3FA(mxp_bg.rgb,(1.0-mxp_fg.a)),\n')
|
|
file.write(INDENT + ' mxp_fg.a + (mxp_bg.a*(1.0-mxp_fg.a)) );\n')
|
|
file.write(INDENT + 'ls = mx_multiply(ls,mk_color4(mxp_mix));\n')
|
|
file.write(INDENT + 'color4 rs = mx_multiply_color4FA(mxp_bg,(1.0-mxp_mix));\n')
|
|
file.write(INDENT + 'color4 result = mx_add(ls, rs);\n')
|
|
file.write(INDENT + 'return result;\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'out':
|
|
if outputType == 'float2':
|
|
file.write(INDENT + 'return (mxp_fg*(1.0-mxp_bg.y) * mxp_mix) + (mxp_bg * (1.0-mxp_mix));\n')
|
|
elif outputType == 'color4':
|
|
file.write(INDENT + 'float4 result =\n')
|
|
file.write(INDENT + ' (mk_float4(mxp_fg)*(1.0-mk_float4(mxp_bg).z) * mxp_mix) +\n')
|
|
file.write(INDENT + ' (mk_float4(mxp_bg) * (1.0-mxp_mix));\n')
|
|
file.write(INDENT + 'return mk_color4(result);\n')
|
|
wroteImplementation = True
|
|
elif nodeCategory == 'over':
|
|
if outputType == 'float2':
|
|
file.write(INDENT + 'return mxp_fg + (mxp_bg*(1.0-mxp_fg.y));\n')
|
|
elif outputType == 'color4':
|
|
file.write(INDENT + 'float4 val = mk_float4(mxp_fg) + (mk_float4(mxp_bg)*(1.0-mk_float4(mxp_fg).y));\n')
|
|
file.write(INDENT + 'return mk_color4(val);\n')
|
|
wroteImplementation = True
|
|
|
|
if wroteImplementation:
|
|
implementedCont += 1
|
|
else:
|
|
file.write(INDENT + '// Not implemented: ' + functionName + '\n')
|
|
file.write(INDENT + outputType + ' defaultValue')
|
|
if routeInputToOutput:
|
|
outputType = ''
|
|
_writeValueAssignment(file, outputValue, outputType, outputType == 'texture_2d')
|
|
file.write(';\n')
|
|
file.write(INDENT + 'return defaultValue;\n')
|
|
file.write('}\n\n')
|
|
|
|
if len(moduleName) == 0:
|
|
file.close()
|
|
|
|
if len(moduleName):
|
|
file.close()
|
|
|
|
# Save implementation reference file to disk
|
|
implFileName = moduleName + '_gen_' + IMPLEMENTATION_STRING + '.ref_mtlx'
|
|
implPath = os.path.join(impl_outputPath, implFileName)
|
|
print('Wrote implementation file: ' + implPath + '. ' + str(implementedCont) + '/' + str(totalCount) + '\n')
|
|
mx.writeToXmlFile(implDoc, implPath)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|