princeton-vl__infinigen METASEP

process_mesh/dependencies/glad/include/glad/glad_egl.h METASEP
/*

    EGL loader generated by glad 0.1.35 on Mon Jan 17 21:14:15 2022.

    Language/Generator: C/C++
    Specification: egl
    APIs: egl=1.5
    Profile: -
    Extensions:
        
    Loader: True
    Local files: False
    Omit khrplatform: False
    Reproducible: False

    Commandline:
        --api="egl=1.5" --generator="c" --spec="egl" --extensions=""
    Online:
        https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.5
*/


#ifndef __glad_egl_h_

#ifdef __egl_h_
#error EGL header already included, remove this include, glad already provides it
#endif

#define __glad_egl_h_
#define __egl_h_

#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
#define APIENTRY __stdcall
#endif

#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
#ifndef GLAPI
#define GLAPI extern
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef void* (* GLADloadproc)(const char *name);

GLAPI int gladLoadEGL(void);
GLAPI int gladLoadEGLLoader(GLADloadproc);

#include <KHR/khrplatform.h>
#include <EGL/eglplatform.h>
struct AHardwareBuffer;
struct wl_buffer;
struct wl_display;
struct wl_resource;
typedef unsigned int EGLBoolean;
typedef unsigned int EGLenum;
typedef intptr_t EGLAttribKHR;
typedef intptr_t EGLAttrib;
typedef void *EGLClientBuffer;
typedef void *EGLConfig;
typedef void *EGLContext;
typedef void *EGLDeviceEXT;
typedef void *EGLDisplay;
typedef void *EGLImage;
typedef void *EGLImageKHR;
typedef void *EGLLabelKHR;
typedef void *EGLObjectKHR;
typedef void *EGLOutputLayerEXT;
typedef void *EGLOutputPortEXT;
typedef void *EGLStreamKHR;
typedef void *EGLSurface;
typedef void *EGLSync;
typedef void *EGLSyncKHR;
typedef void *EGLSyncNV;
typedef void (*__eglMustCastToProperFunctionPointerType)(void);
typedef khronos_utime_nanoseconds_t EGLTimeKHR;
typedef khronos_utime_nanoseconds_t EGLTime;
typedef khronos_utime_nanoseconds_t EGLTimeNV;
typedef khronos_utime_nanoseconds_t EGLuint64NV;
typedef khronos_uint64_t EGLuint64KHR;
typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
typedef int EGLNativeFileDescriptorKHR;
typedef khronos_ssize_t EGLsizeiANDROID;
typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);
typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);
struct EGLClientPixmapHI {
    void  *pData;
    EGLint iWidth;
    EGLint iHeight;
    EGLint iStride;
};
typedef void (APIENTRY *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message);
#define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC
#define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC
#define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC
#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC
#define EGL_ALPHA_SIZE 0x3021
#define EGL_BAD_ACCESS 0x3002
#define EGL_BAD_ALLOC 0x3003
#define EGL_BAD_ATTRIBUTE 0x3004
#define EGL_BAD_CONFIG 0x3005
#define EGL_BAD_CONTEXT 0x3006
#define EGL_BAD_CURRENT_SURFACE 0x3007
#define EGL_BAD_DISPLAY 0x3008
#define EGL_BAD_MATCH 0x3009
#define EGL_BAD_NATIVE_PIXMAP 0x300A
#define EGL_BAD_NATIVE_WINDOW 0x300B
#define EGL_BAD_PARAMETER 0x300C
#define EGL_BAD_SURFACE 0x300D
#define EGL_BLUE_SIZE 0x3022
#define EGL_BUFFER_SIZE 0x3020
#define EGL_CONFIG_CAVEAT 0x3027
#define EGL_CONFIG_ID 0x3028
#define EGL_CORE_NATIVE_ENGINE 0x305B
#define EGL_DEPTH_SIZE 0x3025
#define EGL_DONT_CARE EGL_CAST(EGLint,-1)
#define EGL_DRAW 0x3059
#define EGL_EXTENSIONS 0x3055
#define EGL_FALSE 0
#define EGL_GREEN_SIZE 0x3023
#define EGL_HEIGHT 0x3056
#define EGL_LARGEST_PBUFFER 0x3058
#define EGL_LEVEL 0x3029
#define EGL_MAX_PBUFFER_HEIGHT 0x302A
#define EGL_MAX_PBUFFER_PIXELS 0x302B
#define EGL_MAX_PBUFFER_WIDTH 0x302C
#define EGL_NATIVE_RENDERABLE 0x302D
#define EGL_NATIVE_VISUAL_ID 0x302E
#define EGL_NATIVE_VISUAL_TYPE 0x302F
#define EGL_NONE 0x3038
#define EGL_NON_CONFORMANT_CONFIG 0x3051
#define EGL_NOT_INITIALIZED 0x3001
#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0)
#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0)
#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0)
#define EGL_PBUFFER_BIT 0x0001
#define EGL_PIXMAP_BIT 0x0002
#define EGL_READ 0x305A
#define EGL_RED_SIZE 0x3024
#define EGL_SAMPLES 0x3031
#define EGL_SAMPLE_BUFFERS 0x3032
#define EGL_SLOW_CONFIG 0x3050
#define EGL_STENCIL_SIZE 0x3026
#define EGL_SUCCESS 0x3000
#define EGL_SURFACE_TYPE 0x3033
#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
#define EGL_TRANSPARENT_RED_VALUE 0x3037
#define EGL_TRANSPARENT_RGB 0x3052
#define EGL_TRANSPARENT_TYPE 0x3034
#define EGL_TRUE 1
#define EGL_VENDOR 0x3053
#define EGL_VERSION 0x3054
#define EGL_WIDTH 0x3057
#define EGL_WINDOW_BIT 0x0004
#define EGL_BACK_BUFFER 0x3084
#define EGL_BIND_TO_TEXTURE_RGB 0x3039
#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
#define EGL_CONTEXT_LOST 0x300E
#define EGL_MIN_SWAP_INTERVAL 0x303B
#define EGL_MAX_SWAP_INTERVAL 0x303C
#define EGL_MIPMAP_TEXTURE 0x3082
#define EGL_MIPMAP_LEVEL 0x3083
#define EGL_NO_TEXTURE 0x305C
#define EGL_TEXTURE_2D 0x305F
#define EGL_TEXTURE_FORMAT 0x3080
#define EGL_TEXTURE_RGB 0x305D
#define EGL_TEXTURE_RGBA 0x305E
#define EGL_TEXTURE_TARGET 0x3081
#define EGL_ALPHA_FORMAT 0x3088
#define EGL_ALPHA_FORMAT_NONPRE 0x308B
#define EGL_ALPHA_FORMAT_PRE 0x308C
#define EGL_ALPHA_MASK_SIZE 0x303E
#define EGL_BUFFER_PRESERVED 0x3094
#define EGL_BUFFER_DESTROYED 0x3095
#define EGL_CLIENT_APIS 0x308D
#define EGL_COLORSPACE 0x3087
#define EGL_COLORSPACE_sRGB 0x3089
#define EGL_COLORSPACE_LINEAR 0x308A
#define EGL_COLOR_BUFFER_TYPE 0x303F
#define EGL_CONTEXT_CLIENT_TYPE 0x3097
#define EGL_DISPLAY_SCALING 10000
#define EGL_HORIZONTAL_RESOLUTION 0x3090
#define EGL_LUMINANCE_BUFFER 0x308F
#define EGL_LUMINANCE_SIZE 0x303D
#define EGL_OPENGL_ES_BIT 0x0001
#define EGL_OPENVG_BIT 0x0002
#define EGL_OPENGL_ES_API 0x30A0
#define EGL_OPENVG_API 0x30A1
#define EGL_OPENVG_IMAGE 0x3096
#define EGL_PIXEL_ASPECT_RATIO 0x3092
#define EGL_RENDERABLE_TYPE 0x3040
#define EGL_RENDER_BUFFER 0x3086
#define EGL_RGB_BUFFER 0x308E
#define EGL_SINGLE_BUFFER 0x3085
#define EGL_SWAP_BEHAVIOR 0x3093
#define EGL_UNKNOWN EGL_CAST(EGLint,-1)
#define EGL_VERTICAL_RESOLUTION 0x3091
#define EGL_CONFORMANT 0x3042
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
#define EGL_MATCH_NATIVE_PIXMAP 0x3041
#define EGL_OPENGL_ES2_BIT 0x0004
#define EGL_VG_ALPHA_FORMAT 0x3088
#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B
#define EGL_VG_ALPHA_FORMAT_PRE 0x308C
#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040
#define EGL_VG_COLORSPACE 0x3087
#define EGL_VG_COLORSPACE_sRGB 0x3089
#define EGL_VG_COLORSPACE_LINEAR 0x308A
#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020
#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0)
#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
#define EGL_MULTISAMPLE_RESOLVE 0x3099
#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A
#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B
#define EGL_OPENGL_API 0x30A2
#define EGL_OPENGL_BIT 0x0008
#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
#define EGL_CONTEXT_MAJOR_VERSION 0x3098
#define EGL_CONTEXT_MINOR_VERSION 0x30FB
#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD
#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
#define EGL_NO_RESET_NOTIFICATION 0x31BE
#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF
#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001
#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002
#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1
#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
#define EGL_OPENGL_ES3_BIT 0x00000040
#define EGL_CL_EVENT_HANDLE 0x309C
#define EGL_SYNC_CL_EVENT 0x30FE
#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF
#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0
#define EGL_SYNC_TYPE 0x30F7
#define EGL_SYNC_STATUS 0x30F1
#define EGL_SYNC_CONDITION 0x30F8
#define EGL_SIGNALED 0x30F2
#define EGL_UNSIGNALED 0x30F3
#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001
#define EGL_FOREVER 0xFFFFFFFFFFFFFFFF
#define EGL_TIMEOUT_EXPIRED 0x30F5
#define EGL_CONDITION_SATISFIED 0x30F6
#define EGL_NO_SYNC EGL_CAST(EGLSync,0)
#define EGL_SYNC_FENCE 0x30F9
#define EGL_GL_COLORSPACE 0x309D
#define EGL_GL_COLORSPACE_SRGB 0x3089
#define EGL_GL_COLORSPACE_LINEAR 0x308A
#define EGL_GL_RENDERBUFFER 0x30B9
#define EGL_GL_TEXTURE_2D 0x30B1
#define EGL_GL_TEXTURE_LEVEL 0x30BC
#define EGL_GL_TEXTURE_3D 0x30B2
#define EGL_GL_TEXTURE_ZOFFSET 0x30BD
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
#define EGL_IMAGE_PRESERVED 0x30D2
#define EGL_NO_IMAGE EGL_CAST(EGLImage,0)
EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
EGLDisplay eglGetCurrentDisplay(void);
EGLSurface eglGetCurrentSurface(EGLint readdraw);
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id);
EGLint eglGetError(void);
__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname);
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
const char *eglQueryString(EGLDisplay dpy, EGLint name);
EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);
EGLBoolean eglTerminate(EGLDisplay dpy);
EGLBoolean eglWaitGL(void);
EGLBoolean eglWaitNative(EGLint engine);
EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval);
EGLBoolean eglBindAPI(EGLenum api);
EGLenum eglQueryAPI(void);
EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
EGLBoolean eglReleaseThread(void);
EGLBoolean eglWaitClient(void);
EGLContext eglGetCurrentContext(void);
EGLSync eglCreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
EGLBoolean eglDestroySync(EGLDisplay dpy, EGLSync sync);
EGLint eglClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
EGLBoolean eglGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
EGLImage eglCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
EGLBoolean eglDestroyImage(EGLDisplay dpy, EGLImage image);
EGLDisplay eglGetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
EGLSurface eglCreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
EGLSurface eglCreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
EGLBoolean eglWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags);

#ifdef __cplusplus
}
#endif

#endif

process_mesh/dependencies/glad/include/glad/glad.h METASEP
/*

    OpenGL loader generated by glad 0.1.35 on Mon Jan 17 21:17:15 2022.

    Language/Generator: C/C++
    Specification: gl
    APIs: gl=4.4
    Profile: core
    Extensions:
        
    Loader: True
    Local files: False
    Omit khrplatform: False
    Reproducible: False

    Commandline:
        --profile="core" --api="gl=4.4" --generator="c" --spec="gl" --extensions=""
    Online:
        https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.4
*/


#ifndef __glad_h_
#define __glad_h_

#ifdef __gl_h_
#error OpenGL header already included, remove this include, glad already provides it
#endif
#define __gl_h_

#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
#define APIENTRY __stdcall
#endif

#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif

#ifndef GLAPIENTRY
#define GLAPIENTRY APIENTRY
#endif

#ifdef __cplusplus
extern "C" {
#endif

struct gladGLversionStruct {
    int major;
    int minor;
};

typedef void* (* GLADloadproc)(const char *name);

#ifndef GLAPI
# if defined(GLAD_GLAPI_EXPORT)
#  if defined(_WIN32) || defined(__CYGWIN__)
#   if defined(GLAD_GLAPI_EXPORT_BUILD)
#    if defined(__GNUC__)
#     define GLAPI __attribute__ ((dllexport)) extern
#    else
#     define GLAPI __declspec(dllexport) extern
#    endif
#   else
#    if defined(__GNUC__)
#     define GLAPI __attribute__ ((dllimport)) extern
#    else
#     define GLAPI __declspec(dllimport) extern
#    endif
#   endif
#  elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD)
#   define GLAPI __attribute__ ((visibility ("default"))) extern
#  else
#   define GLAPI extern
#  endif
# else
#  define GLAPI extern
# endif
#endif

GLAPI struct gladGLversionStruct GLVersion;

GLAPI int gladLoadGL(void);

GLAPI int gladLoadGLLoader(GLADloadproc);

#include <KHR/khrplatform.h>
typedef unsigned int GLenum;
typedef unsigned char GLboolean;
typedef unsigned int GLbitfield;
typedef void GLvoid;
typedef khronos_int8_t GLbyte;
typedef khronos_uint8_t GLubyte;
typedef khronos_int16_t GLshort;
typedef khronos_uint16_t GLushort;
typedef int GLint;
typedef unsigned int GLuint;
typedef khronos_int32_t GLclampx;
typedef int GLsizei;
typedef khronos_float_t GLfloat;
typedef khronos_float_t GLclampf;
typedef double GLdouble;
typedef double GLclampd;
typedef void *GLeglClientBufferEXT;
typedef void *GLeglImageOES;
typedef char GLchar;
typedef char GLcharARB;
#ifdef __APPLE__
typedef void *GLhandleARB;
#else
typedef unsigned int GLhandleARB;
#endif
typedef khronos_uint16_t GLhalf;
typedef khronos_uint16_t GLhalfARB;
typedef khronos_int32_t GLfixed;
typedef khronos_intptr_t GLintptr;
typedef khronos_intptr_t GLintptrARB;
typedef khronos_ssize_t GLsizeiptr;
typedef khronos_ssize_t GLsizeiptrARB;
typedef khronos_int64_t GLint64;
typedef khronos_int64_t GLint64EXT;
typedef khronos_uint64_t GLuint64;
typedef khronos_uint64_t GLuint64EXT;
typedef struct __GLsync *GLsync;
struct _cl_context;
struct _cl_event;
typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
typedef unsigned short GLhalfNV;
typedef GLintptr GLvdpauSurfaceNV;
typedef void (APIENTRY *GLVULKANPROCNV)(void);
#define GL_DEPTH_BUFFER_BIT 0x00000100
#define GL_STENCIL_BUFFER_BIT 0x00000400
#define GL_COLOR_BUFFER_BIT 0x00004000
#define GL_FALSE 0
#define GL_TRUE 1
#define GL_POINTS 0x0000
#define GL_LINES 0x0001
#define GL_LINE_LOOP 0x0002
#define GL_LINE_STRIP 0x0003
#define GL_TRIANGLES 0x0004
#define GL_TRIANGLE_STRIP 0x0005
#define GL_TRIANGLE_FAN 0x0006
#define GL_NEVER 0x0200
#define GL_LESS 0x0201
#define GL_EQUAL 0x0202
#define GL_LEQUAL 0x0203
#define GL_GREATER 0x0204
#define GL_NOTEQUAL 0x0205
#define GL_GEQUAL 0x0206
#define GL_ALWAYS 0x0207
#define GL_ZERO 0
#define GL_ONE 1
#define GL_SRC_COLOR 0x0300
#define GL_ONE_MINUS_SRC_COLOR 0x0301
#define GL_SRC_ALPHA 0x0302
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
#define GL_DST_ALPHA 0x0304
#define GL_ONE_MINUS_DST_ALPHA 0x0305
#define GL_DST_COLOR 0x0306
#define GL_ONE_MINUS_DST_COLOR 0x0307
#define GL_SRC_ALPHA_SATURATE 0x0308
#define GL_NONE 0
#define GL_FRONT_LEFT 0x0400
#define GL_FRONT_RIGHT 0x0401
#define GL_BACK_LEFT 0x0402
#define GL_BACK_RIGHT 0x0403
#define GL_FRONT 0x0404
#define GL_BACK 0x0405
#define GL_LEFT 0x0406
#define GL_RIGHT 0x0407
#define GL_FRONT_AND_BACK 0x0408
#define GL_NO_ERROR 0
#define GL_INVALID_ENUM 0x0500
#define GL_INVALID_VALUE 0x0501
#define GL_INVALID_OPERATION 0x0502
#define GL_OUT_OF_MEMORY 0x0505
#define GL_CW 0x0900
#define GL_CCW 0x0901
#define GL_POINT_SIZE 0x0B11
#define GL_POINT_SIZE_RANGE 0x0B12
#define GL_POINT_SIZE_GRANULARITY 0x0B13
#define GL_LINE_SMOOTH 0x0B20
#define GL_LINE_WIDTH 0x0B21
#define GL_LINE_WIDTH_RANGE 0x0B22
#define GL_LINE_WIDTH_GRANULARITY 0x0B23
#define GL_POLYGON_MODE 0x0B40
#define GL_POLYGON_SMOOTH 0x0B41
#define GL_CULL_FACE 0x0B44
#define GL_CULL_FACE_MODE 0x0B45
#define GL_FRONT_FACE 0x0B46
#define GL_DEPTH_RANGE 0x0B70
#define GL_DEPTH_TEST 0x0B71
#define GL_DEPTH_WRITEMASK 0x0B72
#define GL_DEPTH_CLEAR_VALUE 0x0B73
#define GL_DEPTH_FUNC 0x0B74
#define GL_STENCIL_TEST 0x0B90
#define GL_STENCIL_CLEAR_VALUE 0x0B91
#define GL_STENCIL_FUNC 0x0B92
#define GL_STENCIL_VALUE_MASK 0x0B93
#define GL_STENCIL_FAIL 0x0B94
#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
#define GL_STENCIL_REF 0x0B97
#define GL_STENCIL_WRITEMASK 0x0B98
#define GL_VIEWPORT 0x0BA2
#define GL_DITHER 0x0BD0
#define GL_BLEND_DST 0x0BE0
#define GL_BLEND_SRC 0x0BE1
#define GL_BLEND 0x0BE2
#define GL_LOGIC_OP_MODE 0x0BF0
#define GL_DRAW_BUFFER 0x0C01
#define GL_READ_BUFFER 0x0C02
#define GL_SCISSOR_BOX 0x0C10
#define GL_SCISSOR_TEST 0x0C11
#define GL_COLOR_CLEAR_VALUE 0x0C22
#define GL_COLOR_WRITEMASK 0x0C23
#define GL_DOUBLEBUFFER 0x0C32
#define GL_STEREO 0x0C33
#define GL_LINE_SMOOTH_HINT 0x0C52
#define GL_POLYGON_SMOOTH_HINT 0x0C53
#define GL_UNPACK_SWAP_BYTES 0x0CF0
#define GL_UNPACK_LSB_FIRST 0x0CF1
#define GL_UNPACK_ROW_LENGTH 0x0CF2
#define GL_UNPACK_SKIP_ROWS 0x0CF3
#define GL_UNPACK_SKIP_PIXELS 0x0CF4
#define GL_UNPACK_ALIGNMENT 0x0CF5
#define GL_PACK_SWAP_BYTES 0x0D00
#define GL_PACK_LSB_FIRST 0x0D01
#define GL_PACK_ROW_LENGTH 0x0D02
#define GL_PACK_SKIP_ROWS 0x0D03
#define GL_PACK_SKIP_PIXELS 0x0D04
#define GL_PACK_ALIGNMENT 0x0D05
#define GL_MAX_TEXTURE_SIZE 0x0D33
#define GL_MAX_VIEWPORT_DIMS 0x0D3A
#define GL_SUBPIXEL_BITS 0x0D50
#define GL_TEXTURE_1D 0x0DE0
#define GL_TEXTURE_2D 0x0DE1
#define GL_TEXTURE_WIDTH 0x1000
#define GL_TEXTURE_HEIGHT 0x1001
#define GL_TEXTURE_BORDER_COLOR 0x1004
#define GL_DONT_CARE 0x1100
#define GL_FASTEST 0x1101
#define GL_NICEST 0x1102
#define GL_BYTE 0x1400
#define GL_UNSIGNED_BYTE 0x1401
#define GL_SHORT 0x1402
#define GL_UNSIGNED_SHORT 0x1403
#define GL_INT 0x1404
#define GL_UNSIGNED_INT 0x1405
#define GL_FLOAT 0x1406
#define GL_CLEAR 0x1500
#define GL_AND 0x1501
#define GL_AND_REVERSE 0x1502
#define GL_COPY 0x1503
#define GL_AND_INVERTED 0x1504
#define GL_NOOP 0x1505
#define GL_XOR 0x1506
#define GL_OR 0x1507
#define GL_NOR 0x1508
#define GL_EQUIV 0x1509
#define GL_INVERT 0x150A
#define GL_OR_REVERSE 0x150B
#define GL_COPY_INVERTED 0x150C
#define GL_OR_INVERTED 0x150D
#define GL_NAND 0x150E
#define GL_SET 0x150F
#define GL_TEXTURE 0x1702
#define GL_COLOR 0x1800
#define GL_DEPTH 0x1801
#define GL_STENCIL 0x1802
#define GL_STENCIL_INDEX 0x1901
#define GL_DEPTH_COMPONENT 0x1902
#define GL_RED 0x1903
#define GL_GREEN 0x1904
#define GL_BLUE 0x1905
#define GL_ALPHA 0x1906
#define GL_RGB 0x1907
#define GL_RGBA 0x1908
#define GL_POINT 0x1B00
#define GL_LINE 0x1B01
#define GL_FILL 0x1B02
#define GL_KEEP 0x1E00
#define GL_REPLACE 0x1E01
#define GL_INCR 0x1E02
#define GL_DECR 0x1E03
#define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01
#define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03
#define GL_NEAREST 0x2600
#define GL_LINEAR 0x2601
#define GL_NEAREST_MIPMAP_NEAREST 0x2700
#define GL_LINEAR_MIPMAP_NEAREST 0x2701
#define GL_NEAREST_MIPMAP_LINEAR 0x2702
#define GL_LINEAR_MIPMAP_LINEAR 0x2703
#define GL_TEXTURE_MAG_FILTER 0x2800
#define GL_TEXTURE_MIN_FILTER 0x2801
#define GL_TEXTURE_WRAP_S 0x2802
#define GL_TEXTURE_WRAP_T 0x2803
#define GL_REPEAT 0x2901
#define GL_COLOR_LOGIC_OP 0x0BF2
#define GL_POLYGON_OFFSET_UNITS 0x2A00
#define GL_POLYGON_OFFSET_POINT 0x2A01
#define GL_POLYGON_OFFSET_LINE 0x2A02
#define GL_POLYGON_OFFSET_FILL 0x8037
#define GL_POLYGON_OFFSET_FACTOR 0x8038
#define GL_TEXTURE_BINDING_1D 0x8068
#define GL_TEXTURE_BINDING_2D 0x8069
#define GL_TEXTURE_INTERNAL_FORMAT 0x1003
#define GL_TEXTURE_RED_SIZE 0x805C
#define GL_TEXTURE_GREEN_SIZE 0x805D
#define GL_TEXTURE_BLUE_SIZE 0x805E
#define GL_TEXTURE_ALPHA_SIZE 0x805F
#define GL_DOUBLE 0x140A
#define GL_PROXY_TEXTURE_1D 0x8063
#define GL_PROXY_TEXTURE_2D 0x8064
#define GL_R3_G3_B2 0x2A10
#define GL_RGB4 0x804F
#define GL_RGB5 0x8050
#define GL_RGB8 0x8051
#define GL_RGB10 0x8052
#define GL_RGB12 0x8053
#define GL_RGB16 0x8054
#define GL_RGBA2 0x8055
#define GL_RGBA4 0x8056
#define GL_RGB5_A1 0x8057
#define GL_RGBA8 0x8058
#define GL_RGB10_A2 0x8059
#define GL_RGBA12 0x805A
#define GL_RGBA16 0x805B
#define GL_UNSIGNED_BYTE_3_3_2 0x8032
#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
#define GL_UNSIGNED_INT_8_8_8_8 0x8035
#define GL_UNSIGNED_INT_10_10_10_2 0x8036
#define GL_TEXTURE_BINDING_3D 0x806A
#define GL_PACK_SKIP_IMAGES 0x806B
#define GL_PACK_IMAGE_HEIGHT 0x806C
#define GL_UNPACK_SKIP_IMAGES 0x806D
#define GL_UNPACK_IMAGE_HEIGHT 0x806E
#define GL_TEXTURE_3D 0x806F
#define GL_PROXY_TEXTURE_3D 0x8070
#define GL_TEXTURE_DEPTH 0x8071
#define GL_TEXTURE_WRAP_R 0x8072
#define GL_MAX_3D_TEXTURE_SIZE 0x8073
#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
#define GL_UNSIGNED_SHORT_5_6_5 0x8363
#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
#define GL_BGR 0x80E0
#define GL_BGRA 0x80E1
#define GL_MAX_ELEMENTS_VERTICES 0x80E8
#define GL_MAX_ELEMENTS_INDICES 0x80E9
#define GL_CLAMP_TO_EDGE 0x812F
#define GL_TEXTURE_MIN_LOD 0x813A
#define GL_TEXTURE_MAX_LOD 0x813B
#define GL_TEXTURE_BASE_LEVEL 0x813C
#define GL_TEXTURE_MAX_LEVEL 0x813D
#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13
#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23
#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
#define GL_TEXTURE0 0x84C0
#define GL_TEXTURE1 0x84C1
#define GL_TEXTURE2 0x84C2
#define GL_TEXTURE3 0x84C3
#define GL_TEXTURE4 0x84C4
#define GL_TEXTURE5 0x84C5
#define GL_TEXTURE6 0x84C6
#define GL_TEXTURE7 0x84C7
#define GL_TEXTURE8 0x84C8
#define GL_TEXTURE9 0x84C9
#define GL_TEXTURE10 0x84CA
#define GL_TEXTURE11 0x84CB
#define GL_TEXTURE12 0x84CC
#define GL_TEXTURE13 0x84CD
#define GL_TEXTURE14 0x84CE
#define GL_TEXTURE15 0x84CF
#define GL_TEXTURE16 0x84D0
#define GL_TEXTURE17 0x84D1
#define GL_TEXTURE18 0x84D2
#define GL_TEXTURE19 0x84D3
#define GL_TEXTURE20 0x84D4
#define GL_TEXTURE21 0x84D5
#define GL_TEXTURE22 0x84D6
#define GL_TEXTURE23 0x84D7
#define GL_TEXTURE24 0x84D8
#define GL_TEXTURE25 0x84D9
#define GL_TEXTURE26 0x84DA
#define GL_TEXTURE27 0x84DB
#define GL_TEXTURE28 0x84DC
#define GL_TEXTURE29 0x84DD
#define GL_TEXTURE30 0x84DE
#define GL_TEXTURE31 0x84DF
#define GL_ACTIVE_TEXTURE 0x84E0
#define GL_MULTISAMPLE 0x809D
#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
#define GL_SAMPLE_COVERAGE 0x80A0
#define GL_SAMPLE_BUFFERS 0x80A8
#define GL_SAMPLES 0x80A9
#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
#define GL_TEXTURE_CUBE_MAP 0x8513
#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B
#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
#define GL_COMPRESSED_RGB 0x84ED
#define GL_COMPRESSED_RGBA 0x84EE
#define GL_TEXTURE_COMPRESSION_HINT 0x84EF
#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0
#define GL_TEXTURE_COMPRESSED 0x86A1
#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
#define GL_CLAMP_TO_BORDER 0x812D
#define GL_BLEND_DST_RGB 0x80C8
#define GL_BLEND_SRC_RGB 0x80C9
#define GL_BLEND_DST_ALPHA 0x80CA
#define GL_BLEND_SRC_ALPHA 0x80CB
#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128
#define GL_DEPTH_COMPONENT16 0x81A5
#define GL_DEPTH_COMPONENT24 0x81A6
#define GL_DEPTH_COMPONENT32 0x81A7
#define GL_MIRRORED_REPEAT 0x8370
#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
#define GL_TEXTURE_LOD_BIAS 0x8501
#define GL_INCR_WRAP 0x8507
#define GL_DECR_WRAP 0x8508
#define GL_TEXTURE_DEPTH_SIZE 0x884A
#define GL_TEXTURE_COMPARE_MODE 0x884C
#define GL_TEXTURE_COMPARE_FUNC 0x884D
#define GL_BLEND_COLOR 0x8005
#define GL_BLEND_EQUATION 0x8009
#define GL_CONSTANT_COLOR 0x8001
#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
#define GL_CONSTANT_ALPHA 0x8003
#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
#define GL_FUNC_ADD 0x8006
#define GL_FUNC_REVERSE_SUBTRACT 0x800B
#define GL_FUNC_SUBTRACT 0x800A
#define GL_MIN 0x8007
#define GL_MAX 0x8008
#define GL_BUFFER_SIZE 0x8764
#define GL_BUFFER_USAGE 0x8765
#define GL_QUERY_COUNTER_BITS 0x8864
#define GL_CURRENT_QUERY 0x8865
#define GL_QUERY_RESULT 0x8866
#define GL_QUERY_RESULT_AVAILABLE 0x8867
#define GL_ARRAY_BUFFER 0x8892
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
#define GL_ARRAY_BUFFER_BINDING 0x8894
#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
#define GL_READ_ONLY 0x88B8
#define GL_WRITE_ONLY 0x88B9
#define GL_READ_WRITE 0x88BA
#define GL_BUFFER_ACCESS 0x88BB
#define GL_BUFFER_MAPPED 0x88BC
#define GL_BUFFER_MAP_POINTER 0x88BD
#define GL_STREAM_DRAW 0x88E0
#define GL_STREAM_READ 0x88E1
#define GL_STREAM_COPY 0x88E2
#define GL_STATIC_DRAW 0x88E4
#define GL_STATIC_READ 0x88E5
#define GL_STATIC_COPY 0x88E6
#define GL_DYNAMIC_DRAW 0x88E8
#define GL_DYNAMIC_READ 0x88E9
#define GL_DYNAMIC_COPY 0x88EA
#define GL_SAMPLES_PASSED 0x8914
#define GL_SRC1_ALPHA 0x8589
#define GL_BLEND_EQUATION_RGB 0x8009
#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
#define GL_CURRENT_VERTEX_ATTRIB 0x8626
#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
#define GL_STENCIL_BACK_FUNC 0x8800
#define GL_STENCIL_BACK_FAIL 0x8801
#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
#define GL_MAX_DRAW_BUFFERS 0x8824
#define GL_DRAW_BUFFER0 0x8825
#define GL_DRAW_BUFFER1 0x8826
#define GL_DRAW_BUFFER2 0x8827
#define GL_DRAW_BUFFER3 0x8828
#define GL_DRAW_BUFFER4 0x8829
#define GL_DRAW_BUFFER5 0x882A
#define GL_DRAW_BUFFER6 0x882B
#define GL_DRAW_BUFFER7 0x882C
#define GL_DRAW_BUFFER8 0x882D
#define GL_DRAW_BUFFER9 0x882E
#define GL_DRAW_BUFFER10 0x882F
#define GL_DRAW_BUFFER11 0x8830
#define GL_DRAW_BUFFER12 0x8831
#define GL_DRAW_BUFFER13 0x8832
#define GL_DRAW_BUFFER14 0x8833
#define GL_DRAW_BUFFER15 0x8834
#define GL_BLEND_EQUATION_ALPHA 0x883D
#define GL_MAX_VERTEX_ATTRIBS 0x8869
#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_VERTEX_SHADER 0x8B31
#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
#define GL_MAX_VARYING_FLOATS 0x8B4B
#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
#define GL_SHADER_TYPE 0x8B4F
#define GL_FLOAT_VEC2 0x8B50
#define GL_FLOAT_VEC3 0x8B51
#define GL_FLOAT_VEC4 0x8B52
#define GL_INT_VEC2 0x8B53
#define GL_INT_VEC3 0x8B54
#define GL_INT_VEC4 0x8B55
#define GL_BOOL 0x8B56
#define GL_BOOL_VEC2 0x8B57
#define GL_BOOL_VEC3 0x8B58
#define GL_BOOL_VEC4 0x8B59
#define GL_FLOAT_MAT2 0x8B5A
#define GL_FLOAT_MAT3 0x8B5B
#define GL_FLOAT_MAT4 0x8B5C
#define GL_SAMPLER_1D 0x8B5D
#define GL_SAMPLER_2D 0x8B5E
#define GL_SAMPLER_3D 0x8B5F
#define GL_SAMPLER_CUBE 0x8B60
#define GL_SAMPLER_1D_SHADOW 0x8B61
#define GL_SAMPLER_2D_SHADOW 0x8B62
#define GL_DELETE_STATUS 0x8B80
#define GL_COMPILE_STATUS 0x8B81
#define GL_LINK_STATUS 0x8B82
#define GL_VALIDATE_STATUS 0x8B83
#define GL_INFO_LOG_LENGTH 0x8B84
#define GL_ATTACHED_SHADERS 0x8B85
#define GL_ACTIVE_UNIFORMS 0x8B86
#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
#define GL_SHADER_SOURCE_LENGTH 0x8B88
#define GL_ACTIVE_ATTRIBUTES 0x8B89
#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
#define GL_CURRENT_PROGRAM 0x8B8D
#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0
#define GL_LOWER_LEFT 0x8CA1
#define GL_UPPER_LEFT 0x8CA2
#define GL_STENCIL_BACK_REF 0x8CA3
#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
#define GL_PIXEL_PACK_BUFFER 0x88EB
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
#define GL_FLOAT_MAT2x3 0x8B65
#define GL_FLOAT_MAT2x4 0x8B66
#define GL_FLOAT_MAT3x2 0x8B67
#define GL_FLOAT_MAT3x4 0x8B68
#define GL_FLOAT_MAT4x2 0x8B69
#define GL_FLOAT_MAT4x3 0x8B6A
#define GL_SRGB 0x8C40
#define GL_SRGB8 0x8C41
#define GL_SRGB_ALPHA 0x8C42
#define GL_SRGB8_ALPHA8 0x8C43
#define GL_COMPRESSED_SRGB 0x8C48
#define GL_COMPRESSED_SRGB_ALPHA 0x8C49
#define GL_COMPARE_REF_TO_TEXTURE 0x884E
#define GL_CLIP_DISTANCE0 0x3000
#define GL_CLIP_DISTANCE1 0x3001
#define GL_CLIP_DISTANCE2 0x3002
#define GL_CLIP_DISTANCE3 0x3003
#define GL_CLIP_DISTANCE4 0x3004
#define GL_CLIP_DISTANCE5 0x3005
#define GL_CLIP_DISTANCE6 0x3006
#define GL_CLIP_DISTANCE7 0x3007
#define GL_MAX_CLIP_DISTANCES 0x0D32
#define GL_MAJOR_VERSION 0x821B
#define GL_MINOR_VERSION 0x821C
#define GL_NUM_EXTENSIONS 0x821D
#define GL_CONTEXT_FLAGS 0x821E
#define GL_COMPRESSED_RED 0x8225
#define GL_COMPRESSED_RG 0x8226
#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
#define GL_RGBA32F 0x8814
#define GL_RGB32F 0x8815
#define GL_RGBA16F 0x881A
#define GL_RGB16F 0x881B
#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD
#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904
#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905
#define GL_CLAMP_READ_COLOR 0x891C
#define GL_FIXED_ONLY 0x891D
#define GL_MAX_VARYING_COMPONENTS 0x8B4B
#define GL_TEXTURE_1D_ARRAY 0x8C18
#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19
#define GL_TEXTURE_2D_ARRAY 0x8C1A
#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B
#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C
#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
#define GL_R11F_G11F_B10F 0x8C3A
#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
#define GL_RGB9_E5 0x8C3D
#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
#define GL_TEXTURE_SHARED_SIZE 0x8C3F
#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83
#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
#define GL_PRIMITIVES_GENERATED 0x8C87
#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
#define GL_RASTERIZER_DISCARD 0x8C89
#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
#define GL_INTERLEAVED_ATTRIBS 0x8C8C
#define GL_SEPARATE_ATTRIBS 0x8C8D
#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E
#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
#define GL_RGBA32UI 0x8D70
#define GL_RGB32UI 0x8D71
#define GL_RGBA16UI 0x8D76
#define GL_RGB16UI 0x8D77
#define GL_RGBA8UI 0x8D7C
#define GL_RGB8UI 0x8D7D
#define GL_RGBA32I 0x8D82
#define GL_RGB32I 0x8D83
#define GL_RGBA16I 0x8D88
#define GL_RGB16I 0x8D89
#define GL_RGBA8I 0x8D8E
#define GL_RGB8I 0x8D8F
#define GL_RED_INTEGER 0x8D94
#define GL_GREEN_INTEGER 0x8D95
#define GL_BLUE_INTEGER 0x8D96
#define GL_RGB_INTEGER 0x8D98
#define GL_RGBA_INTEGER 0x8D99
#define GL_BGR_INTEGER 0x8D9A
#define GL_BGRA_INTEGER 0x8D9B
#define GL_SAMPLER_1D_ARRAY 0x8DC0
#define GL_SAMPLER_2D_ARRAY 0x8DC1
#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3
#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
#define GL_UNSIGNED_INT_VEC2 0x8DC6
#define GL_UNSIGNED_INT_VEC3 0x8DC7
#define GL_UNSIGNED_INT_VEC4 0x8DC8
#define GL_INT_SAMPLER_1D 0x8DC9
#define GL_INT_SAMPLER_2D 0x8DCA
#define GL_INT_SAMPLER_3D 0x8DCB
#define GL_INT_SAMPLER_CUBE 0x8DCC
#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE
#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1
#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6
#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
#define GL_QUERY_WAIT 0x8E13
#define GL_QUERY_NO_WAIT 0x8E14
#define GL_QUERY_BY_REGION_WAIT 0x8E15
#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16
#define GL_BUFFER_ACCESS_FLAGS 0x911F
#define GL_BUFFER_MAP_LENGTH 0x9120
#define GL_BUFFER_MAP_OFFSET 0x9121
#define GL_DEPTH_COMPONENT32F 0x8CAC
#define GL_DEPTH32F_STENCIL8 0x8CAD
#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
#define GL_FRAMEBUFFER_DEFAULT 0x8218
#define GL_FRAMEBUFFER_UNDEFINED 0x8219
#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
#define GL_DEPTH_STENCIL 0x84F9
#define GL_UNSIGNED_INT_24_8 0x84FA
#define GL_DEPTH24_STENCIL8 0x88F0
#define GL_TEXTURE_STENCIL_SIZE 0x88F1
#define GL_TEXTURE_RED_TYPE 0x8C10
#define GL_TEXTURE_GREEN_TYPE 0x8C11
#define GL_TEXTURE_BLUE_TYPE 0x8C12
#define GL_TEXTURE_ALPHA_TYPE 0x8C13
#define GL_TEXTURE_DEPTH_TYPE 0x8C16
#define GL_UNSIGNED_NORMALIZED 0x8C17
#define GL_FRAMEBUFFER_BINDING 0x8CA6
#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
#define GL_RENDERBUFFER_BINDING 0x8CA7
#define GL_READ_FRAMEBUFFER 0x8CA8
#define GL_DRAW_FRAMEBUFFER 0x8CA9
#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
#define GL_RENDERBUFFER_SAMPLES 0x8CAB
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
#define GL_COLOR_ATTACHMENT0 0x8CE0
#define GL_COLOR_ATTACHMENT1 0x8CE1
#define GL_COLOR_ATTACHMENT2 0x8CE2
#define GL_COLOR_ATTACHMENT3 0x8CE3
#define GL_COLOR_ATTACHMENT4 0x8CE4
#define GL_COLOR_ATTACHMENT5 0x8CE5
#define GL_COLOR_ATTACHMENT6 0x8CE6
#define GL_COLOR_ATTACHMENT7 0x8CE7
#define GL_COLOR_ATTACHMENT8 0x8CE8
#define GL_COLOR_ATTACHMENT9 0x8CE9
#define GL_COLOR_ATTACHMENT10 0x8CEA
#define GL_COLOR_ATTACHMENT11 0x8CEB
#define GL_COLOR_ATTACHMENT12 0x8CEC
#define GL_COLOR_ATTACHMENT13 0x8CED
#define GL_COLOR_ATTACHMENT14 0x8CEE
#define GL_COLOR_ATTACHMENT15 0x8CEF
#define GL_COLOR_ATTACHMENT16 0x8CF0
#define GL_COLOR_ATTACHMENT17 0x8CF1
#define GL_COLOR_ATTACHMENT18 0x8CF2
#define GL_COLOR_ATTACHMENT19 0x8CF3
#define GL_COLOR_ATTACHMENT20 0x8CF4
#define GL_COLOR_ATTACHMENT21 0x8CF5
#define GL_COLOR_ATTACHMENT22 0x8CF6
#define GL_COLOR_ATTACHMENT23 0x8CF7
#define GL_COLOR_ATTACHMENT24 0x8CF8
#define GL_COLOR_ATTACHMENT25 0x8CF9
#define GL_COLOR_ATTACHMENT26 0x8CFA
#define GL_COLOR_ATTACHMENT27 0x8CFB
#define GL_COLOR_ATTACHMENT28 0x8CFC
#define GL_COLOR_ATTACHMENT29 0x8CFD
#define GL_COLOR_ATTACHMENT30 0x8CFE
#define GL_COLOR_ATTACHMENT31 0x8CFF
#define GL_DEPTH_ATTACHMENT 0x8D00
#define GL_STENCIL_ATTACHMENT 0x8D20
#define GL_FRAMEBUFFER 0x8D40
#define GL_RENDERBUFFER 0x8D41
#define GL_RENDERBUFFER_WIDTH 0x8D42
#define GL_RENDERBUFFER_HEIGHT 0x8D43
#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
#define GL_STENCIL_INDEX1 0x8D46
#define GL_STENCIL_INDEX4 0x8D47
#define GL_STENCIL_INDEX8 0x8D48
#define GL_STENCIL_INDEX16 0x8D49
#define GL_RENDERBUFFER_RED_SIZE 0x8D50
#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
#define GL_MAX_SAMPLES 0x8D57
#define GL_FRAMEBUFFER_SRGB 0x8DB9
#define GL_HALF_FLOAT 0x140B
#define GL_MAP_READ_BIT 0x0001
#define GL_MAP_WRITE_BIT 0x0002
#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
#define GL_COMPRESSED_RED_RGTC1 0x8DBB
#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
#define GL_COMPRESSED_RG_RGTC2 0x8DBD
#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
#define GL_RG 0x8227
#define GL_RG_INTEGER 0x8228
#define GL_R8 0x8229
#define GL_R16 0x822A
#define GL_RG8 0x822B
#define GL_RG16 0x822C
#define GL_R16F 0x822D
#define GL_R32F 0x822E
#define GL_RG16F 0x822F
#define GL_RG32F 0x8230
#define GL_R8I 0x8231
#define GL_R8UI 0x8232
#define GL_R16I 0x8233
#define GL_R16UI 0x8234
#define GL_R32I 0x8235
#define GL_R32UI 0x8236
#define GL_RG8I 0x8237
#define GL_RG8UI 0x8238
#define GL_RG16I 0x8239
#define GL_RG16UI 0x823A
#define GL_RG32I 0x823B
#define GL_RG32UI 0x823C
#define GL_VERTEX_ARRAY_BINDING 0x85B5
#define GL_SAMPLER_2D_RECT 0x8B63
#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64
#define GL_SAMPLER_BUFFER 0x8DC2
#define GL_INT_SAMPLER_2D_RECT 0x8DCD
#define GL_INT_SAMPLER_BUFFER 0x8DD0
#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5
#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8
#define GL_TEXTURE_BUFFER 0x8C2A
#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B
#define GL_TEXTURE_BINDING_BUFFER 0x8C2C
#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D
#define GL_TEXTURE_RECTANGLE 0x84F5
#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6
#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7
#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8
#define GL_R8_SNORM 0x8F94
#define GL_RG8_SNORM 0x8F95
#define GL_RGB8_SNORM 0x8F96
#define GL_RGBA8_SNORM 0x8F97
#define GL_R16_SNORM 0x8F98
#define GL_RG16_SNORM 0x8F99
#define GL_RGB16_SNORM 0x8F9A
#define GL_RGBA16_SNORM 0x8F9B
#define GL_SIGNED_NORMALIZED 0x8F9C
#define GL_PRIMITIVE_RESTART 0x8F9D
#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E
#define GL_COPY_READ_BUFFER 0x8F36
#define GL_COPY_WRITE_BUFFER 0x8F37
#define GL_UNIFORM_BUFFER 0x8A11
#define GL_UNIFORM_BUFFER_BINDING 0x8A28
#define GL_UNIFORM_BUFFER_START 0x8A29
#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C
#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32
#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
#define GL_UNIFORM_TYPE 0x8A37
#define GL_UNIFORM_SIZE 0x8A38
#define GL_UNIFORM_NAME_LENGTH 0x8A39
#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
#define GL_UNIFORM_OFFSET 0x8A3B
#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45
#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
#define GL_INVALID_INDEX 0xFFFFFFFF
#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
#define GL_LINES_ADJACENCY 0x000A
#define GL_LINE_STRIP_ADJACENCY 0x000B
#define GL_TRIANGLES_ADJACENCY 0x000C
#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D
#define GL_PROGRAM_POINT_SIZE 0x8642
#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29
#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7
#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8
#define GL_GEOMETRY_SHADER 0x8DD9
#define GL_GEOMETRY_VERTICES_OUT 0x8916
#define GL_GEOMETRY_INPUT_TYPE 0x8917
#define GL_GEOMETRY_OUTPUT_TYPE 0x8918
#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF
#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0
#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123
#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124
#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
#define GL_CONTEXT_PROFILE_MASK 0x9126
#define GL_DEPTH_CLAMP 0x864F
#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C
#define GL_FIRST_VERTEX_CONVENTION 0x8E4D
#define GL_LAST_VERTEX_CONVENTION 0x8E4E
#define GL_PROVOKING_VERTEX 0x8E4F
#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
#define GL_OBJECT_TYPE 0x9112
#define GL_SYNC_CONDITION 0x9113
#define GL_SYNC_STATUS 0x9114
#define GL_SYNC_FLAGS 0x9115
#define GL_SYNC_FENCE 0x9116
#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
#define GL_UNSIGNALED 0x9118
#define GL_SIGNALED 0x9119
#define GL_ALREADY_SIGNALED 0x911A
#define GL_TIMEOUT_EXPIRED 0x911B
#define GL_CONDITION_SATISFIED 0x911C
#define GL_WAIT_FAILED 0x911D
#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF
#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
#define GL_SAMPLE_POSITION 0x8E50
#define GL_SAMPLE_MASK 0x8E51
#define GL_SAMPLE_MASK_VALUE 0x8E52
#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59
#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101
#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103
#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104
#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105
#define GL_TEXTURE_SAMPLES 0x9106
#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107
#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B
#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E
#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F
#define GL_MAX_INTEGER_SAMPLES 0x9110
#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
#define GL_SRC1_COLOR 0x88F9
#define GL_ONE_MINUS_SRC1_COLOR 0x88FA
#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC
#define GL_ANY_SAMPLES_PASSED 0x8C2F
#define GL_SAMPLER_BINDING 0x8919
#define GL_RGB10_A2UI 0x906F
#define GL_TEXTURE_SWIZZLE_R 0x8E42
#define GL_TEXTURE_SWIZZLE_G 0x8E43
#define GL_TEXTURE_SWIZZLE_B 0x8E44
#define GL_TEXTURE_SWIZZLE_A 0x8E45
#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
#define GL_TIME_ELAPSED 0x88BF
#define GL_TIMESTAMP 0x8E28
#define GL_INT_2_10_10_10_REV 0x8D9F
#define GL_SAMPLE_SHADING 0x8C36
#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37
#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E
#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F
#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009
#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A
#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B
#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C
#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D
#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E
#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F
#define GL_DRAW_INDIRECT_BUFFER 0x8F3F
#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43
#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F
#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A
#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B
#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C
#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D
#define GL_MAX_VERTEX_STREAMS 0x8E71
#define GL_DOUBLE_VEC2 0x8FFC
#define GL_DOUBLE_VEC3 0x8FFD
#define GL_DOUBLE_VEC4 0x8FFE
#define GL_DOUBLE_MAT2 0x8F46
#define GL_DOUBLE_MAT3 0x8F47
#define GL_DOUBLE_MAT4 0x8F48
#define GL_DOUBLE_MAT2x3 0x8F49
#define GL_DOUBLE_MAT2x4 0x8F4A
#define GL_DOUBLE_MAT3x2 0x8F4B
#define GL_DOUBLE_MAT3x4 0x8F4C
#define GL_DOUBLE_MAT4x2 0x8F4D
#define GL_DOUBLE_MAT4x3 0x8F4E
#define GL_ACTIVE_SUBROUTINES 0x8DE5
#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6
#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47
#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48
#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49
#define GL_MAX_SUBROUTINES 0x8DE7
#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8
#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A
#define GL_COMPATIBLE_SUBROUTINES 0x8E4B
#define GL_PATCHES 0x000E
#define GL_PATCH_VERTICES 0x8E72
#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74
#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75
#define GL_TESS_GEN_MODE 0x8E76
#define GL_TESS_GEN_SPACING 0x8E77
#define GL_TESS_GEN_VERTEX_ORDER 0x8E78
#define GL_TESS_GEN_POINT_MODE 0x8E79
#define GL_ISOLINES 0x8E7A
#define GL_QUADS 0x0007
#define GL_FRACTIONAL_ODD 0x8E7B
#define GL_FRACTIONAL_EVEN 0x8E7C
#define GL_MAX_PATCH_VERTICES 0x8E7D
#define GL_MAX_TESS_GEN_LEVEL 0x8E7E
#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F
#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80
#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81
#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82
#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83
#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84
#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85
#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86
#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89
#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A
#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C
#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D
#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E
#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F
#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0
#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1
#define GL_TESS_EVALUATION_SHADER 0x8E87
#define GL_TESS_CONTROL_SHADER 0x8E88
#define GL_TRANSFORM_FEEDBACK 0x8E22
#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23
#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24
#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25
#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70
#define GL_FIXED 0x140C
#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
#define GL_LOW_FLOAT 0x8DF0
#define GL_MEDIUM_FLOAT 0x8DF1
#define GL_HIGH_FLOAT 0x8DF2
#define GL_LOW_INT 0x8DF3
#define GL_MEDIUM_INT 0x8DF4
#define GL_HIGH_INT 0x8DF5
#define GL_SHADER_COMPILER 0x8DFA
#define GL_SHADER_BINARY_FORMATS 0x8DF8
#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
#define GL_MAX_VARYING_VECTORS 0x8DFC
#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
#define GL_RGB565 0x8D62
#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257
#define GL_PROGRAM_BINARY_LENGTH 0x8741
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
#define GL_PROGRAM_BINARY_FORMATS 0x87FF
#define GL_VERTEX_SHADER_BIT 0x00000001
#define GL_FRAGMENT_SHADER_BIT 0x00000002
#define GL_GEOMETRY_SHADER_BIT 0x00000004
#define GL_TESS_CONTROL_SHADER_BIT 0x00000008
#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010
#define GL_ALL_SHADER_BITS 0xFFFFFFFF
#define GL_PROGRAM_SEPARABLE 0x8258
#define GL_ACTIVE_PROGRAM 0x8259
#define GL_PROGRAM_PIPELINE_BINDING 0x825A
#define GL_MAX_VIEWPORTS 0x825B
#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C
#define GL_VIEWPORT_BOUNDS_RANGE 0x825D
#define GL_LAYER_PROVOKING_VERTEX 0x825E
#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F
#define GL_UNDEFINED_VERTEX 0x8260
#define GL_COPY_READ_BUFFER_BINDING 0x8F36
#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37
#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24
#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23
#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127
#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128
#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129
#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A
#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B
#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C
#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D
#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E
#define GL_NUM_SAMPLE_COUNTS 0x9380
#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC
#define GL_ATOMIC_COUNTER_BUFFER 0x92C0
#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1
#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2
#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3
#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4
#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5
#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6
#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7
#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8
#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9
#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA
#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB
#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC
#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD
#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE
#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF
#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0
#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1
#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2
#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3
#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4
#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5
#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6
#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7
#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8
#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC
#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9
#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA
#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB
#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
#define GL_UNIFORM_BARRIER_BIT 0x00000004
#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
#define GL_COMMAND_BARRIER_BIT 0x00000040
#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
#define GL_MAX_IMAGE_UNITS 0x8F38
#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39
#define GL_IMAGE_BINDING_NAME 0x8F3A
#define GL_IMAGE_BINDING_LEVEL 0x8F3B
#define GL_IMAGE_BINDING_LAYERED 0x8F3C
#define GL_IMAGE_BINDING_LAYER 0x8F3D
#define GL_IMAGE_BINDING_ACCESS 0x8F3E
#define GL_IMAGE_1D 0x904C
#define GL_IMAGE_2D 0x904D
#define GL_IMAGE_3D 0x904E
#define GL_IMAGE_2D_RECT 0x904F
#define GL_IMAGE_CUBE 0x9050
#define GL_IMAGE_BUFFER 0x9051
#define GL_IMAGE_1D_ARRAY 0x9052
#define GL_IMAGE_2D_ARRAY 0x9053
#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
#define GL_IMAGE_2D_MULTISAMPLE 0x9055
#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056
#define GL_INT_IMAGE_1D 0x9057
#define GL_INT_IMAGE_2D 0x9058
#define GL_INT_IMAGE_3D 0x9059
#define GL_INT_IMAGE_2D_RECT 0x905A
#define GL_INT_IMAGE_CUBE 0x905B
#define GL_INT_IMAGE_BUFFER 0x905C
#define GL_INT_IMAGE_1D_ARRAY 0x905D
#define GL_INT_IMAGE_2D_ARRAY 0x905E
#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060
#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
#define GL_UNSIGNED_INT_IMAGE_1D 0x9062
#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065
#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068
#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
#define GL_MAX_IMAGE_SAMPLES 0x906D
#define GL_IMAGE_BINDING_FORMAT 0x906E
#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7
#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8
#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9
#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA
#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB
#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC
#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD
#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE
#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF
#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F
#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9
#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E
#define GL_COMPRESSED_RGB8_ETC2 0x9274
#define GL_COMPRESSED_SRGB8_ETC2 0x9275
#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
#define GL_COMPRESSED_R11_EAC 0x9270
#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
#define GL_COMPRESSED_RG11_EAC 0x9272
#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
#define GL_MAX_ELEMENT_INDEX 0x8D6B
#define GL_COMPUTE_SHADER 0x91B9
#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB
#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC
#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD
#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262
#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263
#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264
#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265
#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266
#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB
#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE
#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF
#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267
#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC
#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED
#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE
#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF
#define GL_COMPUTE_SHADER_BIT 0x00000020
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
#define GL_DEBUG_SOURCE_API 0x8246
#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
#define GL_DEBUG_SOURCE_APPLICATION 0x824A
#define GL_DEBUG_SOURCE_OTHER 0x824B
#define GL_DEBUG_TYPE_ERROR 0x824C
#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
#define GL_DEBUG_TYPE_PORTABILITY 0x824F
#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
#define GL_DEBUG_TYPE_OTHER 0x8251
#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
#define GL_DEBUG_LOGGED_MESSAGES 0x9145
#define GL_DEBUG_SEVERITY_HIGH 0x9146
#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
#define GL_DEBUG_SEVERITY_LOW 0x9148
#define GL_DEBUG_TYPE_MARKER 0x8268
#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
#define GL_DEBUG_TYPE_POP_GROUP 0x826A
#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
#define GL_BUFFER 0x82E0
#define GL_SHADER 0x82E1
#define GL_PROGRAM 0x82E2
#define GL_VERTEX_ARRAY 0x8074
#define GL_QUERY 0x82E3
#define GL_PROGRAM_PIPELINE 0x82E4
#define GL_SAMPLER 0x82E6
#define GL_MAX_LABEL_LENGTH 0x82E8
#define GL_DEBUG_OUTPUT 0x92E0
#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
#define GL_MAX_UNIFORM_LOCATIONS 0x826E
#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310
#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311
#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312
#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313
#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314
#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315
#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316
#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317
#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318
#define GL_INTERNALFORMAT_SUPPORTED 0x826F
#define GL_INTERNALFORMAT_PREFERRED 0x8270
#define GL_INTERNALFORMAT_RED_SIZE 0x8271
#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272
#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273
#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274
#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275
#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276
#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277
#define GL_INTERNALFORMAT_RED_TYPE 0x8278
#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279
#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A
#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B
#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C
#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D
#define GL_MAX_WIDTH 0x827E
#define GL_MAX_HEIGHT 0x827F
#define GL_MAX_DEPTH 0x8280
#define GL_MAX_LAYERS 0x8281
#define GL_MAX_COMBINED_DIMENSIONS 0x8282
#define GL_COLOR_COMPONENTS 0x8283
#define GL_DEPTH_COMPONENTS 0x8284
#define GL_STENCIL_COMPONENTS 0x8285
#define GL_COLOR_RENDERABLE 0x8286
#define GL_DEPTH_RENDERABLE 0x8287
#define GL_STENCIL_RENDERABLE 0x8288
#define GL_FRAMEBUFFER_RENDERABLE 0x8289
#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A
#define GL_FRAMEBUFFER_BLEND 0x828B
#define GL_READ_PIXELS 0x828C
#define GL_READ_PIXELS_FORMAT 0x828D
#define GL_READ_PIXELS_TYPE 0x828E
#define GL_TEXTURE_IMAGE_FORMAT 0x828F
#define GL_TEXTURE_IMAGE_TYPE 0x8290
#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291
#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292
#define GL_MIPMAP 0x8293
#define GL_MANUAL_GENERATE_MIPMAP 0x8294
#define GL_AUTO_GENERATE_MIPMAP 0x8295
#define GL_COLOR_ENCODING 0x8296
#define GL_SRGB_READ 0x8297
#define GL_SRGB_WRITE 0x8298
#define GL_FILTER 0x829A
#define GL_VERTEX_TEXTURE 0x829B
#define GL_TESS_CONTROL_TEXTURE 0x829C
#define GL_TESS_EVALUATION_TEXTURE 0x829D
#define GL_GEOMETRY_TEXTURE 0x829E
#define GL_FRAGMENT_TEXTURE 0x829F
#define GL_COMPUTE_TEXTURE 0x82A0
#define GL_TEXTURE_SHADOW 0x82A1
#define GL_TEXTURE_GATHER 0x82A2
#define GL_TEXTURE_GATHER_SHADOW 0x82A3
#define GL_SHADER_IMAGE_LOAD 0x82A4
#define GL_SHADER_IMAGE_STORE 0x82A5
#define GL_SHADER_IMAGE_ATOMIC 0x82A6
#define GL_IMAGE_TEXEL_SIZE 0x82A7
#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8
#define GL_IMAGE_PIXEL_FORMAT 0x82A9
#define GL_IMAGE_PIXEL_TYPE 0x82AA
#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC
#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD
#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE
#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF
#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1
#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2
#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3
#define GL_CLEAR_BUFFER 0x82B4
#define GL_TEXTURE_VIEW 0x82B5
#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6
#define GL_FULL_SUPPORT 0x82B7
#define GL_CAVEAT_SUPPORT 0x82B8
#define GL_IMAGE_CLASS_4_X_32 0x82B9
#define GL_IMAGE_CLASS_2_X_32 0x82BA
#define GL_IMAGE_CLASS_1_X_32 0x82BB
#define GL_IMAGE_CLASS_4_X_16 0x82BC
#define GL_IMAGE_CLASS_2_X_16 0x82BD
#define GL_IMAGE_CLASS_1_X_16 0x82BE
#define GL_IMAGE_CLASS_4_X_8 0x82BF
#define GL_IMAGE_CLASS_2_X_8 0x82C0
#define GL_IMAGE_CLASS_1_X_8 0x82C1
#define GL_IMAGE_CLASS_11_11_10 0x82C2
#define GL_IMAGE_CLASS_10_10_10_2 0x82C3
#define GL_VIEW_CLASS_128_BITS 0x82C4
#define GL_VIEW_CLASS_96_BITS 0x82C5
#define GL_VIEW_CLASS_64_BITS 0x82C6
#define GL_VIEW_CLASS_48_BITS 0x82C7
#define GL_VIEW_CLASS_32_BITS 0x82C8
#define GL_VIEW_CLASS_24_BITS 0x82C9
#define GL_VIEW_CLASS_16_BITS 0x82CA
#define GL_VIEW_CLASS_8_BITS 0x82CB
#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC
#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD
#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE
#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF
#define GL_VIEW_CLASS_RGTC1_RED 0x82D0
#define GL_VIEW_CLASS_RGTC2_RG 0x82D1
#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2
#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3
#define GL_UNIFORM 0x92E1
#define GL_UNIFORM_BLOCK 0x92E2
#define GL_PROGRAM_INPUT 0x92E3
#define GL_PROGRAM_OUTPUT 0x92E4
#define GL_BUFFER_VARIABLE 0x92E5
#define GL_SHADER_STORAGE_BLOCK 0x92E6
#define GL_VERTEX_SUBROUTINE 0x92E8
#define GL_TESS_CONTROL_SUBROUTINE 0x92E9
#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA
#define GL_GEOMETRY_SUBROUTINE 0x92EB
#define GL_FRAGMENT_SUBROUTINE 0x92EC
#define GL_COMPUTE_SUBROUTINE 0x92ED
#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE
#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF
#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0
#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1
#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2
#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3
#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4
#define GL_ACTIVE_RESOURCES 0x92F5
#define GL_MAX_NAME_LENGTH 0x92F6
#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7
#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8
#define GL_NAME_LENGTH 0x92F9
#define GL_TYPE 0x92FA
#define GL_ARRAY_SIZE 0x92FB
#define GL_OFFSET 0x92FC
#define GL_BLOCK_INDEX 0x92FD
#define GL_ARRAY_STRIDE 0x92FE
#define GL_MATRIX_STRIDE 0x92FF
#define GL_IS_ROW_MAJOR 0x9300
#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301
#define GL_BUFFER_BINDING 0x9302
#define GL_BUFFER_DATA_SIZE 0x9303
#define GL_NUM_ACTIVE_VARIABLES 0x9304
#define GL_ACTIVE_VARIABLES 0x9305
#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306
#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307
#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308
#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309
#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A
#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B
#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C
#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D
#define GL_LOCATION 0x930E
#define GL_LOCATION_INDEX 0x930F
#define GL_IS_PER_PATCH 0x92E7
#define GL_SHADER_STORAGE_BUFFER 0x90D2
#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3
#define GL_SHADER_STORAGE_BUFFER_START 0x90D4
#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5
#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6
#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7
#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8
#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9
#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA
#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB
#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC
#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD
#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE
#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF
#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39
#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA
#define GL_TEXTURE_BUFFER_OFFSET 0x919D
#define GL_TEXTURE_BUFFER_SIZE 0x919E
#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F
#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB
#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC
#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD
#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE
#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF
#define GL_VERTEX_ATTRIB_BINDING 0x82D4
#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5
#define GL_VERTEX_BINDING_DIVISOR 0x82D6
#define GL_VERTEX_BINDING_OFFSET 0x82D7
#define GL_VERTEX_BINDING_STRIDE 0x82D8
#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9
#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA
#define GL_VERTEX_BINDING_BUFFER 0x8F4F
#define GL_DISPLAY_LIST 0x82E7
#define GL_STACK_UNDERFLOW 0x0504
#define GL_STACK_OVERFLOW 0x0503
#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5
#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221
#define GL_TEXTURE_BUFFER_BINDING 0x8C2A
#define GL_MAP_PERSISTENT_BIT 0x0040
#define GL_MAP_COHERENT_BIT 0x0080
#define GL_DYNAMIC_STORAGE_BIT 0x0100
#define GL_CLIENT_STORAGE_BIT 0x0200
#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000
#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F
#define GL_BUFFER_STORAGE_FLAGS 0x8220
#define GL_CLEAR_TEXTURE 0x9365
#define GL_LOCATION_COMPONENT 0x934A
#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B
#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C
#define GL_QUERY_BUFFER 0x9192
#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000
#define GL_QUERY_BUFFER_BINDING 0x9193
#define GL_QUERY_RESULT_NO_WAIT 0x9194
#define GL_MIRROR_CLAMP_TO_EDGE 0x8743
#ifndef GL_VERSION_1_0
#define GL_VERSION_1_0 1
GLAPI int GLAD_GL_VERSION_1_0;
typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode);
GLAPI PFNGLCULLFACEPROC glad_glCullFace;
#define glCullFace glad_glCullFace
typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode);
GLAPI PFNGLFRONTFACEPROC glad_glFrontFace;
#define glFrontFace glad_glFrontFace
typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode);
GLAPI PFNGLHINTPROC glad_glHint;
#define glHint glad_glHint
typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width);
GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth;
#define glLineWidth glad_glLineWidth
typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size);
GLAPI PFNGLPOINTSIZEPROC glad_glPointSize;
#define glPointSize glad_glPointSize
typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode);
GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode;
#define glPolygonMode glad_glPolygonMode
typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
GLAPI PFNGLSCISSORPROC glad_glScissor;
#define glScissor glad_glScissor
typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param);
GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf;
#define glTexParameterf glad_glTexParameterf
typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params);
GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;
#define glTexParameterfv glad_glTexParameterfv
typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);
GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri;
#define glTexParameteri glad_glTexParameteri
typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params);
GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;
#define glTexParameteriv glad_glTexParameteriv
typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D;
#define glTexImage1D glad_glTexImage1D
typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D;
#define glTexImage2D glad_glTexImage2D
typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf);
GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer;
#define glDrawBuffer glad_glDrawBuffer
typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask);
GLAPI PFNGLCLEARPROC glad_glClear;
#define glClear glad_glClear
typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
GLAPI PFNGLCLEARCOLORPROC glad_glClearColor;
#define glClearColor glad_glClearColor
typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s);
GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil;
#define glClearStencil glad_glClearStencil
typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth);
GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth;
#define glClearDepth glad_glClearDepth
typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask);
GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask;
#define glStencilMask glad_glStencilMask
typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
GLAPI PFNGLCOLORMASKPROC glad_glColorMask;
#define glColorMask glad_glColorMask
typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag);
GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask;
#define glDepthMask glad_glDepthMask
typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap);
GLAPI PFNGLDISABLEPROC glad_glDisable;
#define glDisable glad_glDisable
typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap);
GLAPI PFNGLENABLEPROC glad_glEnable;
#define glEnable glad_glEnable
typedef void (APIENTRYP PFNGLFINISHPROC)(void);
GLAPI PFNGLFINISHPROC glad_glFinish;
#define glFinish glad_glFinish
typedef void (APIENTRYP PFNGLFLUSHPROC)(void);
GLAPI PFNGLFLUSHPROC glad_glFlush;
#define glFlush glad_glFlush
typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor);
GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc;
#define glBlendFunc glad_glBlendFunc
typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode);
GLAPI PFNGLLOGICOPPROC glad_glLogicOp;
#define glLogicOp glad_glLogicOp
typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask);
GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc;
#define glStencilFunc glad_glStencilFunc
typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass);
GLAPI PFNGLSTENCILOPPROC glad_glStencilOp;
#define glStencilOp glad_glStencilOp
typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func);
GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc;
#define glDepthFunc glad_glDepthFunc
typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param);
GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref;
#define glPixelStoref glad_glPixelStoref
typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param);
GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei;
#define glPixelStorei glad_glPixelStorei
typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src);
GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer;
#define glReadBuffer glad_glReadBuffer
typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
GLAPI PFNGLREADPIXELSPROC glad_glReadPixels;
#define glReadPixels glad_glReadPixels
typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data);
GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv;
#define glGetBooleanv glad_glGetBooleanv
typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble *data);
GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev;
#define glGetDoublev glad_glGetDoublev
typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(void);
GLAPI PFNGLGETERRORPROC glad_glGetError;
#define glGetError glad_glGetError
typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data);
GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv;
#define glGetFloatv glad_glGetFloatv
typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data);
GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv;
#define glGetIntegerv glad_glGetIntegerv
typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name);
GLAPI PFNGLGETSTRINGPROC glad_glGetString;
#define glGetString glad_glGetString
typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage;
#define glGetTexImage glad_glGetTexImage
typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params);
GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;
#define glGetTexParameterfv glad_glGetTexParameterfv
typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);
GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;
#define glGetTexParameteriv glad_glGetTexParameteriv
typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat *params);
GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv;
#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv
typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint *params);
GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv;
#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv
typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap);
GLAPI PFNGLISENABLEDPROC glad_glIsEnabled;
#define glIsEnabled glad_glIsEnabled
typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f);
GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange;
#define glDepthRange glad_glDepthRange
typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
GLAPI PFNGLVIEWPORTPROC glad_glViewport;
#define glViewport glad_glViewport
#endif
#ifndef GL_VERSION_1_1
#define GL_VERSION_1_1 1
GLAPI int GLAD_GL_VERSION_1_1;
typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count);
GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays;
#define glDrawArrays glad_glDrawArrays
typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices);
GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements;
#define glDrawElements glad_glDrawElements
typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units);
GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;
#define glPolygonOffset glad_glPolygonOffset
typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D;
#define glCopyTexImage1D glad_glCopyTexImage1D
typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;
#define glCopyTexImage2D glad_glCopyTexImage2D
typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D;
#define glCopyTexSubImage1D glad_glCopyTexSubImage1D
typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;
#define glCopyTexSubImage2D glad_glCopyTexSubImage2D
typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D;
#define glTexSubImage1D glad_glTexSubImage1D
typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;
#define glTexSubImage2D glad_glTexSubImage2D
typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture);
GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture;
#define glBindTexture glad_glBindTexture
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures);
GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures;
#define glDeleteTextures glad_glDeleteTextures
typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures);
GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures;
#define glGenTextures glad_glGenTextures
typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture);
GLAPI PFNGLISTEXTUREPROC glad_glIsTexture;
#define glIsTexture glad_glIsTexture
#endif
#ifndef GL_VERSION_1_2
#define GL_VERSION_1_2 1
GLAPI int GLAD_GL_VERSION_1_2;
typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements;
#define glDrawRangeElements glad_glDrawRangeElements
typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D;
#define glTexImage3D glad_glTexImage3D
typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D;
#define glTexSubImage3D glad_glTexSubImage3D
typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D;
#define glCopyTexSubImage3D glad_glCopyTexSubImage3D
#endif
#ifndef GL_VERSION_1_3
#define GL_VERSION_1_3 1
GLAPI int GLAD_GL_VERSION_1_3;
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture);
GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture;
#define glActiveTexture glad_glActiveTexture
typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert);
GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;
#define glSampleCoverage glad_glSampleCoverage
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D;
#define glCompressedTexImage3D glad_glCompressedTexImage3D
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;
#define glCompressedTexImage2D glad_glCompressedTexImage2D
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D;
#define glCompressedTexImage1D glad_glCompressedTexImage1D
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D;
#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;
#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D;
#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D
typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void *img);
GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage;
#define glGetCompressedTexImage glad_glGetCompressedTexImage
#endif
#ifndef GL_VERSION_1_4
#define GL_VERSION_1_4 1
GLAPI int GLAD_GL_VERSION_1_4;
typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;
#define glBlendFuncSeparate glad_glBlendFuncSeparate
typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays;
#define glMultiDrawArrays glad_glMultiDrawArrays
typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);
GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements;
#define glMultiDrawElements glad_glMultiDrawElements
typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param);
GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf;
#define glPointParameterf glad_glPointParameterf
typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat *params);
GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv;
#define glPointParameterfv glad_glPointParameterfv
typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param);
GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri;
#define glPointParameteri glad_glPointParameteri
typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint *params);
GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv;
#define glPointParameteriv glad_glPointParameteriv
typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor;
#define glBlendColor glad_glBlendColor
typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode);
GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation;
#define glBlendEquation glad_glBlendEquation
#endif
#ifndef GL_VERSION_1_5
#define GL_VERSION_1_5 1
GLAPI int GLAD_GL_VERSION_1_5;
typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint *ids);
GLAPI PFNGLGENQUERIESPROC glad_glGenQueries;
#define glGenQueries glad_glGenQueries
typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint *ids);
GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries;
#define glDeleteQueries glad_glDeleteQueries
typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id);
GLAPI PFNGLISQUERYPROC glad_glIsQuery;
#define glIsQuery glad_glIsQuery
typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id);
GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery;
#define glBeginQuery glad_glBeginQuery
typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target);
GLAPI PFNGLENDQUERYPROC glad_glEndQuery;
#define glEndQuery glad_glEndQuery
typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint *params);
GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv;
#define glGetQueryiv glad_glGetQueryiv
typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint *params);
GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv;
#define glGetQueryObjectiv glad_glGetQueryObjectiv
typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint *params);
GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv;
#define glGetQueryObjectuiv glad_glGetQueryObjectuiv
typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer);
GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer;
#define glBindBuffer glad_glBindBuffer
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers);
GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;
#define glDeleteBuffers glad_glDeleteBuffers
typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers);
GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers;
#define glGenBuffers glad_glGenBuffers
typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer);
GLAPI PFNGLISBUFFERPROC glad_glIsBuffer;
#define glIsBuffer glad_glIsBuffer
typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage);
GLAPI PFNGLBUFFERDATAPROC glad_glBufferData;
#define glBufferData glad_glBufferData
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;
#define glBufferSubData glad_glBufferSubData
typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void *data);
GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData;
#define glGetBufferSubData glad_glGetBufferSubData
typedef void * (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access);
GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer;
#define glMapBuffer glad_glMapBuffer
typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target);
GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer;
#define glUnmapBuffer glad_glUnmapBuffer
typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);
GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;
#define glGetBufferParameteriv glad_glGetBufferParameteriv
typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void **params);
GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv;
#define glGetBufferPointerv glad_glGetBufferPointerv
#endif
#ifndef GL_VERSION_2_0
#define GL_VERSION_2_0 1
GLAPI int GLAD_GL_VERSION_2_0;
typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha);
GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;
#define glBlendEquationSeparate glad_glBlendEquationSeparate
typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs);
GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers;
#define glDrawBuffers glad_glDrawBuffers
typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;
#define glStencilOpSeparate glad_glStencilOpSeparate
typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask);
GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;
#define glStencilFuncSeparate glad_glStencilFuncSeparate
typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask);
GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;
#define glStencilMaskSeparate glad_glStencilMaskSeparate
typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader);
GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader;
#define glAttachShader glad_glAttachShader
typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name);
GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;
#define glBindAttribLocation glad_glBindAttribLocation
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader);
GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader;
#define glCompileShader glad_glCompileShader
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(void);
GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram;
#define glCreateProgram glad_glCreateProgram
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type);
GLAPI PFNGLCREATESHADERPROC glad_glCreateShader;
#define glCreateShader glad_glCreateShader
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program);
GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;
#define glDeleteProgram glad_glDeleteProgram
typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader);
GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader;
#define glDeleteShader glad_glDeleteShader
typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader);
GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader;
#define glDetachShader glad_glDetachShader
typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index);
GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;
#define glDisableVertexAttribArray glad_glDisableVertexAttribArray
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index);
GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;
#define glEnableVertexAttribArray glad_glEnableVertexAttribArray
typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;
#define glGetActiveAttrib glad_glGetActiveAttrib
typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;
#define glGetActiveUniform glad_glGetActiveUniform
typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);
GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;
#define glGetAttachedShaders glad_glGetAttachedShaders
typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name);
GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;
#define glGetAttribLocation glad_glGetAttribLocation
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params);
GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;
#define glGetProgramiv glad_glGetProgramiv
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;
#define glGetProgramInfoLog glad_glGetProgramInfoLog
typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params);
GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv;
#define glGetShaderiv glad_glGetShaderiv
typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;
#define glGetShaderInfoLog glad_glGetShaderInfoLog
typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;
#define glGetShaderSource glad_glGetShaderSource
typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name);
GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;
#define glGetUniformLocation glad_glGetUniformLocation
typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params);
GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;
#define glGetUniformfv glad_glGetUniformfv
typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params);
GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;
#define glGetUniformiv glad_glGetUniformiv
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble *params);
GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv;
#define glGetVertexAttribdv glad_glGetVertexAttribdv
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params);
GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;
#define glGetVertexAttribfv glad_glGetVertexAttribfv
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params);
GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;
#define glGetVertexAttribiv glad_glGetVertexAttribiv
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer);
GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;
#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv
typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program);
GLAPI PFNGLISPROGRAMPROC glad_glIsProgram;
#define glIsProgram glad_glIsProgram
typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader);
GLAPI PFNGLISSHADERPROC glad_glIsShader;
#define glIsShader glad_glIsShader
typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program);
GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram;
#define glLinkProgram glad_glLinkProgram
typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource;
#define glShaderSource glad_glShaderSource
typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program);
GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram;
#define glUseProgram glad_glUseProgram
typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0);
GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f;
#define glUniform1f glad_glUniform1f
typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1);
GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f;
#define glUniform2f glad_glUniform2f
typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f;
#define glUniform3f glad_glUniform3f
typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f;
#define glUniform4f glad_glUniform4f
typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0);
GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i;
#define glUniform1i glad_glUniform1i
typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1);
GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i;
#define glUniform2i glad_glUniform2i
typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2);
GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i;
#define glUniform3i glad_glUniform3i
typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i;
#define glUniform4i glad_glUniform4i
typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value);
GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv;
#define glUniform1fv glad_glUniform1fv
typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value);
GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv;
#define glUniform2fv glad_glUniform2fv
typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value);
GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv;
#define glUniform3fv glad_glUniform3fv
typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value);
GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv;
#define glUniform4fv glad_glUniform4fv
typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value);
GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv;
#define glUniform1iv glad_glUniform1iv
typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value);
GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv;
#define glUniform2iv glad_glUniform2iv
typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value);
GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv;
#define glUniform3iv glad_glUniform3iv
typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value);
GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv;
#define glUniform4iv glad_glUniform4iv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;
#define glUniformMatrix2fv glad_glUniformMatrix2fv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;
#define glUniformMatrix3fv glad_glUniformMatrix3fv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;
#define glUniformMatrix4fv glad_glUniformMatrix4fv
typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program);
GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;
#define glValidateProgram glad_glValidateProgram
typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x);
GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d;
#define glVertexAttrib1d glad_glVertexAttrib1d
typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble *v);
GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv;
#define glVertexAttrib1dv glad_glVertexAttrib1dv
typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x);
GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;
#define glVertexAttrib1f glad_glVertexAttrib1f
typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v);
GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;
#define glVertexAttrib1fv glad_glVertexAttrib1fv
typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x);
GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s;
#define glVertexAttrib1s glad_glVertexAttrib1s
typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort *v);
GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv;
#define glVertexAttrib1sv glad_glVertexAttrib1sv
typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y);
GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d;
#define glVertexAttrib2d glad_glVertexAttrib2d
typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble *v);
GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv;
#define glVertexAttrib2dv glad_glVertexAttrib2dv
typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y);
GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;
#define glVertexAttrib2f glad_glVertexAttrib2f
typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v);
GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;
#define glVertexAttrib2fv glad_glVertexAttrib2fv
typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y);
GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s;
#define glVertexAttrib2s glad_glVertexAttrib2s
typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort *v);
GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv;
#define glVertexAttrib2sv glad_glVertexAttrib2sv
typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);
GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d;
#define glVertexAttrib3d glad_glVertexAttrib3d
typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble *v);
GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv;
#define glVertexAttrib3dv glad_glVertexAttrib3dv
typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z);
GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;
#define glVertexAttrib3f glad_glVertexAttrib3f
typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v);
GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;
#define glVertexAttrib3fv glad_glVertexAttrib3fv
typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z);
GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s;
#define glVertexAttrib3s glad_glVertexAttrib3s
typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort *v);
GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv;
#define glVertexAttrib3sv glad_glVertexAttrib3sv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte *v);
GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv;
#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint *v);
GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv;
#define glVertexAttrib4Niv glad_glVertexAttrib4Niv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort *v);
GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv;
#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub;
#define glVertexAttrib4Nub glad_glVertexAttrib4Nub
typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte *v);
GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv;
#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint *v);
GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv;
#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort *v);
GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv;
#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte *v);
GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv;
#define glVertexAttrib4bv glad_glVertexAttrib4bv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d;
#define glVertexAttrib4d glad_glVertexAttrib4d
typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble *v);
GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv;
#define glVertexAttrib4dv glad_glVertexAttrib4dv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;
#define glVertexAttrib4f glad_glVertexAttrib4f
typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v);
GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;
#define glVertexAttrib4fv glad_glVertexAttrib4fv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint *v);
GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv;
#define glVertexAttrib4iv glad_glVertexAttrib4iv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s;
#define glVertexAttrib4s glad_glVertexAttrib4s
typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort *v);
GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv;
#define glVertexAttrib4sv glad_glVertexAttrib4sv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte *v);
GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv;
#define glVertexAttrib4ubv glad_glVertexAttrib4ubv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint *v);
GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv;
#define glVertexAttrib4uiv glad_glVertexAttrib4uiv
typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort *v);
GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv;
#define glVertexAttrib4usv glad_glVertexAttrib4usv
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;
#define glVertexAttribPointer glad_glVertexAttribPointer
#endif
#ifndef GL_VERSION_2_1
#define GL_VERSION_2_1 1
GLAPI int GLAD_GL_VERSION_2_1;
typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv;
#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv;
#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv;
#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv;
#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv;
#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv;
#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv
#endif
#ifndef GL_VERSION_3_0
#define GL_VERSION_3_0 1
GLAPI int GLAD_GL_VERSION_3_0;
typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski;
#define glColorMaski glad_glColorMaski
typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean *data);
GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v;
#define glGetBooleani_v glad_glGetBooleani_v
typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint *data);
GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v;
#define glGetIntegeri_v glad_glGetIntegeri_v
typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index);
GLAPI PFNGLENABLEIPROC glad_glEnablei;
#define glEnablei glad_glEnablei
typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index);
GLAPI PFNGLDISABLEIPROC glad_glDisablei;
#define glDisablei glad_glDisablei
typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index);
GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi;
#define glIsEnabledi glad_glIsEnabledi
typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode);
GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback;
#define glBeginTransformFeedback glad_glBeginTransformFeedback
typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(void);
GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback;
#define glEndTransformFeedback glad_glEndTransformFeedback
typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange;
#define glBindBufferRange glad_glBindBufferRange
typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer);
GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase;
#define glBindBufferBase glad_glBindBufferBase
typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings;
#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying;
#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying
typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp);
GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor;
#define glClampColor glad_glClampColor
typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode);
GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender;
#define glBeginConditionalRender glad_glBeginConditionalRender
typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(void);
GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender;
#define glEndConditionalRender glad_glEndConditionalRender
typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer;
#define glVertexAttribIPointer glad_glVertexAttribIPointer
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint *params);
GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv;
#define glGetVertexAttribIiv glad_glGetVertexAttribIiv
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint *params);
GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv;
#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x);
GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i;
#define glVertexAttribI1i glad_glVertexAttribI1i
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y);
GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i;
#define glVertexAttribI2i glad_glVertexAttribI2i
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z);
GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i;
#define glVertexAttribI3i glad_glVertexAttribI3i
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w);
GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i;
#define glVertexAttribI4i glad_glVertexAttribI4i
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x);
GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui;
#define glVertexAttribI1ui glad_glVertexAttribI1ui
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y);
GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui;
#define glVertexAttribI2ui glad_glVertexAttribI2ui
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z);
GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui;
#define glVertexAttribI3ui glad_glVertexAttribI3ui
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui;
#define glVertexAttribI4ui glad_glVertexAttribI4ui
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint *v);
GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv;
#define glVertexAttribI1iv glad_glVertexAttribI1iv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint *v);
GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv;
#define glVertexAttribI2iv glad_glVertexAttribI2iv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint *v);
GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv;
#define glVertexAttribI3iv glad_glVertexAttribI3iv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint *v);
GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv;
#define glVertexAttribI4iv glad_glVertexAttribI4iv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint *v);
GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv;
#define glVertexAttribI1uiv glad_glVertexAttribI1uiv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint *v);
GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv;
#define glVertexAttribI2uiv glad_glVertexAttribI2uiv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint *v);
GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv;
#define glVertexAttribI3uiv glad_glVertexAttribI3uiv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint *v);
GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv;
#define glVertexAttribI4uiv glad_glVertexAttribI4uiv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte *v);
GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv;
#define glVertexAttribI4bv glad_glVertexAttribI4bv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort *v);
GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv;
#define glVertexAttribI4sv glad_glVertexAttribI4sv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte *v);
GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv;
#define glVertexAttribI4ubv glad_glVertexAttribI4ubv
typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort *v);
GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv;
#define glVertexAttribI4usv glad_glVertexAttribI4usv
typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint *params);
GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv;
#define glGetUniformuiv glad_glGetUniformuiv
typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar *name);
GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation;
#define glBindFragDataLocation glad_glBindFragDataLocation
typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar *name);
GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation;
#define glGetFragDataLocation glad_glGetFragDataLocation
typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0);
GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui;
#define glUniform1ui glad_glUniform1ui
typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1);
GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui;
#define glUniform2ui glad_glUniform2ui
typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2);
GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui;
#define glUniform3ui glad_glUniform3ui
typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui;
#define glUniform4ui glad_glUniform4ui
typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint *value);
GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv;
#define glUniform1uiv glad_glUniform1uiv
typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint *value);
GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv;
#define glUniform2uiv glad_glUniform2uiv
typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint *value);
GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv;
#define glUniform3uiv glad_glUniform3uiv
typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint *value);
GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv;
#define glUniform4uiv glad_glUniform4uiv
typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint *params);
GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv;
#define glTexParameterIiv glad_glTexParameterIiv
typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint *params);
GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv;
#define glTexParameterIuiv glad_glTexParameterIuiv
typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint *params);
GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv;
#define glGetTexParameterIiv glad_glGetTexParameterIiv
typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint *params);
GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv;
#define glGetTexParameterIuiv glad_glGetTexParameterIuiv
typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint *value);
GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv;
#define glClearBufferiv glad_glClearBufferiv
typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint *value);
GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv;
#define glClearBufferuiv glad_glClearBufferuiv
typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat *value);
GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv;
#define glClearBufferfv glad_glClearBufferfv
typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi;
#define glClearBufferfi glad_glClearBufferfi
typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index);
GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi;
#define glGetStringi glad_glGetStringi
typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer);
GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;
#define glIsRenderbuffer glad_glIsRenderbuffer
typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer);
GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;
#define glBindRenderbuffer glad_glBindRenderbuffer
typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers);
GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;
#define glDeleteRenderbuffers glad_glDeleteRenderbuffers
typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers);
GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;
#define glGenRenderbuffers glad_glGenRenderbuffers
typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;
#define glRenderbufferStorage glad_glRenderbufferStorage
typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);
GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;
#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv
typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer);
GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;
#define glIsFramebuffer glad_glIsFramebuffer
typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer);
GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;
#define glBindFramebuffer glad_glBindFramebuffer
typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers);
GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;
#define glDeleteFramebuffers glad_glDeleteFramebuffers
typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers);
GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;
#define glGenFramebuffers glad_glGenFramebuffers
typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target);
GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;
#define glCheckFramebufferStatus glad_glCheckFramebufferStatus
typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D;
#define glFramebufferTexture1D glad_glFramebufferTexture1D
typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;
#define glFramebufferTexture2D glad_glFramebufferTexture2D
typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D;
#define glFramebufferTexture3D glad_glFramebufferTexture3D
typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;
#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer
typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params);
GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;
#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv
typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target);
GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;
#define glGenerateMipmap glad_glGenerateMipmap
typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer;
#define glBlitFramebuffer glad_glBlitFramebuffer
typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;
#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample
typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer;
#define glFramebufferTextureLayer glad_glFramebufferTextureLayer
typedef void * (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange;
#define glMapBufferRange glad_glMapBufferRange
typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length);
GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange;
#define glFlushMappedBufferRange glad_glFlushMappedBufferRange
typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array);
GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray;
#define glBindVertexArray glad_glBindVertexArray
typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint *arrays);
GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays;
#define glDeleteVertexArrays glad_glDeleteVertexArrays
typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays);
GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays;
#define glGenVertexArrays glad_glGenVertexArrays
typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array);
GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray;
#define glIsVertexArray glad_glIsVertexArray
#endif
#ifndef GL_VERSION_3_1
#define GL_VERSION_3_1 1
GLAPI int GLAD_GL_VERSION_3_1;
typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced;
#define glDrawArraysInstanced glad_glDrawArraysInstanced
typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced;
#define glDrawElementsInstanced glad_glDrawElementsInstanced
typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer);
GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer;
#define glTexBuffer glad_glTexBuffer
typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index);
GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex;
#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex
typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData;
#define glCopyBufferSubData glad_glCopyBufferSubData
typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);
GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices;
#define glGetUniformIndices glad_glGetUniformIndices
typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv;
#define glGetActiveUniformsiv glad_glGetActiveUniformsiv
typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);
GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName;
#define glGetActiveUniformName glad_glGetActiveUniformName
typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar *uniformBlockName);
GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex;
#define glGetUniformBlockIndex glad_glGetUniformBlockIndex
typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);
GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv;
#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv
typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);
GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName;
#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName
typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding;
#define glUniformBlockBinding glad_glUniformBlockBinding
#endif
#ifndef GL_VERSION_3_2
#define GL_VERSION_3_2 1
GLAPI int GLAD_GL_VERSION_3_2;
typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex;
#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex
typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex;
#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex
typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex;
#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex
typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);
GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex;
#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex
typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode);
GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex;
#define glProvokingVertex glad_glProvokingVertex
typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags);
GLAPI PFNGLFENCESYNCPROC glad_glFenceSync;
#define glFenceSync glad_glFenceSync
typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync);
GLAPI PFNGLISSYNCPROC glad_glIsSync;
#define glIsSync glad_glIsSync
typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync);
GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync;
#define glDeleteSync glad_glDeleteSync
typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);
GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync;
#define glClientWaitSync glad_glClientWaitSync
typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);
GLAPI PFNGLWAITSYNCPROC glad_glWaitSync;
#define glWaitSync glad_glWaitSync
typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 *data);
GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v;
#define glGetInteger64v glad_glGetInteger64v
typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values);
GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv;
#define glGetSynciv glad_glGetSynciv
typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 *data);
GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v;
#define glGetInteger64i_v glad_glGetInteger64i_v
typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 *params);
GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v;
#define glGetBufferParameteri64v glad_glGetBufferParameteri64v
typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level);
GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture;
#define glFramebufferTexture glad_glFramebufferTexture
typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample;
#define glTexImage2DMultisample glad_glTexImage2DMultisample
typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample;
#define glTexImage3DMultisample glad_glTexImage3DMultisample
typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat *val);
GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv;
#define glGetMultisamplefv glad_glGetMultisamplefv
typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask);
GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski;
#define glSampleMaski glad_glSampleMaski
#endif
#ifndef GL_VERSION_3_3
#define GL_VERSION_3_3 1
GLAPI int GLAD_GL_VERSION_3_3;
typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
GLAPI PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed;
#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed
typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar *name);
GLAPI PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex;
#define glGetFragDataIndex glad_glGetFragDataIndex
typedef void (APIENTRYP PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint *samplers);
GLAPI PFNGLGENSAMPLERSPROC glad_glGenSamplers;
#define glGenSamplers glad_glGenSamplers
typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint *samplers);
GLAPI PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers;
#define glDeleteSamplers glad_glDeleteSamplers
typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC)(GLuint sampler);
GLAPI PFNGLISSAMPLERPROC glad_glIsSampler;
#define glIsSampler glad_glIsSampler
typedef void (APIENTRYP PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler);
GLAPI PFNGLBINDSAMPLERPROC glad_glBindSampler;
#define glBindSampler glad_glBindSampler
typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param);
GLAPI PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri;
#define glSamplerParameteri glad_glSamplerParameteri
typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint *param);
GLAPI PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv;
#define glSamplerParameteriv glad_glSamplerParameteriv
typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param);
GLAPI PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf;
#define glSamplerParameterf glad_glSamplerParameterf
typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat *param);
GLAPI PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv;
#define glSamplerParameterfv glad_glSamplerParameterfv
typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint *param);
GLAPI PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv;
#define glSamplerParameterIiv glad_glSamplerParameterIiv
typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint *param);
GLAPI PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv;
#define glSamplerParameterIuiv glad_glSamplerParameterIuiv
typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint *params);
GLAPI PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv;
#define glGetSamplerParameteriv glad_glGetSamplerParameteriv
typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint *params);
GLAPI PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv;
#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv
typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat *params);
GLAPI PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv;
#define glGetSamplerParameterfv glad_glGetSamplerParameterfv
typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint *params);
GLAPI PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv;
#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv
typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target);
GLAPI PFNGLQUERYCOUNTERPROC glad_glQueryCounter;
#define glQueryCounter glad_glQueryCounter
typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 *params);
GLAPI PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v;
#define glGetQueryObjecti64v glad_glGetQueryObjecti64v
typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 *params);
GLAPI PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v;
#define glGetQueryObjectui64v glad_glGetQueryObjectui64v
typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor);
GLAPI PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor;
#define glVertexAttribDivisor glad_glVertexAttribDivisor
typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
GLAPI PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui;
#define glVertexAttribP1ui glad_glVertexAttribP1ui
typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
GLAPI PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv;
#define glVertexAttribP1uiv glad_glVertexAttribP1uiv
typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
GLAPI PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui;
#define glVertexAttribP2ui glad_glVertexAttribP2ui
typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
GLAPI PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv;
#define glVertexAttribP2uiv glad_glVertexAttribP2uiv
typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
GLAPI PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui;
#define glVertexAttribP3ui glad_glVertexAttribP3ui
typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
GLAPI PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv;
#define glVertexAttribP3uiv glad_glVertexAttribP3uiv
typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
GLAPI PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui;
#define glVertexAttribP4ui glad_glVertexAttribP4ui
typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
GLAPI PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv;
#define glVertexAttribP4uiv glad_glVertexAttribP4uiv
typedef void (APIENTRYP PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value);
GLAPI PFNGLVERTEXP2UIPROC glad_glVertexP2ui;
#define glVertexP2ui glad_glVertexP2ui
typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint *value);
GLAPI PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv;
#define glVertexP2uiv glad_glVertexP2uiv
typedef void (APIENTRYP PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value);
GLAPI PFNGLVERTEXP3UIPROC glad_glVertexP3ui;
#define glVertexP3ui glad_glVertexP3ui
typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint *value);
GLAPI PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv;
#define glVertexP3uiv glad_glVertexP3uiv
typedef void (APIENTRYP PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value);
GLAPI PFNGLVERTEXP4UIPROC glad_glVertexP4ui;
#define glVertexP4ui glad_glVertexP4ui
typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint *value);
GLAPI PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv;
#define glVertexP4uiv glad_glVertexP4uiv
typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords);
GLAPI PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui;
#define glTexCoordP1ui glad_glTexCoordP1ui
typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint *coords);
GLAPI PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv;
#define glTexCoordP1uiv glad_glTexCoordP1uiv
typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords);
GLAPI PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui;
#define glTexCoordP2ui glad_glTexCoordP2ui
typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint *coords);
GLAPI PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv;
#define glTexCoordP2uiv glad_glTexCoordP2uiv
typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords);
GLAPI PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui;
#define glTexCoordP3ui glad_glTexCoordP3ui
typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint *coords);
GLAPI PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv;
#define glTexCoordP3uiv glad_glTexCoordP3uiv
typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords);
GLAPI PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui;
#define glTexCoordP4ui glad_glTexCoordP4ui
typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint *coords);
GLAPI PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv;
#define glTexCoordP4uiv glad_glTexCoordP4uiv
typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords);
GLAPI PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui;
#define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui
typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);
GLAPI PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv;
#define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv
typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords);
GLAPI PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui;
#define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui
typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);
GLAPI PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv;
#define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv
typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords);
GLAPI PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui;
#define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui
typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);
GLAPI PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv;
#define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv
typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords);
GLAPI PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui;
#define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui
typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint *coords);
GLAPI PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv;
#define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv
typedef void (APIENTRYP PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords);
GLAPI PFNGLNORMALP3UIPROC glad_glNormalP3ui;
#define glNormalP3ui glad_glNormalP3ui
typedef void (APIENTRYP PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint *coords);
GLAPI PFNGLNORMALP3UIVPROC glad_glNormalP3uiv;
#define glNormalP3uiv glad_glNormalP3uiv
typedef void (APIENTRYP PFNGLCOLORP3UIPROC)(GLenum type, GLuint color);
GLAPI PFNGLCOLORP3UIPROC glad_glColorP3ui;
#define glColorP3ui glad_glColorP3ui
typedef void (APIENTRYP PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint *color);
GLAPI PFNGLCOLORP3UIVPROC glad_glColorP3uiv;
#define glColorP3uiv glad_glColorP3uiv
typedef void (APIENTRYP PFNGLCOLORP4UIPROC)(GLenum type, GLuint color);
GLAPI PFNGLCOLORP4UIPROC glad_glColorP4ui;
#define glColorP4ui glad_glColorP4ui
typedef void (APIENTRYP PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint *color);
GLAPI PFNGLCOLORP4UIVPROC glad_glColorP4uiv;
#define glColorP4uiv glad_glColorP4uiv
typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color);
GLAPI PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui;
#define glSecondaryColorP3ui glad_glSecondaryColorP3ui
typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint *color);
GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv
#endif
#ifndef GL_VERSION_4_0
#define GL_VERSION_4_0 1
GLAPI int GLAD_GL_VERSION_4_0;
typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC)(GLfloat value);
GLAPI PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading;
#define glMinSampleShading glad_glMinSampleShading
typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC)(GLuint buf, GLenum mode);
GLAPI PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi;
#define glBlendEquationi glad_glBlendEquationi
typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha);
GLAPI PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei;
#define glBlendEquationSeparatei glad_glBlendEquationSeparatei
typedef void (APIENTRYP PFNGLBLENDFUNCIPROC)(GLuint buf, GLenum src, GLenum dst);
GLAPI PFNGLBLENDFUNCIPROC glad_glBlendFunci;
#define glBlendFunci glad_glBlendFunci
typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
GLAPI PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei;
#define glBlendFuncSeparatei glad_glBlendFuncSeparatei
typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC)(GLenum mode, const void *indirect);
GLAPI PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect;
#define glDrawArraysIndirect glad_glDrawArraysIndirect
typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void *indirect);
GLAPI PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect;
#define glDrawElementsIndirect glad_glDrawElementsIndirect
typedef void (APIENTRYP PFNGLUNIFORM1DPROC)(GLint location, GLdouble x);
GLAPI PFNGLUNIFORM1DPROC glad_glUniform1d;
#define glUniform1d glad_glUniform1d
typedef void (APIENTRYP PFNGLUNIFORM2DPROC)(GLint location, GLdouble x, GLdouble y);
GLAPI PFNGLUNIFORM2DPROC glad_glUniform2d;
#define glUniform2d glad_glUniform2d
typedef void (APIENTRYP PFNGLUNIFORM3DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z);
GLAPI PFNGLUNIFORM3DPROC glad_glUniform3d;
#define glUniform3d glad_glUniform3d
typedef void (APIENTRYP PFNGLUNIFORM4DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
GLAPI PFNGLUNIFORM4DPROC glad_glUniform4d;
#define glUniform4d glad_glUniform4d
typedef void (APIENTRYP PFNGLUNIFORM1DVPROC)(GLint location, GLsizei count, const GLdouble *value);
GLAPI PFNGLUNIFORM1DVPROC glad_glUniform1dv;
#define glUniform1dv glad_glUniform1dv
typedef void (APIENTRYP PFNGLUNIFORM2DVPROC)(GLint location, GLsizei count, const GLdouble *value);
GLAPI PFNGLUNIFORM2DVPROC glad_glUniform2dv;
#define glUniform2dv glad_glUniform2dv
typedef void (APIENTRYP PFNGLUNIFORM3DVPROC)(GLint location, GLsizei count, const GLdouble *value);
GLAPI PFNGLUNIFORM3DVPROC glad_glUniform3dv;
#define glUniform3dv glad_glUniform3dv
typedef void (APIENTRYP PFNGLUNIFORM4DVPROC)(GLint location, GLsizei count, const GLdouble *value);
GLAPI PFNGLUNIFORM4DVPROC glad_glUniform4dv;
#define glUniform4dv glad_glUniform4dv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv;
#define glUniformMatrix2dv glad_glUniformMatrix2dv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv;
#define glUniformMatrix3dv glad_glUniformMatrix3dv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv;
#define glUniformMatrix4dv glad_glUniformMatrix4dv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv;
#define glUniformMatrix2x3dv glad_glUniformMatrix2x3dv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv;
#define glUniformMatrix2x4dv glad_glUniformMatrix2x4dv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv;
#define glUniformMatrix3x2dv glad_glUniformMatrix3x2dv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv;
#define glUniformMatrix3x4dv glad_glUniformMatrix3x4dv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv;
#define glUniformMatrix4x2dv glad_glUniformMatrix4x2dv
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv;
#define glUniformMatrix4x3dv glad_glUniformMatrix4x3dv
typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC)(GLuint program, GLint location, GLdouble *params);
GLAPI PFNGLGETUNIFORMDVPROC glad_glGetUniformdv;
#define glGetUniformdv glad_glGetUniformdv
typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)(GLuint program, GLenum shadertype, const GLchar *name);
GLAPI PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation;
#define glGetSubroutineUniformLocation glad_glGetSubroutineUniformLocation
typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC)(GLuint program, GLenum shadertype, const GLchar *name);
GLAPI PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex;
#define glGetSubroutineIndex glad_glGetSubroutineIndex
typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)(GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);
GLAPI PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv;
#define glGetActiveSubroutineUniformiv glad_glGetActiveSubroutineUniformiv
typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
GLAPI PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName;
#define glGetActiveSubroutineUniformName glad_glGetActiveSubroutineUniformName
typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
GLAPI PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName;
#define glGetActiveSubroutineName glad_glGetActiveSubroutineName
typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC)(GLenum shadertype, GLsizei count, const GLuint *indices);
GLAPI PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv;
#define glUniformSubroutinesuiv glad_glUniformSubroutinesuiv
typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC)(GLenum shadertype, GLint location, GLuint *params);
GLAPI PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv;
#define glGetUniformSubroutineuiv glad_glGetUniformSubroutineuiv
typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC)(GLuint program, GLenum shadertype, GLenum pname, GLint *values);
GLAPI PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv;
#define glGetProgramStageiv glad_glGetProgramStageiv
typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC)(GLenum pname, GLint value);
GLAPI PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri;
#define glPatchParameteri glad_glPatchParameteri
typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC)(GLenum pname, const GLfloat *values);
GLAPI PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv;
#define glPatchParameterfv glad_glPatchParameterfv
typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum target, GLuint id);
GLAPI PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback;
#define glBindTransformFeedback glad_glBindTransformFeedback
typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei n, const GLuint *ids);
GLAPI PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks;
#define glDeleteTransformFeedbacks glad_glDeleteTransformFeedbacks
typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint *ids);
GLAPI PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks;
#define glGenTransformFeedbacks glad_glGenTransformFeedbacks
typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC)(GLuint id);
GLAPI PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback;
#define glIsTransformFeedback glad_glIsTransformFeedback
typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC)(void);
GLAPI PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback;
#define glPauseTransformFeedback glad_glPauseTransformFeedback
typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC)(void);
GLAPI PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback;
#define glResumeTransformFeedback glad_glResumeTransformFeedback
typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC)(GLenum mode, GLuint id);
GLAPI PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback;
#define glDrawTransformFeedback glad_glDrawTransformFeedback
typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)(GLenum mode, GLuint id, GLuint stream);
GLAPI PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream;
#define glDrawTransformFeedbackStream glad_glDrawTransformFeedbackStream
typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC)(GLenum target, GLuint index, GLuint id);
GLAPI PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed;
#define glBeginQueryIndexed glad_glBeginQueryIndexed
typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC)(GLenum target, GLuint index);
GLAPI PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed;
#define glEndQueryIndexed glad_glEndQueryIndexed
typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC)(GLenum target, GLuint index, GLenum pname, GLint *params);
GLAPI PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv;
#define glGetQueryIndexediv glad_glGetQueryIndexediv
#endif
#ifndef GL_VERSION_4_1
#define GL_VERSION_4_1 1
GLAPI int GLAD_GL_VERSION_4_1;
typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)(void);
GLAPI PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler;
#define glReleaseShaderCompiler glad_glReleaseShaderCompiler
typedef void (APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint *shaders, GLenum binaryFormat, const void *binary, GLsizei length);
GLAPI PFNGLSHADERBINARYPROC glad_glShaderBinary;
#define glShaderBinary glad_glShaderBinary
typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);
GLAPI PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat;
#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat
typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f);
GLAPI PFNGLDEPTHRANGEFPROC glad_glDepthRangef;
#define glDepthRangef glad_glDepthRangef
typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC)(GLfloat d);
GLAPI PFNGLCLEARDEPTHFPROC glad_glClearDepthf;
#define glClearDepthf glad_glClearDepthf
typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
GLAPI PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary;
#define glGetProgramBinary glad_glGetProgramBinary
typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
GLAPI PFNGLPROGRAMBINARYPROC glad_glProgramBinary;
#define glProgramBinary glad_glProgramBinary
typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value);
GLAPI PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri;
#define glProgramParameteri glad_glProgramParameteri
typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC)(GLuint pipeline, GLbitfield stages, GLuint program);
GLAPI PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages;
#define glUseProgramStages glad_glUseProgramStages
typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program);
GLAPI PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram;
#define glActiveShaderProgram glad_glActiveShaderProgram
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC)(GLenum type, GLsizei count, const GLchar *const*strings);
GLAPI PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv;
#define glCreateShaderProgramv glad_glCreateShaderProgramv
typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC)(GLuint pipeline);
GLAPI PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline;
#define glBindProgramPipeline glad_glBindProgramPipeline
typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei n, const GLuint *pipelines);
GLAPI PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines;
#define glDeleteProgramPipelines glad_glDeleteProgramPipelines
typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC)(GLsizei n, GLuint *pipelines);
GLAPI PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines;
#define glGenProgramPipelines glad_glGenProgramPipelines
typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC)(GLuint pipeline);
GLAPI PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline;
#define glIsProgramPipeline glad_glIsProgramPipeline
typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint pipeline, GLenum pname, GLint *params);
GLAPI PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv;
#define glGetProgramPipelineiv glad_glGetProgramPipelineiv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC)(GLuint program, GLint location, GLint v0);
GLAPI PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i;
#define glProgramUniform1i glad_glProgramUniform1i
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
GLAPI PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv;
#define glProgramUniform1iv glad_glProgramUniform1iv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC)(GLuint program, GLint location, GLfloat v0);
GLAPI PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f;
#define glProgramUniform1f glad_glProgramUniform1f
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv;
#define glProgramUniform1fv glad_glProgramUniform1fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC)(GLuint program, GLint location, GLdouble v0);
GLAPI PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d;
#define glProgramUniform1d glad_glProgramUniform1d
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv;
#define glProgramUniform1dv glad_glProgramUniform1dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC)(GLuint program, GLint location, GLuint v0);
GLAPI PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui;
#define glProgramUniform1ui glad_glProgramUniform1ui
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
GLAPI PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv;
#define glProgramUniform1uiv glad_glProgramUniform1uiv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC)(GLuint program, GLint location, GLint v0, GLint v1);
GLAPI PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i;
#define glProgramUniform2i glad_glProgramUniform2i
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
GLAPI PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv;
#define glProgramUniform2iv glad_glProgramUniform2iv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1);
GLAPI PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f;
#define glProgramUniform2f glad_glProgramUniform2f
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv;
#define glProgramUniform2fv glad_glProgramUniform2fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1);
GLAPI PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d;
#define glProgramUniform2d glad_glProgramUniform2d
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv;
#define glProgramUniform2dv glad_glProgramUniform2dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1);
GLAPI PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui;
#define glProgramUniform2ui glad_glProgramUniform2ui
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
GLAPI PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv;
#define glProgramUniform2uiv glad_glProgramUniform2uiv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
GLAPI PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i;
#define glProgramUniform3i glad_glProgramUniform3i
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
GLAPI PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv;
#define glProgramUniform3iv glad_glProgramUniform3iv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
GLAPI PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f;
#define glProgramUniform3f glad_glProgramUniform3f
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv;
#define glProgramUniform3fv glad_glProgramUniform3fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);
GLAPI PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d;
#define glProgramUniform3d glad_glProgramUniform3d
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv;
#define glProgramUniform3dv glad_glProgramUniform3dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
GLAPI PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui;
#define glProgramUniform3ui glad_glProgramUniform3ui
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
GLAPI PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv;
#define glProgramUniform3uiv glad_glProgramUniform3uiv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
GLAPI PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i;
#define glProgramUniform4i glad_glProgramUniform4i
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);
GLAPI PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv;
#define glProgramUniform4iv glad_glProgramUniform4iv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
GLAPI PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f;
#define glProgramUniform4f glad_glProgramUniform4f
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv;
#define glProgramUniform4fv glad_glProgramUniform4fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);
GLAPI PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d;
#define glProgramUniform4d glad_glProgramUniform4d
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv;
#define glProgramUniform4dv glad_glProgramUniform4dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
GLAPI PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui;
#define glProgramUniform4ui glad_glProgramUniform4ui
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);
GLAPI PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv;
#define glProgramUniform4uiv glad_glProgramUniform4uiv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv;
#define glProgramUniformMatrix2fv glad_glProgramUniformMatrix2fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv;
#define glProgramUniformMatrix3fv glad_glProgramUniformMatrix3fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv;
#define glProgramUniformMatrix4fv glad_glProgramUniformMatrix4fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv;
#define glProgramUniformMatrix2dv glad_glProgramUniformMatrix2dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv;
#define glProgramUniformMatrix3dv glad_glProgramUniformMatrix3dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv;
#define glProgramUniformMatrix4dv glad_glProgramUniformMatrix4dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv;
#define glProgramUniformMatrix2x3fv glad_glProgramUniformMatrix2x3fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv;
#define glProgramUniformMatrix3x2fv glad_glProgramUniformMatrix3x2fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv;
#define glProgramUniformMatrix2x4fv glad_glProgramUniformMatrix2x4fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv;
#define glProgramUniformMatrix4x2fv glad_glProgramUniformMatrix4x2fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv;
#define glProgramUniformMatrix3x4fv glad_glProgramUniformMatrix3x4fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv;
#define glProgramUniformMatrix4x3fv glad_glProgramUniformMatrix4x3fv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv;
#define glProgramUniformMatrix2x3dv glad_glProgramUniformMatrix2x3dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv;
#define glProgramUniformMatrix3x2dv glad_glProgramUniformMatrix3x2dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv;
#define glProgramUniformMatrix2x4dv glad_glProgramUniformMatrix2x4dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv;
#define glProgramUniformMatrix4x2dv glad_glProgramUniformMatrix4x2dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv;
#define glProgramUniformMatrix3x4dv glad_glProgramUniformMatrix3x4dv
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
GLAPI PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv;
#define glProgramUniformMatrix4x3dv glad_glProgramUniformMatrix4x3dv
typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint pipeline);
GLAPI PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline;
#define glValidateProgramPipeline glad_glValidateProgramPipeline
typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
GLAPI PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog;
#define glGetProgramPipelineInfoLog glad_glGetProgramPipelineInfoLog
typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC)(GLuint index, GLdouble x);
GLAPI PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d;
#define glVertexAttribL1d glad_glVertexAttribL1d
typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC)(GLuint index, GLdouble x, GLdouble y);
GLAPI PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d;
#define glVertexAttribL2d glad_glVertexAttribL2d
typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);
GLAPI PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d;
#define glVertexAttribL3d glad_glVertexAttribL3d
typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
GLAPI PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d;
#define glVertexAttribL4d glad_glVertexAttribL4d
typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC)(GLuint index, const GLdouble *v);
GLAPI PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv;
#define glVertexAttribL1dv glad_glVertexAttribL1dv
typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC)(GLuint index, const GLdouble *v);
GLAPI PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv;
#define glVertexAttribL2dv glad_glVertexAttribL2dv
typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC)(GLuint index, const GLdouble *v);
GLAPI PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv;
#define glVertexAttribL3dv glad_glVertexAttribL3dv
typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC)(GLuint index, const GLdouble *v);
GLAPI PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv;
#define glVertexAttribL4dv glad_glVertexAttribL4dv
typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
GLAPI PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer;
#define glVertexAttribLPointer glad_glVertexAttribLPointer
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC)(GLuint index, GLenum pname, GLdouble *params);
GLAPI PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv;
#define glGetVertexAttribLdv glad_glGetVertexAttribLdv
typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC)(GLuint first, GLsizei count, const GLfloat *v);
GLAPI PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv;
#define glViewportArrayv glad_glViewportArrayv
typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
GLAPI PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf;
#define glViewportIndexedf glad_glViewportIndexedf
typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC)(GLuint index, const GLfloat *v);
GLAPI PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv;
#define glViewportIndexedfv glad_glViewportIndexedfv
typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC)(GLuint first, GLsizei count, const GLint *v);
GLAPI PFNGLSCISSORARRAYVPROC glad_glScissorArrayv;
#define glScissorArrayv glad_glScissorArrayv
typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
GLAPI PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed;
#define glScissorIndexed glad_glScissorIndexed
typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC)(GLuint index, const GLint *v);
GLAPI PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv;
#define glScissorIndexedv glad_glScissorIndexedv
typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC)(GLuint first, GLsizei count, const GLdouble *v);
GLAPI PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv;
#define glDepthRangeArrayv glad_glDepthRangeArrayv
typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f);
GLAPI PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed;
#define glDepthRangeIndexed glad_glDepthRangeIndexed
typedef void (APIENTRYP PFNGLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat *data);
GLAPI PFNGLGETFLOATI_VPROC glad_glGetFloati_v;
#define glGetFloati_v glad_glGetFloati_v
typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC)(GLenum target, GLuint index, GLdouble *data);
GLAPI PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v;
#define glGetDoublei_v glad_glGetDoublei_v
#endif
#ifndef GL_VERSION_4_2
#define GL_VERSION_4_2 1
GLAPI int GLAD_GL_VERSION_4_2;
typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
GLAPI PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance;
#define glDrawArraysInstancedBaseInstance glad_glDrawArraysInstancedBaseInstance
typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance;
#define glDrawElementsInstancedBaseInstance glad_glDrawElementsInstancedBaseInstance
typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance;
#define glDrawElementsInstancedBaseVertexBaseInstance glad_glDrawElementsInstancedBaseVertexBaseInstance
typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params);
GLAPI PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ;
#define glGetInternalformativ glad_glGetInternalformativ
typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)(GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
GLAPI PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv;
#define glGetActiveAtomicCounterBufferiv glad_glGetActiveAtomicCounterBufferiv
typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
GLAPI PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture;
#define glBindImageTexture glad_glBindImageTexture
typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC)(GLbitfield barriers);
GLAPI PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier;
#define glMemoryBarrier glad_glMemoryBarrier
typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
GLAPI PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D;
#define glTexStorage1D glad_glTexStorage1D
typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
GLAPI PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D;
#define glTexStorage2D glad_glTexStorage2D
typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
GLAPI PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D;
#define glTexStorage3D glad_glTexStorage3D
typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)(GLenum mode, GLuint id, GLsizei instancecount);
GLAPI PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced;
#define glDrawTransformFeedbackInstanced glad_glDrawTransformFeedbackInstanced
typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)(GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);
GLAPI PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced;
#define glDrawTransformFeedbackStreamInstanced glad_glDrawTransformFeedbackStreamInstanced
#endif
#ifndef GL_VERSION_4_3
#define GL_VERSION_4_3 1
GLAPI int GLAD_GL_VERSION_4_3;
typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC)(GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);
GLAPI PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData;
#define glClearBufferData glad_glClearBufferData
typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC)(GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
GLAPI PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData;
#define glClearBufferSubData glad_glClearBufferSubData
typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
GLAPI PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute;
#define glDispatchCompute glad_glDispatchCompute
typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC)(GLintptr indirect);
GLAPI PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect;
#define glDispatchComputeIndirect glad_glDispatchComputeIndirect
typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
GLAPI PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData;
#define glCopyImageSubData glad_glCopyImageSubData
typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);
GLAPI PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri;
#define glFramebufferParameteri glad_glFramebufferParameteri
typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);
GLAPI PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv;
#define glGetFramebufferParameteriv glad_glGetFramebufferParameteriv
typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64 *params);
GLAPI PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v;
#define glGetInternalformati64v glad_glGetInternalformati64v
typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
GLAPI PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage;
#define glInvalidateTexSubImage glad_glInvalidateTexSubImage
typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC)(GLuint texture, GLint level);
GLAPI PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage;
#define glInvalidateTexImage glad_glInvalidateTexImage
typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length);
GLAPI PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData;
#define glInvalidateBufferSubData glad_glInvalidateBufferSubData
typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer);
GLAPI PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData;
#define glInvalidateBufferData glad_glInvalidateBufferData
typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments);
GLAPI PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer;
#define glInvalidateFramebuffer glad_glInvalidateFramebuffer
typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
GLAPI PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer;
#define glInvalidateSubFramebuffer glad_glInvalidateSubFramebuffer
typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC)(GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
GLAPI PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect;
#define glMultiDrawArraysIndirect glad_glMultiDrawArraysIndirect
typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
GLAPI PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect;
#define glMultiDrawElementsIndirect glad_glMultiDrawElementsIndirect
typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC)(GLuint program, GLenum programInterface, GLenum pname, GLint *params);
GLAPI PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv;
#define glGetProgramInterfaceiv glad_glGetProgramInterfaceiv
typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC)(GLuint program, GLenum programInterface, const GLchar *name);
GLAPI PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex;
#define glGetProgramResourceIndex glad_glGetProgramResourceIndex
typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
GLAPI PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName;
#define glGetProgramResourceName glad_glGetProgramResourceName
typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLint *params);
GLAPI PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv;
#define glGetProgramResourceiv glad_glGetProgramResourceiv
typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC)(GLuint program, GLenum programInterface, const GLchar *name);
GLAPI PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation;
#define glGetProgramResourceLocation glad_glGetProgramResourceLocation
typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)(GLuint program, GLenum programInterface, const GLchar *name);
GLAPI PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex;
#define glGetProgramResourceLocationIndex glad_glGetProgramResourceLocationIndex
typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC)(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
GLAPI PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding;
#define glShaderStorageBlockBinding glad_glShaderStorageBlockBinding
typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
GLAPI PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange;
#define glTexBufferRange glad_glTexBufferRange
typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
GLAPI PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample;
#define glTexStorage2DMultisample glad_glTexStorage2DMultisample
typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
GLAPI PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample;
#define glTexStorage3DMultisample glad_glTexStorage3DMultisample
typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
GLAPI PFNGLTEXTUREVIEWPROC glad_glTextureView;
#define glTextureView glad_glTextureView
typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
GLAPI PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer;
#define glBindVertexBuffer glad_glBindVertexBuffer
typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
GLAPI PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat;
#define glVertexAttribFormat glad_glVertexAttribFormat
typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
GLAPI PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat;
#define glVertexAttribIFormat glad_glVertexAttribIFormat
typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
GLAPI PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat;
#define glVertexAttribLFormat glad_glVertexAttribLFormat
typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC)(GLuint attribindex, GLuint bindingindex);
GLAPI PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding;
#define glVertexAttribBinding glad_glVertexAttribBinding
typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC)(GLuint bindingindex, GLuint divisor);
GLAPI PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor;
#define glVertexBindingDivisor glad_glVertexBindingDivisor
typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
GLAPI PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl;
#define glDebugMessageControl glad_glDebugMessageControl
typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
GLAPI PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert;
#define glDebugMessageInsert glad_glDebugMessageInsert
typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void *userParam);
GLAPI PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback;
#define glDebugMessageCallback glad_glDebugMessageCallback
typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
GLAPI PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog;
#define glGetDebugMessageLog glad_glGetDebugMessageLog
typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message);
GLAPI PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup;
#define glPushDebugGroup glad_glPushDebugGroup
typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC)(void);
GLAPI PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup;
#define glPopDebugGroup glad_glPopDebugGroup
typedef void (APIENTRYP PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
GLAPI PFNGLOBJECTLABELPROC glad_glObjectLabel;
#define glObjectLabel glad_glObjectLabel
typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
GLAPI PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel;
#define glGetObjectLabel glad_glGetObjectLabel
typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC)(const void *ptr, GLsizei length, const GLchar *label);
GLAPI PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel;
#define glObjectPtrLabel glad_glObjectPtrLabel
typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
GLAPI PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel;
#define glGetObjectPtrLabel glad_glGetObjectPtrLabel
typedef void (APIENTRYP PFNGLGETPOINTERVPROC)(GLenum pname, void **params);
GLAPI PFNGLGETPOINTERVPROC glad_glGetPointerv;
#define glGetPointerv glad_glGetPointerv
#endif
#ifndef GL_VERSION_4_4
#define GL_VERSION_4_4 1
GLAPI int GLAD_GL_VERSION_4_4;
typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
GLAPI PFNGLBUFFERSTORAGEPROC glad_glBufferStorage;
#define glBufferStorage glad_glBufferStorage
typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC)(GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
GLAPI PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage;
#define glClearTexImage glad_glClearTexImage
typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
GLAPI PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage;
#define glClearTexSubImage glad_glClearTexSubImage
typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC)(GLenum target, GLuint first, GLsizei count, const GLuint *buffers);
GLAPI PFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase;
#define glBindBuffersBase glad_glBindBuffersBase
typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC)(GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);
GLAPI PFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange;
#define glBindBuffersRange glad_glBindBuffersRange
typedef void (APIENTRYP PFNGLBINDTEXTURESPROC)(GLuint first, GLsizei count, const GLuint *textures);
GLAPI PFNGLBINDTEXTURESPROC glad_glBindTextures;
#define glBindTextures glad_glBindTextures
typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC)(GLuint first, GLsizei count, const GLuint *samplers);
GLAPI PFNGLBINDSAMPLERSPROC glad_glBindSamplers;
#define glBindSamplers glad_glBindSamplers
typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC)(GLuint first, GLsizei count, const GLuint *textures);
GLAPI PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures;
#define glBindImageTextures glad_glBindImageTextures
typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC)(GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
GLAPI PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers;
#define glBindVertexBuffers glad_glBindVertexBuffers
#endif

#ifdef __cplusplus
}
#endif

#endif

process_mesh/dependencies/glad/include/KHR/khrplatform.h METASEP
#ifndef __khrplatform_h_
#define __khrplatform_h_

/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/

/* Khronos platform-specific types and definitions.
 *
 * The master copy of khrplatform.h is maintained in the Khronos EGL
 * Registry repository at https://github.com/KhronosGroup/EGL-Registry
 * The last semantic modification to khrplatform.h was at commit ID:
 *      67a3e0864c2d75ea5287b9f3d2eb74a745936692
 *
 * Adopters may modify this file to suit their platform. Adopters are
 * encouraged to submit platform specific modifications to the Khronos
 * group so that they can be included in future versions of this file.
 * Please submit changes by filing pull requests or issues on
 * the EGL Registry repository linked above.
 *
 *
 * See the Implementer's Guidelines for information about where this file
 * should be located on your system and for more details of its use:
 *    http://www.khronos.org/registry/implementers_guide.pdf
 *
 * This file should be included as
 *        #include <KHR/khrplatform.h>
 * by Khronos client API header files that use its types and defines.
 *
 * The types in khrplatform.h should only be used to define API-specific types.
 *
 * Types defined in khrplatform.h:
 *    khronos_int8_t              signed   8  bit
 *    khronos_uint8_t             unsigned 8  bit
 *    khronos_int16_t             signed   16 bit
 *    khronos_uint16_t            unsigned 16 bit
 *    khronos_int32_t             signed   32 bit
 *    khronos_uint32_t            unsigned 32 bit
 *    khronos_int64_t             signed   64 bit
 *    khronos_uint64_t            unsigned 64 bit
 *    khronos_intptr_t            signed   same number of bits as a pointer
 *    khronos_uintptr_t           unsigned same number of bits as a pointer
 *    khronos_ssize_t             signed   size
 *    khronos_usize_t             unsigned size
 *    khronos_float_t             signed   32 bit floating point
 *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds
 *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in
 *                                         nanoseconds
 *    khronos_stime_nanoseconds_t signed time interval in nanoseconds
 *    khronos_boolean_enum_t      enumerated boolean type. This should
 *      only be used as a base type when a client API's boolean type is
 *      an enum. Client APIs which use an integer or other type for
 *      booleans cannot use this as the base type for their boolean.
 *
 * Tokens defined in khrplatform.h:
 *
 *    KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
 *
 *    KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
 *    KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
 *
 * Calling convention macros defined in this file:
 *    KHRONOS_APICALL
 *    KHRONOS_APIENTRY
 *    KHRONOS_APIATTRIBUTES
 *
 * These may be used in function prototypes as:
 *
 *      KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
 *                                  int arg1,
 *                                  int arg2) KHRONOS_APIATTRIBUTES;
 */

#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
#   define KHRONOS_STATIC 1
#endif

/*-------------------------------------------------------------------------
 * Definition of KHRONOS_APICALL
 *-------------------------------------------------------------------------
 * This precedes the return type of the function in the function prototype.
 */
#if defined(KHRONOS_STATIC)
    /* If the preprocessor constant KHRONOS_STATIC is defined, make the
     * header compatible with static linking. */
#   define KHRONOS_APICALL
#elif defined(_WIN32)
#   define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
#   define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
#   define KHRONOS_APICALL __attribute__((visibility("default")))
#else
#   define KHRONOS_APICALL
#endif

/*-------------------------------------------------------------------------
 * Definition of KHRONOS_APIENTRY
 *-------------------------------------------------------------------------
 * This follows the return type of the function  and precedes the function
 * name in the function prototype.
 */
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
    /* Win32 but not WinCE */
#   define KHRONOS_APIENTRY __stdcall
#else
#   define KHRONOS_APIENTRY
#endif

/*-------------------------------------------------------------------------
 * Definition of KHRONOS_APIATTRIBUTES
 *-------------------------------------------------------------------------
 * This follows the closing parenthesis of the function prototype arguments.
 */
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif

/*-------------------------------------------------------------------------
 * basic type definitions
 *-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)


/*
 * Using <stdint.h>
 */
#include <stdint.h>
typedef int32_t                 khronos_int32_t;
typedef uint32_t                khronos_uint32_t;
typedef int64_t                 khronos_int64_t;
typedef uint64_t                khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64   1
#define KHRONOS_SUPPORT_FLOAT   1
/*
 * To support platform where unsigned long cannot be used interchangeably with
 * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
 * Ideally, we could just use (u)intptr_t everywhere, but this could result in
 * ABI breakage if khronos_uintptr_t is changed from unsigned long to
 * unsigned long long or similar (this results in different C++ name mangling).
 * To avoid changes for existing platforms, we restrict usage of intptr_t to
 * platforms where the size of a pointer is larger than the size of long.
 */
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif

#elif defined(__VMS ) || defined(__sgi)

/*
 * Using <inttypes.h>
 */
#include <inttypes.h>
typedef int32_t                 khronos_int32_t;
typedef uint32_t                khronos_uint32_t;
typedef int64_t                 khronos_int64_t;
typedef uint64_t                khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64   1
#define KHRONOS_SUPPORT_FLOAT   1

#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)

/*
 * Win32
 */
typedef __int32                 khronos_int32_t;
typedef unsigned __int32        khronos_uint32_t;
typedef __int64                 khronos_int64_t;
typedef unsigned __int64        khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64   1
#define KHRONOS_SUPPORT_FLOAT   1

#elif defined(__sun__) || defined(__digital__)

/*
 * Sun or Digital
 */
typedef int                     khronos_int32_t;
typedef unsigned int            khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int                khronos_int64_t;
typedef unsigned long int       khronos_uint64_t;
#else
typedef long long int           khronos_int64_t;
typedef unsigned long long int  khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64   1
#define KHRONOS_SUPPORT_FLOAT   1

#elif 0

/*
 * Hypothetical platform with no float or int64 support
 */
typedef int                     khronos_int32_t;
typedef unsigned int            khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64   0
#define KHRONOS_SUPPORT_FLOAT   0

#else

/*
 * Generic fallback
 */
#include <stdint.h>
typedef int32_t                 khronos_int32_t;
typedef uint32_t                khronos_uint32_t;
typedef int64_t                 khronos_int64_t;
typedef uint64_t                khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64   1
#define KHRONOS_SUPPORT_FLOAT   1

#endif


/*
 * Types that are (so far) the same on all platforms
 */
typedef signed   char          khronos_int8_t;
typedef unsigned char          khronos_uint8_t;
typedef signed   short int     khronos_int16_t;
typedef unsigned short int     khronos_uint16_t;

/*
 * Types that differ between LLP64 and LP64 architectures - in LLP64,
 * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
 * to be the only LLP64 architecture in current use.
 */
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t               khronos_intptr_t;
typedef uintptr_t              khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed   long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed   long  int     khronos_intptr_t;
typedef unsigned long  int     khronos_uintptr_t;
#endif

#if defined(_WIN64)
typedef signed   long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed   long  int     khronos_ssize_t;
typedef unsigned long  int     khronos_usize_t;
#endif

#if KHRONOS_SUPPORT_FLOAT
/*
 * Float type
 */
typedef          float         khronos_float_t;
#endif

#if KHRONOS_SUPPORT_INT64
/* Time types
 *
 * These types can be used to represent a time interval in nanoseconds or
 * an absolute Unadjusted System Time.  Unadjusted System Time is the number
 * of nanoseconds since some arbitrary system event (e.g. since the last
 * time the system booted).  The Unadjusted System Time is an unsigned
 * 64 bit value that wraps back to 0 every 584 years.  Time intervals
 * may be either signed or unsigned.
 */
typedef khronos_uint64_t       khronos_utime_nanoseconds_t;
typedef khronos_int64_t        khronos_stime_nanoseconds_t;
#endif

/*
 * Dummy value used to pad enum types to 32 bits.
 */
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif

/*
 * Enumerated boolean type
 *
 * Values other than zero should be considered to be true.  Therefore
 * comparisons should not be made against KHRONOS_TRUE.
 */
typedef enum {
    KHRONOS_FALSE = 0,
    KHRONOS_TRUE  = 1,
    KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;

#endif /* __khrplatform_h_ */

process_mesh/dependencies/glad/include/EGL/eglplatform.h METASEP
#ifndef __eglplatform_h_
#define __eglplatform_h_

/*
** Copyright 2007-2020 The Khronos Group Inc.
** SPDX-License-Identifier: Apache-2.0
*/

/* Platform-specific types and definitions for egl.h
 *
 * Adopters may modify khrplatform.h and this file to suit their platform.
 * You are encouraged to submit all modifications to the Khronos group so that
 * they can be included in future versions of this file.  Please submit changes
 * by filing an issue or pull request on the public Khronos EGL Registry, at
 * https://www.github.com/KhronosGroup/EGL-Registry/
 */

#include <KHR/khrplatform.h>

/* Macros used in EGL function prototype declarations.
 *
 * EGL functions should be prototyped as:
 *
 * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
 * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
 *
 * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
 */

#ifndef EGLAPI
#define EGLAPI KHRONOS_APICALL
#endif

#ifndef EGLAPIENTRY
#define EGLAPIENTRY  KHRONOS_APIENTRY
#endif
#define EGLAPIENTRYP EGLAPIENTRY*

/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
 * are aliases of window-system-dependent types, such as X Display * or
 * Windows Device Context. They must be defined in platform-specific
 * code below. The EGL-prefixed versions of Native*Type are the same
 * types, renamed in EGL 1.3 so all types in the API start with "EGL".
 *
 * Khronos STRONGLY RECOMMENDS that you use the default definitions
 * provided below, since these changes affect both binary and source
 * portability of applications using EGL running on different EGL
 * implementations.
 */

#if defined(EGL_NO_PLATFORM_SPECIFIC_TYPES)

typedef void *EGLNativeDisplayType;
typedef void *EGLNativePixmapType;
typedef void *EGLNativeWindowType;

#elif defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>

typedef HDC     EGLNativeDisplayType;
typedef HBITMAP EGLNativePixmapType;
typedef HWND    EGLNativeWindowType;

#elif defined(__EMSCRIPTEN__)

typedef int EGLNativeDisplayType;
typedef int EGLNativePixmapType;
typedef int EGLNativeWindowType;

#elif defined(__WINSCW__) || defined(__SYMBIAN32__)  /* Symbian */

typedef int   EGLNativeDisplayType;
typedef void *EGLNativePixmapType;
typedef void *EGLNativeWindowType;

#elif defined(WL_EGL_PLATFORM)

typedef struct wl_display     *EGLNativeDisplayType;
typedef struct wl_egl_pixmap  *EGLNativePixmapType;
typedef struct wl_egl_window  *EGLNativeWindowType;

#elif defined(__GBM__)

typedef struct gbm_device  *EGLNativeDisplayType;
typedef struct gbm_bo      *EGLNativePixmapType;
typedef void               *EGLNativeWindowType;

#elif defined(__ANDROID__) || defined(ANDROID)

struct ANativeWindow;
struct egl_native_pixmap_t;

typedef void*                           EGLNativeDisplayType;
typedef struct egl_native_pixmap_t*     EGLNativePixmapType;
typedef struct ANativeWindow*           EGLNativeWindowType;

#elif defined(USE_OZONE)

typedef intptr_t EGLNativeDisplayType;
typedef intptr_t EGLNativePixmapType;
typedef intptr_t EGLNativeWindowType;

#elif defined(USE_X11)

/* X11 (tentative)  */
#include <X11/Xlib.h>
#include <X11/Xutil.h>

typedef Display *EGLNativeDisplayType;
typedef Pixmap   EGLNativePixmapType;
typedef Window   EGLNativeWindowType;

#elif defined(__unix__)

typedef void             *EGLNativeDisplayType;
typedef khronos_uintptr_t EGLNativePixmapType;
typedef khronos_uintptr_t EGLNativeWindowType;

#elif defined(__APPLE__)

typedef int   EGLNativeDisplayType;
typedef void *EGLNativePixmapType;
typedef void *EGLNativeWindowType;

#elif defined(__HAIKU__)

#include <kernel/image.h>

typedef void              *EGLNativeDisplayType;
typedef khronos_uintptr_t  EGLNativePixmapType;
typedef khronos_uintptr_t  EGLNativeWindowType;

#elif defined(__Fuchsia__)

typedef void              *EGLNativeDisplayType;
typedef khronos_uintptr_t  EGLNativePixmapType;
typedef khronos_uintptr_t  EGLNativeWindowType;

#else
#error "Platform not recognized"
#endif

/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
typedef EGLNativeDisplayType NativeDisplayType;
typedef EGLNativePixmapType  NativePixmapType;
typedef EGLNativeWindowType  NativeWindowType;


/* Define EGLint. This must be a signed integral type large enough to contain
 * all legal attribute names and values passed into and out of EGL, whether
 * their type is boolean, bitmask, enumerant (symbolic constant), integer,
 * handle, or other.  While in general a 32-bit integer will suffice, if
 * handles are 64 bit types, then EGLint should be defined as a signed 64-bit
 * integer type.
 */
typedef khronos_int32_t EGLint;


/* C++ / C typecast macros for special EGL handle values */
#if defined(__cplusplus)
#define EGL_CAST(type, value) (static_cast<type>(value))
#else
#define EGL_CAST(type, value) ((type) (value))
#endif

#endif /* __eglplatform_h */

worldgen/terrain/source/cpu/soil_machine/soil/README.md METASEP
# SoilMachine

## .soil files

This represents a really simple file format that lets you pre-define a set of soils which are loaded into the simulation at runtime. The goal is to be able to play with parameters and soil-cascades without needing to recompile.

## definition

todo (read the .default file)

process_mesh/dependencies/glad/src/glad_egl.c METASEP
/*

    EGL loader generated by glad 0.1.35 on Mon Jan 17 21:14:15 2022.

    Language/Generator: C/C++
    Specification: egl
    APIs: egl=1.5
    Profile: -
    Extensions:
        
    Loader: True
    Local files: False
    Omit khrplatform: False
    Reproducible: False

    Commandline:
        --api="egl=1.5" --generator="c" --spec="egl" --extensions=""
    Online:
        https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.5
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glad/glad_egl.h>

int gladLoadEGL(void) {
    return gladLoadEGLLoader((GLADloadproc)eglGetProcAddress);
}

static int find_extensionsEGL(void) {
	return 1;
}

static void find_coreEGL(void) {
}

int gladLoadEGLLoader(GLADloadproc load) {
	(void) load;
	find_coreEGL();

	if (!find_extensionsEGL()) return 0;
	return 1;
}


process_mesh/dependencies/glad/src/glad.c METASEP
/*

    OpenGL loader generated by glad 0.1.35 on Mon Jan 17 21:17:15 2022.

    Language/Generator: C/C++
    Specification: gl
    APIs: gl=4.4
    Profile: core
    Extensions:
        
    Loader: True
    Local files: False
    Omit khrplatform: False
    Reproducible: False

    Commandline:
        --profile="core" --api="gl=4.4" --generator="c" --spec="gl" --extensions=""
    Online:
        https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.4
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glad/glad.h>

static void* get_proc(const char *namez);

#if defined(_WIN32) || defined(__CYGWIN__)
#ifndef _WINDOWS_
#undef APIENTRY
#endif
#include <windows.h>
static HMODULE libGL;

typedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*);
static PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;

#ifdef _MSC_VER
#ifdef __has_include
  #if __has_include(<winapifamily.h>)
    #define HAVE_WINAPIFAMILY 1
  #endif
#elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
  #define HAVE_WINAPIFAMILY 1
#endif
#endif

#ifdef HAVE_WINAPIFAMILY
  #include <winapifamily.h>
  #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
    #define IS_UWP 1
  #endif
#endif

static
int open_gl(void) {
#ifndef IS_UWP
    libGL = LoadLibraryW(L"opengl32.dll");
    if(libGL != NULL) {
        void (* tmp)(void);
        tmp = (void(*)(void)) GetProcAddress(libGL, "wglGetProcAddress");
        gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp;
        return gladGetProcAddressPtr != NULL;
    }
#endif

    return 0;
}

static
void close_gl(void) {
    if(libGL != NULL) {
        FreeLibrary((HMODULE) libGL);
        libGL = NULL;
    }
}
#else
#include <dlfcn.h>
static void* libGL;

#if !defined(__APPLE__) && !defined(__HAIKU__)
typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*);
static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;
#endif

static
int open_gl(void) {
#ifdef __APPLE__
    static const char *NAMES[] = {
        "../Frameworks/OpenGL.framework/OpenGL",
        "/Library/Frameworks/OpenGL.framework/OpenGL",
        "/System/Library/Frameworks/OpenGL.framework/OpenGL",
        "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"
    };
#else
    static const char *NAMES[] = {"libGL.so.1", "libGL.so"};
#endif

    unsigned int index = 0;
    for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) {
        libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL);

        if(libGL != NULL) {
#if defined(__APPLE__) || defined(__HAIKU__)
            return 1;
#else
            gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL,
                "glXGetProcAddressARB");
            return gladGetProcAddressPtr != NULL;
#endif
        }
    }

    return 0;
}

static
void close_gl(void) {
    if(libGL != NULL) {
        dlclose(libGL);
        libGL = NULL;
    }
}
#endif

static
void* get_proc(const char *namez) {
    void* result = NULL;
    if(libGL == NULL) return NULL;

#if !defined(__APPLE__) && !defined(__HAIKU__)
    if(gladGetProcAddressPtr != NULL) {
        result = gladGetProcAddressPtr(namez);
    }
#endif
    if(result == NULL) {
#if defined(_WIN32) || defined(__CYGWIN__)
        result = (void*)GetProcAddress((HMODULE) libGL, namez);
#else
        result = dlsym(libGL, namez);
#endif
    }

    return result;
}

int gladLoadGL(void) {
    int status = 0;

    if(open_gl()) {
        status = gladLoadGLLoader(&get_proc);
        close_gl();
    }

    return status;
}

struct gladGLversionStruct GLVersion = { 0, 0 };

#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)
#define _GLAD_IS_SOME_NEW_VERSION 1
#endif

static int max_loaded_major;
static int max_loaded_minor;

static const char *exts = NULL;
static int num_exts_i = 0;
static char **exts_i = NULL;

static int get_exts(void) {
#ifdef _GLAD_IS_SOME_NEW_VERSION
    if(max_loaded_major < 3) {
#endif
        exts = (const char *)glGetString(GL_EXTENSIONS);
#ifdef _GLAD_IS_SOME_NEW_VERSION
    } else {
        unsigned int index;

        num_exts_i = 0;
        glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i);
        if (num_exts_i > 0) {
            exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i));
        }

        if (exts_i == NULL) {
            return 0;
        }

        for(index = 0; index < (unsigned)num_exts_i; index++) {
            const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index);
            size_t len = strlen(gl_str_tmp);

            char *local_str = (char*)malloc((len+1) * sizeof(char));
            if(local_str != NULL) {
                memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char));
            }
            exts_i[index] = local_str;
        }
    }
#endif
    return 1;
}

static void free_exts(void) {
    if (exts_i != NULL) {
        int index;
        for(index = 0; index < num_exts_i; index++) {
            free((char *)exts_i[index]);
        }
        free((void *)exts_i);
        exts_i = NULL;
    }
}

static int has_ext(const char *ext) {
#ifdef _GLAD_IS_SOME_NEW_VERSION
    if(max_loaded_major < 3) {
#endif
        const char *extensions;
        const char *loc;
        const char *terminator;
        extensions = exts;
        if(extensions == NULL || ext == NULL) {
            return 0;
        }

        while(1) {
            loc = strstr(extensions, ext);
            if(loc == NULL) {
                return 0;
            }

            terminator = loc + strlen(ext);
            if((loc == extensions || *(loc - 1) == ' ') &&
                (*terminator == ' ' || *terminator == '\0')) {
                return 1;
            }
            extensions = terminator;
        }
#ifdef _GLAD_IS_SOME_NEW_VERSION
    } else {
        int index;
        if(exts_i == NULL) return 0;
        for(index = 0; index < num_exts_i; index++) {
            const char *e = exts_i[index];

            if(exts_i[index] != NULL && strcmp(e, ext) == 0) {
                return 1;
            }
        }
    }
#endif

    return 0;
}
int GLAD_GL_VERSION_1_0 = 0;
int GLAD_GL_VERSION_1_1 = 0;
int GLAD_GL_VERSION_1_2 = 0;
int GLAD_GL_VERSION_1_3 = 0;
int GLAD_GL_VERSION_1_4 = 0;
int GLAD_GL_VERSION_1_5 = 0;
int GLAD_GL_VERSION_2_0 = 0;
int GLAD_GL_VERSION_2_1 = 0;
int GLAD_GL_VERSION_3_0 = 0;
int GLAD_GL_VERSION_3_1 = 0;
int GLAD_GL_VERSION_3_2 = 0;
int GLAD_GL_VERSION_3_3 = 0;
int GLAD_GL_VERSION_4_0 = 0;
int GLAD_GL_VERSION_4_1 = 0;
int GLAD_GL_VERSION_4_2 = 0;
int GLAD_GL_VERSION_4_3 = 0;
int GLAD_GL_VERSION_4_4 = 0;
PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL;
PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL;
PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;
PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed = NULL;
PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;
PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;
PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;
PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;
PFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase = NULL;
PFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange = NULL;
PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL;
PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL;
PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture = NULL;
PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures = NULL;
PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL;
PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;
PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;
PFNGLBINDSAMPLERSPROC glad_glBindSamplers = NULL;
PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
PFNGLBINDTEXTURESPROC glad_glBindTextures = NULL;
PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL;
PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;
PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer = NULL;
PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers = NULL;
PFNGLBLENDCOLORPROC glad_glBlendColor = NULL;
PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;
PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;
PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei = NULL;
PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi = NULL;
PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;
PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;
PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei = NULL;
PFNGLBLENDFUNCIPROC glad_glBlendFunci = NULL;
PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;
PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL;
PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;
PFNGLCLAMPCOLORPROC glad_glClampColor = NULL;
PFNGLCLEARPROC glad_glClear = NULL;
PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData = NULL;
PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData = NULL;
PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL;
PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL;
PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL;
PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;
PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;
PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;
PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage = NULL;
PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage = NULL;
PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;
PFNGLCOLORMASKPROC glad_glColorMask = NULL;
PFNGLCOLORMASKIPROC glad_glColorMaski = NULL;
PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL;
PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL;
PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL;
PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL;
PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;
PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL;
PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;
PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL;
PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;
PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;
PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData = NULL;
PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;
PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;
PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;
PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL;
PFNGLCULLFACEPROC glad_glCullFace = NULL;
PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL;
PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL;
PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL;
PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;
PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;
PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = NULL;
PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;
PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;
PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;
PFNGLDELETESHADERPROC glad_glDeleteShader = NULL;
PFNGLDELETESYNCPROC glad_glDeleteSync = NULL;
PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL;
PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;
PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;
PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;
PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL;
PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL;
PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;
PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
PFNGLDISABLEPROC glad_glDisable = NULL;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;
PFNGLDISABLEIPROC glad_glDisablei = NULL;
PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute = NULL;
PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect = NULL;
PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL;
PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;
PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance = NULL;
PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL;
PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;
PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL;
PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL;
PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;
PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance = NULL;
PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL;
PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance = NULL;
PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;
PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL;
PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback = NULL;
PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced = NULL;
PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL;
PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced = NULL;
PFNGLENABLEPROC glad_glEnable = NULL;
PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
PFNGLENABLEIPROC glad_glEnablei = NULL;
PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;
PFNGLENDQUERYPROC glad_glEndQuery = NULL;
PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed = NULL;
PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;
PFNGLFENCESYNCPROC glad_glFenceSync = NULL;
PFNGLFINISHPROC glad_glFinish = NULL;
PFNGLFLUSHPROC glad_glFlush = NULL;
PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;
PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri = NULL;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;
PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;
PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL;
PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;
PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL;
PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;
PFNGLFRONTFACEPROC glad_glFrontFace = NULL;
PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;
PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL;
PFNGLGENQUERIESPROC glad_glGenQueries = NULL;
PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;
PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;
PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL;
PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;
PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;
PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv = NULL;
PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL;
PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName = NULL;
PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv = NULL;
PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;
PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;
PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;
PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL;
PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;
PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;
PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;
PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL;
PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL;
PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;
PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL;
PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;
PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL;
PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL;
PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;
PFNGLGETERRORPROC glad_glGetError = NULL;
PFNGLGETFLOATI_VPROC glad_glGetFloati_v = NULL;
PFNGLGETFLOATVPROC glad_glGetFloatv = NULL;
PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL;
PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;
PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv = NULL;
PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;
PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;
PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;
PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v = NULL;
PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL;
PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;
PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL;
PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL;
PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL;
PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL;
PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;
PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv = NULL;
PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL;
PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL;
PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex = NULL;
PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation = NULL;
PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex = NULL;
PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName = NULL;
PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv = NULL;
PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL;
PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = NULL;
PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;
PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;
PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL;
PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;
PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;
PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;
PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL;
PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL;
PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL;
PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL;
PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;
PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL;
PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;
PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;
PFNGLGETSTRINGPROC glad_glGetString = NULL;
PFNGLGETSTRINGIPROC glad_glGetStringi = NULL;
PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex = NULL;
PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation = NULL;
PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;
PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL;
PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL;
PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL;
PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL;
PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;
PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;
PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;
PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;
PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv = NULL;
PFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL;
PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;
PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;
PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;
PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;
PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;
PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL;
PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;
PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;
PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;
PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;
PFNGLHINTPROC glad_glHint = NULL;
PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData = NULL;
PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData = NULL;
PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL;
PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL;
PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage = NULL;
PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage = NULL;
PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
PFNGLISENABLEDPROC glad_glIsEnabled = NULL;
PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL;
PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;
PFNGLISPROGRAMPROC glad_glIsProgram = NULL;
PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = NULL;
PFNGLISQUERYPROC glad_glIsQuery = NULL;
PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;
PFNGLISSAMPLERPROC glad_glIsSampler = NULL;
PFNGLISSHADERPROC glad_glIsShader = NULL;
PFNGLISSYNCPROC glad_glIsSync = NULL;
PFNGLISTEXTUREPROC glad_glIsTexture = NULL;
PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL;
PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;
PFNGLLINEWIDTHPROC glad_glLineWidth = NULL;
PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
PFNGLLOGICOPPROC glad_glLogicOp = NULL;
PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;
PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;
PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier = NULL;
PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading = NULL;
PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;
PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect = NULL;
PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;
PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;
PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect = NULL;
PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL;
PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL;
PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL;
PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL;
PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL;
PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL;
PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL;
PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL;
PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL;
PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL;
PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL;
PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL;
PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv = NULL;
PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL;
PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL;
PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;
PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL;
PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;
PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL;
PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL;
PFNGLPOINTSIZEPROC glad_glPointSize = NULL;
PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;
PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL;
PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;
PFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL;
PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL;
PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d = NULL;
PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv = NULL;
PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL;
PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL;
PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL;
PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL;
PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL;
PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL;
PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d = NULL;
PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv = NULL;
PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL;
PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL;
PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL;
PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL;
PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL;
PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL;
PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d = NULL;
PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv = NULL;
PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL;
PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL;
PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL;
PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL;
PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL;
PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL;
PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d = NULL;
PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv = NULL;
PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL;
PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL;
PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL;
PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL;
PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL;
PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL;
PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv = NULL;
PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL;
PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv = NULL;
PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL;
PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv = NULL;
PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL;
PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv = NULL;
PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL;
PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv = NULL;
PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL;
PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv = NULL;
PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL;
PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv = NULL;
PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL;
PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv = NULL;
PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL;
PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv = NULL;
PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL;
PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;
PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL;
PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;
PFNGLREADBUFFERPROC glad_glReadBuffer = NULL;
PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL;
PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;
PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL;
PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL;
PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL;
PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL;
PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL;
PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL;
PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL;
PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL;
PFNGLSCISSORPROC glad_glScissor = NULL;
PFNGLSCISSORARRAYVPROC glad_glScissorArrayv = NULL;
PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed = NULL;
PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv = NULL;
PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL;
PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL;
PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL;
PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding = NULL;
PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;
PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;
PFNGLSTENCILOPPROC glad_glStencilOp = NULL;
PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;
PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL;
PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange = NULL;
PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL;
PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL;
PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL;
PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL;
PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL;
PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL;
PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL;
PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL;
PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL;
PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL;
PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL;
PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL;
PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL;
PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL;
PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;
PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D = NULL;
PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D = NULL;
PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample = NULL;
PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D = NULL;
PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample = NULL;
PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;
PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;
PFNGLTEXTUREVIEWPROC glad_glTextureView = NULL;
PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;
PFNGLUNIFORM1DPROC glad_glUniform1d = NULL;
PFNGLUNIFORM1DVPROC glad_glUniform1dv = NULL;
PFNGLUNIFORM1FPROC glad_glUniform1f = NULL;
PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;
PFNGLUNIFORM1IPROC glad_glUniform1i = NULL;
PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;
PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL;
PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;
PFNGLUNIFORM2DPROC glad_glUniform2d = NULL;
PFNGLUNIFORM2DVPROC glad_glUniform2dv = NULL;
PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;
PFNGLUNIFORM2IPROC glad_glUniform2i = NULL;
PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;
PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;
PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL;
PFNGLUNIFORM3DPROC glad_glUniform3d = NULL;
PFNGLUNIFORM3DVPROC glad_glUniform3dv = NULL;
PFNGLUNIFORM3FPROC glad_glUniform3f = NULL;
PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;
PFNGLUNIFORM3IPROC glad_glUniform3i = NULL;
PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;
PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;
PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;
PFNGLUNIFORM4DPROC glad_glUniform4d = NULL;
PFNGLUNIFORM4DVPROC glad_glUniform4dv = NULL;
PFNGLUNIFORM4FPROC glad_glUniform4f = NULL;
PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;
PFNGLUNIFORM4IPROC glad_glUniform4i = NULL;
PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;
PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;
PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL;
PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL;
PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv = NULL;
PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;
PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv = NULL;
PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;
PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv = NULL;
PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;
PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv = NULL;
PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;
PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv = NULL;
PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;
PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv = NULL;
PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;
PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv = NULL;
PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;
PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv = NULL;
PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;
PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL;
PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;
PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL;
PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;
PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL;
PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL;
PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL;
PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;
PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;
PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL;
PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL;
PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL;
PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL;
PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;
PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;
PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL;
PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL;
PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL;
PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL;
PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;
PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;
PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL;
PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL;
PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL;
PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL;
PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL;
PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL;
PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL;
PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL;
PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL;
PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL;
PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL;
PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL;
PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;
PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;
PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL;
PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL;
PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL;
PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL;
PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL;
PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL;
PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding = NULL;
PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;
PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat = NULL;
PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL;
PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL;
PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL;
PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL;
PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL;
PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL;
PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL;
PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL;
PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL;
PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL;
PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL;
PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL;
PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL;
PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL;
PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL;
PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL;
PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL;
PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL;
PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;
PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL;
PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat = NULL;
PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;
PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d = NULL;
PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv = NULL;
PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d = NULL;
PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv = NULL;
PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d = NULL;
PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv = NULL;
PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d = NULL;
PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv = NULL;
PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat = NULL;
PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer = NULL;
PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL;
PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL;
PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL;
PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL;
PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL;
PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL;
PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL;
PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL;
PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor = NULL;
PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL;
PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL;
PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL;
PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL;
PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL;
PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL;
PFNGLVIEWPORTPROC glad_glViewport = NULL;
PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL;
PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL;
PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;
PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
static void load_GL_VERSION_1_0(GLADloadproc load) {
	if(!GLAD_GL_VERSION_1_0) return;
	glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
	glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace");
	glad_glHint = (PFNGLHINTPROC)load("glHint");
	glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth");
	glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize");
	glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode");
	glad_glScissor = (PFNGLSCISSORPROC)load("glScissor");
	glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf");
	glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv");
	glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri");
	glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv");
	glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D");
	glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D");
	glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer");
	glad_glClear = (PFNGLCLEARPROC)load("glClear");
	glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor");
	glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil");
	glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth");
	glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask");
	glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask");
	glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask");
	glad_glDisable = (PFNGLDISABLEPROC)load("glDisable");
	glad_glEnable = (PFNGLENABLEPROC)load("glEnable");
	glad_glFinish = (PFNGLFINISHPROC)load("glFinish");
	glad_glFlush = (PFNGLFLUSHPROC)load("glFlush");
	glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc");
	glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp");
	glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc");
	glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp");
	glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc");
	glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref");
	glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei");
	glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer");
	glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels");
	glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv");
	glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev");
	glad_glGetError = (PFNGLGETERRORPROC)load("glGetError");
	glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv");
	glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv");
	glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString");
	glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage");
	glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv");
	glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv");
	glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv");
	glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv");
	glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled");
	glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange");
	glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport");
}
static void load_GL_VERSION_1_1(GLADloadproc load) {
	if(!GLAD_GL_VERSION_1_1) return;
	glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays");
	glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements");
	glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset");
	glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D");
	glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D");
	glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D");
	glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D");
	glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D");
	glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D");
	glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture");
	glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures");
	glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures");
	glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture");
}
static void load_GL_VERSION_1_2(GLADloadproc load) {
	if(!GLAD_GL_VERSION_1_2) return;
	glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements");
	glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D");
	glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D");
	glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D");
}
static void load_GL_VERSION_1_3(GLADloadproc load) {
	if(!GLAD_GL_VERSION_1_3) return;
	glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture");
	glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage");
	glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D");
	glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D");
	glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D");
	glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D");
	glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D");
	glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D");
	glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage");
}
static void load_GL_VERSION_1_4(GLADloadproc load) {
	if(!GLAD_GL_VERSION_1_4) return;
	glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate");
	glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays");
	glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements");
	glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf");
	glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv");
	glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri");
	glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv");
	glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor");
	glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation");
}
static void load_GL_VERSION_1_5(GLADloadproc load) {
	if(!GLAD_GL_VERSION_1_5) return;
	glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries");
	glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries");
	glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery");
	glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery");
	glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery");
	glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv");
	glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv");
	glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv");
	glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer");
	glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers");
	glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers");
	glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer");
	glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData");
	glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData");
	glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData");
	glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer");
	glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer");
	glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv");
	glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv");
}
static void load_GL_VERSION_2_0(GLADloadproc load) {
	if(!GLAD_GL_VERSION_2_0) return;
	glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate");
	glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers");
	glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate");
	glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate");
	glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate");
	glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader");
	glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation");
	glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader");
	glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram");
	glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader");
	glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram");
	glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader");
	glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader");
	glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray");
	glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray");
	glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib");
	glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform");
	glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders");
	glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation");
	glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv");
	glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog");
	glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv");
	glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog");
	glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource");
	glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation");
	glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv");
	glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv");
	glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv");
	glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv");
	glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv");
	glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv");
	glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram");
	glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader");
	glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram");
	glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource");
	glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram");
	glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f");
	glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f");
	glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f");
	glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f");
	glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i");
	glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i");
	glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i");
	glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i");
	glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv");
	glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv");
	glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv");
	glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv");
	glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv");
	glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv");
	glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv");
	glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv");
	glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv");
	glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv");
	glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv");
	glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram");
	glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d");
	glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv");
	glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f");
	glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv");
	glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s");
	glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv");
	glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d");
	glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv");
	glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f");
	glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv");
	glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s");
	glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv");
	glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d");
	glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv");
	glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f");
	glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv");
	glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s");
	glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv");
	glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv");
	glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv");
	glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv");
	glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub");
	glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv");
	glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv");
	glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv");
	glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv");
	glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d");
	glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv");
	glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f");
	glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv");
	glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv");
	glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s");
	glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv");
	glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv");
	glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv");
	glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv");
	glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer");
}
static void load_GL_VERSION_2_1(GLADloadproc load) {
	if(!GLAD_GL_VERSION_2_1) return;
	glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv");
	glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv");
	glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv");
	glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv");
	glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv");
	glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv");
}
static void load_GL_VERSION_3_0(GLADloadproc load) {
	if(!GLAD_GL_VERSION_3_0) return;
	glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski");
	glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v");
	glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v");
	glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei");
	glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei");
	glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi");
	glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback");
	glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback");
	glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange");
	glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase");
	glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings");
	glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying");
	glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor");
	glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender");
	glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender");
	glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer");
	glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv");
	glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv");
	glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i");
	glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i");
	glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i");
	glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i");
	glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui");
	glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui");
	glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui");
	glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui");
	glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv");
	glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv");
	glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv");
	glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv");
	glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv");
	glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv");
	glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv");
	glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv");
	glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv");
	glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv");
	glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv");
	glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv");
	glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv");
	glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation");
	glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation");
	glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui");
	glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui");
	glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui");
	glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui");
	glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv");
	glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv");
	glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv");
	glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv");
	glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv");
	glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv");
	glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv");
	glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv");
	glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv");
	glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv");
	glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv");
	glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi");
	glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi");
	glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer");
	glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer");
	glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers");
	glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers");
	glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage");
	glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv");
	glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer");
	glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer");
	glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers");
	glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers");
	glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus");
	glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D");
	glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D");
	glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D");
	glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer");
	glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv");
	glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap");
	glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer");
	glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample");
	glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer");
	glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange");
	glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange");
	glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray");
	glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays");
	glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays");
	glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray");
}
static void load_GL_VERSION_3_1(GLADloadproc load) {
	if(!GLAD_GL_VERSION_3_1) return;
	glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced");
	glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced");
	glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer");
	glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex");
	glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData");
	glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices");
	glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv");
	glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName");
	glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex");
	glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv");
	glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName");
	glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding");
	glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange");
	glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase");
	glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v");
}
static void load_GL_VERSION_3_2(GLADloadproc load) {
	if(!GLAD_GL_VERSION_3_2) return;
	glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex");
	glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex");
	glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex");
	glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex");
	glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex");
	glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync");
	glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync");
	glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync");
	glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync");
	glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync");
	glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v");
	glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv");
	glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v");
	glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v");
	glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture");
	glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample");
	glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample");
	glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv");
	glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski");
}
static void load_GL_VERSION_3_3(GLADloadproc load) {
	if(!GLAD_GL_VERSION_3_3) return;
	glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)load("glBindFragDataLocationIndexed");
	glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)load("glGetFragDataIndex");
	glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers");
	glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers");
	glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler");
	glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler");
	glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri");
	glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv");
	glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf");
	glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv");
	glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load("glSamplerParameterIiv");
	glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load("glSamplerParameterIuiv");
	glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv");
	glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load("glGetSamplerParameterIiv");
	glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv");
	glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load("glGetSamplerParameterIuiv");
	glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC)load("glQueryCounter");
	glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)load("glGetQueryObjecti64v");
	glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)load("glGetQueryObjectui64v");
	glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor");
	glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)load("glVertexAttribP1ui");
	glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)load("glVertexAttribP1uiv");
	glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)load("glVertexAttribP2ui");
	glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)load("glVertexAttribP2uiv");
	glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)load("glVertexAttribP3ui");
	glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)load("glVertexAttribP3uiv");
	glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)load("glVertexAttribP4ui");
	glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)load("glVertexAttribP4uiv");
	glad_glVertexP2ui = (PFNGLVERTEXP2UIPROC)load("glVertexP2ui");
	glad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)load("glVertexP2uiv");
	glad_glVertexP3ui = (PFNGLVERTEXP3UIPROC)load("glVertexP3ui");
	glad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)load("glVertexP3uiv");
	glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC)load("glVertexP4ui");
	glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)load("glVertexP4uiv");
	glad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)load("glTexCoordP1ui");
	glad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)load("glTexCoordP1uiv");
	glad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)load("glTexCoordP2ui");
	glad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)load("glTexCoordP2uiv");
	glad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)load("glTexCoordP3ui");
	glad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)load("glTexCoordP3uiv");
	glad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)load("glTexCoordP4ui");
	glad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)load("glTexCoordP4uiv");
	glad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)load("glMultiTexCoordP1ui");
	glad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)load("glMultiTexCoordP1uiv");
	glad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)load("glMultiTexCoordP2ui");
	glad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)load("glMultiTexCoordP2uiv");
	glad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)load("glMultiTexCoordP3ui");
	glad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)load("glMultiTexCoordP3uiv");
	glad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)load("glMultiTexCoordP4ui");
	glad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)load("glMultiTexCoordP4uiv");
	glad_glNormalP3ui = (PFNGLNORMALP3UIPROC)load("glNormalP3ui");
	glad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC)load("glNormalP3uiv");
	glad_glColorP3ui = (PFNGLCOLORP3UIPROC)load("glColorP3ui");
	glad_glColorP3uiv = (PFNGLCOLORP3UIVPROC)load("glColorP3uiv");
	glad_glColorP4ui = (PFNGLCOLORP4UIPROC)load("glColorP4ui");
	glad_glColorP4uiv = (PFNGLCOLORP4UIVPROC)load("glColorP4uiv");
	glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui");
	glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv");
}
static void load_GL_VERSION_4_0(GLADloadproc load) {
	if(!GLAD_GL_VERSION_4_0) return;
	glad_glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC)load("glMinSampleShading");
	glad_glBlendEquationi = (PFNGLBLENDEQUATIONIPROC)load("glBlendEquationi");
	glad_glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC)load("glBlendEquationSeparatei");
	glad_glBlendFunci = (PFNGLBLENDFUNCIPROC)load("glBlendFunci");
	glad_glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC)load("glBlendFuncSeparatei");
	glad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC)load("glDrawArraysIndirect");
	glad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC)load("glDrawElementsIndirect");
	glad_glUniform1d = (PFNGLUNIFORM1DPROC)load("glUniform1d");
	glad_glUniform2d = (PFNGLUNIFORM2DPROC)load("glUniform2d");
	glad_glUniform3d = (PFNGLUNIFORM3DPROC)load("glUniform3d");
	glad_glUniform4d = (PFNGLUNIFORM4DPROC)load("glUniform4d");
	glad_glUniform1dv = (PFNGLUNIFORM1DVPROC)load("glUniform1dv");
	glad_glUniform2dv = (PFNGLUNIFORM2DVPROC)load("glUniform2dv");
	glad_glUniform3dv = (PFNGLUNIFORM3DVPROC)load("glUniform3dv");
	glad_glUniform4dv = (PFNGLUNIFORM4DVPROC)load("glUniform4dv");
	glad_glUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC)load("glUniformMatrix2dv");
	glad_glUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC)load("glUniformMatrix3dv");
	glad_glUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC)load("glUniformMatrix4dv");
	glad_glUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC)load("glUniformMatrix2x3dv");
	glad_glUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC)load("glUniformMatrix2x4dv");
	glad_glUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC)load("glUniformMatrix3x2dv");
	glad_glUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC)load("glUniformMatrix3x4dv");
	glad_glUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC)load("glUniformMatrix4x2dv");
	glad_glUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC)load("glUniformMatrix4x3dv");
	glad_glGetUniformdv = (PFNGLGETUNIFORMDVPROC)load("glGetUniformdv");
	glad_glGetSubroutineUniformLocation = (PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)load("glGetSubroutineUniformLocation");
	glad_glGetSubroutineIndex = (PFNGLGETSUBROUTINEINDEXPROC)load("glGetSubroutineIndex");
	glad_glGetActiveSubroutineUniformiv = (PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)load("glGetActiveSubroutineUniformiv");
	glad_glGetActiveSubroutineUniformName = (PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)load("glGetActiveSubroutineUniformName");
	glad_glGetActiveSubroutineName = (PFNGLGETACTIVESUBROUTINENAMEPROC)load("glGetActiveSubroutineName");
	glad_glUniformSubroutinesuiv = (PFNGLUNIFORMSUBROUTINESUIVPROC)load("glUniformSubroutinesuiv");
	glad_glGetUniformSubroutineuiv = (PFNGLGETUNIFORMSUBROUTINEUIVPROC)load("glGetUniformSubroutineuiv");
	glad_glGetProgramStageiv = (PFNGLGETPROGRAMSTAGEIVPROC)load("glGetProgramStageiv");
	glad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC)load("glPatchParameteri");
	glad_glPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC)load("glPatchParameterfv");
	glad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC)load("glBindTransformFeedback");
	glad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC)load("glDeleteTransformFeedbacks");
	glad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC)load("glGenTransformFeedbacks");
	glad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC)load("glIsTransformFeedback");
	glad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC)load("glPauseTransformFeedback");
	glad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC)load("glResumeTransformFeedback");
	glad_glDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC)load("glDrawTransformFeedback");
	glad_glDrawTransformFeedbackStream = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)load("glDrawTransformFeedbackStream");
	glad_glBeginQueryIndexed = (PFNGLBEGINQUERYINDEXEDPROC)load("glBeginQueryIndexed");
	glad_glEndQueryIndexed = (PFNGLENDQUERYINDEXEDPROC)load("glEndQueryIndexed");
	glad_glGetQueryIndexediv = (PFNGLGETQUERYINDEXEDIVPROC)load("glGetQueryIndexediv");
}
static void load_GL_VERSION_4_1(GLADloadproc load) {
	if(!GLAD_GL_VERSION_4_1) return;
	glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load("glReleaseShaderCompiler");
	glad_glShaderBinary = (PFNGLSHADERBINARYPROC)load("glShaderBinary");
	glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load("glGetShaderPrecisionFormat");
	glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load("glDepthRangef");
	glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load("glClearDepthf");
	glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)load("glGetProgramBinary");
	glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC)load("glProgramBinary");
	glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load("glProgramParameteri");
	glad_glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC)load("glUseProgramStages");
	glad_glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC)load("glActiveShaderProgram");
	glad_glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC)load("glCreateShaderProgramv");
	glad_glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC)load("glBindProgramPipeline");
	glad_glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC)load("glDeleteProgramPipelines");
	glad_glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC)load("glGenProgramPipelines");
	glad_glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC)load("glIsProgramPipeline");
	glad_glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC)load("glGetProgramPipelineiv");
	glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load("glProgramParameteri");
	glad_glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC)load("glProgramUniform1i");
	glad_glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC)load("glProgramUniform1iv");
	glad_glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC)load("glProgramUniform1f");
	glad_glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC)load("glProgramUniform1fv");
	glad_glProgramUniform1d = (PFNGLPROGRAMUNIFORM1DPROC)load("glProgramUniform1d");
	glad_glProgramUniform1dv = (PFNGLPROGRAMUNIFORM1DVPROC)load("glProgramUniform1dv");
	glad_glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC)load("glProgramUniform1ui");
	glad_glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC)load("glProgramUniform1uiv");
	glad_glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC)load("glProgramUniform2i");
	glad_glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC)load("glProgramUniform2iv");
	glad_glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC)load("glProgramUniform2f");
	glad_glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC)load("glProgramUniform2fv");
	glad_glProgramUniform2d = (PFNGLPROGRAMUNIFORM2DPROC)load("glProgramUniform2d");
	glad_glProgramUniform2dv = (PFNGLPROGRAMUNIFORM2DVPROC)load("glProgramUniform2dv");
	glad_glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC)load("glProgramUniform2ui");
	glad_glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC)load("glProgramUniform2uiv");
	glad_glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC)load("glProgramUniform3i");
	glad_glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC)load("glProgramUniform3iv");
	glad_glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC)load("glProgramUniform3f");
	glad_glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC)load("glProgramUniform3fv");
	glad_glProgramUniform3d = (PFNGLPROGRAMUNIFORM3DPROC)load("glProgramUniform3d");
	glad_glProgramUniform3dv = (PFNGLPROGRAMUNIFORM3DVPROC)load("glProgramUniform3dv");
	glad_glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC)load("glProgramUniform3ui");
	glad_glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC)load("glProgramUniform3uiv");
	glad_glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC)load("glProgramUniform4i");
	glad_glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC)load("glProgramUniform4iv");
	glad_glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC)load("glProgramUniform4f");
	glad_glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC)load("glProgramUniform4fv");
	glad_glProgramUniform4d = (PFNGLPROGRAMUNIFORM4DPROC)load("glProgramUniform4d");
	glad_glProgramUniform4dv = (PFNGLPROGRAMUNIFORM4DVPROC)load("glProgramUniform4dv");
	glad_glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC)load("glProgramUniform4ui");
	glad_glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC)load("glProgramUniform4uiv");
	glad_glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC)load("glProgramUniformMatrix2fv");
	glad_glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC)load("glProgramUniformMatrix3fv");
	glad_glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC)load("glProgramUniformMatrix4fv");
	glad_glProgramUniformMatrix2dv = (PFNGLPROGRAMUNIFORMMATRIX2DVPROC)load("glProgramUniformMatrix2dv");
	glad_glProgramUniformMatrix3dv = (PFNGLPROGRAMUNIFORMMATRIX3DVPROC)load("glProgramUniformMatrix3dv");
	glad_glProgramUniformMatrix4dv = (PFNGLPROGRAMUNIFORMMATRIX4DVPROC)load("glProgramUniformMatrix4dv");
	glad_glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)load("glProgramUniformMatrix2x3fv");
	glad_glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)load("glProgramUniformMatrix3x2fv");
	glad_glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)load("glProgramUniformMatrix2x4fv");
	glad_glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)load("glProgramUniformMatrix4x2fv");
	glad_glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)load("glProgramUniformMatrix3x4fv");
	glad_glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)load("glProgramUniformMatrix4x3fv");
	glad_glProgramUniformMatrix2x3dv = (PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)load("glProgramUniformMatrix2x3dv");
	glad_glProgramUniformMatrix3x2dv = (PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)load("glProgramUniformMatrix3x2dv");
	glad_glProgramUniformMatrix2x4dv = (PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)load("glProgramUniformMatrix2x4dv");
	glad_glProgramUniformMatrix4x2dv = (PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)load("glProgramUniformMatrix4x2dv");
	glad_glProgramUniformMatrix3x4dv = (PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)load("glProgramUniformMatrix3x4dv");
	glad_glProgramUniformMatrix4x3dv = (PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)load("glProgramUniformMatrix4x3dv");
	glad_glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC)load("glValidateProgramPipeline");
	glad_glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC)load("glGetProgramPipelineInfoLog");
	glad_glVertexAttribL1d = (PFNGLVERTEXATTRIBL1DPROC)load("glVertexAttribL1d");
	glad_glVertexAttribL2d = (PFNGLVERTEXATTRIBL2DPROC)load("glVertexAttribL2d");
	glad_glVertexAttribL3d = (PFNGLVERTEXATTRIBL3DPROC)load("glVertexAttribL3d");
	glad_glVertexAttribL4d = (PFNGLVERTEXATTRIBL4DPROC)load("glVertexAttribL4d");
	glad_glVertexAttribL1dv = (PFNGLVERTEXATTRIBL1DVPROC)load("glVertexAttribL1dv");
	glad_glVertexAttribL2dv = (PFNGLVERTEXATTRIBL2DVPROC)load("glVertexAttribL2dv");
	glad_glVertexAttribL3dv = (PFNGLVERTEXATTRIBL3DVPROC)load("glVertexAttribL3dv");
	glad_glVertexAttribL4dv = (PFNGLVERTEXATTRIBL4DVPROC)load("glVertexAttribL4dv");
	glad_glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC)load("glVertexAttribLPointer");
	glad_glGetVertexAttribLdv = (PFNGLGETVERTEXATTRIBLDVPROC)load("glGetVertexAttribLdv");
	glad_glViewportArrayv = (PFNGLVIEWPORTARRAYVPROC)load("glViewportArrayv");
	glad_glViewportIndexedf = (PFNGLVIEWPORTINDEXEDFPROC)load("glViewportIndexedf");
	glad_glViewportIndexedfv = (PFNGLVIEWPORTINDEXEDFVPROC)load("glViewportIndexedfv");
	glad_glScissorArrayv = (PFNGLSCISSORARRAYVPROC)load("glScissorArrayv");
	glad_glScissorIndexed = (PFNGLSCISSORINDEXEDPROC)load("glScissorIndexed");
	glad_glScissorIndexedv = (PFNGLSCISSORINDEXEDVPROC)load("glScissorIndexedv");
	glad_glDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC)load("glDepthRangeArrayv");
	glad_glDepthRangeIndexed = (PFNGLDEPTHRANGEINDEXEDPROC)load("glDepthRangeIndexed");
	glad_glGetFloati_v = (PFNGLGETFLOATI_VPROC)load("glGetFloati_v");
	glad_glGetDoublei_v = (PFNGLGETDOUBLEI_VPROC)load("glGetDoublei_v");
}
static void load_GL_VERSION_4_2(GLADloadproc load) {
	if(!GLAD_GL_VERSION_4_2) return;
	glad_glDrawArraysInstancedBaseInstance = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)load("glDrawArraysInstancedBaseInstance");
	glad_glDrawElementsInstancedBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)load("glDrawElementsInstancedBaseInstance");
	glad_glDrawElementsInstancedBaseVertexBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)load("glDrawElementsInstancedBaseVertexBaseInstance");
	glad_glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC)load("glGetInternalformativ");
	glad_glGetActiveAtomicCounterBufferiv = (PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)load("glGetActiveAtomicCounterBufferiv");
	glad_glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)load("glBindImageTexture");
	glad_glMemoryBarrier = (PFNGLMEMORYBARRIERPROC)load("glMemoryBarrier");
	glad_glTexStorage1D = (PFNGLTEXSTORAGE1DPROC)load("glTexStorage1D");
	glad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)load("glTexStorage2D");
	glad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)load("glTexStorage3D");
	glad_glDrawTransformFeedbackInstanced = (PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)load("glDrawTransformFeedbackInstanced");
	glad_glDrawTransformFeedbackStreamInstanced = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)load("glDrawTransformFeedbackStreamInstanced");
}
static void load_GL_VERSION_4_3(GLADloadproc load) {
	if(!GLAD_GL_VERSION_4_3) return;
	glad_glClearBufferData = (PFNGLCLEARBUFFERDATAPROC)load("glClearBufferData");
	glad_glClearBufferSubData = (PFNGLCLEARBUFFERSUBDATAPROC)load("glClearBufferSubData");
	glad_glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC)load("glDispatchCompute");
	glad_glDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC)load("glDispatchComputeIndirect");
	glad_glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC)load("glCopyImageSubData");
	glad_glFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC)load("glFramebufferParameteri");
	glad_glGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC)load("glGetFramebufferParameteriv");
	glad_glGetInternalformati64v = (PFNGLGETINTERNALFORMATI64VPROC)load("glGetInternalformati64v");
	glad_glInvalidateTexSubImage = (PFNGLINVALIDATETEXSUBIMAGEPROC)load("glInvalidateTexSubImage");
	glad_glInvalidateTexImage = (PFNGLINVALIDATETEXIMAGEPROC)load("glInvalidateTexImage");
	glad_glInvalidateBufferSubData = (PFNGLINVALIDATEBUFFERSUBDATAPROC)load("glInvalidateBufferSubData");
	glad_glInvalidateBufferData = (PFNGLINVALIDATEBUFFERDATAPROC)load("glInvalidateBufferData");
	glad_glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC)load("glInvalidateFramebuffer");
	glad_glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC)load("glInvalidateSubFramebuffer");
	glad_glMultiDrawArraysIndirect = (PFNGLMULTIDRAWARRAYSINDIRECTPROC)load("glMultiDrawArraysIndirect");
	glad_glMultiDrawElementsIndirect = (PFNGLMULTIDRAWELEMENTSINDIRECTPROC)load("glMultiDrawElementsIndirect");
	glad_glGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC)load("glGetProgramInterfaceiv");
	glad_glGetProgramResourceIndex = (PFNGLGETPROGRAMRESOURCEINDEXPROC)load("glGetProgramResourceIndex");
	glad_glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC)load("glGetProgramResourceName");
	glad_glGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC)load("glGetProgramResourceiv");
	glad_glGetProgramResourceLocation = (PFNGLGETPROGRAMRESOURCELOCATIONPROC)load("glGetProgramResourceLocation");
	glad_glGetProgramResourceLocationIndex = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)load("glGetProgramResourceLocationIndex");
	glad_glShaderStorageBlockBinding = (PFNGLSHADERSTORAGEBLOCKBINDINGPROC)load("glShaderStorageBlockBinding");
	glad_glTexBufferRange = (PFNGLTEXBUFFERRANGEPROC)load("glTexBufferRange");
	glad_glTexStorage2DMultisample = (PFNGLTEXSTORAGE2DMULTISAMPLEPROC)load("glTexStorage2DMultisample");
	glad_glTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC)load("glTexStorage3DMultisample");
	glad_glTextureView = (PFNGLTEXTUREVIEWPROC)load("glTextureView");
	glad_glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC)load("glBindVertexBuffer");
	glad_glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC)load("glVertexAttribFormat");
	glad_glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC)load("glVertexAttribIFormat");
	glad_glVertexAttribLFormat = (PFNGLVERTEXATTRIBLFORMATPROC)load("glVertexAttribLFormat");
	glad_glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC)load("glVertexAttribBinding");
	glad_glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC)load("glVertexBindingDivisor");
	glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)load("glDebugMessageControl");
	glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC)load("glDebugMessageInsert");
	glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)load("glDebugMessageCallback");
	glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)load("glGetDebugMessageLog");
	glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)load("glPushDebugGroup");
	glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)load("glPopDebugGroup");
	glad_glObjectLabel = (PFNGLOBJECTLABELPROC)load("glObjectLabel");
	glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)load("glGetObjectLabel");
	glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)load("glObjectPtrLabel");
	glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)load("glGetObjectPtrLabel");
	glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv");
}
static void load_GL_VERSION_4_4(GLADloadproc load) {
	if(!GLAD_GL_VERSION_4_4) return;
	glad_glBufferStorage = (PFNGLBUFFERSTORAGEPROC)load("glBufferStorage");
	glad_glClearTexImage = (PFNGLCLEARTEXIMAGEPROC)load("glClearTexImage");
	glad_glClearTexSubImage = (PFNGLCLEARTEXSUBIMAGEPROC)load("glClearTexSubImage");
	glad_glBindBuffersBase = (PFNGLBINDBUFFERSBASEPROC)load("glBindBuffersBase");
	glad_glBindBuffersRange = (PFNGLBINDBUFFERSRANGEPROC)load("glBindBuffersRange");
	glad_glBindTextures = (PFNGLBINDTEXTURESPROC)load("glBindTextures");
	glad_glBindSamplers = (PFNGLBINDSAMPLERSPROC)load("glBindSamplers");
	glad_glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC)load("glBindImageTextures");
	glad_glBindVertexBuffers = (PFNGLBINDVERTEXBUFFERSPROC)load("glBindVertexBuffers");
}
static int find_extensionsGL(void) {
	if (!get_exts()) return 0;
	(void)&has_ext;
	free_exts();
	return 1;
}

static void find_coreGL(void) {

    /* Thank you @elmindreda
     * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176
     * https://github.com/glfw/glfw/blob/master/src/context.c#L36
     */
    int i, major, minor;

    const char* version;
    const char* prefixes[] = {
        "OpenGL ES-CM ",
        "OpenGL ES-CL ",
        "OpenGL ES ",
        NULL
    };

    version = (const char*) glGetString(GL_VERSION);
    if (!version) return;

    for (i = 0;  prefixes[i];  i++) {
        const size_t length = strlen(prefixes[i]);
        if (strncmp(version, prefixes[i], length) == 0) {
            version += length;
            break;
        }
    }

/* PR #18 */
#ifdef _MSC_VER
    sscanf_s(version, "%d.%d", &major, &minor);
#else
    sscanf(version, "%d.%d", &major, &minor);
#endif

    GLVersion.major = major; GLVersion.minor = minor;
    max_loaded_major = major; max_loaded_minor = minor;
	GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
	GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
	GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;
	GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;
	GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;
	GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1;
	GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;
	GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2;
	GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3;
	GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3;
	GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3;
	GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3;
	GLAD_GL_VERSION_4_0 = (major == 4 && minor >= 0) || major > 4;
	GLAD_GL_VERSION_4_1 = (major == 4 && minor >= 1) || major > 4;
	GLAD_GL_VERSION_4_2 = (major == 4 && minor >= 2) || major > 4;
	GLAD_GL_VERSION_4_3 = (major == 4 && minor >= 3) || major > 4;
	GLAD_GL_VERSION_4_4 = (major == 4 && minor >= 4) || major > 4;
	if (GLVersion.major > 4 || (GLVersion.major >= 4 && GLVersion.minor >= 4)) {
		max_loaded_major = 4;
		max_loaded_minor = 4;
	}
}

int gladLoadGLLoader(GLADloadproc load) {
	GLVersion.major = 0; GLVersion.minor = 0;
	glGetString = (PFNGLGETSTRINGPROC)load("glGetString");
	if(glGetString == NULL) return 0;
	if(glGetString(GL_VERSION) == NULL) return 0;
	find_coreGL();
	load_GL_VERSION_1_0(load);
	load_GL_VERSION_1_1(load);
	load_GL_VERSION_1_2(load);
	load_GL_VERSION_1_3(load);
	load_GL_VERSION_1_4(load);
	load_GL_VERSION_1_5(load);
	load_GL_VERSION_2_0(load);
	load_GL_VERSION_2_1(load);
	load_GL_VERSION_3_0(load);
	load_GL_VERSION_3_1(load);
	load_GL_VERSION_3_2(load);
	load_GL_VERSION_3_3(load);
	load_GL_VERSION_4_0(load);
	load_GL_VERSION_4_1(load);
	load_GL_VERSION_4_2(load);
	load_GL_VERSION_4_3(load);
	load_GL_VERSION_4_4(load);

	if (!find_extensionsGL()) return 0;
	return GLVersion.major != 0 || GLVersion.minor != 0;
}


worldgen/assets/creatures/geometry/cpp_utils/.gitignore METASEP
bnurbs.c*
build

worldgen/assets/creatures/genomes/nurbs/head_insect_wasp.npy METASEP

worldgen/assets/creatures/genomes/nurbs/head_insect_beetle.npy METASEP

worldgen/assets/creatures/genomes/nurbs/head_herbivore_llama.npy METASEP

worldgen/assets/creatures/genomes/nurbs/head_herbivore_goat.npy METASEP

worldgen/assets/creatures/genomes/nurbs/head_herbivore_giraffe.npy METASEP

worldgen/assets/creatures/genomes/nurbs/head_herbivore_cow.npy METASEP

worldgen/assets/creatures/genomes/nurbs/head_carnivore_wolf.npy METASEP

worldgen/assets/creatures/genomes/nurbs/head_carnivore_tiger.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_llama.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_insect_tarantula.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_insect_beetle.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_insect_bee.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_herbivore_llama.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_herbivore_goat.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_herbivore_giraffe.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_herbivore_cow.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_fish_spadefish.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_fish_pufferfish.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_fish_pickerel.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_fish_eel.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_fish_crappie.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_fish_bluefish.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_feline_wolf.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_feline_tiger_2.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_feline_tiger.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_feline_housecat.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_feline_cheetah.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_bird_robin.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_bird_gull.npy METASEP

worldgen/assets/creatures/genomes/nurbs/body_bird_duck.npy METASEP

process_mesh/dependencies/scharstein_flow_viz/colorcode.h METASEP

typedef unsigned char uchar;

void computeColor(float fx, float fy, uchar *pix);

process_mesh/dependencies/scharstein_flow_viz/colorcode.cpp METASEP
// colorcode.cpp
//
// Color encoding of flow vectors
// adapted from the color circle idea described at
//   http://members.shaw.ca/quadibloc/other/colint.htm
//
// Daniel Scharstein, 4/2007
// added tick marks and out-of-range coding 6/05/07

#include <stdlib.h>
#include <math.h>
typedef unsigned char uchar;

int ncols = 0;
#define MAXCOLS 60
int colorwheel[MAXCOLS][3];


void setcols(int r, int g, int b, int k)
{
    colorwheel[k][0] = r;
    colorwheel[k][1] = g;
    colorwheel[k][2] = b;
}

void makecolorwheel()
{
    // relative lengths of color transitions:
    // these are chosen based on perceptual similarity
    // (e.g. one can distinguish more shades between red and yellow 
    //  than between yellow and green)
    int RY = 15;
    int YG = 6;
    int GC = 4;
    int CB = 11;
    int BM = 13;
    int MR = 6;
    ncols = RY + YG + GC + CB + BM + MR;
    //printf("ncols = %d\n", ncols);
    if (ncols > MAXCOLS)
	exit(1);
    int i;
    int k = 0;
    for (i = 0; i < RY; i++) setcols(255,	   255*i/RY,	 0,	       k++);
    for (i = 0; i < YG; i++) setcols(255-255*i/YG, 255,		 0,	       k++);
    for (i = 0; i < GC; i++) setcols(0,		   255,		 255*i/GC,     k++);
    for (i = 0; i < CB; i++) setcols(0,		   255-255*i/CB, 255,	       k++);
    for (i = 0; i < BM; i++) setcols(255*i/BM,	   0,		 255,	       k++);
    for (i = 0; i < MR; i++) setcols(255,	   0,		 255-255*i/MR, k++);
}

void computeColor(float fx, float fy, uchar *pix)
{
    if (ncols == 0)
	makecolorwheel();

    float rad = sqrt(fx * fx + fy * fy);
    rad = fminf(rad, 0.999); // Added by Lahav

    float a = atan2(-fy, -fx) / M_PI;
    float fk = (a + 1.0) / 2.0 * (ncols-1);
    int k0 = (int)fk;
    int k1 = (k0 + 1) % ncols;
    float f = fk - k0;
    //f = 0; // uncomment to see original color wheel
    for (int b = 0; b < 3; b++) {
	float col0 = colorwheel[k0][b] / 255.0;
	float col1 = colorwheel[k1][b] / 255.0;
	float col = (1 - f) * col0 + f * col1;
	if (rad <= 1)
	    col = 1 - rad * (1 - col); // increase saturation with radius
	else
	    col *= .75; // out of range
	pix[2 - b] = (int)(255.0 * col);
    }
}

process_mesh/dependencies/scharstein_flow_viz/README.txt METASEP
Some utilities for reading, writing, and color-coding .flo images

Daniel Scharstein, 7/2/07
updated 2/9/08 to fix bug in color_flow.cpp
updated 6/9/09 to make robust to NaN or constant 0 flow (thanks Jan Bouecke)

See flowIO.cpp for sample code for reading and writing .flo files.
Here's an excerpt from this file describing the flow file format:

// ".flo" file format used for optical flow evaluation
//
// Stores 2-band float image for horizontal (u) and vertical (v) flow components.
// Floats are stored in little-endian order.
// A flow value is considered "unknown" if either |u| or |v| is greater than 1e9.
//
//  bytes  contents
//
//  0-3     tag: "PIEH" in ASCII, which in little endian happens to be the float 202021.25
//          (just a sanity check that floats are represented correctly)
//  4-7     width as an integer
//  8-11    height as an integer
//  12-end  data (width*height*2*4 bytes total)
//          the float values for u and v, interleaved, in row order, i.e.,
//          u[row0,col0], v[row0,col0], u[row0,col1], v[row0,col1], ...
//


Once you have a .flo file, you can create a color coding of it using
color_flow

Use colortest to visualize the encoding


To compile

cd imageLib
make
cd ..
make
./colortest 10 colors.png

worldgen/assets/creatures/parts/crustacean/__init__.py METASEP

process_mesh/glsl/wings.vert METASEP
// VERTEX SHADER

#version 440 core

layout (location = 0) in mat4 instanceMatrix;
layout (location = 4) in mat4 instanceMatrixNext;
layout (location = 8) in vec3 aPos;
layout (location = 9) in vec3 aPos_next;
layout (location = 10) in ivec2 instance_id;
layout (location = 11) in int tag;


uniform mat4 projection;
uniform mat4 view;
uniform mat4 viewNext;

mat4 opengl_to_cv = mat4(
	vec4(1., 0., 0., 0.),
	vec4(0., -1., 0., 0.),
	vec4(0., 0., -1., 0.),
	vec4(0., 0., 0., 1.));

out VS_OUT {
    vec3 pos_wc;
	vec3 pos_cc;
	vec3 pos_cc_next;
	bool has_flow;
	int vertex_id;
	ivec2 instance_id;
	int tag;
} vs_out;

void main() {
	vec4 pos_wc = instanceMatrix * vec4(aPos, 1.0);
	vs_out.pos_wc = vec3(pos_wc);

	vec4 pos_cc_opengl = view * pos_wc;
	vec4 pos_cc = opengl_to_cv * pos_cc_opengl;
	vs_out.pos_cc = pos_cc.xyz / pos_cc.w;

	vs_out.has_flow = (abs(instanceMatrixNext[3][3]) > 1e-4);

	vec4 pos_wc_next = instanceMatrixNext * vec4(aPos_next, 1.0);
	vec4 pos_cc_next = opengl_to_cv * viewNext * pos_wc_next;
	vs_out.pos_cc_next = pos_cc_next.xyz / pos_cc_next.w;

	gl_Position = projection * pos_cc_opengl;

	vs_out.vertex_id = gl_VertexID;
	vs_out.instance_id = instance_id;

	vs_out.tag = tag;
}

process_mesh/glsl/wings.geom METASEP
#version 440 core

layout (lines_adjacency) in;
layout (triangle_strip, max_vertices = 6) out;

out vec3 normal;
out vec3 cc_normal;
out vec3 interp_pos_wc;
out vec3 interp_pos_cc;
out vec3 interp_pos_cc_next;
out float tri_area;
out float px_area;
out float has_flow;
out ivec3 face_id;
out ivec2 instance_id;
out ivec3 tag;

uniform mat4 wc2img;

in VS_OUT {
    vec3 pos_wc;
    vec3 pos_cc;
    vec3 pos_cc_next;
    bool has_flow;
    int vertex_id;
    ivec2 instance_id;
    int tag;
} gs_in[];

vec2 proj(vec3 inp){
    vec4 tmp = vec4(inp, 1.0);
    vec4 tmp2 = wc2img * tmp;
    return vec2(tmp2[0]/tmp2[2], tmp2[1]/tmp2[2]);
}

bool is_frontfacing(vec3 v1, vec3 v2, vec3 v3){
    vec2 uv1 = proj(v1);
    vec2 uv2 = proj(v2);
    vec2 uv3 = proj(v3);

    vec2 a = (uv2-uv1);
    vec2 b = (uv3-uv2);
    float winding = a.x * b.y - b.x * a.y;
    return winding > 0;
}

vec3 to_z_B_y_U(vec3 v){
    return vec3(v.x, -v.y, -v.z);
}

void save(int i){
    gl_Position = gl_in[i].gl_Position;
    interp_pos_wc = gs_in[i].pos_wc;
    interp_pos_cc = gs_in[i].pos_cc;
    interp_pos_cc_next = gs_in[i].pos_cc_next;
    EmitVertex();
}

void main() {

    face_id = ivec3(gs_in[0].vertex_id, gs_in[1].vertex_id, gs_in[2].vertex_id);
    instance_id = gs_in[0].instance_id;

    has_flow = float(gs_in[0].has_flow && gs_in[1].has_flow && gs_in[2].has_flow && gs_in[3].has_flow);

    vec3 v1 = gs_in[0].pos_wc;
    vec3 v2 = gs_in[1].pos_wc;
    vec3 v3 = gs_in[2].pos_wc;
    vec3 v4 = gs_in[3].pos_wc;

    vec2 p1 = proj(v1);
    vec2 p2 = proj(v2);
    vec2 p3 = proj(v3);
    vec2 p4 = proj(v4);
    vec2 a = p1 - p2;
    vec2 b = p1 - p3;
    vec2 c = p1 - p4;

    // First triangle
    cc_normal = normalize(cross(to_z_B_y_U(gs_in[0].pos_cc-gs_in[1].pos_cc), to_z_B_y_U(gs_in[0].pos_cc-gs_in[2].pos_cc)));
    tri_area = length(cross(v1 - v2, v1 - v3))/2;
    normal = normalize(cross(v1-v2, v1-v3));
    px_area = abs(a.x*b.y - a.y*b.x)/2;
    tag = ivec3(gs_in[0].tag, gs_in[1].tag, gs_in[2].tag);

    if (!is_frontfacing(v1, v2, v3))
        cc_normal = -cc_normal;

    save(0);
    save(1);
    save(2);

    // Second triangle
    cc_normal = normalize(cross(to_z_B_y_U(gs_in[0].pos_cc-gs_in[1].pos_cc), to_z_B_y_U(gs_in[0].pos_cc-gs_in[3].pos_cc)));
    tri_area = length(cross(v1 - v2, v1 - v4))/2;
    normal = normalize(cross(v1-v2, v1-v4));
    px_area = abs(a.x*c.y - a.y*c.x)/2;
    tag = ivec3(gs_in[0].tag, gs_in[1].tag, gs_in[3].tag);

    if (!is_frontfacing(v1, v2, v4))
        cc_normal = -cc_normal;

    save(0);
    save(1);
    save(3);
}
process_mesh/glsl/wings.frag METASEP
// FRAGMENT SHADER

#version 440 core

uniform vec3 cameraPos;

uniform int object_index;

in vec3 interp_pos_wc;
in vec3 interp_pos_cc;
in vec3 interp_pos_cc_next;
in vec3 normal;
in vec3 cc_normal;
in float tri_area;
in float px_area;
flat in float has_flow;
flat in ivec2 instance_id;
flat in ivec3 face_id;
flat in ivec3 tag;

layout (location = 0) out ivec4 rasterized_occ_bounds;
layout (location = 1) out vec4 rasterized_cc;
layout (location = 2) out vec4 next_rasterized_cc;
layout (location = 3) out vec4 rasterized_face_id;
layout (location = 5) out ivec4 tag_segmentation;
layout (location = 6) out ivec4 instance_object_segmentation;
layout (location = 7) out vec4 geo_normal;

/*
// No longer used
layout (location = 3) out vec4 faceSize;
layout (location = 4) out vec4 pixelSize;
*/

void main() {
	vec3 updated_normal = normal;
	if (dot((cameraPos - interp_pos_wc), updated_normal) < 0){
		updated_normal = updated_normal * -1;
	}

	rasterized_cc = vec4(interp_pos_cc, 1.0);
	if (has_flow > 0.99)
		next_rasterized_cc = vec4(interp_pos_cc_next, 1.0);
	else
		next_rasterized_cc = vec4(0.0, 0.0, -1.0, 1.0);
	tag_segmentation = ivec4(tag, 0);
	instance_object_segmentation = ivec4(instance_id[0], instance_id[1], object_index, 1);

	geo_normal = vec4(normalize(-cc_normal), 1.0);
	rasterized_occ_bounds = ivec4(0, 0, 0, 1);

	rasterized_face_id = vec4(face_id, 1.0);

	/*
	// No longer used
	faceSize = vec4(tri_area, 0.0, 0.0, 1.0);
	pixelSize = vec4(px_area, 0.0, 0.0, 1.0);
	*/

}

process_mesh/glsl/spine.geom METASEP
#version 440 core

layout (lines_adjacency) in;
layout (line_strip, max_vertices = 2) out;

uniform mat4 wc2img;

out vec3 normal;
out vec3 interp_pos_wc;

in VS_OUT {
    vec3 pos_wc;
    vec3 pos_cc;
    vec3 pos_cc_next;
    bool has_flow;
    int vertex_id;
    ivec2 instance_id;
    int tag;
} gs_in[];

vec2 proj(vec3 v){
    vec4 h = wc2img * vec4(v, 1.0);
    return vec2(h[0] / abs(h[2]), h[1] / abs(h[2]));
}

vec4 offset_amount = vec4(0.0, 0.0, -0.00001, 0.00);

bool is_frontfacing(vec3 v1, vec3 v2, vec3 v3){
    vec2 uv1 = proj(v1);
    vec2 uv2 = proj(v2);
    vec2 uv3 = proj(v3);

    vec2 a = (uv2-uv1);
    vec2 b = (uv3-uv2);
    float winding = a.x * b.y - b.x * a.y;
    return winding > 0;

}

void main() {
    vec3 v1 = gs_in[0].pos_wc; // A
    vec3 v2 = gs_in[1].pos_wc; // B
    vec3 v3 = gs_in[2].pos_wc;
    vec3 v4 = gs_in[3].pos_wc;

    bool draw_boundary = (is_frontfacing(v1, v2, v3) != is_frontfacing(v2, v1, v4));

    if (draw_boundary){
        gl_Position = gl_in[0].gl_Position + offset_amount;
        EmitVertex();
        gl_Position = gl_in[1].gl_Position + offset_amount;
        EmitVertex();
    }
}
process_mesh/glsl/spine.frag METASEP
// FRAGMENT SHADER

#version 440 core

layout (location = 0) out ivec4 rasterized_occ_bounds;

void main() {
	rasterized_occ_bounds = ivec4(0, 1, 0, 1);
}

process_mesh/glsl/next_wings.vert METASEP
// VERTEX SHADER

#version 440 core

layout (location = 0) in mat4 instanceMatrix;
layout (location = 4) in mat4 instanceMatrixNext;
layout (location = 8) in vec3 aPos;
layout (location = 9) in vec3 aPos_next;
layout (location = 10) in ivec2 instance_id;
layout (location = 11) in int tag;


uniform mat4 projection;
uniform mat4 view;
uniform mat4 viewNext;

mat4 opengl_to_cv = mat4(
	vec4(1., 0., 0., 0.),
	vec4(0., -1., 0., 0.),
	vec4(0., 0., -1., 0.),
	vec4(0., 0., 0., 1.));

out VS_OUT {
    vec3 pos_wc;
	vec3 pos_cc;
	vec3 pos_cc_next;
	bool has_flow;
	int vertex_id;
	ivec2 instance_id;
	int tag;
} vs_out;

void main() {
	vec4 pos_wc = instanceMatrix * vec4(aPos, 1.0);
	vs_out.pos_wc = vec3(pos_wc);

	vec4 pos_cc_opengl = view * pos_wc;
	vec4 pos_cc = opengl_to_cv * pos_cc_opengl;
	vs_out.pos_cc = pos_cc.xyz / pos_cc.w;

	vs_out.has_flow = (abs(instanceMatrixNext[3][3]) > 1e-4);

	vec4 pos_wc_next = instanceMatrixNext * vec4(aPos_next, 1.0);
	vec4 pos_cc_next_opengl = viewNext * pos_wc_next;
	vec4 pos_cc_next = opengl_to_cv * pos_cc_next_opengl;
	vs_out.pos_cc_next = pos_cc_next.xyz / pos_cc_next.w;

	gl_Position = projection * pos_cc_next_opengl;

	vs_out.vertex_id = gl_VertexID;
	vs_out.instance_id = instance_id;

	vs_out.tag = tag;
}

process_mesh/glsl/hair.vert METASEP
// VERTEX SHADER

#version 440 core

layout (location = 0) in mat4 instanceMatrix;
layout (location = 4) in mat4 instanceMatrixNext;
layout (location = 8) in vec3 aPos;
layout (location = 9) in vec3 aPos_next;
layout (location = 10) in ivec2 instance_id;
layout (location = 11) in int tag;
layout (location = 12) in float radius;

uniform mat4 projection;
uniform mat4 view;
uniform mat4 viewNext;

out VS_OUT {
    vec3 pos_wc;
	vec3 pos_cc;
	vec3 pos_cc_next;
	float radius;
} vs_out;

void main() {
	vec4 pos_wc = instanceMatrix * vec4(aPos, 1.0);
	vs_out.pos_wc = vec3(pos_wc);
	vec4 pos_cc = view * pos_wc;
	vs_out.pos_cc = pos_cc.xyz / pos_cc.w;

	vec4 pos_wc_next = instanceMatrixNext * vec4(aPos_next, 1.0);
	vec4 pos_cc_next = viewNext * pos_wc_next;
	vs_out.pos_cc_next = pos_cc_next.xyz / pos_cc_next.w;

	gl_Position = projection * pos_cc;
	vs_out.radius = radius;
}

process_mesh/glsl/hair.geom METASEP
#version 440 core

layout (lines_adjacency) in;
layout (triangle_strip, max_vertices = 60) out;

out vec3 interp_pos_cc; // technically opengl
out vec3 interp_pos_cc_next; // technically opengl
out vec3 pa;
out vec3 pb;
out float hair_width;

uniform mat4 projection;

in VS_OUT {
    vec3 pos_wc;
	vec3 pos_cc;
    vec3 pos_cc_next;
	float radius;
} gs_in[];

vec3 forward = vec3(0.0, 0.0, -1.0);

vec3 catmull_rom(float t, vec3 P0, vec3 P1, vec3 P2, vec3 P3){
    float t0 = 0;
    float t1 = length(P1 - P0) + t0;
    float t2 = length(P2 - P1) + t1;
    float t3 = length(P3 - P2) + t2;

    vec3 A1 = (t1 - t) / (t1 - t0) * P0 + (t - t0) / (t1 - t0) * P1;
    vec3 A2 = (t2 - t) / (t2 - t1) * P1 + (t - t1) / (t2 - t1) * P2;
    vec3 A3 = (t3 - t) / (t3 - t2) * P2 + (t - t2) / (t3 - t2) * P3;
    vec3 B1 = (t2 - t) / (t2 - t0) * A1 + (t - t0) / (t2 - t0) * A2;
    vec3 B2 = (t3 - t) / (t3 - t1) * A2 + (t - t1) / (t3 - t1) * A3;
    vec3 C = (t2 - t) / (t2 - t1) * B1 + (t - t1) / (t2 - t1) * B2;
    return C;
}

void save(vec3 v, vec3 v_next){
    gl_Position = projection * vec4(v, 1.0);
    interp_pos_cc = v;
    interp_pos_cc_next = v_next;
    EmitVertex();
}

vec3[4] hitbox_between_points(vec3 p1, vec3 p2){
    vec3 vs[4];
    vec3 perp = normalize(cross(p1 - p2, forward)) * 4e-3;
    vs[0] = p1 + perp;
    vs[1] = p1 - perp;
    vs[2] = p2 + perp;
    vs[3] = p2 - perp;
    return vs;
}

void main() {

    vec3 P0 = gs_in[0].pos_cc;
    vec3 P1 = gs_in[1].pos_cc;
    vec3 P2 = gs_in[2].pos_cc;
    vec3 P3 = gs_in[3].pos_cc;

    vec3 P0n = gs_in[0].pos_cc_next;
    vec3 P1n = gs_in[1].pos_cc_next;
    vec3 P2n = gs_in[2].pos_cc_next;
    vec3 P3n = gs_in[3].pos_cc_next;

    float t1 = length(P1 - P0);
    float t2 = length(P2 - P1) + t1;

    float r1 = gs_in[1].radius * 2;
    float r2 = gs_in[2].radius * 2;

    float step = 0.1;
    for (float f=0; f<1; f+=step){ // f in [0, 1]
        float rad1 = f        * (r2 - r1) + r1;
        float rad2 = (f+step) * (r2 - r1) + r1;

        // Current
        vec3 point1 = catmull_rom(f * (t2 - t1) + t1, P0, P1, P2, P3);
        vec3 point2 = catmull_rom((f+step) * (t2 - t1) + t1, P0, P1, P2, P3);
        vec3 hitbox_cc[4] = hitbox_between_points(point1, point2);
        pa = point1;
        pb = point2;

        // Next
        vec3 point1n = catmull_rom(f * (t2 - t1) + t1, P0n, P1n, P2n, P3n);
        vec3 point2n = catmull_rom((f+step) * (t2 - t1) + t1, P0n, P1n, P2n, P3n);
        vec3 hitbox_cc_next[4] = hitbox_between_points(point1n, point2n);

        hair_width = rad1;
        save(hitbox_cc[0], hitbox_cc_next[0]);
        hair_width = rad2;
        save(hitbox_cc[2], hitbox_cc_next[2]);
        save(hitbox_cc[3], hitbox_cc_next[3]);

        hair_width = rad1;
        save(hitbox_cc[0], hitbox_cc_next[0]);
        save(hitbox_cc[1], hitbox_cc_next[1]);
        hair_width = rad2;
        save(hitbox_cc[2], hitbox_cc_next[2]);
    }
}
process_mesh/glsl/hair.frag METASEP
// FRAGMENT SHADER

#version 440 core

in vec3 interp_pos_cc;
in vec3 interp_pos_cc_next;
in vec3 pa;
in vec3 pb;
in float hair_width;

uniform mat4 wc2img;

layout (location = 0) out ivec4 rasterized_occ_bounds;
layout (location = 1) out vec4 rasterized_cc;
layout (location = 2) out vec4 next_rasterized_cc;
layout (location = 7) out vec4 geo_normal;

float dist_to_line(vec3 a, vec3 b, vec3 p){
    vec3 n = (b - a);
    float numer = length(cross(p-a, n));
    return numer / length(n);
}

vec3 meeting_point(vec3 a, vec3 b, vec3 p){
    vec3 n = (b - a);
    vec3 perp = cross(p-a, n);
	vec3 dir = cross(perp, n);
	dir = normalize(dir) * dist_to_line(a, b, p);
    return p + dir;
}

vec2 proj(vec3 inp){
    vec4 tmp = vec4(inp, 1.0);
    vec4 tmp2 = wc2img * tmp;
    return vec2(tmp2[0]/tmp2[2], tmp2[1]/tmp2[2]);
}

void main() {

	float distance_to_line = dist_to_line(pa, pb, interp_pos_cc);
	if (distance_to_line > hair_width){
		discard;
	}

	float d_normalized = distance_to_line / hair_width;
	float theta = acos(d_normalized);
	float z_delta = sin(theta) * hair_width;

	vec3 vloc_3d = interp_pos_cc + vec3(0., 0., z_delta); // opengl format
	rasterized_cc = vec4(vloc_3d.x, -vloc_3d.y, -vloc_3d.z, 1.0);
	vec3 vloc_3dn = interp_pos_cc_next + vec3(0., 0., z_delta); // opengl format
	next_rasterized_cc = vec4(vloc_3dn.x, -vloc_3dn.y, -vloc_3dn.z, 1.0);

	float approx_hair_width_in_px = length(proj(interp_pos_cc) -  proj(interp_pos_cc + vec3(hair_width, 0.0, 0.0)));
	int occ = int((d_normalized > 0.3) || (approx_hair_width_in_px < 1.1));
	rasterized_occ_bounds = ivec4(0, occ, 0, 1);

	// Geo normal
	vec3 norml = vloc_3d - meeting_point(pa, pb, vloc_3d);
	geo_normal = vec4(norml.x, norml.y, norml.z, 1.0);
}

images/gt_annotations/warped_rocks.png METASEP

images/gt_annotations/petal.png METASEP

images/gt_annotations/caves.png METASEP

images/gt_annotations/blender_rock_3d.png METASEP

images/gt_annotations/blender_rock_2d.png METASEP

images/gt_annotations/SurfaceNormal_0001_00_00.png METASEP

images/gt_annotations/OcclusionBoundaries_0001_00_00.png METASEP

images/gt_annotations/Depth_0001_00_00.png METASEP

worldgen/assets/creatures/util/__init__.py METASEP

worldgen/assets/creatures/geometry/__init__.py METASEP

worldgen/tools/pipeline_configs/.gitignore METASEP
smb_login.gin
debug*
worldgen/tools/palette/readme.md METASEP
# How to use

This palette generating tool is enabled using `GoogleImagesSearch` (currently using Zeyu's API key). Also you need `json5`.

## Step 1

```
cd worldgen/tools/palette/
# you can change "mountain rock" to other key words
python palette.py -k "mountain rock"
```

This downloads 10 images from Google by default:
![](demo1.png)

and runs Mixed Gaussian Model (MGM) on HSV space to get an initial palette:
![](demo2.png)

You can see the above palette in folder `images`. By default it has 10 centers, and the first row is the color of all centers, and the second row is the range of color when you vary it according to MGM with range (-std, std) (V dimension is ommited for 2D display)

Some colors are background colors and do not belong to the keyword you search.

## Step 2

Under folder `json`, there is a `mountain rock.json`. By installing Add-on `Flutter Color` and `JSON5 syntax` in VSCode, you can see the color icon. 

![](demo3.png)

After manually comemnt out them, you have:

![](demo4.png)

Then you move the ready palatte to location: `infinigen/worldgen/config/palette`

## Step 3

When you want some color to sample from it, use the `palette` keyword in parameter parsing, e.g.:

```
surfaces.templates.water.shader.color = ("palette", "water")
surfaces.templates.ocean.shader.color = ("palette", "water")
surfaces.templates.mountain.shader.color = ("palette", "mountain rock")
surfaces.templates.sand.shader.color = ("palette", "desert")
surfaces.templates.sandstone.shader.color = ("palette", "sandstone")
```

Note that Blender uses lienar RGB while web content uses sRGB, so a conversion is done in the parsing function `random_general`
worldgen/tools/palette/demo4.png METASEP

worldgen/tools/palette/demo3.png METASEP

worldgen/tools/palette/demo2.png METASEP

worldgen/tools/palette/demo1.png METASEP

worldgen/tools/palette/.gitignore METASEP
images
css
json
worldgen/tools/export/install.sh METASEP
#!/bin/bash

OS=$(uname -s)
ARCH=$(uname -m)


if [ "${OS}" = "Linux" ]; then
    BLENDER_DIR='blender_3.6'
    BLENDER_WGET_LINK='https://builder.blender.org/download/daily/archive/blender-3.6.0-beta+v36.962331c256b0-linux.x86_64-release.tar.xz'
    BLENDER_WGET_FILE='blender.tar.xz'
    BLENDER_UNTAR_DIR='blender-3.6.0-beta+v36.962331c256b0-linux.x86_64-release'

elif [ "${OS}" = "Darwin" ]; then
    BLENDER_VOLM='/Volumes/Blender'
    BLENDER_DIR='./Blender.app'
    BLENDER_WGET_FILE='blender.dmg'
    if [ "${ARCH}" = "arm64" ]; then
        BLENDER_WGET_LINK='https://builder.blender.org/download/daily/archive/blender-3.6.0-beta+v36.83ef3bc9232b-darwin.arm64-release.dmg'
    else
        BLENDER_WGET_LINK='https://builder.blender.org/download/daily/archive/blender-3.6.0-beta+v36.83ef3bc9232b-darwin.x86_64-release.dmg'
    fi

else
    echo "Unsupported OS"
    exit -1
fi

if [ ! -d "${BLENDER_DIR}" ]; then
    # Download Blender
    wget -q -O "${BLENDER_WGET_FILE}" "${BLENDER_WGET_LINK}"

    # Unzip Blender
    if [ "${OS}" = "Darwin" ]; then
        hdiutil attach "${BLENDER_WGET_FILE}"
        cp -r "${BLENDER_VOLM}/Blender.app" "${BLENDER_DIR}"
        hdiutil detach "${BLENDER_VOLM}"
    else
        tar -xf "${BLENDER_WGET_FILE}"
        mv "${BLENDER_UNTAR_DIR}" "${BLENDER_DIR}"
    fi

    rm "${BLENDER_WGET_FILE}"
fi
worldgen/tools/export/README.md METASEP

# Asset Exporter

Export individaully generated assets in .blend files to various general-purpose file formats.

In ```/export/```, install Blender 3.6 by running 

```
bash install.sh
```

Note: We install a separate instance of Blender because 3.6 has vastly improved auto-UV unwrapping. You can run this script on other blender versions, but the export may fail on meshes with complex UV unwraps such as bushes or snakes.

Create a folder of ```.blend``` files and another empty folder for the export results.

To export,

```cd blender_3.6``` if on Linux or ```cd Blender.app/Contents/MacOS``` if on MacOS

If on Linux, run

```
./blender -b -P ../export.py -- -b {PATH_TO_BLEND_FILE_FOLDER} -e {PATH_TO_OUTPUT_FOLDER} -o -r 1024
```

If on MacOS, run

```
./Blender -b -P ../../../export.py -- -b {PATH_TO_BLEND_FILE_FOLDER} -e {PATH_TO_OUTPUT_FOLDER} -o -r 1024
```

```-o``` will export in .obj format, ```-f``` will export in .fbx format, ```-s``` will export in .stl format, and ```-p``` will export in .ply format. If the ```-v``` flag is included, the meshes will export with per-vertex colors (only compatible with .fbx and .ply formats). Only one file type can be specified for each export.

```-r {INT}``` controls the resolution of the baked texture maps. For instance, ```-r 1024``` will export 1024 x 1024 texture maps.
## Known Issues and Limitations

* Assets that use transparency or have fur will have incorrect textures when exporting. This is unavoidable due to texture maps being generated from baking.

* When using the vertex color export option, no roughness will be exported, only diffuse color

* Very big assets (e.g. full trees with leaves) may take a long time to export and will crash Blender if you do not have a sufficiently large amount of memory. The export results may also be unusably large.

* When exporting in .fbx format, the embedded roughness texture maps in the file may sometimes be too bright or too dark. The .png roughness map in the folder is correct, however.

* .ply bush exports will have missing leaves when uploaded to SketchFab, but are otherwise intact in other renderers such as Meshlab.

* .fbx exports ocassionally fail due to invalid UV values on complicated geometry. Adjusting the 'island_margin' value in bpy.ops.uv.smart_project() sometimes remedies this

* If using exported .obj files in PyTorch3D, make sure to use the TexturesAtlas because a mesh may have multiple associated texture maps

* Loading .obj files with a PyTorch3D inside a online Google Colabs sessions often inexplicably fails - try hosting locally

* The native PyTorch 3D renderer does not support roughness maps on .objs






worldgen/terrain/marching_cubes/.gitignore METASEP
*.c
test.py
worldgen/config/scene_types/under_water.gin METASEP
multi_mountains_params.height = ("uniform", 4, 10)
multi_mountains_params.min_freq = ("uniform", 0.01, 0.015)
multi_mountains_params.max_freq = ("uniform", 0.03, 0.06)

keep_cam_pose_proposal.terrain_coverage_range = (0.4, 1)
camera.camera_pose_proposal.altitude = ("clip_gaussian", 3.5, 0.7, 2, 6)
camera.camera_pose_proposal.pitch = ("clip_gaussian", 90, 15, 60, 110)

compose_scene.trees_chance = 0.
compose_scene.bushes_chance = 0.
compose_scene.creatures_chance = 1.0
compose_scene.glowing_rocks_chance = 0.05
compose_scene.rocks_chance = 0.5
compose_scene.ground_leaves_chance = 0.05
compose_scene.ground_twigs_chance = 0.05
compose_scene.chopped_trees_chance = 0.1
compose_scene.grass_chance = 0.05
compose_scene.kelp_chance = 0.7
compose_scene.cactus_chance = 0.
compose_scene.ferns_chance = 0.01
compose_scene.camera_based_lighting_chance = 1.0

compose_scene.corals_chance = 0.8
compose_scene.seaweed_chance = 0.8
compose_scene.seashell_chance = 0.8
compose_scene.urchin_chance = 0.8
compose_scene.jellyfish_chance = 0.0
compose_scene.mushroom_chance = 0.0
compose_scene.pinecone_chance = 0.0
compose_scene.pine_needle_chance = 0.0
compose_scene.boulders_chance = 0.0
compose_scene.monocots_chance = 0.0

water.geo.water_detail = ("uniform", 0.2, 0.5)
water.geo.water_height = ("uniform", 0.05, 0.15)
water.geo.with_ripples = 0
water.shader.volume_density = ("uniform", 0.03, 0.05)
water.shader.color = ("color_category", 'under_water')
water.shader.colored = 0
water.shader.emissive_foam = 0
water.is_ocean = ("bool", 0.5)


compose_scene.wind_chance = 0
compose_scene.rain_particles_chance = 0
compose_scene.snow_particles_chance = 0
compose_scene.leaf_particles_chance = 0
compose_scene.dust_particles_chance = 0
compose_scene.marine_snow_particles_chance = 0
compose_scene.caustics_chance = 0.8

atmosphere_light_haze.shader_atmosphere.enable_scatter = False 
compose_scene.fancy_clouds_chance=0.0

surface.registry.rock_collection = [
    ('stone', 1),
    ('mountain', 0.5),
]

compose_scene.ground_creatures_chance = 0.4
compose_scene.ground_creature_registry = [
    (@CrustaceanFactory, 1),
]
compose_scene.flying_creatures_chance = 0.0
compose_scene.bug_swarm_chance = 0.0
compose_scene.fish_school_chance = 0.3

# scene composition config
LandTiles.tile_heights = [-20]
Ground.height = -20
Atmosphere.hacky_offset = 0.1
WarpedRocks.slope_shift = -23
scene.waterbody_chance = 1

full/render_image.min_samples = 100
render_image.adaptive_threshold = 0.01

Terrain.under_water = 1

compose_scene.turbulence_chance = 0.7
turbulence_effector.strength = ("uniform", 0, 7)
turbulence_effector.size = ("uniform", 1.5, 4.5)
turbulence_effector.flow = 1
turbulence_effector.noise = 10
worldgen/config/scene_types/snowy_mountain.gin METASEP
include 'config/no_assets.gin'

surface.registry.rock_collection = [
    ('mountain', 1),
]
surface.registry.mountain_collection = [
    ('mountain', 1),
]

compose_scene.snow_particles_chance = 0.5

shader_atmosphere.density = 0
nishita_lighting.sun_elevation = ("spherical_sample", 10, 30)
LandTiles.land_process = "snowfall"
scene.waterbody_chance = 0
scene.caves_chance = 0
scene.ground_chance = 0
scene.warped_rocks_chance = 0
scene.voronoi_rocks_chance = 0
scene.voronoi_grains_chance = 0

tile_directions.MultiMountains = "initial"

compose_scene.flying_creatures_chance = 0.5
compose_scene.flying_creature_registry = [
    (@FlyingBirdFactory, 1),
]

surfaces.templates.mountain.shader.layered_mountain = 0
surfaces.templates.mountain.shader.snowy = 1
compose_scene.boulders_chance = 1

camera.camera_pose_proposal.pitch = ("clip_gaussian", 90, 30, 90, 100)
keep_cam_pose_proposal.terrain_coverage_range = (0.3, 1)
keep_cam_pose_proposal.min_terrain_distance = 40
worldgen/config/scene_types/river.gin METASEP
surface.registry.erosion_collection = [
    ('sand', 2),
    ('cracked_ground', 2),
    ('dirt', 1),
    ('stone', 3),
    ('soil', 1),
]

compose_scene.ground_creatures_chance = 0.0
compose_scene.ground_creature_registry = [
    (@CarnivoreFactory, 2),
    (@HerbivoreFactory, 0.5),
    (@SnakeFactory, 0.5)
]

compose_scene.flying_creatures_chance = 0.7
compose_scene.flying_creature_registry = [
    (@DragonflyFactory, 1),
    (@FlyingBirdFactory, 0.2)
]

compose_scene.rain_particles_chance = 0.4
populate_scene.slime_mold_chance = 0.3
populate_scene.ivy_chance = 0.3
populate_scene.lichen_chance = 0.3
populate_scene.moss_chance = 0.0

random_season.weights = {'autumn': 1, 'summer': 1, 'spring': 1, 'winter': 0.1}

# scene composition config
LandTiles.tiles = ["Mountain", "River", "Mountain"]
LandTiles.tile_heights = [1.75, -0.75, 1.75]
LandTiles.randomness = 1

scene.waterbody_chance = 1
scene.ground_chance = 0
scene.warped_rocks_chance = 0

# camera selection config
UniformMesher.dimensions = (-25, 25, -25, 25, -15, 35)
camera_selection_preprocessing.terrain_tags_ratio = {("altitude", -1e9, 0.75): (0.1, 1), "liquid": (0.05, 1)}

worldgen/config/scene_types/plain.gin METASEP
compose_scene.ground_creature_registry = [
    (@CarnivoreFactory, 1),
    (@HerbivoreFactory, 1.5),
    (@BirdFactory, 0.7),
]

compose_scene.ground_creatures_chance = 0.0
compose_scene.ground_creature_registry = [
    (@CarnivoreFactory, 2),
    (@HerbivoreFactory, 0.8),
    (@SnakeFactory, 2)
]

compose_scene.flying_creatures_chance = 0.7
compose_scene.flying_creature_registry = [
    (@DragonflyFactory, 1),
    (@FlyingBirdFactory, 0.1)
]

compose_scene.grass_select_max = 0.35
compose_scene.tree_density = 0.02
compose_scene.grass_chance = 1

compose_scene.bug_swarm_chance=0.0

# scene composition config
scene.landtiles_chance = 0
scene.warped_rocks_chance = 0

worldgen/config/scene_types/mountain.gin METASEP
compose_scene.flying_creatures_chance=0.7
compose_scene.max_flying_creatures = 3

animate_cameras.follow_poi_chance=0.0

compose_scene.trees_chance = 0.5
compose_scene.tree_density = 0.06

# scene composition config
scene.upsidedown_mountains_chance = 0.4
WarpedRocks.slope_shift = -3

water.shader.volume_density = ("uniform", 2, 10)

worldgen/config/scene_types/kelp_forest.gin METASEP
include 'config/scene_types/under_water.gin'

multi_mountains_params.height = ("uniform", 1, 4)
multi_mountains_params.min_freq = ("uniform", 0.01, 0.015)
multi_mountains_params.max_freq = ("uniform", 0.03, 0.06)

compose_scene.glowing_rocks_chance = 0.
compose_scene.ground_leaves_chance = 0.2
compose_scene.ground_twigs_chance = 0.4
compose_scene.chopped_trees_chance = 0.

compose_scene.kelp_chance = 1.0
compose_scene.urchin_chance = 0.7

compose_scene.corals_chance = 0.0
compose_scene.seaweed_chance = 0.8
compose_scene.seashell_chance = 0.8
compose_scene.jellyfish_chance = 0.0

water.shader.volume_density = ("uniform", 0.09, 0.13)
water.shader.anisotropy = ("uniform", 0.45, 0.7)
water.geo.with_waves=False

camera.camera_pose_proposal.pitch = ("clip_gaussian", 90, 15, 60, 140)

worldgen/config/scene_types/forest.gin METASEP
Ground.scale = 10
multi_mountains_params.height = 15
multi_mountains_params.min_freq = ("uniform", 0.008, 0.012)
multi_mountains_params.max_freq = ("uniform", 0.024, 0.036)
scene.warped_rocks_chance = 0

compose_scene.inview_distance = 40
placement.populate_all.dist_cull = 40

surface.registry.ground_collection = [
    ('mud', 2),
    ('dirt', 1),
    ('soil', 1),
]

surface.registry.mountain_collection = [
    ('dirt', 1),
    ('soil', 1),
    ('cracked_ground', 0.5)
]

compose_scene.ground_creatures_chance = 0.1
compose_scene.ground_creature_registry = [
    #(@CarnivoreFactory, 2),
    #(@HerbivoreFactory, 0.8),
    (@SnakeFactory, 2)
]

compose_scene.flying_creatures_chance = 0.7
compose_scene.flying_creature_registry = [
    (@DragonflyFactory, 1),
    (@FlyingBirdFactory, 0.2)
]

compose_scene.bug_swarm_chance = 0.0

compose_scene.trees_chance = 1.0
compose_scene.tree_density = 0.11

compose_scene.ground_leaves_chance = 0.7
compose_scene.ground_twigs_chance = 0.7
compose_scene.chopped_trees_chance = 0.3
compose_scene.grass_chance = 0.4
compose_scene.ferns_chance = 0.6
compose_scene.flowers_chance = 0.4
compose_scene.monocots_chance = 0.5
compose_scene.mushroom_chance = 0.3
compose_scene.pinecone_chance = 0.5
compose_scene.pine_needle_chance = 0.6

populate_scene.slime_mold_chance = 0.0
populate_scene.ivy_chance = 0.0
populate_scene.lichen_chance = 0.6
populate_scene.mushroom_chance = 0.0
populate_scene.moss_chance = 0.0

compose_scene.rain_particles_chance = 0.3
compose_scene.leaf_particles_chance = 0.7
worldgen/config/scene_types/desert.gin METASEP

compose_scene.trees_chance = 0.25
compose_scene.cactus_chance = .7
compose_scene.ground_leaves_chance = 0.5
compose_scene.ground_twigs_chance = 0.3
compose_scene.chopped_trees_chance = 0.1
compose_scene.grass_chance = 0.1
compose_scene.ferns_chance = 0.0
compose_scene.pine_needle_chance = 0.05
compose_scene.fancy_clouds_chance = 0.0

compose_scene.tree_density = 0.02

compose_scene.rain_particles_chance = 0.01
compose_scene.snow_particles_chance = 0
compose_scene.leaf_particles_chance = 0.05
compose_scene.dust_particles_chance = 0.0

atmosphere_light_haze.shader_atmosphere.density = ("uniform", 0, 0.0015)
atmosphere_light_haze.shader_atmosphere.anisotropy = 0

animate_cameras.follow_poi_chance=0.5

compose_scene.ground_creatures_chance = 1.0
compose_scene.ground_creature_registry = [
    (@SnakeFactory, 1)
]

surface.registry.ground_collection = [
    ('sand', 1),
]

surface.registry.mountain_collection = [
    ("sandstone", 1),
]

# scene composition config
LandTiles.tiles = ["Mountain"]
LandTiles.randomness = 1
LandTiles.tile_heights = [-2]
LandTiles.tile_density = 0.25
WarpedRocks.slope_shift = -3
Ground.with_sand_dunes = 1

scene.waterbody_chance = 0
worldgen/config/scene_types/coral_reef.gin METASEP
include 'config/scene_types/under_water.gin'

compose_scene.kelp_chance = 0.1
compose_scene.urchin_chance = 0.1

compose_scene.corals_chance = 1.
compose_scene.seaweed_chance = 0.2
compose_scene.seashell_chance = 0.7
compose_scene.jellyfish_chance = 0.0

water.geo.with_waves=True
worldgen/config/scene_types/coast.gin METASEP
water.is_ocean = ("bool", 0.5)
water.coastal = 1
water.shader.colored = 0
water.geo.with_ripples = 0
sand.shader.wet = 1


# scene composition config
LandTiles.tile_density = 1.5
LandTiles.tiles = ["MultiMountains", "Coast", "MultiMountains"]
LandTiles.tile_heights = [-10, 0, 0]
LandTiles.attribute_modification_start_height = ("uniform", -6, -5)
LandTiles.attribute_modification_end_height = ("uniform", 2, 4)
LandTiles.use_cblerp = 1
LandTiles.smooth = 1

scene.ground_chance = 0
scene.waterbody_chance = 1
scene.warped_rocks_chance = 0
scene.voronoi_rocks_chance = 0.8
scene.volcanos_chance = 0.5


# lighting
nishita_lighting.dust_density = 0
nishita_lighting.air_density = ("uniform", 0.2, 0.5)

shader_atmosphere.anisotropy = 1
shader_atmosphere.density = 0

# camera selection config
camera_selection_preprocessing.terrain_tags_ratio = {"liquid": (0.05, 0.6), "beach": (0.05, 0.6)}

compose_scene.ground_creatures_chance = 0.0
compose_scene.ground_creature_registry = [
    (@BirdFactory, 0.1),
    (@CrabFactory, 1)
]
compose_scene.max_ground_creatures = 8
compose_scene.flying_creatures_chance=0.6
compose_scene.flying_creature_registry = [
    (@FlyingBirdFactory, 1)
]
worldgen/config/scene_types/cliff.gin METASEP
compose_scene.ground_creature_registry = [
    (@CarnivoreFactory, 0.2),
    (@HerbivoreFactory, 1),
    (@BirdFactory, 1),
]

# scene composition config
LandTiles.tiles = ["Mountain", "Cliff", "Mountain"]
LandTiles.tile_heights = [-15, -15, 10]
LandTiles.tile_density = 1.6
LandTiles.randomness = 1
WarpedRocks.slope_shift=-15
Ground.height = -15

# camera selection config
UniformMesher.dimensions = (-25, 25, -25, 25, -15, 35)
keep_cam_pose_proposal.terrain_coverage_range = (0, 0.8)
camera_selection_preprocessing.terrain_tags_ratio = {("altitude", 10, 1e9): (0.01, 1)}

compose_scene.flying_creatures_chance=0.6
compose_scene.flying_creature_registry = [
    (@FlyingBirdFactory, 1),
]
worldgen/config/scene_types/cave.gin METASEP
compose_scene.land_domain_tags = 'landscape,-liquid_covered'
compose_scene.nonliving_domain_tags = 'landscape'
compose_scene.underwater_domain_tags = 'landscape,liquid_covered'

compose_scene.trees_chance = 0.4
compose_scene.rocks_chance = 0.8
compose_scene.glowing_rocks_chance = 1.0
compose_scene.grass_chance = 0.4
compose_scene.ferns_chance = 0.6
compose_scene.mushroom_chance = 0.8

compose_scene.snow_particles_chance=0.0
compose_scene.leaves_chance=0.0
compose_scene.rain_particles_chance=0.0

surface.registry.liquid_collection = [
    ('water', 0.7),
    ('lava', 0.3)
]

compose_scene.bug_swarm_chance=0.0

compose_scene.ground_creatures_chance = 0.0
compose_scene.ground_creature_registry = [
    (@CarnivoreFactory, 1),
    (@HerbivoreFactory, 0.3),
    (@BirdFactory, 0.5),
    (@BeetleFactory, 1)
]

compose_scene.flying_creatures_chance=0.2
compose_scene.flying_creature_registry = [
    (@DragonflyFactory, 1),
]

atmosphere_light_haze.shader_atmosphere.enable_scatter = False
render_image.exposure = 1.3


# scene composition config
scene.caves_chance = 1
scene.ground_chance = 0.5
Caves.randomness = 0
Caves.height_offset = -4
Caves.frequency = 0.01
Caves.noise_scale = ("uniform", 2, 5)
Caves.n_lattice = 1
Caves.is_horizontal = 1
Caves.scale_increase = 1

scene.waterbody_chance = 0.8
Waterbody.height = -5

full/render_image.min_samples = 500

# camera selection config
UniformMesher.dimensions = (-25, 25, -25, 25, -25, 0)
keep_cam_pose_proposal.terrain_coverage_range = (1, 1)
camera_selection_preprocessing.terrain_tags_ratio = {"cave": (0.3, 1), ("closeup", 4): (0, 0.3)}

SphericalMesher.r_min = 0.2

worldgen/config/scene_types/canyon.gin METASEP
atmosphere_light_haze.shader_atmosphere.anisotropy = 0

# scene composition config
LandTiles.tiles = ["Canyons", "Canyon", "Canyons"]
LandTiles.tile_heights = [-4, -4, -4]
LandTiles.randomness = 1

# camera selection config
keep_cam_pose_proposal.terrain_coverage_range = (0.5, 0.9)
camera_selection_preprocessing.terrain_tags_ratio = {("altitude", 16, 1e9): (0.01, 1)}

compose_scene.ground_creatures_chance = 0.2
compose_scene.ground_creature_registry = [
    (@SnakeFactory, 0.9)
]

worldgen/config/scene_types/arctic.gin METASEP
surface.registry.mountain_collection = [
    ('ice', 1),
]

surface.registry.rock_collection = [
    ('ice', 1),
]

compose_scene.ground_creature_registry = [
    (@CarnivoreFactory, 0),
    (@HerbivoreFactory, 0.3),
    (@BirdFactory, 1),
]

Terrain.main_terrain = "CollectiveTransparentTerrain"
# scene composition config
LandTiles.transparency = "CollectiveTransparent"
VoronoiRocks.transparency = "CollectiveTransparent"

LandTiles.randomness = 1
LandTiles.land_process = "ice_erosion"
LandTiles.tiles = ["Mesa"]
LandTiles.tile_heights = [-2.75]
LandTiles.tile_density = 0.4
LandTiles.height_modification_start = -1.5
LandTiles.height_modification_end = -2.5
scene.ground_chance = 0
scene.warped_rocks_chance = 0
scene.ground_ice_chance = 1
scene.waterbody_chance = 1

include 'config/no_assets.gin'

compose_scene.wind_chance = 0.5
compose_scene.turbulence_chance = 0.5
compose_scene.boulders_chance = 0.3
compose_scene.rocks_chance = 0.3

shader_atmosphere.density = 0
water.geo.water_height = ("uniform", 0.002, 0.004)
water.geo.with_ripples = 0
worldgen/config/palette/water.json METASEP
{
    "color": {
        "0": "#6E7D2F",
        "1": "#BDE2F1",
        // "2": "#3A4057",
        // "3": "#C4AD9F",
        "4": "#1257AF",
        // "5": "#746540",
        // "6": "#0A191B",
        "7": "#5A81A6",
        "8": "#C8CFCB",
        "9": "#EBF4FF",
    },
    "hsv": [
        [0.1998698448748673, 0.6227424304195031, 0.9],
        [0.5477689208424551, 0.21434992687900004, 0.9],
        [0.6327339484560036, 0.3301061840533684, 0.3411190950097478],
        [0.06576767355095, 0.1902924046222359, 0.7679953591117661],
        [0.5935058967834421, 0.8959440559146917, 0.9],
        [0.11937877277552099, 0.4469960374738681, 0.45581881653370837],
        [0.5272123497876567, 0.6314621695371699, 0.10895084790679604],
        [0.5810977301330732, 0.4563813388796311, 0.9],
        [0.4042145148967165, 0.03653873629550301, 0.8110671784023343],
        [0.588842011357473, 0.07633112423084452, 0.9971316256726519],
    ],
    "std": [
        [0.03206789371889551,0.0,0.0,-0.09940084287521272,0.2014960370575989,0.0,-0.06979341422226887,-0.03900638828203717,0.1416734782788235],
        [0.024681178423931242,0.0,0.0,0.02939248770862711,0.09169067270613647,0.0,0.009430208836412922,-0.0032004806956673674,0.02481388033554004],
        [0.16809486176362895,0.0,0.0,0.011226939513474987,0.174445352820211,0.0,0.027974145349038415,-0.0678937318848718,0.1494990544030961],
        [0.02001521596784851,0.0,0.0,0.006959399840153715,0.09381009065949539,0.0,0.05222874155544712,-0.0748604714079399,0.09900250080092063],
        [0.0474162722621789,0.0,0.0,-0.03644028297475588,0.09031440286909108,0.0,-0.0637067275282711,-0.0863007241399916,0.11730203229232809],
        [0.049168447625302265,0.0,0.0,-0.10377550780787329,0.22980566919872517,0.0,0.047195279956696125,-0.014367250314799686,0.2200199734242498],
        [0.01877967113215237,0.0,0.0,0.08090617995859212,0.09912713051727054,0.0,0.015131591219016464,0.02134215914673112,0.023951737156055402],
        [0.034702354527418794,0.0,0.0,-0.07479294383101005,0.21949601112215142,0.0,-0.020925356073290755,-0.1211073421502184,0.16108630390471018],
        [0.2591825701503923,0.0,0.0,0.0022643621311114596,0.02544728516555819,0.0,0.004201868980983058,-0.07165274824193764,0.12481469262133676],
        [0.014708560237241201,0.0,0.0,-0.011567861584189643,0.05804825019819519,0.0,0.0007671669264771607,-0.00032150182378043316,0.004520022343069957],
    ],
    "prob": [
        0.09540157681621321,
        0.17309766731396575,
        0.04771643945956729,
        0.07188687273754074,
        0.039379729860260226,
        0.0832492754861786,
        0.022716047752889684,
        0.25607938059700114,
        0.08029614024461185,
        0.1301768697317716,
    ]
}

worldgen/config/palette/sandstone.json METASEP
{
    "color": {
        "0": "#C3885E",
        // "1": "#6C8197",
        // "2": "#FEFDFD",
        // "3": "#806A51",
        // "4": "#CCD9D3",
        // "5": "#1172BB",
        // "6": "#A09C94",
        // "7": "#0C0F1C",
        // "8": "#FCD4A5",
        // "9": "#000000",
    },
    "hsv": [
        [0.06861373426969633, 0.5134158200972263, 0.7621370895404943],
        [0.5852393290828793, 0.2849759496103228, 0.5932719505700472],
        [0.01945137716629203, 0.005648329181058526, 0.9948881453082624],
        [0.08867017049693292, 0.3634299602486472, 0.5002505403089967],
        [0.43116202137109777, 0.059058173987177276, 0.8487924342832054],
        [0.5718258251180441, 0.9081841619786962, 0.7334477748532275],
        [0.1142702240736942, 0.07451071524524755, 0.62525165858801],
        [0.6368670239208275, 0.5673733592586013, 0.11187507692229874],
        [0.09057977245498154, 0.34196667513327306, 0.9846039179645466],
        [0.0, 1.3292218524660857e-164, 0.0031057615382051045],
    ],
    "std": [
        [0.03351715981398969,0.0,0.0,-0.10157413575620575,0.12688602732135154,0.0,0.004066895305684374,-0.07236435399679367,0.09157514369861482],
        [0.10290998666106625,0.0,0.0,0.03316779615033728,0.19627285112611817,0.0,0.004399731203544361,-0.018652761712523398,0.19328369111817797],
        [0.06637010378804975,0.0,0.0,0.019212659985615645,0.0034568085422515336,0.0,-0.016883507216752663,-0.00023496262128931003,0.0034949494756654764],
        [0.03836500482827415,0.0,0.0,-0.08562187469069105,0.1803121491066336,0.0,0.03213291060921508,-0.06878678430852345,0.1778246819661134],
        [0.2032075441733468,0.0,0.0,-0.025398818397257477,0.03266886588882594,0.0,-0.023967841820520665,-0.060055296578712065,0.06858969891403699],
        [0.012222958907540781,0.0,0.0,-0.05781258340017472,0.025501515976553348,0.0,-0.03310017127514591,0.0026946751689168663,0.014633994102545515],
        [0.06686855344799054,0.0,0.0,-0.0013021802876484999,0.05953314541358922,0.0,0.0159690892428685,-0.13334169442766802,0.1690386950018539],
        [0.1395202536065173,0.0,0.0,-0.0014602596618678064,0.20616312549247665,0.0,-0.0023134476848319222,0.022779062790615385,0.04764933721102901],
        [0.045530667348600916,0.0,0.0,-0.0969352160306074,0.08526128775157774,0.0,0.0004776604045931929,-0.0053334552498859635,0.01578033067680964],
        [0.0033166247903554003,0.0,0.0,0.0,0.0033166247903554003,0.0,0.0,7.733871205814574e-163,0.010592340281639457],
    ],
    "prob": [
        0.2964633051644379,
        0.07718580042884955,
        0.098177703093352,
        0.11636968711175157,
        0.1573489486482434,
        0.01709457735133201,
        0.10577846179345056,
        0.02994256050999359,
        0.07800890247485014,
        0.023630053423739333,
    ]
}

worldgen/config/palette/mountain soil.json METASEP
{
    "color": {
        "0": "#916036",
        "1": "#CFA677",
        // "2": "#C1CBDF",
        "3": "#384946",
        // "4": "#5C83B8",
        "5": "#4C4623",
        "6": "#9D884E",
        // "7": "#FFF9F8",
        "8": "#A29D81",
        "9": "#51250A",
    },
    "hsv": [
        [0.07657200610458859, 0.6218981568424602, 0.568095301296071],
        [0.08871291011143334, 0.42452686112786103, 0.8104250687813854],
        [0.6140700215233733, 0.13288612784624504, 0.8730243901503021],
        [0.47346124527783656, 0.22768637564378527, 0.28529322850725286],
        [0.5961218425011782, 0.49810503051093324, 0.7223871831892953],
        [0.14544462943019612, 0.5389329914616029, 0.29703170640400595],
        [0.12202185913813124, 0.49872400694381797, 0.614810311196337],
        [0.02216908447486423, 0.027253574342521403, 0.9994307999673898],
        [0.13984012270413265, 0.20105405545965413, 0.6344186455983115],
        [0.0620713740714641, 0.8670860688594698, 0.3201029563817151],
    ],
    "std": [
        [0.01789703571127652,0.0,0.0,-0.12597331599571596,0.1291790795498408,0.0,0.014011416277454765,0.016482971792371452,0.13343880210454545],
        [0.007744047862909046,0.0,0.0,0.012097193794030701,0.051526477352250744,0.0,0.003980522892370001,-0.019226818357123424,0.06316769321252796],
        [0.09980781923323018,0.0,0.0,-0.02751107358853669,0.07348168453829067,0.0,0.03823990807304074,0.007156125966110767,0.09896511745818332],
        [0.1554993390085664,0.0,0.0,0.06533844291739956,0.13682650189476622,0.0,0.009608147854344253,-0.058398154335554245,0.09181325340416716],
        [0.010030408116143077,0.0,0.0,0.036937285719487165,0.14591077523998403,0.0,-0.02501126600237874,-0.026409038081482275,0.10355895739448526],
        [0.06474239210522445,0.0,0.0,0.008133894434491999,0.20737552443259993,0.0,-0.007359426282875676,-0.05112646185112438,0.09877621827546076],
        [0.05182286396833515,0.0,0.0,0.051138327526411384,0.14230590221035327,0.0,0.0427792445588568,0.0022117825436210794,0.13239327935553516],
        [0.05822501097377041,0.0,0.0,0.07131802897006612,0.005299444518355579,0.0,-0.0012379613670810304,-5.4681679491867775e-05,0.0033877668057344145],
        [0.07661598914233601,0.0,0.0,-0.0018042105407654976,0.12477201699512865,0.0,-0.038383553414123014,-0.13518589408121312,0.21018245422010579],
        [0.03650937782912379,0.0,0.0,-0.024334393960077933,0.09154625092902843,0.0,0.0375423755906796,-0.0369424430932128,0.12079544868468167],
    ],
    "prob": [
        0.18173535415922157,
        0.12693188009479223,
        0.11203245756478104,
        0.10729577747369581,
        0.10508095198299697,
        0.08720755326805475,
        0.08547331599457036,
        0.06928970489547422,
        0.06438450615250647,
        0.060568498413906664,
    ]
}

worldgen/config/palette/desert.json METASEP
{
    "color": {
        "0": "#B3754F",
        // "1": "#62657A",
        // "2": "#9CCEEE",
        "3": "#6D451D",
        "4": "#8F7660",
        "5": "#D8C89C",
        // "6": "#160C1C",
        // "7": "#DEE8E0",
        // "8": "#50A4E1",
        "9": "#C97C32",
    },
    "hsv": [
        [0.06396132514608845, 0.5582491476192758, 0.7022182223321519],
        [0.6441832628487171, 0.19454300112160486, 0.4767518973652816],
        [0.564190361179602, 0.34202695968716623, 0.9301707627613979],
        [0.08284060661345186, 0.7337905844901346, 0.4272330354964103],
        [0.0769917744760461, 0.32274623644085537, 0.5593148282503584],
        [0.12207630659931097, 0.2770291091247469, 0.8474854702159862],
        [0.7695164059617565, 0.5427145223332442, 0.10942474920772048],
        [0.37323918859114563, 0.046151794073734466, 0.9100722491636853],
        [0.5699411934104351, 0.6445360235611376, 0.8802112876154443],
        [0.08179176098048567, 0.7492023127276, 0.7863168974740541],
    ],
    "std": [
        [0.012908699629179485,0.0,0.0,-0.002992053546886112,0.13123439103584697,0.0,0.05049175804306987,0.052468201908552434,0.13103411925339703],
        [0.18102011999099382,0.0,0.0,0.01318644582756094,0.11371263907318814,0.0,0.00782790306181972,-0.04193187380401193,0.17072542399582752],
        [0.02369379830230515,0.0,0.0,0.04310165857721542,0.1276653542541642,0.0,0.057220957353411615,0.004351347547703299,0.05109219056769986],
        [0.0331799756267655,0.0,0.0,-0.031687668421694945,0.13454013140804447,0.0,0.09581616075277187,-0.09260252383770698,0.14259361328666428],
        [0.040848529475037504,0.0,0.0,-0.0016752230553350447,0.15093798737799663,0.0,0.032168541301644704,-0.09018582013324412,0.20641829785563356],
        [0.013588067316197586,0.0,0.0,-0.028293590482349883,0.014177809637071553,0.0,0.01642770540085266,-0.0083672890034097,0.017696230126111653],
        [0.1617839972715444,0.0,0.0,-0.041760177903303504,0.26695075192098405,0.0,0.021488256578748293,-0.02160111100582096,0.043455837777885434],
        [0.1883493627771559,0.0,0.0,0.006194577059180789,0.01746060511330079,0.0,-0.026627762258874144,-0.011014813607127841,0.06220814716064264],
        [0.011453222683526386,0.0,0.0,-0.0779316163108227,0.19853855995383052,0.0,-0.03472134238530878,0.0031820305834247857,0.043373684701738295],
        [0.010090922509845487,0.0,0.0,-0.006903699176068146,0.08213922091223957,0.0,0.0527454883754538,-0.0564609436155142,0.07792530447321612],
    ],
    "prob": [
        0.248546101814309,
        0.047729878354018915,
        0.0946262117573813,
        0.09823173176548962,
        0.1534055812208923,
        0.06295277756073889,
        0.017033634619889257,
        0.03596282001352191,
        0.09317954200651211,
        0.14833172088724667,
    ]
}

worldgen/assets/trees/README.md METASEP
# Tree Generation

Overview of the generation pipeline for trees and other plants.

## Initial geometry

To start, we define a skeleton for the tree. That is, we procedurally place and connect vertices defining the core tree shape. There are two approaches to this that are complementary to each other. Note, compelling trees can be made exclusively by using just one method or the other.

### Recursive paths

### Space colonization

## Branch thickness

With the skeleton laid out, we need to fill out the tree by defining the thickness of stems and branches. Originally this was done with a skinning modifier, but this has been updated as defining the radius in Geometry Nodes (GN) is easier to tune and yields a better end result.

We define a nodegroup that takes as input the tree skeleton and produces a filled out mesh by leveraging the function `Curve to Mesh`. The radius calculation is made possible by providing the additional attribute `rev depth` as input which specifies the distance to a leaf node for each vertex in the tree.

We get instant feedback when adjusting parameters and can carefully tune a function that looks nice and behaves well. A handful of parameters are sufficient to govern a variety of looks and these can easily be recorded for future use for a particular class of tree/plant.

Odd artifacts can pop up when converting to a mesh, and there are a couple of details which control the final look of the tree which we adjust to get the best looking mesh without going overboard on the number of vertices.

 - we turn off `Shade smooth` which is turned on by default with `Curve to Mesh`
 - the resolution of the profile curve can be adjusted with the exposed variable: `profile res`
 - weird behavior is usually due to vertices that are too close to each other, we can add `Merge by distance` to remove duplicates. Unfortunately this collapses the thin twigs. One way around this is to use `Separate Geometry` and apply the merge to the main trunk and large branches. This is not too much trouble to set up, but currently not implemented

**Note on materials:** Currently there's one pain point in terms of materials which is that we cannot get a good UV unwrapping until the mesh is finalized. The current code assigns a material to the generated mesh after `set radius` but you'll just notice a color change mostly because it does not map properly across the tree geometry. We provide a function `finalize` that can be called that will separate out the tree from its instances, finalize the mesh, and call the appropriate UV unwrapping.


## Instancing child geometry

## Nodes Tips + Tricks

In some ways the node setup makes life easier, but in others it can be a bit frustrating to write code to implement new ideas in nodes. While tedious, there is some incredible flexibility that is introduced. Here are some features that are made possible that I think are worth paying attention to:

- **partitioning of geometry:** Most functions in nodes take `selection` as an additional input which means you can apply a function to a subset of a given mesh. With the attributes we have available for the tree geometry this makes it straightforward to apply filters such that different functions are applied in different ways to different parts of the tree. For example, a `level` is defined to distinguish recursive levels of the tree paths, so the trunk is `level=0` and the roots are `level=-1`. We make use of this to instance child geometry on leaves of the tree while excluding the "leaves" on the roots. Another thing we can do is have different levels of detail at different regions, e.g. using a `Profile res` of `4` for small twigs and `16` for the trunk and branches _(not currently implemented)_. This reduces vertices without sacrificing visual fidelity.

worldgen/assets/trees/.gitignore METASEP
*.blend

worldgen/assets/creatures/README.md METASEP

## Part Definition

a Part is comprised of:
- a blender mesh object
- a line curve that runs centrally through it (specified as an np.array of points in order)
- metadata for rigging / animating that part 

a GeonodesPartFactory produces a Part using a geometry nodes group of a particular format. For the nodegroup's input:
- The geonodes will be applied to a single vert as its input, unless you override the base_obj method
- Any nodegroup inputs / 'genes' should be specified by overriding the GeonodesParts.params() method with rng calls
As output, it should have output sockets for:
- output a 'Geometry' field, which will be included in the final creature
- output a 'Skeleton Curve' field, which will be used to populate the skeleton curve
- optionally: output any number of other extra geometry bits
    - these will be parented to the part but not remeshed etc
    - use this for eyes / teeth you want to remain separate
- optionally: output some attributes over its 'Geometry' field
    - use this to specifiy skin rigidity, or hair related parameters

## Part Conventions

+X is the long axis, +Z is the up axis, +Y is the left side of a creature, or the leading edge of a leg or wing
parity 1 is right side, -1 is left side

Length/Yaw/Rad is a 3D polar coordinate for addressing the surface of a Part
- Length is a 0-1 scalar specifying the percentage of the length along the skeleton to travel
- Yaw is a [-1,1] scalar specifying the yaw tangentially to the skeleton curve to shoot a ray. 0=downwards, +-0.5=left/right, +-1=upwards
- Rad is a 0-1 (or more than 1 in some cases) percentage scalar. The code will raycast using Length/Yaw to the surface of the part, then move 'Rad' percentage of the way along that ray towards the surface

Parts are produced by a PartFactory, which contains a dict of params. This dict may be interpolated to produce intermediate parts. We will even attempt to interpolate the matching keys of two dicts from different PartFactory types. To maximize the quality of these interpolations, the param dict should contain these keys, whenever possible:
- 'length_rad1_rad2': The overall length , and starting / ending approx radius of the part
- 'aspect' - what percent of the height is the width
- 'angles_deg' - R^3 
process_mesh/utils.hpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#pragma once
#include <iostream>
#include <fstream>
#include <memory>
#include <glad/glad.h>
#include <Eigen/Dense>
#include <unsupported/Eigen/CXX11/Tensor>
#include <tinycolormap.hpp>
typedef tinycolormap::ColormapType clrmap;
#include <indicators/progress_bar.hpp>
#include "cnpy/cnpy.h"
#include <array>

void release_assert(const char *file, int line, bool condition, const std::string &msg);
#define RASSERT(c) release_assert(__FILE__, __LINE__, c, "")
#define MRASSERT(c, m) release_assert(__FILE__, __LINE__, c, m)

void glCheckError_(const char *file, int line);
#define glCheckError() glCheckError_(__FILE__, __LINE__)

class loop_obj {
public:
  const int x, y, j;
  const std::shared_ptr<indicators::ProgressBar> progbar;
  
  loop_obj(int xc, int yc, int jc, std::shared_ptr<indicators::ProgressBar> pb) : x(xc), y(yc), j(jc), progbar(pb) {}
  void progressbar() const {if (progbar) progbar->tick();}
};

Eigen::Tensor<unsigned char, 3> compute_flow_viz(const Eigen::Tensor<double, 3> &input_image);

Eigen::Tensor<unsigned char, 3> to_color_map(const Eigen::Tensor<double, 2> &input_image, const double &min_percentile, const double &max_percentile, const double &minval=1e-3, const clrmap &type=clrmap::Jet);

Eigen::Tensor<unsigned char, 3> to_color_map(const Eigen::Tensor<int, 2> &input_image);

const std::vector<loop_obj> image_iterator(const int width, const int height, const std::string desc="");
process_mesh/utils.cpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#include <iostream>
#include <fstream>
#include <math.h>
#include <limits>
#include <unsupported/Eigen/CXX11/Tensor>
#include "utils.hpp"
#include "cnpy/cnpy.h"
#include "colorcode.h"

void release_assert(const char *file, int line, bool condition, const std::string &msg){
    if (!condition)
        throw std::runtime_error(std::string("Assertion failed: ") + file + " (" + std::to_string(line) + ")\n" + msg + "\n");
}

void glCheckError_(const char *file, int line)
{
    GLenum errorCode;
    while ((errorCode = glGetError()) != GL_NO_ERROR)
    {
        std::string error;
        switch (errorCode)
        {
            case GL_INVALID_ENUM:                  error = "INVALID_ENUM"; break;
            case GL_INVALID_VALUE:                 error = "INVALID_VALUE"; break;
            case GL_INVALID_OPERATION:             error = "INVALID_OPERATION"; break;
            case GL_STACK_OVERFLOW:                error = "STACK_OVERFLOW"; break;
            case GL_STACK_UNDERFLOW:               error = "STACK_UNDERFLOW"; break;
            case GL_OUT_OF_MEMORY:                 error = "OUT_OF_MEMORY"; break;
            case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break;
        }
        std::cout << error << " | " << file << " (" << line << ")" << std::endl;
        throw std::runtime_error(error + " | " + file + " (" + std::to_string(line) + ")\n");
    }
}

const std::vector<loop_obj> image_iterator(const int width, const int height, const std::string desc){
    using namespace indicators;
    std::shared_ptr<ProgressBar> bar(new ProgressBar{
        option::BarWidth{20},
        option::Start{"["},
        option::End{"]"},
        option::ShowElapsedTime{true},
        option::ShowRemainingTime{true},
        option::ForegroundColor{Color::blue},
        option::FontStyles{std::vector<FontStyle>{FontStyle::bold}},
        option::PrefixText{desc}
    });
    const size_t num_elements = width*height;
    std::vector<loop_obj> output;
    output.reserve(num_elements);
    size_t current_idx = 0;
    int prev_percent = 0;
    for (int y=0; y<height; y++){
        for (int x=0; x<width; x++){
            const int current_percent = ((++current_idx)*100)/num_elements;
            const bool should_tick = (current_percent > prev_percent);
            output.push_back(loop_obj(x, y, (x+(height-y-1)*width) * 4, should_tick ? bar : nullptr));
            prev_percent = current_percent;
        }    
    }
    assert (current_idx == num_elements);
    assert (num_elements == output.size());
    assert (output.back().progbar);
    return output;
}

Eigen::Tensor<unsigned char, 3> compute_flow_viz(const Eigen::Tensor<double, 3> &input_image){
    const int width = input_image.dimension(1);
    const int height = input_image.dimension(0);
    const double fac_x = (160.0/2) / width;
    const double fac_y = (120.0/2) / height;
    Eigen::Tensor<unsigned char, 3> output(height, width, 3);
    output.setZero();

    const int LEGEND_SIZE = 0;

    for (int y=0; y<height; y++){
        for (int x=0; x<width; x++){
            if ((y < LEGEND_SIZE) && (width < x + LEGEND_SIZE)){
                const double u = (x-(width-LEGEND_SIZE/2)) * fac_x;
                const double v = (y - LEGEND_SIZE/2) * fac_y;
                unsigned char px[3];
                computeColor(u, v, px);
                output(y,x,0) = px[0];
                output(y,x,1) = px[1];
                output(y,x,2) = px[2];
            } else {
                const double u = input_image(y, x, 0) * fac_x;
                const double v = input_image(y, x, 1) * fac_y;
                if (!std::isnan(u) && !std::isnan(v)){
                    unsigned char px[3];
                    computeColor(u, v, px);
                    output(y,x,0) = px[0];
                    output(y,x,1) = px[1];
                    output(y,x,2) = px[2];
                }
            }
        }
    }
    return output;
}

Eigen::Tensor<unsigned char, 3> to_color_map(const Eigen::Tensor<double, 2> &input_image, const double &min_percentile, const double &max_percentile, const double &minval, const clrmap &type) {
    std::vector<double> all_nonzero_values;
    const size_t width = input_image.dimension(1);
    const size_t height = input_image.dimension(0);
    all_nonzero_values.reserve(height*width);
    for (int y=0; y<height; y++){
        for (int x=0; x<width; x++){
            if ((input_image(y,x) > minval) && (input_image(y,x) < 1e4))
                all_nonzero_values.push_back(input_image(y,x));
        }
    }
    std::sort(all_nonzero_values.begin(), all_nonzero_values.end());
    const double N = all_nonzero_values.size();
    const double cur_min = all_nonzero_values[int(N * min_percentile)];
    const double cur_max = all_nonzero_values[int(N * max_percentile) - 1];
    assert (cur_max > cur_min);
    Eigen::Tensor<unsigned char, 3> output(height, width, 3);
    output.setZero();
    for (int y=0; y<height; y++){
        for (int x=0; x<width; x++){
            const double value = (input_image(y,x)-cur_min)/(cur_max - cur_min);
            if ((input_image(y,x) > minval) && (input_image(y,x) < 1e4)){
                const tinycolormap::Color color = tinycolormap::GetColor(value, type);
                output(y,x,0) = color.r()*255;
                output(y,x,1) = color.g()*255;
                output(y,x,2) = color.b()*255;
            }
        }
    }
    return output;
}


Eigen::Tensor<unsigned char, 3> to_color_map(const Eigen::Tensor<int, 2> &input_image) {
    std::vector<double> all_nonzero_values;
    const size_t width = input_image.dimension(1);
    const size_t height = input_image.dimension(0);
    Eigen::Tensor<unsigned char, 3> output(height, width, 3);
    output.setZero();
    std::unordered_map<int, double> int2double;
    for (int y=0; y<height; y++){
        for (int x=0; x<width; x++){
            const int key = input_image(y, x);
            double value;
            if (int2double.find(key) != int2double.end()) {
                value = int2double[key];
            } else {
                srand(key);
                value = static_cast <double> (rand()) / static_cast <double> (RAND_MAX);
                int2double[key] = value;
            }
            const tinycolormap::Color color = tinycolormap::GetColor(value, clrmap::Turbo);
            output(y,x,0) = color.r()*255;
            output(y,x,1) = color.g()*255;
            output(y,x,2) = color.b()*255;
        }
    }
    return output;
}

process_mesh/string_tools.hpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#include <regex>
#include <vector>

std::vector<std::string> match_regex(const std::string &pattern, const std::string &input);

std::string increment_int_substr(const std::vector<std::string> &patterns, const std::string &input);

template <typename T>
std::string zfill(const size_t n_zero, const T old_obj){
  const auto old_str = std::to_string(old_obj);
  return std::string(n_zero - std::min(n_zero, old_str.length()), '0') + old_str;
}
process_mesh/string_tools.cpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#include <string>
#include <iostream>
#include "string_tools.hpp"

std::vector<std::string> match_regex(const std::string &pattern, const std::string &input){
        const std::regex regex{pattern.c_str()};
        std::smatch m;
        std::vector<std::string> output;
        if (std::regex_match(input, m, regex)){
            for (auto it : m)
                output.push_back(it.str());
        }
        return output;
}

std::string increment_int_substr(const std::vector<std::string> &patterns, const std::string &input_orig){
    std::string input(input_orig);
    std::smatch res;

    for (const auto pattern : patterns){
        std::string::const_iterator searchStart( input.cbegin() );
        std::regex exp(pattern.c_str());
        while ( std::regex_search( searchStart, input.cend(), res, exp ) )
        {
            std::string number = res[1];
            std::string new_number = zfill(number.size(), std::atoi(number.c_str())+1);
            input.replace(res[1].first, res[1].second, new_number);

            searchStart = res.suffix().first;
        }
    }

    return input;

}
process_mesh/shader.hpp METASEP
#pragma once

#include <glad/glad.h>
#include <glm/glm.hpp>

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

//#ifndef APIENTRYP
//#define APIENTRYP APIENTRY *
//#endif

//typedef void (*PFNGLCREATESHADERPROC)(EGLenum type);
//PFNGLCREATESHADERPROC glCreateShader  = (PFNGLCREATESHADERPROC)eglGetProcAddress("glCreateShader");

class ShaderBase {
public:
	unsigned int ID;

	void use();

	void setFloat(const std::string& name, float value) const;
	void setDouble(const std::string& name, double value) const;
	void setBool(const std::string& name, bool value) const;
	void setInt(const std::string& name, int value) const;
	void setUInt(const std::string& name, unsigned int value) const;

	void setVec2(const std::string& name, const glm::vec2& value) const;
	void setVec2(const std::string& name, float x, float y) const;
	void setVec3(const std::string& name, const glm::vec3& value) const;
	void setVec3(const std::string& name, float x, float y, float z) const;
	void setVec4(const std::string& name, const glm::vec4& value) const;
	void setVec4(const std::string& name, float x, float y, float z, float w) const;

	void setDVec2(const std::string& name, const glm::dvec2& value) const;
	void setDVec2(const std::string& name, double x, double y) const;
	void setDVec3(const std::string& name, const glm::dvec3& value) const;
	void setDVec3(const std::string& name, double x, double y, double z) const;
	void setDVec4(const std::string& name, const glm::dvec4& value) const;
	void setDVec4(const std::string& name, double x, double y, double z, double w) const;

	void setIVec2(const std::string& name, const glm::ivec2& value) const;
	void setIVec2(const std::string& name, int x, int y) const;
	void setIVec3(const std::string& name, const glm::ivec3& value) const;
	void setIVec3(const std::string& name, int x, int y, int z) const;
	void setIVec4(const std::string& name, const glm::ivec4& value) const;
	void setIVec4(const std::string& name, int x, int y, int z, int w) const;

	void setUVec2(const std::string& name, const glm::uvec2& value) const;
	void setUVec2(const std::string& name, unsigned int x, unsigned int y) const;
	void setUVec3(const std::string& name, const glm::uvec3& value) const;
	void setUVec3(const std::string& name, unsigned int x, unsigned int y, unsigned int z) const;
	void setUVec4(const std::string& name, const glm::uvec4& value) const;
	void setUVec4(const std::string& name, unsigned int x, unsigned int y, unsigned int z, unsigned int w) const;

	void setMat2(const std::string& name, const glm::mat2& mat) const;
	void setMat3(const std::string& name, const glm::mat3& mat) const;
	void setMat4(const std::string& name, const glm::mat4& mat) const;

protected:
	void checkCompileErrors(unsigned int shader, std::string type);
};

class Shader : public ShaderBase {
public:
	Shader(const GLchar* vertexPath, const GLchar* fragmentPath, const GLchar* geometryPath);
	Shader(const GLchar* vertexPath, const GLchar* fragmentPath);
	Shader();
};

class ComputeShader : public ShaderBase {
public:
	ComputeShader(const GLchar* path);
	ComputeShader();
};

process_mesh/shader.cpp METASEP
#include "shader.hpp"

// Base class

void ShaderBase::use() {
	glUseProgram(ID);
}

void ShaderBase::setFloat(const std::string& name, float value) const {
	glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}

void ShaderBase::setDouble(const std::string& name, double value) const {
	glUniform1d(glGetUniformLocation(ID, name.c_str()), value);
}

void ShaderBase::setBool(const std::string& name, bool value) const {
	glUniform1i(glGetUniformLocation(ID, name.c_str()), int(value));
}

void ShaderBase::setInt(const std::string& name, int value) const {
	glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}

void ShaderBase::setUInt(const std::string& name, unsigned int value) const {
	glUniform1ui(glGetUniformLocation(ID, name.c_str()), value);
}

void ShaderBase::setVec2(const std::string& name, const glm::vec2& value) const {
	glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setVec2(const std::string& name, float x, float y) const {
	glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
}

void ShaderBase::setVec3(const std::string& name, const glm::vec3& value) const {
	glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setVec3(const std::string& name, float x, float y, float z) const {
	glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}

void ShaderBase::setVec4(const std::string& name, const glm::vec4& value) const {
	glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setVec4(const std::string& name, float x, float y, float z, float w) const {
	glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}

void ShaderBase::setDVec2(const std::string& name, const glm::dvec2& value) const {
	glUniform2dv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setDVec2(const std::string& name, double x, double y) const {
	glUniform2d(glGetUniformLocation(ID, name.c_str()), x, y);
}

void ShaderBase::setDVec3(const std::string& name, const glm::dvec3& value) const {
	glUniform3dv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setDVec3(const std::string& name, double x, double y, double z) const {
	glUniform3d(glGetUniformLocation(ID, name.c_str()), x, y, z);
}

void ShaderBase::setDVec4(const std::string& name, const glm::dvec4& value) const {
	glUniform4dv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setDVec4(const std::string& name, double x, double y, double z, double w) const {
	glUniform4d(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}

void ShaderBase::setIVec2(const std::string& name, const glm::ivec2& value) const {
	glUniform2iv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setIVec2(const std::string& name, int x, int y) const {
	glUniform2i(glGetUniformLocation(ID, name.c_str()), x, y);
}

void ShaderBase::setIVec3(const std::string& name, const glm::ivec3& value) const {
	glUniform3iv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setIVec3(const std::string& name, int x, int y, int z) const {
	glUniform3i(glGetUniformLocation(ID, name.c_str()), x, y, z);
}

void ShaderBase::setIVec4(const std::string& name, const glm::ivec4& value) const {
	glUniform4iv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setIVec4(const std::string& name, int x, int y, int z, int w) const {
	glUniform4i(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}

void ShaderBase::setUVec2(const std::string& name, const glm::uvec2& value) const {
	glUniform2uiv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setUVec2(const std::string& name, unsigned int x, unsigned int y) const {
	glUniform2ui(glGetUniformLocation(ID, name.c_str()), x, y);
}

void ShaderBase::setUVec3(const std::string& name, const glm::uvec3& value) const {
	glUniform3uiv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setUVec3(const std::string& name, unsigned int x, unsigned int y, unsigned int z) const {
	glUniform3ui(glGetUniformLocation(ID, name.c_str()), x, y, z);
}

void ShaderBase::setUVec4(const std::string& name, const glm::uvec4& value) const {
	glUniform4uiv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void ShaderBase::setUVec4(const std::string& name, unsigned int x, unsigned int y, unsigned int z, unsigned int w) const {
	glUniform4ui(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}

void ShaderBase::setMat2(const std::string& name, const glm::mat2& mat) const {
	glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}

void ShaderBase::setMat3(const std::string& name, const glm::mat3& mat) const {
	glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}

void ShaderBase::setMat4(const std::string& name, const glm::mat4& mat) const {
	glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}

void ShaderBase::checkCompileErrors(unsigned int shader, std::string type) {
	int success;
	char infoLog[1024];
	if (type != "PROGRAM") {
		glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
		if (!success) {
			glGetShaderInfoLog(shader, 1024, NULL, infoLog);
			std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
		}
	}
	else {
		glGetProgramiv(shader, GL_LINK_STATUS, &success);
		if (!success) {
			glGetProgramInfoLog(shader, 1024, NULL, infoLog);
			std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
		}
	}
}

// Child classes

Shader::Shader(const GLchar* vertexPath, const GLchar* fragmentPath, const GLchar* geometryPath) {
	std::string vertexCode, fragmentCode, geometryCode;
	std::ifstream vShaderFile, fShaderFile, gShaderFile;

	vShaderFile.open(vertexPath);
	fShaderFile.open(fragmentPath);
	gShaderFile.open(geometryPath);
	std::stringstream vShaderStream, fShaderStream, gShaderStream;

	vShaderStream << vShaderFile.rdbuf();
	fShaderStream << fShaderFile.rdbuf();
	gShaderStream << gShaderFile.rdbuf();

	vShaderFile.close();
	fShaderFile.close();
	gShaderFile.close();

	vertexCode = vShaderStream.str();
	fragmentCode = fShaderStream.str();
	geometryCode = gShaderStream.str();

	const char* vShaderCode = vertexCode.c_str();
	const char* fShaderCode = fragmentCode.c_str();
	const char* gShaderCode = geometryCode.c_str();

	// Compiling the shaders

	unsigned int vertex, fragment, geometry;

	vertex = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertex, 1, &vShaderCode, NULL);
	glCompileShader(vertex);
	checkCompileErrors(vertex, "VERTEX");

	fragment = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragment, 1, &fShaderCode, NULL);
	glCompileShader(fragment);
	checkCompileErrors(fragment, "FRAGMENT");

	geometry = glCreateShader(GL_GEOMETRY_SHADER);
	glShaderSource(geometry, 1, &gShaderCode, NULL);
	glCompileShader(geometry);
	checkCompileErrors(geometry, "GEOMETRY");

	// Shader program

	ID = glCreateProgram();
	glAttachShader(ID, vertex);
	glAttachShader(ID, fragment);
	glAttachShader(ID, geometry);
	glLinkProgram(ID);
	checkCompileErrors(ID, "PROGRAM");

	glDeleteShader(vertex);
	glDeleteShader(fragment);
	glDeleteShader(geometry);
}

Shader::Shader(const GLchar* vertexPath, const GLchar* fragmentPath) {
	std::string vertexCode, fragmentCode;
	std::ifstream vShaderFile, fShaderFile;

	vShaderFile.open(vertexPath);
	fShaderFile.open(fragmentPath);
	std::stringstream vShaderStream, fShaderStream;

	vShaderStream << vShaderFile.rdbuf();
	fShaderStream << fShaderFile.rdbuf();

	vShaderFile.close();
	fShaderFile.close();

	vertexCode = vShaderStream.str();
	fragmentCode = fShaderStream.str();

	const char* vShaderCode = vertexCode.c_str();
	const char* fShaderCode = fragmentCode.c_str();

	// Compiling the shaders

	unsigned int vertex, fragment;
        // std::cout << "#10.5\n";

	vertex = glCreateShader(GL_VERTEX_SHADER);
        // std::cout << "#10.6\n";
	glShaderSource(vertex, 1, &vShaderCode, NULL);
	glCompileShader(vertex);
	checkCompileErrors(vertex, "VERTEX");

	fragment = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragment, 1, &fShaderCode, NULL);
	glCompileShader(fragment);
	checkCompileErrors(fragment, "FRAGMENT");

	// Shader program

	ID = glCreateProgram();
	glAttachShader(ID, vertex);
	glAttachShader(ID, fragment);
	glLinkProgram(ID);
	checkCompileErrors(ID, "PROGRAM");

	glDeleteShader(vertex);
	glDeleteShader(fragment);
}

ComputeShader::ComputeShader(const GLchar* path) {
	std::string code;
	std::ifstream shaderFile;

	shaderFile.open(path);
	std::stringstream shaderStream;

	shaderStream << shaderFile.rdbuf();
	shaderFile.close();
	code = shaderStream.str();

	const char* shaderCode = code.c_str();

	// Compiling the shaders

	unsigned int shader = glCreateShader(GL_COMPUTE_SHADER);
	glShaderSource(shader, 1, &shaderCode, NULL);
	glCompileShader(shader);
	checkCompileErrors(shader, "COMPUTE");

	// Shader program

	ID = glCreateProgram();
	glAttachShader(ID, shader);
	glLinkProgram(ID);
	checkCompileErrors(ID, "PROGRAM");

	glDeleteShader(shader);
}

Shader::Shader() {
	ID = 0;
}

ComputeShader::ComputeShader() {
	ID = 0;
}

process_mesh/normals_example.png METASEP

process_mesh/main.cpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#include <glad/glad.h>
#if SYSTEM_NUM == 0
    #include <EGL/egl.h>
    #include <EGL/eglext.h>
#elif SYSTEM_NUM == 1
    #include <GLFW/glfw3.h>
#endif
#include <Eigen/Dense>
#include <argparse/argparse.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <random>
#include <stack>
#include <chrono>
#include <regex>
#include <math.h>
#include <indicators/progress_bar.hpp>
#include <unsupported/Eigen/CXX11/Tensor>
#include "shader.hpp"
#include "blender_object.hpp"
#include "camera_view.hpp"
#include "string_tools.hpp"
#include "load_blender_mesh.hpp"
#include "utils.hpp"
#include "io.hpp"

#define VERSION "1.34"

using std::cout, std::cerr, std::endl;

#if SYSTEM_NUM == 0
static const EGLint configAttribs[] = {
    EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
    EGL_BLUE_SIZE, 8,
    EGL_GREEN_SIZE, 8,
    EGL_RED_SIZE, 8,
    EGL_DEPTH_SIZE, 8,
    EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
    EGL_NONE,
    EGL_CONFORMANT, EGL_OPENGL_ES2_BIT,
};
#elif SYSTEM_NUM == 1
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}
#endif

template <typename T>
std::vector<T> read_buffer(GLenum color_attachment, const int width, const int height){
    std::vector<T> pixels(width * height * 4);
    static_assert(std::is_same<T, int>::value || std::is_same<T, float>::value);
    GLint format = 0, type = 0;
    glReadBuffer(color_attachment);
    glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format);
    glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);
    const std::string message = "type=" + std::to_string(type) + " format=" + std::to_string(format);
    if constexpr(std::is_same<T, float>::value)
        MRASSERT((type == GL_FLOAT) && (format == GL_RGBA), message);
    else
        MRASSERT((type == GL_INT) && (format == GL_RGBA_INTEGER), message);
    glReadPixels(0, 0, width, height, format, type, pixels.data());
    return pixels;
}

// From https://stackoverflow.com/a/10791845/5057543
#define XSTR(x) STR(x)
#define STR(x) #x


int main(int argc, char *argv[]) {

    const fs::path source_directory = XSTR(PROJECT_SOURCE_DIR) ;
    const auto cpp_path = source_directory / "main.cpp";
    assert_exists(cpp_path);
    std::ifstream t(cpp_path.c_str());
    std::stringstream buffer;
    buffer << t.rdbuf();
    const auto file_text = buffer.str();
    const std::regex regex{"VERSION \\\"([0-9\\.]+)\\\""};
    std::smatch m;
    if ((std::regex_search(file_text, m, regex)) && (VERSION != m[1])){
        std::cerr << "Error: The process_mesh executable is out-of-date, you need to re-compile it." << std::endl;
        exit(1);
    }

    setenv("MESA_GL_VERSION_OVERRIDE", "3.3", true);

    argparse::ArgumentParser program("main", VERSION);
    program.add_argument("--width").default_value(1920).help("Width of output").scan<'i', int>();
    program.add_argument("--height").default_value(1080).help("Height of output").scan<'i', int>();
    program.add_argument("--frame").required().help("Current frame").scan<'i', int>();
    program.add_argument("-in", "--input_dir").required().help("The input/output dir");
    program.add_argument("-out", "--output_dir").required().help("The input/output dir");
    program.add_argument("-lw", "--line_width").default_value(2).help("The width of the occlusion boundaries").scan<'i', int>();
    program.add_argument("-s", "--subdivide").default_value(2).help("How many times to subdivide").scan<'i', int>();
    program.add_argument("-nrf", "--normal_receptive_field").default_value(1).help("Receptive field of normal calculation (in px)").scan<'i', int>();
    program.parse_args(argc, argv);

    const int occlusion_boundary_line_width = program.get<int>("--line_width");
    const int factor = program.get<int>("--subdivide");
    const int frame_number = program.get<int>("--frame");
    const int output_h = program.get<int>("--height");
    const int output_w = program.get<int>("--width");
    const int buffer_width = output_w * factor;
    const int buffer_height = output_h * factor;
    if ((buffer_width > 10000) || (buffer_height > 10000)){
        cout << "The image size [" << buffer_width << " x " << buffer_height << "] is too large." << endl;
        return 1;
    }

    // Linux (works headless)
    #if SYSTEM_NUM == 0

        static const EGLint pbufferAttribs[] = {
            EGL_WIDTH, buffer_width,
            EGL_HEIGHT, buffer_height,
            EGL_NONE,
        };

        EGLDisplay eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);

        EGLint major, minor;

        EGLBoolean res = eglInitialize(eglDpy, &major, &minor);
        assert (res != EGL_FALSE);

        // 2. Select an appropriate configuration
        EGLint numConfigs;
        EGLConfig eglCfg;

        eglChooseConfig(eglDpy, configAttribs, &eglCfg, 1, &numConfigs);

        // 3. Create a surface
        EGLSurface eglSurf = eglCreatePbufferSurface(eglDpy, eglCfg, pbufferAttribs); // eglSurf

        // 4. Bind the API
        eglBindAPI(EGL_OPENGL_API);

        // 5. Create a context and make it current
        const EGLint GiveMeGLES2[] = {
            EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL_CONTEXT_CLIENT_VERSION, 4,
            EGL_CONTEXT_CLIENT_VERSION, 4,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 
            EGL_NONE
        };

        EGLContext eglCtx = eglCreateContext(eglDpy, eglCfg, EGL_NO_CONTEXT, NULL);//GiveMeGLES2);

        eglMakeCurrent(eglDpy, eglSurf, eglSurf, eglCtx);

        GLADloadproc load = (GLADloadproc)eglGetProcAddress;
        if (!gladLoadGLLoader(load)){
            cerr << "Failed to initialize GLAD" << endl;
            return 188;
        }

    // MacOS, Windows?
    #elif SYSTEM_NUM == 0

        // glfw: initialize and configure
        // ------------------------------
        glfwInit();
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

        #ifdef __APPLE__
        std::cout << "Apple!" << std::endl;
            glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
        #endif

        // glfw window creation
        // --------------------
        GLFWwindow* window = glfwCreateWindow(buffer_width, buffer_height, "LearnOpenGL", NULL, NULL);
        if (window == NULL)
        {
            std::cout << "Failed to create GLFW window" << std::endl;
            glfwTerminate();
            return -1;
        }
        glfwMakeContextCurrent(window);
        glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

        // glad: load all OpenGL function pointers
        // ---------------------------------------
        if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
        {
            std::cout << "Failed to initialize GLAD" << std::endl;
            return -1;
        }
    #endif

    const fs::path input_dir(program.get<std::string>("--input_dir"));
    const fs::path output_dir(program.get<std::string>("--output_dir"));
    if (input_dir.stem().string() == "x")
        exit(174); // Custom error code for checking if EGL is working
    assert_exists(input_dir);
    if (!fs::exists(output_dir))
        fs::create_directory(output_dir);

    std::vector<CameraView> camera_views;
    const std::string frame_str = "frame_" + zfill(4, frame_number);
    const auto camera_dir = input_dir / frame_str / "cameras";
    assert_exists(camera_dir);
    for (const auto &entry : fs::directory_iterator(camera_dir)){
        const auto matches = match_regex("T_([0-9]+_[0-9]+_[0-9]+)", entry.path().stem().string());
        if (!matches.empty()){
            const auto output_suffix = matches[1];
            camera_views.push_back({output_suffix, output_dir, camera_dir, buffer_width, buffer_height});
        }
    }

    const auto glsl = source_directory / "glsl";
    Shader spineShader((glsl / "wings.vert").c_str(), (glsl / "spine.frag").c_str(), (glsl / "spine.geom").c_str());
    Shader wingsShader((glsl / "wings.vert").c_str(), (glsl / "wings.frag").c_str(), (glsl / "wings.geom").c_str());
    Shader hairShader((glsl / "hair.vert").c_str(), (glsl / "hair.frag").c_str(), (glsl / "hair.geom").c_str());
    Shader nextShader((glsl / "next_wings.vert").c_str(), (glsl / "wings.frag").c_str(), (glsl / "wings.geom").c_str());

    glEnable(GL_DEPTH_TEST);
    glLineWidth(occlusion_boundary_line_width);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  

    GLint storage_buf_size;
    glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &storage_buf_size);
    const size_t max_buf_size = (((size_t)storage_buf_size)+1) / (1024 * 1024);
    std::cout << "GL_MAX_SHADER_STORAGE_BLOCK_SIZE is " << max_buf_size << " MB." << endl;

    /*
        Drawing the 3D meshes. Instances are small-ish so we draw them all at once. Non-instances are
        larger so we draw them in chunks. Smaller stride -> smaller maxmimum memory.
    */
   std::vector<json> all_bboxes;
    while (true) {
        const auto some_object_model = load_blender_mesh(input_dir / frame_str / "mesh" / "saved_mesh.json");
        if (some_object_model == nullptr)
            break;

        if (some_object_model->type == Mesh)
            all_bboxes.push_back(some_object_model->bounding_box);

        for (const auto &cd : camera_views){

            // DEPTH
            glBindFramebuffer(GL_FRAMEBUFFER, cd.framebuffer);
            cd.activateShader(wingsShader);

            if (some_object_model->type == Mesh)
                some_object_model->draw(wingsShader);

            cd.activateShader(hairShader);
            if (some_object_model->type == Hair)
                some_object_model->draw(hairShader);

            cd.activateShader(wingsShader);


            // OCCLUSION BOUNDARIES
            glBindFramebuffer(GL_FRAMEBUFFER, cd.framebuffer_ob);

            if (some_object_model->type == Mesh)
                some_object_model->draw(wingsShader);

            cd.activateShader(hairShader);
            if (some_object_model->type == Hair)
                some_object_model->draw(hairShader);

            cd.activateShader(spineShader);

            if (some_object_model->type == Mesh)
                some_object_model->draw(spineShader);

            // NEXT FACE IDS
            glBindFramebuffer(GL_FRAMEBUFFER, cd.framebuffer_next_faceids);
            cd.activateShader(nextShader);

            if (some_object_model->type == Mesh)
                some_object_model->draw(wingsShader);

        }
    }

    BaseBlenderObject::print_stats();

    for (const auto &cd : camera_views){
        glBindFramebuffer(GL_FRAMEBUFFER, cd.framebuffer);

        /*
        Save bounding boxes
        */
        {
            std::ofstream o(output_dir / ("Objects_" + cd.frame_string + ".json"));
            o << std::setw(4) << all_bboxes << std::endl;
        }

        /*
            Reading/Writing the depth map
        */
       Eigen::Tensor<double, 3> flow3d;
        {
        auto pixels = read_buffer<float>(GL_COLOR_ATTACHMENT1, buffer_width, buffer_height);
        Eigen::Tensor<double, 2> depth(buffer_height, buffer_width);
        depth.setConstant(std::numeric_limits<double>::max());
        Eigen::Tensor<double, 3> points_3d(buffer_height, buffer_width, 3);
        points_3d.setZero();
        for (const loop_obj &o : image_iterator(buffer_width, buffer_height, "Copying Depth")){
            if (pixels[o.j+2] > 0){
                for (int k=0; k<3; k++)
                    points_3d(o.y, o.x,k) = pixels[o.j+k];
                depth(o.y, o.x) = pixels[o.j+2];
            }
            o.progressbar();
        }
        auto depth_color = to_color_map(depth, 0.0, 0.90);
        imwrite(output_dir / ("Depth_" + cd.frame_string + ".png"), depth_color);
        save_npy(output_dir / ("Depth_" + cd.frame_string + ".npy"), depth);
        

        /*
            Reading/Writing the 3D optical flow
        */
        pixels = read_buffer<float>(GL_COLOR_ATTACHMENT2, buffer_width, buffer_height);
        Eigen::Tensor<double, 3> next_points_3d(buffer_height, buffer_width, 3);
        next_points_3d.setZero();
        for (const loop_obj &o : image_iterator(buffer_width, buffer_height, "Copying Optical Flow")){
            if (pixels[o.j+2] > 0){
                for (int k=0; k<3; k++)
                    next_points_3d(o.y, o.x,k) = pixels[o.j+k];
            }
            o.progressbar();
        }
        flow3d = cd.project(next_points_3d) - cd.project(points_3d);
        const auto flow_viz = compute_flow_viz(flow3d);
        imwrite(output_dir / ("Flow3D_" + cd.frame_string + ".png"), flow_viz);
        save_npy(output_dir / ("Flow3D_" + cd.frame_string + ".npy"), flow3d);
        }

        /*
            Reading/Writing the geometry normal
        */
       {
        const auto pixels = read_buffer<float>(GL_COLOR_ATTACHMENT7, buffer_width, buffer_height);
        Eigen::Tensor<double, 3> geo_normals(output_h, output_w, 3);
        geo_normals.setZero();
        for (const loop_obj &o : image_iterator(buffer_width, buffer_height, "Geometry Surface Normals")){
            for (int k=0; k<3; k++)
                geo_normals(o.y/2, o.x/2, k) += pixels[o.j+k];
            o.progressbar();
        }

        Eigen::Tensor<unsigned char, 3> geo_normal_color(output_h, output_w, 3);
        geo_normal_color.setZero();
        for (const loop_obj &o : image_iterator(output_w, output_h, "")){
            const double norm = std::pow(std::pow(geo_normals(o.y, o.x, 0), 2) + std::pow(geo_normals(o.y, o.x, 1), 2) + std::pow(geo_normals(o.y, o.x, 2), 2), 0.5);
            for (int k=0; k<3; k++){
                geo_normals(o.y, o.x, k) = geo_normals(o.y, o.x, k)/norm;
                geo_normal_color(o.y, o.x, k) = ((geo_normals(o.y, o.x, k) + 1) * (255/2));
            }
        }
        
        imwrite(output_dir / ("SurfaceNormal_" + cd.frame_string + ".png"), geo_normal_color);
        save_npy(output_dir / ("SurfaceNormal_" + cd.frame_string + ".npy"), geo_normals);
       }

        /*
            Reading/Writing the segmentation map
        */
        {
            const auto pixels = read_buffer<int>(GL_COLOR_ATTACHMENT6, buffer_width, buffer_height);
            Eigen::Tensor<long, 2> instance_seg(buffer_height, buffer_width);
            instance_seg.setZero();
            Eigen::Tensor<int, 2> object_seg(buffer_height, buffer_width);
            object_seg.setZero();
            for (const loop_obj &o : image_iterator(buffer_width, buffer_height, "Copying object & instance segmentation masks")){
                instance_seg(o.y, o.x) = InstanceID{pixels[o.j], pixels[o.j+1]}.as_long();
                object_seg(o.y, o.x) = pixels[o.j+2];
                o.progressbar();
            }
            save_npy(output_dir / ("InstanceSegmentation_" + cd.frame_string + ".npy"), instance_seg);
            imwrite(output_dir / ("InstanceSegmentation_" + cd.frame_string + ".png"), to_color_map(instance_seg.cast<int>()));
            save_npy(output_dir / ("ObjectSegmentation_" + cd.frame_string + ".npy"), object_seg);
            imwrite(output_dir / ("ObjectSegmentation_" + cd.frame_string + ".png"), to_color_map(object_seg));
        }
        {
            const auto pixels = read_buffer<int>(GL_COLOR_ATTACHMENT5, buffer_width, buffer_height);
            Eigen::Tensor<int, 2> tag_seg(buffer_height, buffer_width);
            tag_seg.setZero();
            for (const loop_obj &o : image_iterator(buffer_width, buffer_height, "Copying tag segmentation mask")){
                tag_seg(o.y, o.x) = pixels[o.j];
                o.progressbar();
            }
            save_npy(output_dir / ("TagSegmentation_" + cd.frame_string + ".npy"), tag_seg);
            imwrite(output_dir / ("TagSegmentation_" + cd.frame_string + ".png"), to_color_map(tag_seg));
        }


        /*
            Reading/Writing the face id map
        */
        {
        Eigen::Tensor<int, 4> faceids(2, buffer_height, buffer_width, 3);
        faceids.setZero();
        {
            const auto pixels = read_buffer<int>(GL_COLOR_ATTACHMENT3, buffer_width, buffer_height);
            for (const loop_obj &o : image_iterator(buffer_width, buffer_height, "Copying face ids from first frame")){
                for (int k=0; k<3; k++)
                    faceids(0, o.y, o.x, k) = pixels[o.j+k];
                o.progressbar();
            }
        }
        glBindFramebuffer(GL_FRAMEBUFFER, cd.framebuffer_next_faceids);
        {
            const auto pixels = read_buffer<int>(GL_COLOR_ATTACHMENT3, buffer_width, buffer_height);
            for (const loop_obj &o : image_iterator(buffer_width, buffer_height, "Copying face ids from second frame")){
                for (int k=0; k<3; k++)
                    faceids(1, o.y, o.x, k) = pixels[o.j+k];
                o.progressbar();
            }
        }
        Eigen::Array<unsigned char, -1, -1> flow_occlusion(buffer_height, buffer_width);
        for (const loop_obj &o : image_iterator(buffer_width, buffer_height, "Calculating flow occlusion")){
            const float fx = flow3d(o.y, o.x, 0);
            const float fy = flow3d(o.y, o.x, 1);
            bool match_exists = false;
            for (int i=-1; i<=1; i++){
                for (int j=-1; j<=1; j++){
                    const int next_x = o.x + lround(fx) + i;
                    const int next_y = o.y + lround(fy) + j;
                    const bool face_ids_match = (
                        (faceids(0, o.y, o.x, 0) == faceids(1, next_y, next_x, 0)) &&
                        (faceids(0, o.y, o.x, 1) == faceids(1, next_y, next_x, 1)) &&
                        (faceids(0, o.y, o.x, 2) == faceids(1, next_y, next_x, 2))
                    );
                    match_exists = match_exists || face_ids_match;
                }
            }
            flow_occlusion(o.y, o.x) = ((int)match_exists) * 255;
            o.progressbar();
        }
        imwrite(output_dir / ("Flow3DMask_" + cd.frame_string + ".png"), flow_occlusion);

        }

        /*
        //  Reading/Writing the face size in m^2
        read_buffer<float>(GL_COLOR_ATTACHMENT3, pixels, buffer_width, buffer_height);
        auto face_size = Eigen::Tensor<double, 2>(output_h,output_w);
        face_size.setZero();
        for (const loop_obj &o : image_iterator(buffer_width, buffer_height, "Copying Face-Sizes (in m^2)")){
            face_size(o.y/2, o.x/2) = pixels[o.j]/4;
            o.progressbar();
        }
        auto face_size_color = to_color_map(face_size, 0, 0.5, 0);
        imwrite(output_dir / ("FaceSizeCM" + cd.frame_string + ".png"), face_size_color);

        //    Reading/Writing the face size in pixels
        read_buffer<float>(GL_COLOR_ATTACHMENT4, pixels, buffer_width, buffer_height);
        auto pixel_size = Eigen::Tensor<double, 2>(output_h,output_w);
        pixel_size.setZero();
        for (const loop_obj &o : image_iterator(buffer_width, buffer_height, "Copying Face-Sizes (in pixels)")){
            pixel_size(o.y/2, o.x/2) = pixels[o.j]/4;
            o.progressbar();
        }
        auto pixel_size_color = to_color_map(pixel_size, 0, 0.5, 0);
        imwrite(output_dir / ("FaceSizePX" + cd.frame_string + ".png"), pixel_size_color);

        */

        glBindFramebuffer(GL_FRAMEBUFFER, cd.framebuffer_ob);

        /*
            Reading/Writing the occlusion boundaries
        */
       {
        const auto pixels = read_buffer<int>(GL_COLOR_ATTACHMENT0, buffer_width, buffer_height);
        Eigen::Array<unsigned char, -1, -1> occlusion_boundaries(buffer_height,buffer_width);
        occlusion_boundaries.setZero();
        for (const loop_obj &o : image_iterator(buffer_width, buffer_height, "Copying Occlusion Boundaries")){
            occlusion_boundaries(o.y, o.x) = pixels[o.j+1]*255;
            o.progressbar();
        }
        imwrite(output_dir / ("OcclusionBoundaries_" + cd.frame_string + ".png"), occlusion_boundaries);
       }

    }
    cout << "Done." << endl;
}

process_mesh/load_blender_mesh.hpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#include <iostream>
#include <string>
#include <vector>
#include <string>
#include <glm/glm.hpp>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <random>
#include <glm/glm.hpp>
#include "glm/gtx/string_cast.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include "utils.hpp"
#include "cnpy/cnpy.h"
#include "blender_object.hpp"
#include <nlohmann/json.hpp>
#include "io.hpp"

inline std::string truncate(const std::string &str, const size_t width){
    if (str.length() > width)
        return str.substr(0, width-3) + "...";
    return str + std::string(width - str.length(), ' ');
}

std::shared_ptr<BaseBlenderObject> load_blender_mesh(const fs::path json_path);

std::vector<unsigned int> generate_buffer(const std::vector<unsigned int> &indices);



process_mesh/load_blender_mesh.cpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#include <random>
#include <iostream>
#include <functional> //without .h
#include <indicators/progress_bar.hpp>
#include <regex>
#include <unordered_map>
#include <unordered_set>
#include "string_tools.hpp"
#include "load_blender_mesh.hpp"
#include "buffer_arrays.hpp"

using json = nlohmann::json;
using namespace indicators;
using namespace indicators::option;

auto parse_json(const fs::path json_path){
    const json data = json::parse(std::ifstream(json_path));
    std::unordered_map<std::string, ObjectInfo> output;
    for (const auto &instance_item : data){
        if (instance_item.contains("filename")){
            const ObjectInfo ii(instance_item);
            MRASSERT(output.count(ii.mesh_id) == 0, ii.mesh_id);
            output[ii.mesh_id] = ii;
        }
    }
    return output;
}

std::shared_ptr<BaseBlenderObject> load_blender_mesh(const fs::path json_path){
    assert_exists(json_path);

    // Progress bar
    static int object_idx = 0;
    static ProgressBar bar{
        BarWidth{20}, Start{"["}, End{"]"},
        ShowElapsedTime{true}, ShowRemainingTime{true},
        ForegroundColor{Color::blue},
        FontStyles{std::vector<FontStyle>{FontStyle::bold}}
    };
    if (object_idx == 0){
        bar.set_option(PrefixText{truncate(std::string("Loading..."), 20)});
        bar.set_progress(0);
    }

    static std::unordered_map<std::string, npz> npz_lookup;

    // Current frame
    static BufferArrays current_buf;
    static ObjectInfo current_obj;
    static const auto info_lookup = parse_json(json_path);

    // Next frame
    static BufferArrays next_buf;
    static ObjectInfo next_obj;
    static const auto next_info_lookup = parse_json(increment_int_substr({"frame_([0-9]{4})"}, json_path));

    static auto it = info_lookup.begin();

    if (current_buf.is_empty()){
        // while ((it != info_lookup.end()) && match_regex(".*errain.*", it->second.name).empty()) it++;
        if (it == info_lookup.end())
            return nullptr;
        const std::string current_mesh_id = it->first;

        // Current frame
        current_obj = it->second;
        const fs::path current_npz_path = json_path.parent_path() / current_obj.npz_filename;
        if (npz_lookup.count(current_npz_path.string()) == 0)
            npz_lookup[current_npz_path.string()] = current_npz_path;
        const npz &current_npz = npz_lookup.at(current_npz_path.string());
        current_buf = BufferArrays(current_npz, current_mesh_id, current_obj.type);

        bar.set_option(PrefixText{"Loading " + truncate(current_obj.name, 20) + " " + std::to_string(object_idx++) + "/" + std::to_string(info_lookup.size())});

        if (next_info_lookup.count(current_mesh_id) > 0){
            next_obj = next_info_lookup.at(current_mesh_id);
            const fs::path next_npz_path = fs::path(increment_int_substr({"frame_([0-9]{4})"}, json_path.parent_path())) / next_obj.npz_filename;
            if (npz_lookup.count(next_npz_path.string()) == 0)
                npz_lookup[next_npz_path.string()] = next_npz_path;
            const npz &next_npz = npz_lookup.at(next_npz_path.string());
            next_buf = BufferArrays(next_npz, current_mesh_id, next_obj.type);
        } else {
            next_buf = current_buf;
        }
        it++;
    }

    std::shared_ptr<BaseBlenderObject> new_obj;
    if (current_obj.type == "MESH"){
        const auto instance_ids = current_buf.get_some_instance_ids(1e8);
        new_obj = std::shared_ptr<BaseBlenderObject>(new MeshBlenderObject(current_buf, next_buf, instance_ids, current_obj));
        current_buf.remove_instances(instance_ids);
    } else if (current_obj.type == "CURVES"){
        const auto all_instance_ids = current_buf.get_some_instance_ids();
        new_obj = std::shared_ptr<BaseBlenderObject>(new CurvesBlenderObject(current_buf, next_buf, all_instance_ids, current_obj));
        current_buf.remove_instances(all_instance_ids);
    }
    bar.set_progress((object_idx * 100)/info_lookup.size());
    RASSERT((object_idx == info_lookup.size()) == (it == info_lookup.end()));
    return new_obj;
}

process_mesh/io.hpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#pragma once
#include <iostream>
#include <fstream>
#include <memory>
#include <glad/glad.h>
#include <Eigen/Dense>
#include <unsupported/Eigen/CXX11/Tensor>
#include <tinycolormap.hpp>
typedef tinycolormap::ColormapType clrmap;
#include <indicators/progress_bar.hpp>
#include "cnpy/cnpy.h"
#include <array>

#if __has_include(<filesystem>)
  #include <filesystem>
  namespace fs = std::filesystem;
#elif __has_include(<experimental/filesystem>)
  #include <experimental/filesystem> 
  namespace fs = std::experimental::filesystem;
#else
  error "Missing the <filesystem> header."
#endif

void imwrite(const fs::path filepath, const Eigen::Tensor<unsigned char, 3> &image);

void imwrite(const fs::path filepath, const Eigen::Array<unsigned char, -1, -1> &image);

template <typename T, int S>
void save_npy(const fs::path filepath, const Eigen::Tensor<T, S> &mat){
  assert (filepath.extension() == ".npy");
  std::vector<size_t> dims(S);
  for (int i=0; i<S; i++)
    dims[i] = mat.dimension(i);

  std::array<int, S> shuffle;
  if constexpr (S == 3)
    shuffle = {2, 1, 0};
  else if constexpr (S == 2)
    shuffle = {1, 0};

  const Eigen::Tensor<T, S, Eigen::RowMajor> swapped = mat.swap_layout().shuffle(shuffle);

  if constexpr(std::is_same<T, double>::value){
    const Eigen::Tensor<float, S, Eigen::RowMajor> tmp = swapped.template cast<float>();
    cnpy::npy_save(filepath.c_str(), tmp.data(), dims, "w");
  } else {
    cnpy::npy_save(filepath.c_str(), swapped.data(), dims, "w");
  }
}

Eigen::MatrixXd read_npy(const fs::path filepath);

void assert_exists(const fs::path &filepath);

std::array<int, 2> get_png_size(const fs::path &image_path);

process_mesh/io.cpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#include <iostream>
#include <fstream>
#include <math.h>
#include <limits>
#include <unsupported/Eigen/CXX11/Tensor>
#include <arpa/inet.h> // or <winsock.h>
#include "io.hpp"
#include "utils.hpp"
#include "cnpy/cnpy.h"
#include "colorcode.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb/stb_image_write.h"


void imwrite(const fs::path filepath, const Eigen::Array<unsigned char, -1, -1> &image){
    const int H = image.rows();
    const int W = image.cols();
    std::vector<u_char> color_data_vec(H*W);

    for (int i = 0; i < W*H; i++) {
        const int x = i%W;
        const int y = i/W;
        color_data_vec[i] = image(y,x);
    }

    stbi_write_png(filepath.c_str(), W, H, 1, &color_data_vec[0], W);
}

void imwrite(const fs::path filepath, const Eigen::Tensor<unsigned char, 3> &image){
    const int H = image.dimension(0);
    const int W = image.dimension(1);
    std::vector<u_char> color_data_vec(H*W*3);

    for (int i = 0; i < W*H; i++) {
        const int x = i%W;
        const int y = i/W;
          for (int k=0; k<3; k++)
              color_data_vec[i*3 + k] = image(y,x,k);
    }

    stbi_write_png(filepath.c_str(), W, H, 3, &color_data_vec[0], W*3);
}

Eigen::MatrixXd read_npy(const fs::path filepath){
    assert_exists(filepath);
    const cnpy::NpyArray myarr = cnpy::npy_load(filepath.c_str());
    const double *x = myarr.data<double>();
    const std::vector<double> v(x, x + myarr.num_bytes()/sizeof(double));

    const int W = myarr.shape[1];
    const int H = myarr.shape[0];
    Eigen::ArrayXXd output_data(H,W);
    for (int i=0; i<v.size(); i++){
        assert (fabs(v[i]) < 1e6);
        output_data(i/W, i%W) = v[i];
    }
    return output_data;
}

void assert_exists(const fs::path &filepath){
    MRASSERT(fs::exists(filepath), "Error: " + filepath.string() + " does not exist.");
}

std::array<int, 2> get_png_size(const fs::path &image_path){
    RASSERT(image_path.extension().string() == ".png");
    assert_exists(image_path);
    std::ifstream in(image_path.c_str());
    int width, height;

    in.seekg(16);
    in.read((char *)&width, 4);
    in.read((char *)&height, 4);

    width = ntohl(width);
    height = ntohl(height);

    return {width, height};
}

process_mesh/depth_example.png METASEP

process_mesh/camera_view.hpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#include "shader.hpp"
#include "utils.hpp"
#include <glad/glad.h>
#include "io.hpp"


class CameraView
{

private:

    float calc_resolution_scale();
    unsigned int create_framebuffer();

    glm::mat4 wc2img, projection, current_frame_view_matrix, next_frame_view_matrix;
    glm::vec3 position;
    double fx, fy, cx, cy;
    const int buffer_width, buffer_height;
    const fs::path frames_directory;

public:

    const std::string frame_string;
    unsigned int framebuffer, framebuffer_ob, framebuffer_next_faceids;

    CameraView(const std::string fstr, const fs::path fdir, const fs::path input_dir, const int width, const int height);
    void activateShader(Shader &shader) const;
    Eigen::Tensor<double, 3> project(const Eigen::Tensor<double, 3> &cam_coords) const;
    
};

process_mesh/camera_view.cpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "camera_view.hpp"
#include "string_tools.hpp"
#include "utils.hpp"

using Eigen::Matrix4f, Eigen::Matrix3f, Eigen::Tensor;

unsigned int CameraView::create_framebuffer(){
    unsigned int framebuffer;
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);  
    constexpr GLenum color_attachments[8] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5, GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT7};
    constexpr bool is_float[8] = {false, true, true, false, true, false, false, true};
    constexpr size_t num_color_attachments = sizeof(color_attachments)/sizeof(GLenum);
    glDrawBuffers(num_color_attachments, color_attachments);
    unsigned int textureColorbuffers[num_color_attachments];
    for (int ai=0; ai<num_color_attachments; ai++){
        // generate texture
        GLenum col_attach = color_attachments[ai];
        unsigned int textureColorbuffer;
        glGenTextures(1, &textureColorbuffer);
        textureColorbuffers[ai] = textureColorbuffer;
        glActiveTexture(GL_TEXTURE0 + ai);
        glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
        if (is_float[ai])
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, buffer_width, buffer_height, 0, GL_RGBA, GL_FLOAT, NULL);
        else
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32I, buffer_width, buffer_height, 0, GL_RGBA_INTEGER, GL_INT, NULL);
        glCheckError();
        glFramebufferTexture2D(GL_FRAMEBUFFER, col_attach, GL_TEXTURE_2D, textureColorbuffer, 0);  // attach it to currently bound framebuffer object
    }

    unsigned int rbo;
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo); 
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, buffer_width, buffer_height);
    glBindRenderbuffer(GL_RENDERBUFFER, 0);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
    assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    return framebuffer;
}

const Matrix4f FLIP_Y_Z = Eigen::Vector4f({1,-1,-1,1}).asDiagonal();

float CameraView::calc_resolution_scale(){
    const auto image_shape = get_png_size(frames_directory / ("Image_" + frame_string + ".png"));
    RASSERT((buffer_width % image_shape[0]) == 0);
    RASSERT((buffer_height % image_shape[1]) == 0);
    RASSERT((buffer_height / image_shape[1]) == (buffer_width / image_shape[0]));
    return buffer_height / image_shape[1];
}

CameraView::CameraView(const std::string fstr, const fs::path fdir, const fs::path input_dir, const int width, const int height) : frame_string(fstr), frames_directory(fdir), buffer_width(width), buffer_height(height)
{
    // Current Frame
    const fs::path current_frame_cam_path = input_dir / ("T_"+frame_string+".npy");
    const Matrix4f blender_camera_pose = read_npy(current_frame_cam_path).cast<float>() * FLIP_Y_Z; // TODO REMOVE
    current_frame_view_matrix = glm::make_mat4(Matrix4f(blender_camera_pose.inverse()).data());

    // Next Frame
    const fs::path next_frame_cam_path = increment_int_substr({"frame_([0-9]{4})", "T_([0-9]{4})_00_00"}, current_frame_cam_path);
    const Matrix4f next_blender_camera_pose = read_npy(next_frame_cam_path).cast<float>() * FLIP_Y_Z; // TODO REMOVE
    next_frame_view_matrix = glm::make_mat4(Matrix4f(next_blender_camera_pose.inverse()).data());

    // Set Camera Position
    position = glm::make_vec3(blender_camera_pose.block<3, 1>(0, 3).data());

    // Set WC -> Img Transformation
    const Matrix3f K_mat3x3 = read_npy(input_dir / ("K_"+frame_string+".npy")).cast<float>();
    Matrix4f K_mat = Matrix4f::Identity();
    K_mat.block<2,3>(0, 0) = calc_resolution_scale() * K_mat3x3.block<2,3>(0, 0);
    wc2img = glm::make_mat4(Matrix4f(K_mat * FLIP_Y_Z * blender_camera_pose.inverse()).data());

    fx = K_mat(0,0);
    fy = K_mat(1,1);
    cx = K_mat(0,2);
    cy = K_mat(1,2);
    // Source https://stackoverflow.com/a/22312303/5057543
    const double near = 0.1;
    const double far = 10000.0;
    projection = glm::mat4(0);
    projection[0][0] = fx / cx;
    projection[1][1] = fy / cy;
    projection[2][2] = -(far+near)/(far-near);
    projection[3][2] = -(2*far*near)/(far-near);
    projection[2][3] = -1.0;

    framebuffer = create_framebuffer();
    framebuffer_ob = create_framebuffer();
    framebuffer_next_faceids = create_framebuffer();
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

    /* clear the color buffer */
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

void CameraView::activateShader(Shader &shader) const {
    shader.use();
    shader.setMat4("projection", projection);
    shader.setMat4("view", current_frame_view_matrix);
    shader.setMat4("viewNext", next_frame_view_matrix);
    shader.setMat4("wc2img", wc2img);
    shader.setVec3("cameraPos", position);
}

Tensor<double, 3> CameraView::project(const Tensor<double, 3> &cam_coords) const {
    const size_t width = cam_coords.dimension(1);
    const size_t height = cam_coords.dimension(0);
    Tensor<double, 3> output(height, width, 3);
    output.setZero();
    for (int x=0; x<width; x++){
        for (int y=0; y<height; y++){
            const double z = cam_coords(y, x, 2);
            const double u = cam_coords(y, x, 0) * (fx / z) + cx;
            const double v = cam_coords(y, x, 1) * (fy / z) + cy;
            output(y, x, 0) = u; output(y, x, 1) = v; output(y, x, 2) = z;
        }
    }
    return output;
}

process_mesh/buffer_arrays.hpp METASEP
#pragma once
#include <vector>
#include <unordered_map>
#include <Eigen/Dense>
#include <iostream>
#include "cnpy/cnpy.h"
#include "utils.hpp"
#include "io.hpp"

struct InstanceID {
    const int n1, n2;

    // https://codereview.stackexchange.com/a/2608
    long as_long() const {
        const unsigned int n1ui = n1;
        const unsigned int n2ui = n2;
        return (((size_t) n2ui) << 32) | ((size_t) n1ui);
    }
};

inline bool operator==(const InstanceID& lhs, const InstanceID& rhs)
{
    return lhs.as_long() == rhs.as_long();
}

template <>
struct std::hash<InstanceID>
{
  std::size_t operator()(const InstanceID& k) const
  {
    return hash<int>()(k.as_long());
  }
};

class npz {
private:
  cnpy::npz_t lookup;

public:
  fs::path path;

  npz() {}

  npz(const fs::path p) : path(p) {
    assert_exists(path);
    RASSERT(path.extension() == ".npz");
    try {
        lookup = cnpy::npz_load(path);
    }
    catch(const std::exception& e) {
        throw std::runtime_error("Couldn't open " + path.string() + " - probably a BadZipFile error.");
    }
  }

  bool check_key(const std::string &key) const {
    return (lookup.count(key) != 0);
  }

    template<typename T>
    std::vector<T> read_data(const std::string &key) const {
        if (!check_key(key)){
            std::cerr << "Key " << key << " not found in " << path << std::endl;
            exit(1);
        }
        cnpy::NpyArray arr = lookup.at(key);
        T* arr_ptr = arr.data<T>();
        return std::vector<T>(arr_ptr, arr_ptr+arr.num_vals);
    }

};

class BufferArrays
{
public:
    std::vector<int> tag_lookup;
    std::vector<float> lookup;
    std::vector<unsigned int> indices;
    std::unordered_map<InstanceID, Eigen::Matrix4f> model_mats;

    BufferArrays(){}

    BufferArrays(const npz &my_npz, std::string mesh_id, std::string obj_type);

    size_t sizeof_instance() const {
        return indices.size();
    }

    void clear(){
        model_mats.clear();
        RASSERT(is_empty());
    }

    bool is_empty() const {
        return model_mats.empty();
    }

    std::vector<InstanceID> get_some_instance_ids(const size_t max_size=std::numeric_limits<size_t>::max()) const {
        std::vector<InstanceID> keys;
        for (const auto &kv : model_mats){
            if ((keys.size() * sizeof_instance()) < max_size)
                keys.push_back(kv.first);
        }
        return keys;
    }

    void remove_instances(const std::vector<InstanceID> &keys) {
        for (const auto &key : keys){
            const auto keyval = model_mats.find(key);
            if (keyval != model_mats.end())
                model_mats.erase(keyval);
        }
    }

    std::vector<Eigen::Matrix4f> get_instances(const std::vector<InstanceID> &keys) const {
        std::vector<Eigen::Matrix4f> matrix_worlds_subset;
        for (const auto &key : keys){
            const auto keyval = model_mats.find(key);
            if (keyval != model_mats.end())
                matrix_worlds_subset.push_back(keyval->second);
            else
                matrix_worlds_subset.push_back(Eigen::Matrix4f::Zero(4,4));
        }
        return matrix_worlds_subset;
    }

};

process_mesh/buffer_arrays.cpp METASEP
#include "buffer_arrays.hpp"
#include <string>
#include <unordered_map>
#include <map>
#include <set>
#include "utils.hpp"

template <typename T>
std::vector<T> triangulate_face(std::vector<T> &polygon){
    std::vector<T> output;
    const int num_tri_verts = ((int)(polygon.size()) - 2) * 3;
    output.reserve(num_tri_verts);

    while (polygon.size() > 2){
        const T a = polygon.back();
        polygon.pop_back();
        const T b = polygon.back();
        polygon.pop_back();
        const T c = polygon.back();

        output.push_back(a);
        output.push_back(b);
        output.push_back(c);

        polygon.push_back(a);
    }
    return output;
}

void curve_quartet(const float *verts, const float *radii, std::vector<float> &point_lookup, std::vector<unsigned int> &indices, int offs){
    using Eigen::Vector3f, Eigen::Map;
    std::array<Vector3f, 7> P;
    for (int pt=0; pt<5; pt++)
        P[pt+1] = Map<const Vector3f>(verts+pt*3); // fill 1-5, still need 0 & 6

    P[0] = P[1] + (P[1] - P[2]);
    P[6] = P[5] + (P[5] - P[4]);

    for (int p=0; p<7; p++){
        const auto v = P[p];
        point_lookup.insert(point_lookup.end(), v.begin(), v.end());
        const int r = std::clamp(p-1, 0, 4);
        point_lookup.push_back(radii[r]);
    }

    for (int seg=0; seg<4; seg++){
        for (int p=0; p<4; p++)
            indices.push_back(offs + seg + p);
    }
}

std::vector<unsigned int> generate_buffer(const std::vector<unsigned int> &indices){

    using std::unordered_map, std::map, std::set, std::vector;

    unordered_map<uint, map<uint, set<uint>>> edge_neighbors;
    for (int i=0; i < indices.size(); i+=3){
        std::array<uint, 3> tri = {indices[i], indices[i+1], indices[i+2]};
        std::sort(tri.begin(), tri.end());
        edge_neighbors[tri[0]][tri[1]].insert(tri[2]);
        edge_neighbors[tri[0]][tri[2]].insert(tri[1]);
        edge_neighbors[tri[1]][tri[2]].insert(tri[0]);
    }

    vector<unsigned int> vertices;
    for (const auto &keyval : edge_neighbors){
        const uint &v1 = keyval.first;
        const map<uint, set<uint>> &mapping = keyval.second;
        for (const auto &v2_v3s : mapping){
            const auto &v2 = v2_v3s.first;
            vector<uint> v3s;
            v3s.insert(v3s.end(), v2_v3s.second.begin(), v2_v3s.second.end());
            RASSERT(v3s.size() == v2_v3s.second.size());
            if (v3s.size() == 1)
                v3s.push_back(v3s[0]); // i.e. treat dangling edges as two triangles folded together
            RASSERT(v3s.size() >= 2);
            for (int i=0; i<v3s.size(); i++){
                for (int j=0; j<i; j++){
                    for (const uint idx : {v1, v2, v3s[i], v3s[j]}){
                        vertices.push_back(idx);
                    }
                }
            }
        }
    }
    return vertices;
  }

BufferArrays::BufferArrays(const npz &my_npz, std::string mesh_id, std::string obj_type){

    {
        const std::vector<int> instance_ids = my_npz.read_data<int>(mesh_id + "_instance_ids");
        const auto mwd = my_npz.read_data<float>(mesh_id + "_transformations");
        RASSERT((mwd.size()/16) == instance_ids.size()/2);
        for (int i=0; i<(mwd.size()/16); i++)
            model_mats[{instance_ids[i*2], instance_ids[i*2+1]}] = Eigen::Matrix<float, 4, 4, Eigen::RowMajor>(&mwd[i*16]);
    }

    if (obj_type == "MESH") {

        lookup = my_npz.read_data<float>(mesh_id + "_vertices");
        // const auto face_tag_lookup = my_npz.read_data<int>(mesh_id + "_masktag");
        // tag_lookup.resize(lookup.size());
        tag_lookup = my_npz.read_data<int>(mesh_id + "_masktag");

        const auto loop_totals = my_npz.read_data<int>(mesh_id + "_loop_totals");
        // MRASSERT(loop_totals.size() == face_tag_lookup.size(), "loop_totals.size() ["+std::to_string(loop_totals.size())+"] != tag_lookup.size() ["+std::to_string(face_tag_lookup.size())+"]");

        const auto npy_data = my_npz.read_data<int>(mesh_id + "_indices");
        auto it = npy_data.begin();
        int face_index = 0;
        for (const int &polygon_size : loop_totals){
            // const int face_id = face_tag_lookup[face_index++];
            std::vector<int> polygon(it, it+polygon_size);
            const std::vector<int> triangles = triangulate_face(polygon);
            // for (const int &t : triangles)
            //     tag_lookup[t] = std::max(face_id, tag_lookup[t]); // tag is per-vertex, ideally should be per-face
            indices.insert(indices.end(),triangles.begin(),triangles.end());
            it += polygon_size;
        }

        indices = generate_buffer(indices);

    } else if (obj_type == "CURVES") {
        const auto vert_data = my_npz.read_data<float>(mesh_id + "_vertices");
        const auto radii_data = my_npz.read_data<float>(mesh_id + "_radii");
        const size_t num_hairs = vert_data.size() / (5*3);
        // std::cout << "We've got hair!: " << num_hairs << std::endl;
        for (int hair_idx=0; hair_idx < num_hairs; hair_idx++)
            curve_quartet(vert_data.data()+(hair_idx*5*3), radii_data.data()+(hair_idx*5), lookup, indices, hair_idx*7);
    } else {
        throw std::runtime_error("");
    }
}

process_mesh/blender_object.hpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#pragma once
#include <vector>
#include "glm/gtx/string_cast.hpp"
#include <Eigen/Dense>
#include <chrono>
#include "shader.hpp"
#include <nlohmann/json.hpp>
#include "buffer_arrays.hpp"

using json = nlohmann::json;

struct ObjectInfo
{
    int index, num_instances;
    std::string name, type, mesh_id, npz_filename;

    ObjectInfo(){}

    ObjectInfo(nlohmann::json_abi_v3_11_2::json instance_item) :
    name(instance_item["object_name"].get<std::string>()),
    type(instance_item["object_type"].get<std::string>()),
    index(instance_item["object_idx"].get<int>()),
    num_instances(instance_item["num_instances"].get<int>()),
    mesh_id(instance_item["mesh_id"].get<std::string>()),
    npz_filename(instance_item["filename"].get<std::string>()){}

};

enum ObjectType { Mesh, Hair };

class BaseBlenderObject
{

private:

    void set_matrix_buffer(unsigned int &buffer, const std::vector<Eigen::Matrix4f> &model_matrices_next, int attrib_idx);
    json compute_bbox(const std::vector<unsigned int> &indices, const std::vector<float> &vertex_lookup, const std::vector<InstanceID> &instance_ids, const std::vector<Eigen::Matrix4f> &model_matrices, const std::vector<int> &tag_lookup, const int &attrib_stride);

protected:

    static inline std::chrono::duration<double, std::milli> total_elapsed_drawing, total_elapsed_sending;
    static inline size_t num_draw_calls = 0;
    unsigned int VAO, EBO, VBO, VBO_next, VBO_matrices, VBO_matrices_next, VBO_instance_ids, VBO_tag;
    const size_t num_verts, num_instances;
    size_t indices_buf_size, lookup_buf_size;

public:

    json bounding_box;
    const ObjectType type;
    const std::string name;
    const int obj_index;

    BaseBlenderObject(const BufferArrays &current_buf, const BufferArrays &next_buf, const std::vector<InstanceID> &instance_ids, const ObjectInfo& object_info, const ObjectType tp, int attrib_stride);
    virtual ~BaseBlenderObject();
    virtual void draw(Shader &shader) const;
    static void print_stats();
};


class MeshBlenderObject : public BaseBlenderObject
{
public:

    MeshBlenderObject(const BufferArrays &current_buf, const BufferArrays &next_buf, const std::vector<InstanceID> &instance_ids, const ObjectInfo& object_info);
    ~MeshBlenderObject();
    void draw(Shader &shader) const;
};

class CurvesBlenderObject : public BaseBlenderObject
{
public:

    CurvesBlenderObject(const BufferArrays &current_buf, const BufferArrays &next_buf, const std::vector<InstanceID> &instance_ids, const ObjectInfo& object_info);
    ~CurvesBlenderObject();
    void draw(Shader &shader) const;
};

process_mesh/blender_object.cpp METASEP
// Copyright (c) Princeton University.
// This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

// Authors: Lahav Lipson
// Date Signed: May 2 2023

#include "blender_object.hpp"
#include <glad/glad.h>
#include <random>
#include <iostream>
#include <regex>
#include <set>
#include <limits>
#include "utils.hpp"
#include "buffer_arrays.hpp"
using std::cout;
using std::endl;

template <typename T>
void set_regular_buffer(unsigned int &buffer, const std::vector<T> &data_vec, int attrib_idx, int attrib_size, int attrib_stride){
    glGenBuffers(1, &buffer);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, data_vec.size() * sizeof(T), data_vec.data(), GL_STATIC_DRAW);

    glEnableVertexAttribArray(attrib_idx);
    static_assert(std::is_same<T,float>::value || std::is_same<T,int>::value);
    if constexpr (std::is_same<T,float>::value)
        glVertexAttribPointer(attrib_idx, attrib_size, GL_FLOAT, GL_FALSE, attrib_stride * sizeof(T), 0);
    else if constexpr (std::is_same<T,int>::value)
        glVertexAttribIPointer(attrib_idx, attrib_size, GL_INT, attrib_stride * sizeof(T), 0);
}

void BaseBlenderObject::set_matrix_buffer(unsigned int &buffer, const std::vector<Eigen::Matrix4f> &model_matrices_next, int attrib_idx){
    glGenBuffers(1, &buffer);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, num_instances * sizeof(Eigen::Matrix4f), model_matrices_next.data(), GL_STATIC_DRAW);

    // vertex attributes
    std::size_t vec4Size = sizeof(Eigen::RowVector4f);
    for (int ii=0; ii<4; ii++){
        glEnableVertexAttribArray(ii+attrib_idx);
        glVertexAttribPointer(ii+attrib_idx, 4, GL_FLOAT, GL_FALSE, 4 * vec4Size, (void*)(ii * vec4Size));
    }

    for (int ii=0; ii<4; ii++)
        glVertexAttribDivisor(ii+attrib_idx, 1);
}

json BaseBlenderObject::compute_bbox(const std::vector<unsigned int> &indices, const std::vector<float> &vertex_lookup, const std::vector<InstanceID> &instance_ids, const std::vector<Eigen::Matrix4f> &model_matrices, const std::vector<int> &tag_lookup, const int &attrib_stride){
    constexpr float inf = std::numeric_limits<float>::infinity();
    Eigen::Vector3f max({-inf, -inf, -inf}), min({inf, inf, inf});
    for (const auto &idx : indices){
        for (int i=0; i<3; i++){
            max(i) = std::max(max(i), vertex_lookup[idx * attrib_stride + i]);
            min(i) = std::min(min(i), vertex_lookup[idx * attrib_stride + i]);
        }
    }

    int idx = 0;
    std::unordered_map<std::string, json> json_serializable_model_matrices;
    for (const auto &m : model_matrices){
        const auto instance_id = std::to_string(instance_ids[idx++].as_long());
        json_serializable_model_matrices[instance_id] = {
            {m(0,0), m(0,1), m(0,2), m(0,3)},
            {m(1,0), m(1,1), m(1,2), m(1,3)},
            {m(2,0), m(2,1), m(2,2), m(2,3)},
            {m(3,0), m(3,1), m(3,2), m(3,3)},
        };
    }

    MRASSERT(json(json_serializable_model_matrices).is_object(), "is not object");

    const std::set<int> unique_tags(tag_lookup.begin(), tag_lookup.end());

    json output = {
        {"model matrices", json_serializable_model_matrices},
        {"tags", std::vector<int>(unique_tags.begin(), unique_tags.end())},
        {"name", name},
        {"object index", obj_index}
    };

    if ((num_verts > 0) && ((max - min).norm() > 1e-4)){
        output["min"] = {min(0), min(1), min(2)};
        output["max"] = {max(0), max(1), max(2)};
    } else {
        output["min"] = nullptr;
        output["max"] = nullptr;
    }

    return output;
}

BaseBlenderObject::BaseBlenderObject(const BufferArrays &current_buf, const BufferArrays &next_buf, const std::vector<InstanceID> &instance_ids, const ObjectInfo& object_info, const ObjectType tp, int attrib_stride)
 : num_verts(current_buf.indices.size()), type(tp), name(object_info.name), num_instances(instance_ids.size()), obj_index(object_info.index) {

        const std::vector<Eigen::Matrix4f> &model_matrices = current_buf.get_instances(instance_ids);
        const std::vector<Eigen::Matrix4f> &model_matrices_next = next_buf.get_instances(instance_ids);

        MRASSERT(model_matrices.size() == num_instances, "Incorrect number of instances");
        MRASSERT(model_matrices_next.size() == num_instances, "Incorrect number of instances");
        const auto t1 = std::chrono::high_resolution_clock::now();

        const auto &indices = current_buf.indices;
        const auto &vertex_lookup = current_buf.lookup;
        const auto &vertex_lookup_next = next_buf.lookup;
        const auto &tag_lookup = current_buf.tag_lookup;

        glGenVertexArrays(1, &VAO);
        glBindVertexArray(VAO);

        // Vertices
        glGenBuffers(1, &EBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
        indices_buf_size = indices.size()*sizeof(unsigned int);
        lookup_buf_size = vertex_lookup.size() * sizeof(float);

        set_matrix_buffer(VBO_matrices, model_matrices, 0);
        set_matrix_buffer(VBO_matrices_next, model_matrices_next, 4);

        set_regular_buffer(VBO, vertex_lookup, 8, 3, attrib_stride);
        set_regular_buffer(VBO_next, vertex_lookup_next, 9, 3, attrib_stride);

        static_assert(sizeof(int)*2 == sizeof(InstanceID));
        glGenBuffers(1, &VBO_instance_ids);
        glBindBuffer(GL_ARRAY_BUFFER, VBO_instance_ids);
        glBufferData(GL_ARRAY_BUFFER, num_instances * sizeof(InstanceID), instance_ids.data(), GL_STATIC_DRAW);
        glEnableVertexAttribArray(10);
        glVertexAttribIPointer(10, 2, GL_INT, sizeof(InstanceID), 0);
        glVertexAttribDivisor(10, 1);

        set_regular_buffer(VBO_tag, tag_lookup, 11, 1, 1);

        total_elapsed_sending += (std::chrono::high_resolution_clock::now() - t1);
        num_draw_calls++;

        bounding_box = compute_bbox(indices, vertex_lookup, instance_ids, model_matrices, tag_lookup, attrib_stride);
}

void BaseBlenderObject::draw(Shader &shader) const {
    throw std::runtime_error("Base class draw() called!");
}

void BaseBlenderObject::print_stats() {
    std::cout << "Spent " << total_elapsed_drawing.count() << "milliseconds in draw calls." << std::endl;
    std::cout << "Spent " << total_elapsed_sending.count() << "milliseconds across " << num_draw_calls << " buffer calls." << std::endl;
}

BaseBlenderObject::~BaseBlenderObject(){
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, lookup_buf_size, nullptr, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, VBO_next);
    glBufferData(GL_ARRAY_BUFFER, lookup_buf_size, nullptr, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, VBO_matrices);
    glBufferData(GL_ARRAY_BUFFER, num_instances * sizeof(Eigen::Matrix4f), nullptr, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, VBO_matrices_next);
    glBufferData(GL_ARRAY_BUFFER, num_instances * sizeof(Eigen::Matrix4f), nullptr, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, VBO_instance_ids);
    glBufferData(GL_ARRAY_BUFFER, num_instances * sizeof(int), nullptr, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_buf_size, nullptr, GL_STATIC_DRAW);
    glDeleteVertexArrays(1, &VAO);
    unsigned int to_delete[7] = {EBO, VBO, VBO_next, VBO_matrices, VBO_matrices_next, VBO_instance_ids, VBO_tag};
    glDeleteBuffers(7, to_delete);
}

MeshBlenderObject::MeshBlenderObject(const BufferArrays &current_buf, const BufferArrays &next_buf, const std::vector<InstanceID> &instance_ids, const ObjectInfo& object_info)
 : BaseBlenderObject(current_buf, next_buf, instance_ids, object_info, Mesh, 3) {
    glBindVertexArray(0);
}
MeshBlenderObject::~MeshBlenderObject(){}

void MeshBlenderObject::draw(Shader &shader) const {
    const auto t1 = std::chrono::high_resolution_clock::now();
    shader.setInt("object_index", obj_index);
    glBindVertexArray(VAO);
    glDrawElementsInstanced(GL_LINES_ADJACENCY, num_verts, GL_UNSIGNED_INT, 0, num_instances);
    glCheckError();
    total_elapsed_drawing += (std::chrono::high_resolution_clock::now() - t1);
    glBindVertexArray(0);
}


CurvesBlenderObject::CurvesBlenderObject(const BufferArrays &current_buf, const BufferArrays &next_buf, const std::vector<InstanceID> &instance_ids, const ObjectInfo& object_info)
 : BaseBlenderObject(current_buf, next_buf, instance_ids, object_info, Hair, 4){
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glEnableVertexAttribArray(12); // Radius
    glVertexAttribPointer(12, 1, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(sizeof(float)*3));
    glBindVertexArray(0);
}
CurvesBlenderObject::~CurvesBlenderObject(){}

void CurvesBlenderObject::draw(Shader &shader) const {
    const auto t1 = std::chrono::high_resolution_clock::now();
    glBindVertexArray(VAO);
    glDrawElementsInstanced(GL_LINES_ADJACENCY, num_verts, GL_UNSIGNED_INT, 0, num_instances);
    glCheckError();
    total_elapsed_drawing += (std::chrono::high_resolution_clock::now() - t1);
    glBindVertexArray(0);
}

process_mesh/README.md METASEP
<img src="depth_example.png" width="50%"><img src="normals_example.png" width="50%">

## Instructions (for linux server)

1. Run `git submodule update --init` in the infinigen repo to ensure the dependencies are populated

2. Start an interactive GPU job and cd into `infinigen/process_mesh`

3. Configure CMAKE by running
    ```
    /usr/bin/cmake -S . -Bbuild -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_BUILD_TYPE=Release
    ```
    which should print
    ```
    -- The C compiler identification is GNU 8.5.0
    -- The CXX compiler identification is GNU 8.5.0
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Check for working C compiler: /usr/bin/gcc - skipped
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Check for working CXX compiler: /usr/bin/c++ - skipped
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    -- Found ZLIB: /usr/lib64/libz.so (found version "1.2.11")
    -- Found OpenGL: /usr/lib64/libOpenGL.so found components: OpenGL EGL GLX
    -- Configuring done
    -- Generating done
    -- Build files have been written to: infinigen/process_mesh/build
    ```

4. Build the program
    ```
    /usr/bin/cmake --build build --target all
    ```

5. Run a test
    ```
    ./build/process_mesh --height 1080 --width 1920 -out output_images -in /path/to/examples/INTVFSGK/frames_INTVFSGK_resmpl0
    ```

    or to just check if OpenGL/EGL is working correctly, run

    ```
    ./build/process_mesh -in x -out x --height 100 --width 100
    ```
    which should print `ERROR: "x" does not exist.`

## Arguments

```
--width                     Image Width
--height                    Image Height
--input_dir                 Input frames directory
--output_dir                Output directory
--line_width                Width of occlusion boundaries, in pixels [default: 2]
--subdivide                 How many depth samples per-pixel (squared) for fitting normals [default: 2]
--normal_receptive_field    Radius of plane for fitting surface normals, in pixels [default 1]
```

## Other useful info

To download EGL on Ubuntu
```
sudo apt-get install libglfw3-dev libgles2-mesa-dev
```

process_mesh/CMakeLists.txt METASEP
cmake_minimum_required(VERSION 3.10.0)
project(process_mesh VERSION 0.1.0)

if (NOT (${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux"))
    message(FATAL_ERROR "${CMAKE_SYSTEM_NAME} not supported")
endif()

add_definitions(-D GLM_ENABLE_EXPERIMENTAL)
add_definitions(-D PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR})
include_directories(/usr/include/) # on linux
include_directories(dependencies) # for cnpy
include_directories(dependencies/indicators/include)
include_directories(dependencies/argparse/include)
include_directories(dependencies/eigen)
include_directories(dependencies/tinycolormap/include)
include_directories(dependencies/glm)
include_directories(dependencies/json/single_include)
include_directories(dependencies/glad/include)
include_directories(dependencies/scharstein_flow_viz)

add_subdirectory(dependencies/cnpy)
add_subdirectory(dependencies/fast_obj)
add_subdirectory(dependencies/tinycolormap)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

include(CTest)
enable_testing()

if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
    add_definitions(-D SYSTEM_NUM=1)
    include_directories(dependencies/glfw/include)
    add_subdirectory(dependencies/glfw)
    find_package(OpenGL REQUIRED)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
    add_definitions(-D SYSTEM_NUM=0)
    find_package(OpenGL REQUIRED COMPONENTS OpenGL EGL GLX)
endif()

file(GLOB ADJACENT_SRC_FILES
     "*.hpp"
     "*.cpp"
)

# This line was taken from https://stackoverflow.com/a/52137618/5057543
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
    link_libraries(stdc++fs)
endif()

add_executable(process_mesh ${ADJACENT_SRC_FILES} dependencies/scharstein_flow_viz/colorcode.cpp dependencies/fast_obj/fast_obj.h dependencies/fast_obj/fast_obj.c dependencies/glad/src/glad.c dependencies/glad/src/glad_egl.c)

set_property(TARGET process_mesh PROPERTY CXX_STANDARD 17)

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
    target_link_libraries(process_mesh dl m stdc++ cnpy glfw)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
    target_link_libraries(process_mesh GL GLU dl EGL m stdc++ X11 cnpy)
endif()

process_mesh/.gitignore METASEP
.vscode
CMakeFiles
*.cmake
*.jpg
*.jpeg
model-test
CMakeCache.txt
DartConfiguration.tcl
build

images/video_thumbnail.png METASEP

images/Image0048_00_00.png METASEP

images/Depth0048_00_00.png METASEP

worldgen/tools/export/__init__.py METASEP

worldgen/nodes/nodegroups/__init__.py METASEP

worldgen/assets/leaves/__init__.py METASEP

worldgen/assets/cloud/base.py METASEP

process_mesh/show.py METASEP
## Copyright (c) Princeton University.
## This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

## Authors: Lahav Lipson
## Date Signed: May 2 2023

import argparse
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.text import Text
from imageio import imread

import numpy as np; np.random.seed(42)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('input_path', type=Path)
    parser.add_argument('pos', type=int, nargs='*')
    args = parser.parse_args()

    if args.input_path.suffix == ".npy":
        image = np.load(args.input_path)
    else:
        image = imread(args.input_path)

    if len(args.pos) > 0:
        assert len(args.pos) == 4
        x1,y1,x2,y2 = args.pos
        image = image[y1:y2+1, x1:x2+1]

    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.imshow(image)

    textvar: Text = ax.text(0, -15, "", style='italic')

    def hover(event):
        if event.xdata is not None:
            x, y = round(event.xdata), round(event.ydata)
            val = image[y,x]
            if len(args.pos) > 0:
                x += x1
                y += y1
            if val.dtype in [np.float32, np.float64]:
                val = np.around(val, 3)
            textvar.set_text(f"({x}, {y}) -> {val}")
        else:
            textvar.set_text("")
        fig.canvas.draw_idle()

    # add callback for mouse moves
    fig.canvas.mpl_connect('motion_notify_event', hover)

    plt.show()
worldgen/terrain/.gitignore METASEP
*.obj
set_env.sh
build
trash
*.in
*.out
dev
*.zip
__pycache__
.DS_Store
draft.py
draft.cpp
*egg-info
build
dist
test
Python-3.10.2
*_pyx.cpp
*.so
lib
*.air
*.metallib
dev_install*
worldgen/config/trailer.gin METASEP
full/render_image.passes_to_save = [
    #['diffuse_direct', 'DiffDir'],
    #['diffuse_color', 'DiffCol'],
    #['diffuse_indirect', 'DiffInd'],
    #['glossy_direct', 'GlossDir'],
    #['glossy_color', 'GlossCol'],
    #['glossy_indirect', 'GlossInd'],
    #['transmission_direct', 'TransDir'],
    #['transmission_color', 'TransCol'],
    #['transmission_indirect', 'TransInd'],
    #['emit', 'Emit'],
    #['environment', 'Env'],
    ['ambient_occlusion', 'AO']
]
flat/render_image.passes_to_save = [
    #['z', 'Depth'],
    #['normal', 'Normal'],
    #['vector', 'Vector'],
    ['object_index', 'IndexOB']
]

worldgen/config/stereo_training.gin METASEP
# eliminate blurs / distortion that cause blurs or bad alignment of the depth map
compositor_postprocessing.distort = False
render_image.motion_blur = False
render_image.use_dof = False

# remove volume scatters, as the corrupt blender's depth map
atmosphere_light_haze.shader_atmosphere.enable_scatter = False
water.shader.enable_scatter = False

# dont include tiny particles, they arent sufficiently visible
compose_scene.rain_particles_chance = 0
compose_scene.dust_particles_chance = 0
compose_scene.snow_particles_chance = 0

# eliminate lava, the emissive surface is too noisy
# now by default lava is a separate material
surface.registry.liquid_collection = [
    ('water', 0.95),
]
surface.registry.lava = [
    ('water', 1),
]

# reduce the baseline and pitch variance, requested by Lahav
stereo_baseline = 0.075
sample_camera_rotation.pitch_params = {'min': -20, 'max': 20, 'mean': 0, 'std': 15}

worldgen/config/simple.gin METASEP
include 'config/dev.gin'
include 'config/no_creatures.gin'
include 'config/fast_terrain_assets.gin'
run_erosion.n_iters = [1,1]
full/render_image.num_samples = 64
worldgen/config/reuse_terrain_assets.gin METASEP
Terrain.asset_folder = None

landtiles.load_assets.on_the_fly_instances = 0
landtiles.load_assets.reused_instances = 5

upsidedown_mountains.load_assets.on_the_fly_instances = 0
upsidedown_mountains.load_assets.reused_instances = 5

caves.load_assets.on_the_fly_instances = 0
caves.load_assets.reused_instances = 5

worldgen/config/no_rocks.gin METASEP
compose_scene.boulders_chance = 0.0
compose_scene.rocks_chance = 0.0
worldgen/config/no_particles.gin METASEP
compose_scene.rain_particles_chance = 0.0
compose_scene.snow_particles_chance = 0.0
compose_scene.leaf_particles_chance = 0.0
compose_scene.dust_particles_chance = 0.0
compose_scene.marine_snow_particles_chance = 0.0
worldgen/config/no_creatures.gin METASEP
compose_scene.ground_creatures_chance = 0.0
compose_scene.flying_creatures_chance = 0.0
compose_scene.fish_school_chance = 0.0
compose_scene.bug_swarm_chance = 0.0

worldgen/config/no_assets.gin METASEP
compose_scene.fancy_clouds_chance = 0.0

compose_scene.trees_chance = 0.0
compose_scene.bushes_chance = 0.0
compose_scene.ground_creatures_chance = 0.0
compose_scene.flying_creatures_chance = 0.0
compose_scene.clouds_chance = 0.0
compose_scene.boulders_chance = 0.0
compose_scene.glowing_rocks_chance = 0.0
compose_scene.rocks_chance = 0.0
compose_scene.ground_leaves_chance = 0.0
compose_scene.ground_twigs_chance = 0.0
compose_scene.chopped_trees_chance = 0.0
compose_scene.grass_chance = 0.0
compose_scene.flowers_chance = 0.0
compose_scene.kelp_chance = 0.0
compose_scene.cactus_chance = 0.0
compose_scene.rain_particles_chance = 0.0
compose_scene.snow_particles_chance = 0.0
compose_scene.leaf_particles_chance = 0.0
compose_scene.dust_particles_chance = 0.0
compose_scene.camera_based_lighting_chance = 0.0
compose_scene.wind_chance = 0.0
compose_scene.turbulence_chance = 0.0
compose_scene.ferns_chance = 0.0

compose_scene.fish_school_chance = 0.0
compose_scene.marine_snow_particles_chance = 0.0

compose_scene.corals_chance = 0.0
compose_scene.seaweed_chance = 0.0
compose_scene.urchin_chance = 0.0
compose_scene.seashells_chance = 0.0
compose_scene.jellyfish_chance = 0.0
compose_scene.mushroom_chance = 0.0
compose_scene.pinecone_chance = 0.0
compose_scene.monocots_chance = 0.0 
compose_scene.pine_needle_chance = 0.0
compose_scene.caustics_chance = 0.0

compose_scene.decorative_plants_chance = 0.0

populate_scene.moss_chance = 0.0
populate_scene.lichen_chance = 0.0
populate_scene.slime_mold_chance = 0.0
populate_scene.ivy_chance = 0.0
populate_scene.snow_layer_chance = 0.0
worldgen/config/natural.gin METASEP
# surfaces.templates.water.shader.color = ("palette", "water")
surfaces.templates.mountain.shader.color = ("palette", "mountain soil")
surfaces.templates.sandstone.shader.color = ("palette", "sandstone")
worldgen/config/monocular.gin METASEP
camera.spawn_camera_rigs.camera_rig_config = [
    {'loc': (0, 0, 0), 'rot_euler': (0, 0, 0)},
]

worldgen/config/high_quality_terrain.gin METASEP
OpaqueSphericalMesher.pixels_per_cube = 0.92
TransparentSphericalMesher.pixels_per_cube = 1.38

get_surface_type.degrade_sdf_to_displacement = 0
voronoi_grains_chance = 0.5
worldgen/config/fast_terrain_assets.gin METASEP
landtiles.load_assets.on_the_fly_instances = 1
upsidedown_mountains.load_assets.on_the_fly_instances = 1
caves.load_assets.on_the_fly_instances = 1
run_erosion.n_iters = [10000, 50000]
worldgen/config/dev.gin METASEP
compose_scene.generate_resolution = (960, 540)

full/render_image.min_samples = 32
full/render_image.num_samples = 512

OpaqueSphericalMesher.pixels_per_cube = 4
TransparentSphericalMesher.pixels_per_cube = 4
target_face_size.global_multiplier = 2

compose_scene.ground_creatures_chance = 0.0
compose_scene.flying_creatures_chance = 0.0

compose_scene.inview_distance = 35
placement.populate_all.dist_cull = 35
compose_scene.near_distance = 10
compose_scene.center_distance = 20
worldgen/config/base_surface_registry.gin METASEP
surface.registry.ground_collection = [
    ('mud', 2),
    ('sand', 1),
    ('cobble_stone', 1),
    ('cracked_ground', 1),   
    ('dirt', 1),
    ('stone', 1),
    ('soil', 1),
    ('chunkyrock', 0),
]

surface.registry.beach = [
    ('sand', 10),
    ('cracked_ground', 1),
    ('dirt', 1),
    ('stone', 1),
    ('soil', 1),
]

surface.registry.eroded = [
    ('sand', 1),
    ('cracked_ground', 1),
    ('dirt', 1),
    ('stone', 1),
    ('soil', 1),
]

surface.registry.mountain_collection = [
    ('mountain', 10),
    ("sandstone", 2),
]

surface.registry.rock_collection = [
    # ('aluminumdisp2tut', 0.5),
    ('stone', 1),
    ('mountain', 5),
    # ('ice', 1),
]

surface.registry.liquid_collection = [
    ('water', 0.95),
    # ('lava', 0.05),
]

surface.registry.lava = [
    ('lava', 1),
]

surface.registry.snow = [
    ('snow', 1),
]

surface.registry.atmosphere = [
    ('atmosphere_light_haze', 1),
]

surface.registry.bark = [
    ('bark_birch', 0.1),
    ('bark_random', 0.9),
    #('wood', 0.01),
]

surface.registry.greenery = [
    ('simple_greenery', 1),
]

surface.registry.smooth_categories = 0

worldgen/config/base.gin METASEP
OVERALL_SEED = 0
LOG_DIR = '.'

Terrain.asset_folder = "" # Will read from $INFINIGEN_ASSET_FOLDER environment var when set to None, and on the fly when set to ""
Terrain.asset_version = 'May27'

util.math.FixedSeed.seed = %OVERALL_SEED

execute_tasks.frame_range = [1, 1] # Between start/end frames should this job consider? Increase end frame to tackle video
execute_tasks.camera_id = [0, 0] # Which camera rig

save_obj_and_instances.output_folder="saved_mesh.obj"

util.logging.create_text_file.log_dir = %LOG_DIR

compose_scene.inview_distance = 70
placement.populate_all.dist_cull = 70
compose_scene.near_distance = 20
compose_scene.center_distance = 35

compose_scene.land_domain_tags = 'landscape,-liquid_covered,-cave,-beach'
compose_scene.nonliving_domain_tags = 'landscape,-cave'
compose_scene.underwater_domain_tags = 'landscape,liquid_covered,-cave'

compose_scene.terrain_enabled = True
compose_scene.lighting_enabled = True
compose_scene.coarse_terrain_enabled = True
compose_scene.terrain_surface_enabled = True

compose_scene.fancy_clouds_chance = 0.6

compose_scene.trees_chance = 0.85
compose_scene.bushes_chance = 0.7
compose_scene.clouds_chance = 0.0
compose_scene.boulders_chance = 0.7

compose_scene.glowing_rocks_chance = 0.0
compose_scene.rocks_chance = 0.9

compose_scene.ground_leaves_chance = 0.7
compose_scene.ground_twigs_chance = 0.7
compose_scene.chopped_trees_chance = 0.7

compose_scene.grass_chance = 0.8
compose_scene.ferns_chance = 0.25
compose_scene.monocots_chance = 0.15

compose_scene.flowers_chance = 0.2
compose_scene.kelp_chance = 0.0
compose_scene.cactus_chance = 0.0
compose_scene.coconut_trees_chance = 0.0
compose_scene.palm_trees_chance = 0.0

compose_scene.instanced_trees_chance = 0.0 # conditioned on trees_chance as prereq

compose_scene.fish_school_chance = 0.0
compose_scene.bug_swarm_chance = 0.0

compose_scene.rain_particles_chance = 0.1
compose_scene.snow_particles_chance = 0.0
compose_scene.leaf_particles_chance = 0.0
compose_scene.dust_particles_chance = 0.0
compose_scene.marine_snow_particles_chance = 0.1
compose_scene.camera_based_lighting_chance = 0.0

compose_scene.wind_chance = 0.5
compose_scene.turbulence_chance = 0.3
wind_effector.strength = ('uniform', 0, 0.02)
turbulence_effector.strength = ('uniform', 0, 0.02)
turbulence_effector.noise = ('uniform', 0, 0.015)

compose_scene.corals_chance = 0.0
compose_scene.seaweed_chance = 0.0
compose_scene.seashells_chance = 0.0
compose_scene.urchin_chance = 0.0
compose_scene.jellyfish_chance = 0.0

compose_scene.mushroom_chance = 0 # TEMP
compose_scene.pinecone_chance = 0.1
compose_scene.pine_needle_chance = 0.1
compose_scene.caustics_chance = 0.0
compose_scene.decorative_plants_chance = 0.1

populate_scene.slime_mold_chance = 0.0
populate_scene.ivy_chance = 0.0
populate_scene.lichen_chance = 0.0
populate_scene.mushroom_chance = 0.0
populate_scene.moss_chance = 0.0
populate_scene.snow_layer_chance = 0

populate_scene.snow_layer_chance=0.0

target_face_size.global_multiplier = 2
scatter_res_distance.dist = 4

random_color_mapping.hue_stddev = 0.05 # Note: 1.0 is the whole color spectrum

render.render_image_func = @full/render_image
render_image.time_limit = 0

full/render_image.min_samples = 100
full/render_image.num_samples = 8192
render_image.adaptive_threshold = 0.005
full/render_image.flat_shading = False

flat/render_image.min_samples = 10
flat/render_image.num_samples = 10
flat/render_image.flat_shading = True
full/render_image.passes_to_save = [
    ['diffuse_direct', 'DiffDir'],
    ['diffuse_color', 'DiffCol'],
    ['diffuse_indirect', 'DiffInd'],
    ['glossy_direct', 'GlossDir'],
    ['glossy_color', 'GlossCol'],
    ['glossy_indirect', 'GlossInd'],
    ['transmission_direct', 'TransDir'],
    ['transmission_color', 'TransCol'],
    ['transmission_indirect', 'TransInd'],
    ['volume_direct', 'VolumeDir'],
    ['emit', 'Emit'],
    ['environment', 'Env'],
    ['ambient_occlusion', 'AO']
]
flat/render_image.passes_to_save = [
    ['z', 'Depth'],
    ['normal', 'Normal'],
    ['vector', 'Vector'],
    ['object_index', 'IndexOB']
]

render_image.exposure = 1

render_image.use_dof = 'IF_TARGET_SET'
render_image.dof_aperture_fstop = 3
render_image.motion_blur = True
render_image.motion_blur_shutter = 0.15

compositor_postprocessing.distort = False
compositor_postprocessing.color_correct=True

compose_scene.generate_resolution = (1920, 1080)
get_sensor_coords.H = 720
get_sensor_coords.W = 1280


min_terrain_distance = 2
keep_cam_pose_proposal.min_terrain_distance = %min_terrain_distance
SphericalMesher.r_min = %min_terrain_distance

build_terrain_bvh_and_attrs.avoid_border = False # disabled due to crashes 5/15

animate_cameras.follow_poi_chance=0.0
camera.camera_pose_proposal.altitude = ("weighted_choice",
    (0.975, ("clip_gaussian", 2, 0.3, 0.5, 3)), # person height usually
    (0.025, ("clip_gaussian", 15, 7, 5, 30)) # drone height sometimes
)

camera.camera_pose_proposal.pitch = ("clip_gaussian", 90, 30, 20, 160)

camera.spawn_camera_rigs.n_camera_rigs = 1

# WARNING: Large camera rig translations or rotations require special handling. 
#    if your cameras are not all approximately forward facing within a few centimeters, you must either:
#    -  configure the pipeline to generate assets / terrain for each camera separately, rather than sharing it between the whole rig
#    -  or, treat your camera rig as multiple camera rigs each with one camera, and implement code to positon them correctly
camera.spawn_camera_rigs.camera_rig_config = [
    {'loc': (0, 0, 0), 'rot_euler': (0, 0, 0)},
    {'loc': (0.075, 0, 0), 'rot_euler': (0, 0, 0)}
]

# TERRAIN SEED #
surfaces.templates.ice.geo_ice.random_seed = %OVERALL_SEED
surfaces.templates.lava.lava_geo.random_seed = %OVERALL_SEED
surfaces.templates.mud.geo_mud.random_seed = %OVERALL_SEED
surfaces.templates.cobble_stone.geo_cobblestone.random_seed = %OVERALL_SEED
surfaces.templates.dirt.geo_dirt.random_seed = %OVERALL_SEED
surfaces.templates.stone.geo_stone.random_seed = %OVERALL_SEED
surfaces.templates.cracked_ground.geo_cracked_ground.random_seed = %OVERALL_SEED
surfaces.templates.soil.geometry_soil.random_seed = %OVERALL_SEED
surfaces.templates.chunkyrock.geo_rocks.random_seed = %OVERALL_SEED

surfaces.templates.mountain.shader.random_seed = %OVERALL_SEED
surfaces.templates.sand.shader.random_seed = %OVERALL_SEED
surfaces.templates.water.shader.random_seed = %OVERALL_SEED

compose_scene.ground_creatures_chance = 0.0
compose_scene.ground_creature_registry = [
    (@CarnivoreFactory, 1),
    (@HerbivoreFactory, 1),
    (@BirdFactory, 1),
    (@SnakeFactory, 1)
]

compose_scene.flying_creatures_chance=0.1
compose_scene.flying_creature_registry = [
    (@FlyingBirdFactory, 1),
    (@DragonflyFactory, 0.1),
]

group_collections.config = [
    {'name': 'assets',         'hide_viewport': True,  'hide_render': True}, # collections of assets used by scatters
    {'name': 'scatter',        'hide_viewport': True,  'hide_render': False}, # actual instanced objects for scatters
    {'name': 'placeholders',   'hide_viewport': False, 'hide_render': False}, # low-res markers / proxies for where assets will be spawned 
    {'name': 'unique_assets',  'hide_viewport': True,  'hide_render': False}, # actual hi-res assets spawned at each placeholder location
    {'name': 'particleassets', 'hide_viewport': True,  'hide_render': False}, # actual hi-res assets spawned at each placeholder location
    {'name': 'particles',      'hide_viewport': True,  'hide_render': False}, # actual particle emitters / particle systems
    {'name': 'animhelper',     'hide_viewport': False, 'hide_render': True}, # curves and iks
]

include 'config/base_surface_registry.gin'
include 'config/natural.gin'


worldgen/config/asset_demo.gin METASEP
compose_scene.inview_distance = 30

full/render_image.min_samples = 50
full/render_image.num_samples = 300

render_image.motion_blur = False
render_image.use_dof = True

full/render_image.passes_to_save = []
worldgen/config/.gitignore METASEP
local_debug*.gin
requirements.txt METASEP
gin-config>=0.5.0
tqdm
opencv-python
matplotlib
scipy
fastcore
imageio
scikit-image==0.19.3
termcolor
submitit
frozendict
flow_vis
vnoise
trimesh
einops
mesh_to_sdf
geomdl
numpy==1.21.5
wandb
zarr
jinja2
shapely
rtree
pycparser==2.21
json5==0.9.10
google-images-search==1.4.4
landlab==2.4.1
scikit-learn
psutil

install.sh METASEP
#!/bin/bash

if ! command -v wget &> /dev/null
then
    echo "wget could not be found, please 'sudo apt-get install wget' or 'brew install wget'"
    exit
fi

OS=$(uname -s)
ARCH=$(uname -m)

if [ "${OS}" = "Linux" ]; then
    BLENDER_WGET_LINK='https://download.blender.org/release/Blender3.3/blender-3.3.1-linux-x64.tar.xz'
    BLENDER_WGET_FILE='blender.tar.xz'

    BLENDER_UNTAR_DIR='blender-3.3.1-linux-x64'
    BLENDER_DIR='blender'
    BLENDER_PYTHON="${BLENDER_DIR}/3.3/python/bin/python3.10"
    BLENDER_INCLUDE="${BLENDER_DIR}/3.3/python/include/python3.10"
    BLENDER_PACKAGES="${BLENDER_DIR}/3.3/python/lib/python3.10/site-packages"

    NURBS_SCRIPT="setup_linux.py"
elif [ "${OS}" = "Darwin" ]; then
    if [ "${ARCH}" = "arm64" ]; then
        BLENDER_WGET_LINK='https://download.blender.org/release/Blender3.3/blender-3.3.1-macos-arm64.dmg'
        NURBS_SCRIPT="setup_macos_as.py"
    else
        BLENDER_WGET_LINK='https://download.blender.org/release/Blender3.3/blender-3.3.1-macos-x64.dmg'
        NURBS_SCRIPT="setup_macos.py"
    fi
    if [ "${ARCH}" = "arm64" ]; then
        HOMEBREW_PREFIX="/opt/homebrew/"
    else
        HOMEBREW_PREFIX="/usr/local"
    fi
    BLENDER_WGET_FILE='blender.dmg'

    BLENDER_VOLM='/Volumes/Blender'
    BLENDER_DIR='./Blender.app'
    BLENDER_PYTHON="${BLENDER_DIR}/Contents/Resources/3.3/python/bin/python3.10"
    BLENDER_INCLUDE="${BLENDER_DIR}/Contents/Resources/3.3/python/include/python3.10"
    BLENDER_PACKAGES="${BLENDER_DIR}/Contents/Resources/3.3/python/lib/python3.10/site-packages"

    export CC="${HOMEBREW_PREFIX}/opt/llvm/bin/clang"
    export CPATH="${HOMEBREW_PREFIX}/include:${CPATH}"
else
    echo "Unsupported OS"
    exit -1
fi
REQUIREMENTS_PATH='./requirements.txt'
PYTHON_WGET_LINK='https://www.python.org/ftp/python/3.10.2/Python-3.10.2.tgz'
PYTHON_WGET_FILE='Python-3.10.2.tgz'
PYTHON_DIR='Python-3.10.2'

git submodule init
git submodule update

if [ ! -d "${BLENDER_DIR}" ]; then
    # Download Blender
    wget -O "${BLENDER_WGET_FILE}" "${BLENDER_WGET_LINK}"

    # Unzip Blender
    if [ "${OS}" = "Darwin" ]; then
        hdiutil attach "${BLENDER_WGET_FILE}"
        cp -r "${BLENDER_VOLM}/Blender.app" "${BLENDER_DIR}"
        hdiutil detach "${BLENDER_VOLM}"
    else
        tar -xf "${BLENDER_WGET_FILE}"
        mv "${BLENDER_UNTAR_DIR}" "${BLENDER_DIR}"
    fi

    rm "${BLENDER_WGET_FILE}"
fi

# Install llvm for MacOS
if [ "${OS}" = "Darwin" ]; then
    brew install llvm open-mpi libomp glm glew
fi

# Install Conda dependencies
pip install -r "${REQUIREMENTS_PATH}"
pip install fake-bpy-module-latest

if [ ! -d "${PYTHON_DIR}" ]; then
    # Install Python include file
    wget -O "${PYTHON_WGET_FILE}" "${PYTHON_WGET_LINK}"
    tar -xf "${PYTHON_WGET_FILE}"
    rm "${PYTHON_WGET_FILE}"
fi
cp -r "${PYTHON_DIR}/Include/"* "${BLENDER_INCLUDE}"

# Install Blender dependencies
"${BLENDER_PYTHON}" -m ensurepip
CFLAGS="-I$(realpath ${BLENDER_INCLUDE}) ${CFLAGS}" "${BLENDER_PYTHON}" -m pip install -r "${REQUIREMENTS_PATH}"

# Build terrain
rm -rf ${BLENDER_PACKAGES}/terrain-*
rm -rf *.egg-info
rm -rf __pycache__
rm -rf ./worldgen/terrain/build

cd ./worldgen/terrain
if [ -f "/usr/local/cuda/bin/nvcc" ]; then
    USE_CUDA=1 bash install_terrain.sh
else
    USE_CUDA=0 bash install_terrain.sh
fi
"../../${BLENDER_PYTHON}" setup.py build_ext --inplace --force
cd -

# Build NURBS
cd ./worldgen/assets/creatures/geometry/cpp_utils
rm -f *.so
rm -rf build
"../../../../../${BLENDER_PYTHON}" "${NURBS_SCRIPT}" build_ext --inplace
cd -

if [ "$1" = "opengl" ]; then
    bash ./worldgen/tools/compile_opengl.sh
fi
README.md METASEP
## [Infinigen: Infinite Photorealistic Worlds using Procedural Generation](https://infinigen.org)

Please visit our website, [https://infinigen.org](https://infinigen.org)

[![Infinigen Trailer](images/video_thumbnail.png)](https://youtu.be/6tgspeI-GHY)

If you use Infinigen in your work, please cite our [academic paper]([https://arxiv.org/abs/2306.09310](https://arxiv.org/abs/2306.09310)):

<h3 align="center"><a href="https://arxiv.org/pdf/2306.09310">Infinite Photorealistic Worlds using Procedural Generation</a></h3>
<p align="center">
<a href="http://araistrick.com/">Alexander Raistrick</a>*, <a href="https://www.lahavlipson.com/">Lahav Lipson</a>*, <a href="https://mazeyu.github.io/">Zeyu Ma</a>* (*equal contribution, alphabetical order) <br>
<a href="https://www.cs.princeton.edu/~lm5483/">Lingjie Mei</a>, <a href="https://www.cs.princeton.edu/~mingzhew">Mingzhe Wang</a>, <a href="https://zuoym15.github.io/">Yiming Zuo</a>, <a href="https://kkayan.com/">Karhan Kayan</a>, <a href="https://hermera.github.io/">Hongyu Wen</a>, <a href="https://pvl.cs.princeton.edu/people.html">Beining Han</a>, <br>
<a href="https://pvl.cs.princeton.edu/people.html">Yihan Wang</a>, <a href="http://www-personal.umich.edu/~alnewell/index.html">Alejandro Newell</a>, <a href="https://heilaw.github.io/">Hei Law</a>, <a href="https://imankgoyal.github.io/">Ankit Goyal</a>, <a href="https://yangky11.github.io/">Kaiyu Yang</a>, <a href="http://www.cs.princeton.edu/~jiadeng">Jia Deng</a><br>
Conference on Computer Vision and Pattern Recognition (CVPR) 2023
</p>

```
@inproceedings{infinigen2023infinite,
  title={Infinite Photorealistic Worlds Using Procedural Generation},
  author={Raistrick, Alexander and Lipson, Lahav and Ma, Zeyu and Mei, Lingjie and Wang, Mingzhe and Zuo, Yiming and Kayan, Karhan and Wen, Hongyu and Han, Beining and Wang, Yihan and Newell, Alejandro and Law, Hei and Goyal, Ankit and Yang, Kaiyu and Deng, Jia},
  booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition},
  pages={12630--12641},
  year={2023}
}
```

## Installation

Installation is tested and working on the following platforms:

- Ubuntu 22.04.2 LTS 
    - GPUs options tested: CPU only, GTX-1080, RTX-2080, RTX-3090, RTX-4090 (Driver 525, CUDA 12.0)
    - RAM: 16GB
- MacOS Monterey & Ventura, Apple M1 Pro, 16GB RAM

We are working on support for rendering with AMD GPUs. Windows users should use [WSL2](https://ubuntu.com/tutorials/install-ubuntu-on-wsl2-on-windows-11-with-gui-support#1-overview). More instructions coming soon.

**Run these commands to get started**
```
git clone https://github.com/princeton-vl/infinigen.git
cd infinigen
conda create --name infinigen python=3.10
conda activate infinigen
bash install.sh
```
`install.sh` may take significant time to download Blender3.3 and compile all source files.

Ignore non-fatal warnings. See [Getting Help](#getting-help) for guidelines on posting github issues

Run the following or add it to your `~/.bashrc` (Linux/WSL) or `~/.bash_profile` (Mac)
```
# on Linux/WSL
export BLENDER="/PATH/TO/infinigen/blender/blender"
# on MAC
export BLENDER="/PATH/TO/infinigen/Blender.app/Contents/MacOS/Blender"
```

<details closed>
<summary><b>(Optional) Running Infinigen in a Docker Container</b></summary>

**Docker on Linux**

In `/infinigen/`
```
make docker-build
make docker-setup
make docker-run
```
To enable CUDA compilation, use `make docker-build-cuda` instead of `make docker-build`

To run without GPU passthrough use `make docker-run-no-gpu`

To run without OpenGL ground truth use `docker-run-no-opengl` 

To run without either, use `docker-run-no-gpu-opengl` 

Note: `make docker-setup` can be skipped if not using OpenGL.

Use `exit` to exit the container and `docker exec -it infinigen bash` to re-enter the container as needed. Remember to `conda activate infinigen` before running scenes.


**Docker on Windows**

Install [WSL2](https://infinigen.org/docs/installation/intro#setup-for-windows) and [Docker Desktop](https://www.docker.com/products/docker-desktop/), with "Use the WSL 2 based engine..." enabled in settings. Keep the Docker Desktop application open while running containers. Then follow instructions as above.

</details>

### "Hello World": Generate your first Infinigen scene

 :warning: **Known issue** :warning: : We are actively fixing an issue which causes commands not to be reproducible on many platforms. The same command may produce multiple rearranged scenes with different runtimes and memory requirements.

<p align="center">
  <img src="images/Image0048_00_00.png" width="330" />
  <img src="images/Depth0048_00_00.png" width="330" /> 
</p>

This guide will show you how to generate an image and it's corresponding depth ground-truth, similar to those shown above.

#### Generate a scene step by step
Infinigen generates scenes by running multiple tasks (usually executed automatically, like in [Generate image(s) in one command](#generate-images-in-one-command)). Here we will run them one by one to demonstrate. These commands take approximately 10 minutes and 16GB of memory to execute on an M1 Mac or Linux Desktop.

```
cd worldgen
mkdir outputs

# Generate a scene layout
$BLENDER -noaudio --background --python generate.py -- --seed 0 --task coarse -g desert simple --output_folder outputs/helloworld/coarse

# Populate unique assets
$BLENDER -noaudio --background --python generate.py -- --seed 0 --task populate fine_terrain -g desert simple --input_folder outputs/helloworld/coarse --output_folder outputs/helloworld/fine

# Render RGB images
$BLENDER -noaudio --background --python generate.py -- --seed 0 --task render -g desert simple --input_folder outputs/helloworld/fine --output_folder outputs/helloworld/frames

# Render again for accurate ground-truth
$BLENDER -noaudio --background --python generate.py -- --seed 0 --task render -g desert simple --input_folder outputs/helloworld/fine --output_folder outputs/helloworld/frames -p render.render_image_func=@flat/render_image 
```

The full specification for the ground-truth is located in [GroundTruthAnnotations.md](/GroundTruthAnnotations.md), including instructions for our own OpenGL-based implementation with additional annotations.

Output logs should indicate what the code is working on. Use `--debug` for even more detail. After each command completes you can inspect it's `--output_folder` for results, including running `$BLENDER outputs/helloworld/coarse/scene.blend` or similar to view blender files. We hide many meshes by default for viewport stability; to view them, click "Render" or use the UI to unhide them.

#### Generate image(s) in one command

We provide `tools/manage_datagen_jobs.py`, a utility which runs these or similar steps automatically.

```
python -m tools.manage_datagen_jobs --output_folder outputs/hello_world --num_scenes 1 --specific_seed 0
--configs desert simple --pipeline_configs local_16GB monocular blender_gt --pipeline_overrides LocalScheduleHandler.use_gpu=False
```

Ready to remove the guardrails? Try the following:
- Swap `desert` for any of `config/scene_types` to get different biome (or write your own crazy config!). You can also add in the name of any file in `configs`.
- Change the `--specific_seed` to any number to produce different scenes, or remove it and set --num_scenes 50 to try many random seeds.
- Remove `simple` to generate more detailed (but *EXPENSIVE*) scenes, as shown in the trailer.
- Read and customize `generate.py` to understand how infinigen works under the hood. 
- Append `-p compose_scene.grass_chance=1.0` to the first command to force grass (or any of `generate.py's` 'run_stage' asset names) to appear in the scene. You can modify the kwargs @gin.configurable() python function in the entire repo via this mechanism. 

`--configs` enables you to customize the random *distribution* of visual content. If you do not select any config in the folder `config/scene_types`, the code choose one for you at random. 

`--pipeline_configs` determines what compute resources will be used, and what render jobs are necessary for each scene. A list of configs are available in `tools/pipeline_configs`. You must pick one config to determine compute type (ie `local_64GB` or `slurm`) and one to determine the dataset type (such as `monocular` or `monocular_video`). Run `python -m tools.manage_datagen_jobs --help` for more options related to dataset generation.

If you intend to use CUDA-accelerated terrain (`--pipeline_configs cuda_terrain`), you must run `install.sh` on a CUDA-enabled machine. 

Infinigen uses [Google's "Gin Config"](https://github.com/google/gin-config) heavily, and we encourage you to consult their documentation to familiarize yourself with its capabilities.


## Exploring the Infinigen Codebase

Infinigen has evolved significantly since the version described in our CVPR paper. It now features some procedural code obtained from the internet under CC-0 licenses, which are marked with code comments where applicable - no such code was present in the system for the CVPR version.

Infinigen is an ongoing research project, and has some known issues. Through experimenting with Infinigen's code and config files, you will find scenes which crash or cannot be handled on your hardware. Infinigen scenes are randomized, with a long tail of possible scene complexity and thus compute requirements. If you encounter a scene that does not fit your computing hardware, you should try other seeds, use other config files, or follow up for help.

## Coming Soon

Infinigen will evolve rapidly over the coming months. Follow us at [https://twitter.com/PrincetonVL](https://twitter.com/PrincetonVL) for updates. 

There are some aspects of the code used for our launch video that are still being polished and will be released as soon as possible, notably:
- Fluid simulations for dynamic water and fire
- Some categories of plants, namely snake plants and spider plants

### Tutorials & Documentation
We will add comprehensive tutorials and documentation for all aspects of Infinigen. This README is **preliminary**, and our docs will be expanded to cover all aspects of the project in detail. 

### Contributing
We welcome contributions! You can contribute in many ways:
- **Contribute code to this repository** - We welcome code contributions. More guidelines coming soon.
- **Contribute procedural generators** - `worldgen/nodes/node_transpiler/dev_script.py` provides tools to convert artist-friendly [Blender Nodes](https://docs.blender.org/manual/en/2.79/render/blender_render/materials/nodes/introduction.html) into python code. Tutorials and guidelines coming soon.
- **Contribute pre-generated data** - Anyone can contribute their computing power to create data and share it with the community. Please stay tuned for a repository of pre-generated data.

## Getting Help

Please post this repository's Github Issues page for help. Please run your command with `--debug`, and let us know:
- What is your computing setup, including OS version, CPU, RAM, GPU(s) and any drivers?
- What version of the code are you using (link a commit hash), and what if any modifications have you made (new configs, code edits)
- What exact command did you run?
- What were the output logs of the command you ran? 
    - If using `manage_datagen_jobs`, look in `outputs/MYJOB/MYSEED/logs/` to find the right one.
    - What was the exact python error and stacktrace, if applicable?



Makefile METASEP
DOCKER_BUILD_PROGRESS ?= auto
DOCKER_TAG ?= infinigen_docker_img

PWD = $(shell pwd)

XSOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth

default:

docker-build:
	git submodule init
	git submodule update
	docker build \
		--tag $(DOCKER_TAG) \
		--progress $(DOCKER_BUILD_PROGRESS) .

docker-build-cuda:
	git submodule init
	git submodule update
	docker build \
		--tag $(DOCKER_TAG) \
		--progress $(DOCKER_BUILD_PROGRESS) \
		--build-arg APP_IMAGE=nvidia/cuda:12.0.0-devel-ubuntu22.04 .

docker-clean:
	echo "Removing infinigen docker image if already exists..."
	-docker rmi -f $(DOCKER_TAG)

docker-setup:
	sudo apt-get install x11-xserver-utils \
		&& touch ~/.Xauthority \
		&& xauth add $(HOST):0 . $(shell xxd -l 16 -p /dev/urandom) \
		&& touch "$(XAUTH)" \
		&& xauth nlist "$(DISPLAY)" | sed -e 's/^..../ffff/' | xauth -f "$(XAUTH)" nmerge - \
		&& xhost +local:docker

docker-run:
	docker run -td --privileged --net=host --ipc=host \
		--name="infinigen" \
		--gpus=all \
		--env NVIDIA_DISABLE_REQUIRE=1 \
		-e "BLENDER=/opt/infinigen/blender/blender" \
		-e "DISPLAY=$(DISPLAY)" \
		-e "QT_X11_NO_MITSHM=1" \
		-v "/tmp/.X11-unix:/tmp/.X11-unix:rw" \
		-v $(PWD)/worldgen/outputs:/opt/infinigen/worldgen/outputs \
		-e "XAUTHORITY=$(XAUTH)" \
		-e ROS_IP=127.0.0.1 \
		--cap-add=SYS_PTRACE \
		-v /etc/group:/etc/group:ro \
		"$(DOCKER_TAG)" /bin/bash \
	|| docker run -td --privileged --net=host --ipc=host \
		--name="infinigen" \
		--device /dev/dri \
		-e "BLENDER=/opt/infinigen/blender/blender" \
		-e "DISPLAY=$(DISPLAY)" \
		-e "QT_X11_NO_MITSHM=1" \
		-v "/tmp/.X11-unix:/tmp/.X11-unix:rw" \
		-v $(PWD)/worldgen/outputs:/opt/infinigen/worldgen/outputs \
		-e "XAUTHORITY=$(XAUTH)" \
		-e ROS_IP=127.0.0.1 \
		--cap-add=SYS_PTRACE \
		-v /etc/group:/etc/group:ro \
		"$(DOCKER_TAG)" bash

	docker exec infinigen /bin/bash -c worldgen/tools/compile_opengl.sh

docker-run-no-opengl:
	echo "Launching Docker image without OpenGL ground truth"
	docker run -td --rm --privileged --net=host --ipc=host \
		--name="infinigen" \
		--gpus=all \
		--env NVIDIA_DISABLE_REQUIRE=1 \
		-e "BLENDER=/opt/infinigen/blender/blender" \
		-v $(PWD)/worldgen/outputs:/opt/infinigen/worldgen/outputs \
		"$(DOCKER_TAG)" /bin/bash

docker-run-no-gpu:
	echo "Launching Docker image without GPU passthrough"
	docker run -td --privileged --net=host --ipc=host \
		--name="infinigen" \
		-e "BLENDER=/opt/infinigen/blender/blender" \
		-e "DISPLAY=$(DISPLAY)" \
		-e "QT_X11_NO_MITSHM=1" \
		-v "/tmp/.X11-unix:/tmp/.X11-unix:rw" \
		-v $(PWD)/worldgen/outputs:/opt/infinigen/worldgen/outputs \
		-e "XAUTHORITY=$(XAUTH)" \
		-e ROS_IP=127.0.0.1 \
		--cap-add=SYS_PTRACE \
		-v /etc/group:/etc/group:ro \
		"$(DOCKER_TAG)" /bin/bash \

	docker exec infinigen /bin/bash -c worldgen/tools/compile_opengl.sh

docker-run-no-gpu-opengl:
	echo "Launching Docker image without GPU passthrough or OpenGL"
	docker run -td --rm --privileged --net=host --ipc=host \
		--name="infinigen" \
		-e "BLENDER=/opt/infinigen/blender/blender" \
		-v $(PWD)/worldgen/outputs:/opt/infinigen/worldgen/outputs \
		"$(DOCKER_TAG)" /bin/bash
	
GroundTruthAnnotations.md METASEP
# Ground-Truth Annotations

## Default Annotations from Blender

Infinigen can produce some dense annotations using Blender's built-in render passes. Users may prefer to use these annotations over our extended annotation system's since it requires only the bare-minimum installation. It is also able to run without a GPU.

These annotations are produced when using the `--pipeline_configs opengl_gt` ground truth extraction config in [manage_datagen_jobs.py](/README.md#generate-images-in-one-command), or can be done manually as shown in the final step of the [Hello-World](/README.md#generate-a-scene-step-by-step) example.

### Specification

**Coming Soon**

## OpenGL-Based Annotation Pipeline

We also provide a separate pipeline for extracting the full set of annotations from each image or scene.

This section will allow you to use our own `--pipeline_configs opengl_gt` ground truth extraction config, which provides additional labels such as occlusion boundaries, sub-object segmentation, 3D flow and easy 3D bounding boxes. If you do not need these features, we recommend using the [default annotations](#default-annotations-from-blender). This section is intended for computer vision researchers and power-users. 

### Installation

To ensure all submodule dependencies have been properly cloned, run:
```
git submodule init
git submodule update
```

On Ubuntu, run
```
sudo apt-get install libglm-dev libglew-dev libglfw3-dev libgles2-mesa-dev zlib1g-dev
```

If compiling on WSL, additionally run 
```
sudo apt-get install doxygen
sudo apt-get install libxinerama-dev
sudo apt-get install libxcursor-dev
sudo apt-get install libxi-dev
```

On MacOS, run
```
brew install glfw3
brew install glew
```

If you do not have sudo access, you may attempt the following:
- Install dependencies manually and set your $CPATH variables appropriately. 
- Ask your administrator to install them on your behalf (YMMV).

Finally, run
```
bash install.sh opengl
```
Or, if you have already run `install.sh` earlier, you can just run
```
bash worldgen/tools/compile_opengl.sh
```

### Extended Hello-World

Continuing the [Hello-World](/README.md#generate-a-scene-step-by-step) example, we can produce the full set of annotations that Infinigen supports. Following step 3:

4. Export the geometry from blender to disk
```
$BLENDER -noaudio --background --python generate.py -- --seed 0 --task mesh_save -g desert simple --input_folder outputs/helloworld/fine --output_folder outputs/helloworld/saved_mesh
```
5. Generate dense annotations
```
../process_mesh/build/process_mesh --frame 1 -in outputs/helloworld/saved_mesh -out outputs/helloworld/frames
```
6. Summarize the file structure into a single JSON
```
python tools/summarize.py outputs/helloworld # creating outputs/helloworld/summary.json
```
7. (Optional) Select for a segmentation mask of certain semantic tags, e.g. cactus
```
python tools/ground_truth/segmentation_lookup.py outputs/helloworld 1 --query cactus
```

### Specification

**File structure:**

We provide a python script `summarize.py` which will aggregate all relevant output file paths into a JSON:
```
python tools/summarize.py <output-folder>
```
The resulting `<output-folder>/summary.json` will contains all file paths in the form:
```
{
    <type>: {
        <file-ext>: {
            <rig>: {
                <sub-cam>: {
                    <frame>: <file-path> 
                }
            }
        }
    }
}
```

`<rig>` and `<sub-cam>` are typically both "00" in the monocular setting; `<file-ext>` is typically "npy" or "png" for the the actual data and the visualization, respectively; `<frame>` is a 0-padded 4-digit number, e.g. "0013". `<type>` can be "SurfaceNormal", "Depth", etc. For example
`summary_json["SurfaceNormal"]["npy"]["00"]["00"]["0001"]` -> `'frames/SurfaceNormal_0001_00_00.npy'`

*Note: Currently our ground-truth has only been tested for the aspect-ratio 16-9.*

**Depth**

Depth is stored as a 2160 x 3840 32-bit floating point numpy array.

*Path:* `summary_json["Depth"]["npy"]["00"]["00"]["0001"]` -> `frames/Depth_0001_00_00.npy`

*Visualization:* `summary_json["Depth"]["png"]["00"]["00"]["0001"]` -> `frames/Depth_0001_00_00.png`

<p align="center">
<img src="images/gt_annotations/Depth_0001_00_00.png" width="400" />
</p>

The depth and camera parameters can be used to warp one image to another frame by running:
```
python tools/ground_truth/rigid_warp.py <folder> <first-frame> <second-frame>
```

**Surface Normals**

Surface Normals are stored as a 1080 x 1920 x 3 32-bit floating point numpy array.

*Path:* `summary_json["SurfaceNormal"]["npy"]["00"]["00"]["0001"]` -> `frames/SurfaceNormal_0001_00_00.npy`

*Visualization:* `summary_json["SurfaceNormal"]["png"]["00"]["00"]["0001"]` -> `frames/SurfaceNormal_0001_00_00.png`

<p align="center">
<img src="images/gt_annotations/SurfaceNormal_0001_00_00.png" width="400" />
</p>

**Occlusion Boundaries**

Occlusion Boundaries are stored as a 2160 x 3840 png, with 255 indicating a boundary and 0 otherwise.

*Path/Visualization:* `summary_json["OcclusionBoundaries"]["png"]["00"]["00"]["0001"]` -> `frames/OcclusionBoundaries_0001_00_00.png`

<p align="center">
<img src="images/gt_annotations/OcclusionBoundaries_0001_00_00.png" width="400" />
</p>

**Optical Flow / Scene Flow**

Optical Flow / Scene Flow is stored as a 2160 x 3840 x 3 32-bit floating point numpy array.

*Note: The values won't be meaningful if this is the final frame in a series, or in the single-view setting.*

Channels 1 & 2 are standard optical flow. Note that the units of optical flow are in pixels measured in the resolution of the *original image*. So if the rendered image is 1080 x 1920, you would want to average-pool this array by 2x.

Channel 3 is the depth change between this frame and the next.

To see an example of how optical flow can be used to warp one frame to the next, run

```
python tools/ground_truth/optical_flow_warp.py <folder> <frame-number>
```

*Path:* `summary_json["Flow3D"]["npy"]["00"]["00"]["0001"]` -> `frames/Flow3D_0001_00_00.npy`

*Visualization:* `summary_json["Flow3D"]["png"]["00"]["00"]["0001"]` -> `frames/ObjectSegmentation_0001_00_00.png`

**Optical Flow Occlusion**

The mask of occluded pixels for the aforementioned optical flow is stored as a 2160 x 3840 png, with 255 indicating a co-visible pixel and 0 otherwise.

*Note: This mask is computed by comparing the face-ids on the triangle meshes at either end of each flow vector. Infinigen meshes often contain multiple faces per-pixel, resulting in frequent false-negatives (negative=occluded). These false-negatives are generally distributed uniformly over the image (like salt-and-pepper noise), and can be reduced by max-pooling the occlusion mask down to the image resolution.*

*Path/Visualization:* `summary_json["Flow3DMask"]["png"]["00"]["00"]["0001"]` -> `frames/Flow3DMask_0001_00_00.png`

**Camera Intrinsics**

Infinigen renders images using a pinhole camera model. The resulting camera intrinsics for each frame are stored as a 3 x 3 numpy matrix.

*Path:* `summary_json["Camera Intrinsics"]["npy"]["00"]["00"]["0001"]` -> `saved_mesh/frame_0001/cameras/K_0001_00_00.npy`

**Camera Extrinsics**

The camera pose is stored as a 4 x 4 numpy matrix mapping from camera coordinates to world coordinates.

As is standard in computer vision, the assumed world coordinate system in the saved camera poses is +X -> Right, +Y -> Down, +Z Forward. This is opposed to how Blender internally represents geometry, with flipped Y and Z axes.

*Path:* `summary_json["Camera Pose"]["npy"]["00"]["00"]["0001"]` -> `saved_mesh/frame_0001/cameras/T_0001_00_00.npy`

**Panoptic Segmentation and 3D Bounding Boxes**

Infinigen saves three types of semantic segmentation masks: 1) Object Segmentation 2) Tag Segmentation 3) Instance Segmentation

*Object Segmentation* distinguishes individual blender objects, and is stored as a 2160 x 3840 32-bit integer numpy array. The association between each integer in the mask and the related object is stored in Objects_XXXX_XX_XX.json. The definition of "object" is imposed by Blender; generally large or complex assets such as the terrain, trees, or animals are considered one singular object, while a large number of smaller assets (e.g. grass, coral) may be grouped together if they are using instanced-geometry for their implementation.

*Tag Segmentation* distinguishes vertices based on their semantic tags, and is stored as a 2160 x 3840 64-bit integer numpy array. Infinigen tags all vertices with an integer which can be associated to a list of semantic labels in `MaskTag.json`. Compared to Object Segmentation, Infinigen's tagging system is less automatic but much more flexible. Missing features in the tagging system are usually possible and straightforward to implement, wheras in the automaically generated Object Segmentation they are not. 

*Instance Segmentation* distinguishes individual instances of a single object from one another (e.g. separate blades of grass, separate ferns, etc.), and is stored as a 2160 x 3840 32-bit integer numpy array. Each integer in this mask is the *instance-id* for a particular instance, which is unique for that object as defined in the Object Segmentation mask and Objects_XXXX_XX_XX.json. The list of **3D bounding boxes** for each instance are also defined in the `Objects_XXXX_XX_XX.json`.

*Paths:*

`summary_json["ObjectSegmentation"]["npy"]["00"]["00"]["0001"]` -> `frames/ObjectSegmentation_0001_00_00.npy`

`summary_json["TagSegmentation"]["npy"]["00"]["00"]["0001"]` -> `frames/TagSegmentation_0001_00_00.npy`

`summary_json["InstanceSegmentation"]["npy"]["00"]["00"]["0001"]` -> `frames/InstanceSegmentation_0001_00_00.npy`

`summary_json["Objects"]["json"]["00"]["00"]["0001"]` -> `frames/Objects_0001_00_00.json`

`summary_json["Mask Tags"][<frame>]` -> `fine/MaskTag.json`

*Visualizations:*

`summary_json["ObjectSegmentation"]["png"]["00"]["00"]["0001"]` -> `frames/ObjectSegmentation_0001_00_00.png`

`summary_json["TagSegmentation"]["png"]["00"]["00"]["0001"]` -> `frames/TagSegmentation_0001_00_00.png`

`summary_json["InstanceSegmentation"]["png"]["00"]["00"]["0001"]` -> `frames/InstanceSegmentation_0001_00_00.png`

Generally, most useful panoptic segmentation masks can be constructed by combining the aforementioned three arrays in some way. As an example, to visualize the 2D and 3D bounding boxes for objects with the *blender_rock* semantic tag in the hello world scene, run 
```
python tools/ground_truth/segmentation_lookup.py outputs/helloworld 1 --query blender_rock --boxes
python tools/ground_truth/bounding_boxes_3d.py outputs/helloworld 1 --query blender_rock
```
which will output

<p align="center">
<img src="images/gt_annotations/blender_rock_2d.png" width="400" /> <img src="images/gt_annotations/blender_rock_3d.png" width="400" />
</p>

By ommitting the --query flag, a list of available tags will be printed.

One could also produce a mask for only *flower petals*:

```
python tools/ground_truth/segmentation_lookup.py outputs/helloworld 1 --query petal
```
<p align="center">
<img src="images/gt_annotations/petal.png" width="400" />
</p>

A benefit of our tagging system is that one can produce a segmentation mask for things which are not a distinct object, such as terrain attributes. For instance, we can highlight only *caves* or *warped rocks*

```
python tools/ground_truth/segmentation_lookup.py outputs/helloworld 1 --query cave
python tools/ground_truth/segmentation_lookup.py outputs/helloworld 1 --query warped_rocks
```
<p align="center">
<img src="images/gt_annotations/caves.png" width="400" /> <img src="images/gt_annotations/warped_rocks.png" width="400" />
</p>

Dockerfile METASEP
ARG APP_IMAGE=continuumio/miniconda3
FROM ${APP_IMAGE}
ARG APP_IMAGE
ENV PATH="/root/miniconda3/bin:${PATH}"
RUN if [ "$APP_IMAGE" = "nvidia/cuda:12.0.0-devel-ubuntu22.04" ]; then \
    echo "Using CUDA image" && \
    apt-get update && \
    apt-get install -y unzip sudo git g++ libglm-dev libglew-dev libglfw3-dev libgles2-mesa-dev zlib1g-dev wget cmake vim libxi6 libgconf-2-4 && \
    wget \
    https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \
    && mkdir /root/.conda \
    && bash Miniconda3-latest-Linux-x86_64.sh -b \
    && rm -f Miniconda3-latest-Linux-x86_64.sh; \
else \
    echo "Using Conda image" && \
    apt-get update -yq \
    && apt-get install -yq \
        cmake \
        g++ \
        libgconf-2-4 \
        libgles2-mesa-dev \
        libglew-dev \
        libglfw3-dev \
        libglm-dev \
        libxi6 \
        sudo \
        unzip \
        vim \
        zlib1g-dev; \
fi

RUN mkdir /opt/infinigen
WORKDIR /opt/infinigen
COPY . .
RUN chmod +x worldgen/tools/compile_opengl.sh
RUN conda init bash \
    && . ~/.bashrc \
    && conda create --name infinigen python=3.10 \
    && conda activate infinigen \
    && ./install.sh
worldgen/surfaces/scatters/utils/__init__.py METASEP

worldgen/rendering/__init__.py METASEP

worldgen/nodes/__init__.py METASEP

worldgen/lighting/__init__.py METASEP

worldgen/assets/__init__.py METASEP

__init__.py METASEP

worldgen/surfaces/scatters/__init__.py METASEP

worldgen/generate.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

import argparse
import ast
import os
import random
import sys
import cProfile
from pathlib import Path
import logging
from functools import partial
import pprint
from collections import defaultdict

import bpy
import mathutils
from mathutils import Vector
import gin
import numpy as np
from numpy.random import uniform, normal, randint
from tqdm import tqdm
from frozendict import frozendict

sys.path.append(os.getcwd())

from terrain import Terrain
from util.organization import Task, Attributes, Tags, ElementNames

from placement import placement, density, camera as cam_util
from placement.split_in_view import split_inview
from lighting import lighting, kole_clouds

from assets.trees.generate import TreeFactory, BushFactory, random_season, random_leaf_collection
from assets.glowing_rocks import GlowingRocksFactory
from assets.creatures import CarnivoreFactory, HerbivoreFactory, FishFactory, FishSchoolFactory, \
    BeetleFactory, AntSwarmFactory, BirdFactory, SnakeFactory, \
    CrustaceanFactory, FlyingBirdFactory, CrabFactory, LobsterFactory, SpinyLobsterFactory
from assets.insects.assembled.dragonfly import DragonflyFactory
from assets.cloud.generate import CloudFactory
from assets.cactus import CactusFactory
from assets.creatures import boid_swarm

import surfaces.scatters
from surfaces.scatters import rocks, grass, snow_layer, ground_leaves, ground_twigs, \
    chopped_trees, pinecone, fern, flowerplant, monocot, ground_mushroom, \
    slime_mold, moss, ivy, lichen, mushroom, decorative_plants, seashells
from surfaces.scatters.utils.selection import scatter_lower, scatter_upward
from surfaces.templates import mountain, sand, water, atmosphere_light_haze, sandstone, cracked_ground, \
    soil, dirt, cobble_stone, chunkyrock, stone, lava, ice, mud, snow

from placement import particles, placement, density, camera as cam_util, animation_policy, instance_scatter, detail
from assets import particles as particle_assets

from surfaces.scatters import pine_needle, seaweed, coral_reef, jellyfish, urchin
from assets import boulder, cactus, caustics_lamp
from assets.monocot import kelp
from surfaces import surface

import surfaces.scatters

from placement.factory import make_asset_collection
from util import blender as butil
from util.logging import Timer
from util.math import FixedSeed, int_hash
from util.pipeline import RandomStageExecutor
from util.random import sample_registry, random_general

import core as infinigen

@gin.configurable
def compose_scene(output_folder, terrain, scene_seed, **params):

    p = RandomStageExecutor(scene_seed, output_folder, params)

    p.run_stage('fancy_clouds', kole_clouds.add_kole_clouds)

    season = p.run_stage('season', random_season, use_chance=False)
    logging.info(f'{season=}')

    terrain_mesh = p.run_stage('terrain', terrain.coarse_terrain, use_chance=False)
    density.set_tag_dict(terrain.tag_dict)
    terrain_bvh = mathutils.bvhtree.BVHTree.FromObject(terrain_mesh, bpy.context.evaluated_depsgraph_get())

    land_domain = params.get('land_domain_tags')
    underwater_domain = params.get('underwater_domain_tags')
    nonliving_domain = params.get('nonliving_domain_tags')

    def choose_forest_params():
        # params to be shared between unique and instanced trees
        n_tree_species = randint(1, params.get("max_tree_species", 3) + 1)
        tree_params = lambda: {
            'density': params.get("tree_density", uniform(0.045, 0.15)) / n_tree_species,
            'distance_min': uniform(1, 2.5),
            'select_scale': uniform(0.03, 0.3)
        }
        return [tree_params() for _ in range(n_tree_species)]
    tree_species_params = p.run_stage('forest_params', choose_forest_params, use_chance=False)

    def add_trees(terrain_mesh):
        for i, params in enumerate(tree_species_params):
            fac = TreeFactory(np.random.randint(1e7), coarse=True)
            selection = density.placement_mask(params['select_scale'], tag=land_domain)
            placement.scatter_placeholders_mesh(terrain_mesh, fac, selection=selection, altitude=-0.1,
                overall_density=params['density'], distance_min=params['distance_min'])
    p.run_stage('trees', add_trees, terrain_mesh)

    def add_bushes(terrain_mesh):
        n_bush_species = randint(1, params.get("max_bush_species", 2) + 1)
        for i in range(n_bush_species):
            spec_density = params.get("bush_density", uniform(0.03, 0.12)) / n_bush_species
            fac = BushFactory(int_hash((scene_seed, i)), coarse=True)
            selection = density.placement_mask(uniform(0.015, 0.2), normal_thresh=0.3, 
                select_thresh=uniform(0.5, 0.6), tag=land_domain)
            placement.scatter_placeholders_mesh(terrain_mesh, fac, altitude=-0.05,
                overall_density=spec_density, distance_min=uniform(0.05, 0.3),
                selection=selection)
    p.run_stage('bushes', add_bushes, terrain_mesh)

    def add_clouds(terrain_mesh):
        cloud_factory = CloudFactory(int_hash((scene_seed, 0)), coarse=True, terrain_mesh=terrain_mesh)
        placement.scatter_placeholders(cloud_factory.spawn_locations(), cloud_factory)
    p.run_stage('clouds', add_clouds, terrain_mesh)

    def add_boulders(terrain_mesh):
        n_boulder_species = randint(1, params.get("max_boulder_species", 5))
        for i in range(n_boulder_species):
            selection = density.placement_mask(0.05, tag=nonliving_domain, select_thresh=uniform(0.55, 0.6))
            fac = boulder.BoulderFactory(int_hash((scene_seed, i)), coarse=True)
            placement.scatter_placeholders_mesh(terrain_mesh, fac, 
                overall_density=params.get("boulder_density", uniform(.02, .05)) / n_boulder_species,
                selection=selection, altitude=-0.25)
    p.run_stage('boulders', add_boulders, terrain_mesh)

    def add_glowing_rocks(terrain_mesh):
        selection = density.placement_mask(uniform(0.03, 0.3), normal_thresh=-1.1, select_thresh=0, tag=Tags.Cave)
        fac = GlowingRocksFactory(int_hash((scene_seed, 0)), coarse=True)
        placement.scatter_placeholders_mesh(terrain_mesh, fac,
            overall_density=params.get("glow_rock_density", 0.025), selection=selection)
    p.run_stage('glowing_rocks', add_glowing_rocks, terrain_mesh)

    def add_kelp(terrain_mesh):
        fac = kelp.KelpMonocotFactory(int_hash((scene_seed, 0)), coarse=True)
        selection = density.placement_mask(scale=0.05, tag=underwater_domain)
        placement.scatter_placeholders_mesh(terrain_mesh, fac, altitude=-0.05,
            overall_density=params.get('kelp_density', uniform(.2, 1)),
            selection=selection, distance_min=3)
    p.run_stage('kelp', add_kelp, terrain_mesh)

    def add_cactus(terrain_mesh):
        n_cactus_species = randint(2, params.get("max_cactus_species", 4))
        for i in range(n_cactus_species):
            fac = cactus.CactusFactory(int_hash((scene_seed, i)), coarse=True)
            selection = density.placement_mask(scale=.05, tag=land_domain, select_thresh=0.57)
            placement.scatter_placeholders_mesh(terrain_mesh, fac, altitude=-0.05,
                overall_density=params.get('cactus_density', uniform(.02, .1) / n_cactus_species),
                selection=selection, distance_min=1)
    p.run_stage('cactus', add_cactus, terrain_mesh)

    def camera_preprocess():
        camera_rigs = cam_util.spawn_camera_rigs()
        scene_bvhtrees = cam_util.camera_selection_preprocessing(terrain)   
        return camera_rigs, scene_bvhtrees 
    camera_rigs, scene_bvhtrees = p.run_stage('camera_preprocess', camera_preprocess, use_chance=False)
    p.run_stage('pose_cameras', lambda: cam_util.configure_cameras(
        camera_rigs, scene_bvhtrees, terrain), use_chance=False)
    cam = cam_util.get_camera(0, 0)
    
    p.run_stage('lighting', lighting.add_lighting, cam, use_chance=False)
    # determine a small area of the terrain for the creatures to run around on
    # must happen before camera is animated, as camera may want to follow them around
    terrain_center, *_ = split_inview(terrain_mesh, cam=cam, 
            start=0, end=0, outofview=False, vis_margin=5, dist_max=params["center_distance"],
            hide_render=True, suffix='center')
    deps = bpy.context.evaluated_depsgraph_get()
    terrain_center_bvh = mathutils.bvhtree.BVHTree.FromObject(terrain_center, deps)
    
    pois = [] # objects / points of interest, for the camera to look at

    def add_ground_creatures(target):
        fac_class = sample_registry(params['ground_creature_registry'])
        fac = fac_class(int_hash((scene_seed, 0)), bvh=terrain_bvh, animation_mode='idle')
        n = params.get('max_ground_creatures', randint(1, 4))
        selection = density.placement_mask(select_thresh=0, tag='beach', altitude_range=(-0.5, 0.5)) if fac_class is CrabFactory else 1
        col = placement.scatter_placeholders_mesh(target, fac, num_placeholders=n, overall_density=1, selection=selection, altitude=0.2)
        return list(col.objects)
    pois += p.run_stage('ground_creatures', add_ground_creatures, target=terrain_center, default=[])

    def flying_creatures():
        fac_class = sample_registry(params['flying_creature_registry'])
        fac = fac_class(randint(1e7), bvh=terrain_bvh, animation_mode='idle')
        n = params.get('max_flying_creatures', randint(2, 7))
        col = placement.scatter_placeholders_mesh(terrain_center, fac, num_placeholders=n, overall_density=1, altitude=0.2)
        return list(col.objects)
    pois += p.run_stage('flying_creatures', flying_creatures, default=[])

    p.run_stage('animate_cameras', lambda: cam_util.animate_cameras(
        camera_rigs, scene_bvhtrees, pois=pois), use_chance=False)

    with Timer('Compute coarse terrain frustrums'):
        terrain_inview, *_ = split_inview(terrain_mesh, verbose=True, outofview=False, print_areas=True,
            cam=cam, vis_margin=2, dist_max=params['inview_distance'], hide_render=True, suffix='inview')
        terrain_near, *_ = split_inview(terrain_mesh, verbose=True, outofview=False, print_areas=True,
            cam=cam, vis_margin=2, dist_max=params['near_distance'], hide_render=True, suffix='near')

        collider = butil.modify_mesh(butil.deep_clone_obj(terrain_near), 'COLLISION', apply=False, show_viewport=True)
        collider.name = collider.name + '.collider'
        collider.collision.use_culling = False
        collider_col = butil.get_collection('colliders')
        butil.put_in_collection(collider, collider_col)

        butil.modify_mesh(terrain_near, 'SUBSURF', levels=2, apply=True)

        deps = bpy.context.evaluated_depsgraph_get()
        terrain_inview_bvh = mathutils.bvhtree.BVHTree.FromObject(terrain_inview, deps)

    p.run_stage('caustics', lambda: caustics_lamp.add_caustics(terrain_near))

    def add_fish_school():
        n = random_general(params.get("max_fish_schools", 3))
        for i in range(n):
            selection = density.placement_mask(0.1, select_thresh=0, tag=underwater_domain)
            fac = FishSchoolFactory(randint(1e7), bvh=terrain_inview_bvh)
            col = placement.scatter_placeholders_mesh(terrain_near, fac, selection=selection,
                overall_density=1, num_placeholders=1, altitude=2)
            placement.populate_collection(fac, col)
    p.run_stage('fish_school', add_fish_school, default=[])

    def add_bug_swarm():
        n = randint(1, params.get("max_bug_swarms", 3) + 1)
        selection = density.placement_mask(0.1, select_thresh=0, tag=land_domain)
        fac = AntSwarmFactory(randint(1e7), bvh=terrain_inview_bvh, coarse=True)
        col = placement.scatter_placeholders_mesh(terrain_inview, fac, 
            selection=selection, overall_density=1, num_placeholders=n, altitude=2)
        placement.populate_collection(fac, col)
    p.run_stage('bug_swarm', add_bug_swarm)

    def add_rocks(target):
        selection = density.placement_mask(scale=0.15, select_thresh=0.5,
            normal_thresh=0.7, return_scalar=True, tag=nonliving_domain)
        _, rock_col = surfaces.scatters.rocks.apply(target, selection=selection)
        return rock_col
    p.run_stage('rocks', add_rocks, terrain_inview)

    def add_ground_leaves(target):
        selection = density.placement_mask(scale=0.1, select_thresh=0.52, normal_thresh=0.7, return_scalar=True, tag=land_domain)
        surfaces.scatters.ground_leaves.apply(target, selection=selection, season=season)
    p.run_stage('ground_leaves', add_ground_leaves, terrain_near, prereq='trees')
                
    def add_ground_twigs(target):
        use_leaves = uniform() < 0.5
        selection = density.placement_mask(scale=0.15, select_thresh=0.55, normal_thresh=0.7, return_scalar=True, tag=nonliving_domain)
        surfaces.scatters.ground_twigs.apply(target, selection=selection, use_leaves=use_leaves)
    p.run_stage('ground_twigs', add_ground_twigs, terrain_near)

    def add_chopped_trees(target):
        selection = density.placement_mask(scale=0.15, select_thresh=uniform(0.55, 0.6), 
                                           normal_thresh=0.7, return_scalar=True, tag=nonliving_domain)
        surfaces.scatters.chopped_trees.apply(target, selection=selection)
    p.run_stage('chopped_trees', add_chopped_trees, terrain_inview)

    def add_grass(target):
        select_max = params.get('grass_select_max', 0.5)
        selection = density.placement_mask(
            normal_dir=(0, 0, 1), scale=0.1, tag=land_domain,
            return_scalar=True, select_thresh=uniform(select_max/2, select_max))
        surfaces.scatters.grass.apply(target, selection=selection)
    p.run_stage('grass', add_grass, terrain_inview)

    def add_monocots(target):
        selection = density.placement_mask(
            normal_dir=(0, 0, 1), scale=0.2, tag=land_domain)
        surfaces.scatters.monocot.apply(terrain_inview, grass=True, selection=selection)
        selection = density.placement_mask(
            normal_dir=(0, 0, 1), scale=0.2, select_thresh=0.55,
            tag=params.get("grass_habitats", None))
        surfaces.scatters.monocot.apply(target, grass=False, selection=selection)
    p.run_stage('monocots', add_monocots, terrain_inview)

    def add_ferns(target):
        selection = density.placement_mask(normal_dir=(0, 0, 1), scale=0.1, 
                    select_thresh=0.6, return_scalar=True, tag=land_domain)
        surfaces.scatters.fern.apply(target, selection=selection)
    p.run_stage('ferns', add_ferns, terrain_inview)

    def add_flowers(target):
        selection = density.placement_mask(normal_dir=(0, 0, 1), scale=0.01,
            select_thresh=0.6, return_scalar=True, tag=land_domain)
        surfaces.scatters.flowerplant.apply(target, selection=selection)
    p.run_stage('flowers', add_flowers, terrain_inview)

    def add_corals(target):
        vertical_faces = density.placement_mask(scale=0.15, select_thresh=uniform(.44, .48))
        coral_reef.apply(target, selection=vertical_faces, tag=underwater_domain,
                         density=params.get('coral_density', 2.5))
        horizontal_faces = density.placement_mask(scale=.15, normal_thresh=-.4, normal_thresh_high=.4)
        coral_reef.apply(target, selection=horizontal_faces, n=5, horizontal=True, tag=underwater_domain,
                         density=params.get('horizontal_coral_density', 2.5))
    p.run_stage('corals', add_corals, terrain_inview)

    p.run_stage('mushroom', lambda: surfaces.scatters.ground_mushroom.Mushrooms().apply(terrain_near,
        selection=density.placement_mask(scale=.1, select_thresh=.65, return_scalar=True, tag=land_domain),
        density=params.get('mushroom_density', 2)))

    p.run_stage('seaweed', lambda: seaweed.apply(terrain_inview, 
        selection=density.placement_mask(scale=0.05, select_thresh=.5, normal_thresh=0.4, tag=underwater_domain)))
    p.run_stage('urchin', lambda: urchin.apply(terrain_inview,
        selection=density.placement_mask(scale=0.05, select_thresh=.5, tag=underwater_domain)))
    p.run_stage('jellyfish', lambda: jellyfish.apply(terrain_inview,
        selection=density.placement_mask(scale=0.05, select_thresh=.5, tag=underwater_domain)))
    
    p.run_stage('seashells', lambda: surfaces.scatters.seashells.apply(terrain_near,
        selection=density.placement_mask(scale=0.05, select_thresh=.5, tag='landscape,', return_scalar=True)))
    p.run_stage('pinecone', lambda: surfaces.scatters.pinecone.apply(terrain_near,
        selection=density.placement_mask(scale=.1, select_thresh=.63, tag=land_domain)))
    p.run_stage('pine_needle', lambda: pine_needle.apply(terrain_near,
        selection=density.placement_mask(scale=uniform(0.05, 0.2), select_thresh=uniform(0.4, 0.55), tag=land_domain, return_scalar=True)))
    p.run_stage('decorative_plants', lambda: surfaces.scatters.decorative_plants.apply(terrain_near,
        selection=density.placement_mask(scale=uniform(0.05, 0.2), select_thresh=uniform(0.5, 0.65), tag=land_domain, return_scalar=True)))

    p.run_stage('wind', particle_assets.wind_effector)
    p.run_stage('turbulence', particle_assets.turbulence_effector)
    emitter_off = Vector((0, 0, 5)) # to allow space to fall into frame from off screen

    def add_leaf_particles():
        return particles.particle_system(
            emitter=butil.spawn_plane(location=emitter_off, size=60),
            subject=random_leaf_collection(n=5, season=season),
            settings=particles.falling_leaf_settings())
    def add_rain_particles():
        return particles.particle_system(
            emitter=butil.spawn_plane(location=emitter_off, size=30),
            subject=make_asset_collection(particle_assets.RaindropFactory(scene_seed), 5),
            settings=particles.rain_settings())
    def add_dust_particles():
        return particles.particle_system(
            emitter=butil.spawn_cube(location=Vector(), size=30),
            subject=make_asset_collection(particle_assets.DustMoteFactory(scene_seed), 5),
            settings=particles.floating_dust_settings())
    def add_marine_snow_particles():
        return particles.particle_system(
            emitter=butil.spawn_cube(location=Vector(), size=30),
            subject=make_asset_collection(particle_assets.DustMoteFactory(scene_seed), 5),
            settings=particles.marine_snow_setting())
    def add_snow_particles():
        return particles.particle_system(
            emitter=butil.spawn_plane(location=emitter_off, size=60),
            subject=make_asset_collection(particle_assets.SnowflakeFactory(scene_seed), 5),
            settings=particles.snow_settings())

    particle_systems = [
        p.run_stage('leaf_particles', add_leaf_particles, prereq='trees'),
        p.run_stage('rain_particles', add_rain_particles),
        p.run_stage('dust_particles', add_dust_particles),
        p.run_stage('marine_snow_particles', add_marine_snow_particles),
        p.run_stage('snow_particles', add_snow_particles),
    ]

    for emitter, system in filter(lambda s: s is not None, particle_systems):
        with Timer(f"Baking particle system"):
            butil.constrain_object(emitter, "COPY_LOCATION", use_offset=True, target=cam.parent)
            particles.bake(emitter, system)
        butil.put_in_collection(emitter, butil.get_collection('particles'))

    p.save_results(output_folder/'pipeline_coarse.csv')

    return terrain

def main():
    
    parser = argparse.ArgumentParser()
    parser.add_argument('--output_folder', type=Path)
    parser.add_argument('--input_folder', type=Path, default=None)
    parser.add_argument('-s', '--seed', default=None, help="The seed used to generate the scene")
    parser.add_argument('-t', '--task', nargs='+', default=['coarse'],
                        choices=['coarse', 'populate', 'fine_terrain', 'ground_truth', 'render', 'mesh_save'])
    parser.add_argument('-g', '--gin_config', nargs='+', default=['base'],
                        help='Set of config files for gin (separated by spaces) '
                             'e.g. --gin_config file1 file2 (exclude .gin from path)')
    parser.add_argument('-p', '--gin_param', nargs='+', default=[],
                        help='Parameter settings that override config defaults '
                             'e.g. --gin_param module_1.a=2 module_2.b=3')
    parser.add_argument('--task_uniqname', type=str, default=None)
    parser.add_argument('-d', '--debug', action="store_const", dest="loglevel", const=logging.DEBUG, default=logging.INFO)
    parser.add_argument( '-v', '--verbose', action="store_const", dest="loglevel", const=logging.INFO)

    args = parser.parse_args(sys.argv[sys.argv.index("--") + 1:])

    extras = '[%(filename)s:%(lineno)d] ' if args.loglevel == logging.DEBUG else ''
    logging.basicConfig(
        format=f'[%(asctime)s.%(msecs)03d] [%(name)s] [%(levelname)s] {extras}| %(message)s',
        level=args.loglevel,
        datefmt='%H:%M:%S'
    )

    scene_seed = infinigen.apply_scene_seed(args)
    infinigen.apply_gin_configs(args, scene_seed)
    
    infinigen.main(
        compose_scene_func=compose_scene,
        input_folder=args.input_folder, 
        output_folder=args.output_folder, 
        task=args.task, 
        task_uniqname=args.task_uniqname, 
        scene_seed=scene_seed
    )

if __name__ == "__main__":
    main()

worldgen/core.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

import argparse
import ast
import os
import random
import sys
import cProfile
import shutil
from pathlib import Path
import logging
from functools import partial
import pprint
from collections import defaultdict

os.environ["OPENCV_IO_ENABLE_OPENEXR"] = "1"  # This must be done BEFORE import cv2.
# See https://github.com/opencv/opencv/issues/21326#issuecomment-1008517425

sys.path.append(os.path.split(os.path.abspath(__file__))[0])

import bpy
import mathutils
from mathutils import Vector
import gin
import numpy as np
from numpy.random import uniform, normal, randint
from tqdm import tqdm
from frozendict import frozendict

from terrain import Terrain
from util.organization import Task, Attributes, TerrainNames

from placement import placement, density, camera as cam_util
from placement.split_in_view import split_inview
from lighting import lighting, kole_clouds

from assets.trees.generate import TreeFactory, BushFactory, random_season, random_leaf_collection
from assets import boulder
from assets.glowing_rocks import GlowingRocksFactory
from assets.creatures import CarnivoreFactory, HerbivoreFactory, FishFactory, FishSchoolFactory, \
    BeetleFactory, AntSwarmFactory, BirdFactory, SnakeFactory, \
    CrustaceanFactory, FlyingBirdFactory, CrabFactory, LobsterFactory, SpinyLobsterFactory
from assets.insects.assembled.dragonfly import DragonflyFactory
from assets.cloud.generate import CloudFactory
from assets.cactus import CactusFactory
from assets.creatures import boid_swarm

from placement import placement, camera as cam_util
from assets.utils.misc import log_uniform

from rendering.render import render_image
from rendering.resample import resample_scene
from assets.monocot import kelp
from surfaces import surface

import surfaces.scatters
from surfaces.scatters import ground_mushroom, slime_mold, moss, ivy, lichen, snow_layer
from surfaces.scatters.utils.selection import scatter_lower, scatter_upward


from placement.factory import make_asset_collection
from util import blender as butil
from util import exporting
from util.logging import Timer, save_polycounts, create_text_file
from util.math import FixedSeed, int_hash
from util.pipeline import RandomStageExecutor
from util.random import sample_registry

from assets.utils.tag import tag_system

VERSION = '1.0.0'

def sanitize_gin_override(overrides: list):
    if len(overrides) > 0:
        print("Overriden parameters:", overrides)
    output = list(overrides)
    for i, o in enumerate(overrides):
        if ('=' in o) and not any((c in o) for c in "\"'[]"):
            k, v = o.split('=')
            try:
                ast.literal_eval(v)
            except:
                if "@" not in v:
                    output[i] = f'{k}="{v}"'
    return output
   
@gin.configurable
def populate_scene(
    output_folder, terrain, scene_seed, **params
):
    p = RandomStageExecutor(scene_seed, output_folder, params)
    camera = bpy.context.scene.camera

    season = p.run_stage('choose_season', random_season, use_chance=False, default=[])

    populated = {}
    populated['trees'] = p.run_stage('populate_trees', use_chance=False, default=[],
        fn=lambda: placement.populate_all(TreeFactory, camera, season=season, vis_cull=4, dist_cull=70))#,
                                        #meshing_camera=camera, adapt_mesh_method='subdivide', cam_meshing_max_dist=8)) 
    populated['boulders'] = p.run_stage('populate_boulders', use_chance=False, default=[],
        fn=lambda: placement.populate_all(boulder.BoulderFactory, camera, vis_cull=3, dist_cull=70))#,
                                        #meshing_camera=camera, adapt_mesh_method='subdivide', cam_meshing_max_dist=8))
    p.run_stage('populate_bushes', use_chance=False,
        fn=lambda: placement.populate_all(BushFactory, camera, vis_cull=1, adapt_mesh_method='subdivide'))
    p.run_stage('populate_kelp', use_chance=False,
        fn=lambda: placement.populate_all(kelp.KelpMonocotFactory, camera, vis_cull=5))
    p.run_stage('populate_cactus', use_chance=False,
        fn=lambda: placement.populate_all(CactusFactory, camera, vis_cull=6))
    p.run_stage('populate_clouds', use_chance=False,
        fn=lambda: placement.populate_all(CloudFactory, camera, dist_cull=None, vis_cull=None))
    p.run_stage('populate_glowing_rocks', use_chance=False,
        fn=lambda: placement.populate_all(GlowingRocksFactory, camera, dist_cull=None, vis_cull=None))
    
    grime_selection_funcs = {
        'trees': scatter_lower,
        'boulders': scatter_upward,
    }
    grime_types = {
        'slime_mold': slime_mold.SlimeMold,
        'lichen': lichen.Lichen,
        'ivy': ivy.Ivy,
        'mushroom': ground_mushroom.Mushrooms,
        'moss': moss.MossCover
    }
    def apply_grime(grime_type, surface_cls):
        surface_fac = surface_cls()
        for target_type, results, in populated.items():
            selection_func = grime_selection_funcs.get(target_type, None)
            for fac_seed, fac_pholders, fac_assets in results:
                if len(fac_pholders) == 0:
                    continue
                for inst_seed, obj in fac_assets:
                    with FixedSeed(int_hash((grime_type, fac_seed, inst_seed))):
                        p_k = f'{grime_type}_on_{target_type}_per_instance_chance'
                        if uniform() > params.get(p_k, 0.4):
                            continue
                        logging.debug(f'Applying {surface_fac} on {obj}')
                        surface_fac.apply(obj, selection=selection_func)
    for grime_type, surface_cls in grime_types.items():
        p.run_stage(grime_type, lambda: apply_grime(grime_type, surface_cls))

    def apply_snow_layer(surface_cls):
        surface_fac = surface_cls()
        for target_type, results, in populated.items():
            selection_func = grime_selection_funcs.get(target_type, None)
            for fac_seed, fac_pholders, fac_assets in results:
                if len(fac_pholders) == 0:
                    continue
                for inst_seed, obj in fac_assets:
                    tmp = obj.users_collection[0].hide_viewport
                    obj.users_collection[0].hide_viewport = False
                    surface_fac.apply(obj, selection=selection_func)
                    obj.users_collection[0].hide_viewport = tmp
    p.run_stage("snow_layer", lambda: apply_snow_layer(snow_layer.Snowlayer))

    creature_facs = {
        'carnivore': CarnivoreFactory, 'herbivore': HerbivoreFactory,
        'bird': BirdFactory, 'fish': FishFactory, 'snake': SnakeFactory,
        'beetles': BeetleFactory, 
        'flyingbird': FlyingBirdFactory, 'dragonfly': DragonflyFactory,
        'crab': CrabFactory, 'crustacean': CrustaceanFactory
    }
    for k, fac in creature_facs.items():
        p.run_stage(f'populate_{k}', use_chance=False,
            fn=lambda: placement.populate_all(fac, camera=None))

    p.save_results(output_folder/'pipeline_fine.csv')

def get_scene_tag(name):
    try:
        o = next(o for o in bpy.data.objects if o.name.startswith(f'{name}='))
        return o.name.split('=')[-1].strip('\'\"')
    except StopIteration:
        return None

@gin.configurable
def render(scene_seed, output_folder, camera_id, render_image_func=render_image, resample_idx=None):
    if resample_idx is not None and resample_idx != 0:
        resample_scene(int_hash((scene_seed, resample_idx)))
    with Timer('Render Frames'):
        render_image_func(frames_folder=Path(output_folder), camera_id=camera_id)

@gin.configurable
def save_meshes(scene_seed, output_folder, frame_range, camera_id, resample_idx=False):
    
    if resample_idx is not None and resample_idx > 0:
        resample_scene(int_hash((scene_seed, resample_idx)))

    for obj in bpy.data.objects:
        obj.hide_viewport = obj.hide_render

    for col in bpy.data.collections:
        col.hide_viewport = col.hide_render

    camera_rig_id, subcam_id = camera_id
    previous_frame_mesh_id_mapping = frozendict()
    current_frame_mesh_id_mapping = defaultdict(dict)
    for frame_idx in range(int(frame_range[0]), int(frame_range[1]+2)):
        bpy.context.scene.frame_set(frame_idx)
        bpy.context.view_layer.update()
        frame_info_folder = Path(output_folder) / f"frame_{frame_idx:04d}"
        frame_info_folder.mkdir(parents=True, exist_ok=True)
        logging.info(f"Working on frame {frame_idx}")
        exporting.save_obj_and_instances(str(frame_info_folder /  "mesh"), previous_frame_mesh_id_mapping, current_frame_mesh_id_mapping)
        cam_util.save_camera_parameters(camera_rig_id, [subcam_id], str(frame_info_folder / "cameras"), frame_idx)
        previous_frame_mesh_id_mapping = frozendict(current_frame_mesh_id_mapping)
        current_frame_mesh_id_mapping.clear()

def validate_version(scene_version):
    if scene_version is None or scene_version.split('.')[:-1] != VERSION.split('.')[:-1]:
        raise ValueError(
            f'generate.py {VERSION=} attempted to load a scene created by version {scene_version=}')
    if scene_version != VERSION:
        logging.warning(f'Worldgen {VERSION=} has minor version mismatch with {scene_version=}')

@gin.configurable
def group_collections(config):
    for config in config: # Group collections before fine runs
        butil.group_in_collection([o for o in bpy.data.objects if o.name.startswith(f'{config["name"]}:')], config["name"])
        butil.group_toplevel_collections(config['name'], hide_viewport=config['hide_viewport'], hide_render=config['hide_render'])

@gin.configurable
def execute_tasks(
    compose_scene_func,
    input_folder, output_folder,
    task, scene_seed,
    frame_range, camera_id,
    resample_idx=None,
    output_blend_name="scene.blend",
    generate_resolution=(1920,1080),
    reset_assets=True,
    focal_length=None,
):
    if input_folder != output_folder:
        if reset_assets:
            if os.path.islink(output_folder/"assets"):
                os.unlink(output_folder/"assets")
            elif (output_folder/"assets").exists():
                shutil.rmtree(output_folder/"assets")
        if (not os.path.islink(output_folder/"assets")) and (not (output_folder/"assets").exists()) and input_folder is not None and (input_folder/"assets").exists():
            os.symlink(input_folder/"assets", output_folder/"assets")
            # in this way, even coarse task can have input_folder to have pregenerated on-the-fly assets (e.g., in last run) to speed up developing
    if Task.Coarse not in task:
        with Timer('Reading input blendfile'):
            bpy.ops.wm.open_mainfile(filepath=str(input_folder / 'scene.blend'))
            tag_system.load_tag(path=str(input_folder / "MaskTag.json"))
        scene_version = get_scene_tag('VERSION')
        butil.approve_all_drivers()
    
    if frame_range[1] < frame_range[0]:
        raise ValueError(f'{frame_range=} is invalid, frame range must be nonempty. Blender end frame is INCLUSIVE')

    logging.info(f'Processing frames {frame_range[0]} through {frame_range[1]} inclusive')
    bpy.context.scene.frame_start = int(frame_range[0])
    bpy.context.scene.frame_end = int(frame_range[1])
    bpy.context.scene.frame_set(int(frame_range[0]))
    bpy.context.view_layer.update()

    surface.registry.initialize_from_gin()
    bpy.ops.preferences.addon_enable(module='ant_landscape')
    bpy.ops.preferences.addon_enable(module='real_snow')
    bpy.context.preferences.system.scrollback = 0 
    bpy.context.preferences.edit.undo_steps = 0
    bpy.context.scene.render.resolution_x = generate_resolution[0]
    bpy.context.scene.render.resolution_y = generate_resolution[1]
    bpy.context.scene.render.engine = 'CYCLES'
    bpy.context.scene.cycles.device = 'GPU'

    bpy.context.scene.cycles.volume_step_rate = 0.1
    bpy.context.scene.cycles.volume_preview_step_rate = 0.1
    bpy.context.scene.cycles.volume_max_steps = 32

    if Task.Coarse in task or Task.FineTerrain in task or Task.Fine in task or Task.Populate in task:
        terrain = Terrain(scene_seed, surface.registry, task=task, on_the_fly_asset_folder=output_folder/"assets")

    if Task.Coarse in task:
        butil.clear_scene(targets=[bpy.data.objects])
        butil.spawn_empty(f'{VERSION=}')
        compose_scene_func(output_folder, terrain, scene_seed)

    camera = cam_util.set_active_camera(*camera_id)
    if focal_length is not None:
        camera.data.lens = focal_length

    group_collections()

    if Task.Populate in task:
        populate_scene(output_folder, terrain, scene_seed)

    if Task.Fine in task:
        raise RuntimeError(f'{task=} contains deprecated {Task.Fine=}')

    if Task.FineTerrain in task:
        terrain.fine_terrain(output_folder)
    
    group_collections()

    if Task.Coarse in task or Task.Populate in task or Task.FineTerrain in task:
        bpy.context.preferences.system.scrollback = 100 
        bpy.context.preferences.edit.undo_steps = 100
        with Timer(f'Writing output blendfile to {output_folder / output_blend_name}'):
            bpy.ops.wm.save_mainfile(filepath=str(output_folder / output_blend_name))
            tag_system.save_tag(path=str(output_folder / "MaskTag.json"))

        with (output_folder/ "version.txt").open('w') as f:
            scene_version = get_scene_tag('VERSION')
            f.write(f"{scene_version}\n")

        with (output_folder/'polycounts.txt').open('w') as f:
            save_polycounts(f)

    for col in bpy.data.collections['unique_assets'].children:
        col.hide_viewport = False

    if Task.Render in task or Task.GroundTruth in task:
        render(scene_seed, output_folder=output_folder, camera_id=camera_id, resample_idx=resample_idx)

    if Task.MeshSave in task:
        save_meshes(scene_seed, output_folder=output_folder, frame_range=frame_range, camera_id=camera_id)


def determine_scene_seed(args):

    if args.seed is None:
        if Task.Coarse not in args.task:
            raise ValueError(
                f'Running tasks on an already generated scene, you need to specify --seed or results will'
                f' not be view-consistent')
        return randint(1e7), 'chosen at random'

    # WARNING: Do not add support for decimal numbers here, it will cause ambiguity, as some hex numbers are valid decimals

    try:
        return int(args.seed, 16), 'parsed as hexadecimal'
    except ValueError:
        pass

    return int_hash(args.seed), 'hashed string to integer'

def apply_scene_seed(args):
    scene_seed, reason = determine_scene_seed(args)
    logging.info(f'Converted {args.seed=} to {scene_seed=}, {reason}')
    gin.constant('OVERALL_SEED', scene_seed)
    del args.seed

    random.seed(scene_seed)
    np.random.seed(scene_seed)
    return scene_seed

def apply_gin_configs(args, scene_seed, skip_unknown=False):

    scene_types = [p.stem for p in Path('config/scene_types').iterdir()]
    scene_specified = any(s in scene_types or s.startswith("figure") for s in args.gin_config)

    weights = {
        "kelp_forest": 0.3,
        "coral_reef": 1,
        "forest": 2,
        "river": 2,
        "desert": 1,
        "coast": 1,
        "cave": 1,
        "mountain": 1,
        "canyon": 1,
        "plain": 1,
        "cliff": 1,
        "arctic": 1,
        "snowy_mountain": 1,
    }
    assert all(k in scene_types for k in weights)

    scene_types = [s for s in scene_types if s in weights]
    weights = np.array([weights[k] for k in scene_types], dtype=float)
    weights /= weights.sum()

    if not scene_specified:
        scene_type = np.random.RandomState(scene_seed).choice(scene_types, p=weights)
        logging.warning(f'Randomly selected {scene_type=}. IF THIS IS NOT INTENDED THEN YOU ARE MISSING SCENE CONFIGS')
        if len(args.gin_config) > 0 and args.gin_config[0] == 'base':
            args.gin_config = [scene_type] + args.gin_config[1:]
        else:
            args.gin_config = [scene_type] + args.gin_config

    def find_config(g):
        as_figure_type = f'config/figure_types/{g}.gin'
        if os.path.exists(as_figure_type):
            return as_figure_type
        as_scene_type = f'config/scene_types/{g}.gin'
        if os.path.exists(as_scene_type):
            return as_scene_type
        as_base = f'config/{g}.gin'
        if os.path.exists(as_base):
            return as_base
        raise ValueError(f'Couldn not locate {g} in either config/ or config/scene_types')

    bindings = sanitize_gin_override(args.gin_param)
    confs = [find_config(g) for g in ['base'] + args.gin_config]
    gin.parse_config_files_and_bindings(confs, bindings=bindings, skip_unknown=skip_unknown)

def main(
    input_folder, 
    output_folder,
    scene_seed,
    task, 
    task_uniqname,
    **kwargs
):
    
    version_req = ['3.3.1']
    assert bpy.app.version_string in version_req, f'You are using blender={bpy.app.version_string} which is ' \
                                                  f'not supported. Please use {version_req}'
    logging.info(f'infinigen version {VERSION}')
    logging.info(f"CUDA_VISIBLE_DEVICES={os.environ.get('CUDA_VISIBLE_DEVICES')}")

    if input_folder is not None:
        input_folder = Path(input_folder).absolute()
    output_folder = Path(output_folder).absolute()
    output_folder.mkdir(exist_ok=True, parents=True)

    if task_uniqname is not None:
        create_text_file(filename=f"START_{task_uniqname}")

    with Timer('MAIN TOTAL'):
        execute_tasks(
            input_folder=input_folder, output_folder=output_folder,
            task=task, scene_seed=scene_seed, **kwargs
        )

    if task_uniqname is not None:
        create_text_file(filename=f"FINISH_{task_uniqname}")
        create_text_file(filename=f"operative_gin_{task_uniqname}.txt", text=gin.operative_config_str())

worldgen/asset_demo.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

import argparse
import os
import sys
from pathlib import Path
import logging
from copy import copy

import bpy
from mathutils import Vector, Matrix, bvhtree
import gin
import numpy as np
from tqdm import tqdm, trange

sys.path.append(os.getcwd())

from terrain import Terrain

from assets.small_plants.fern import FernFactory
from assets.creatures.animation.run_cycle import follow_path
from lighting import lighting, kole_clouds
from surfaces.scatters import grass, rocks, pine_needle, pinecone
from surfaces.templates import mountain, sand, water, atmosphere_light_haze, sandstone, cracked_ground, \
    soil, dirt, cobble_stone, chunkyrock, stone, lava, ice, mud, snow, clouds

from placement import placement, density, camera as cam_util
from placement.split_in_view import split_inview
from util import blender as butil

import core as infinigen

def find_flat_location(
   mesh, 
   bvh: bvhtree.BVHTree, 
   rad: float, 
   alt: float,
   retries=100, margin_pct=0.2, 
   ang_samples=36
):

    for i in trange(retries):
        
        ground_loc = copy(np.random.choice(mesh.data.vertices).co)
        origin = ground_loc + Vector((0, 0, alt))

        *_, center_alt = bvh.ray_cast(origin, Vector((0, 0, -1)))
        if center_alt is None:
            continue

        for j, ang in enumerate(np.linspace(0, 2*np.pi, ang_samples)):
            sample_loc = origin + Matrix.Rotation(ang, 4, 'Z') @ Vector((rad, 0, 0))

            *_, dist = bvh.ray_cast(origin, sample_loc - origin)
            if dist is not None and dist < rad:
                break

            *_, sample_alt = bvh.ray_cast(sample_loc, Vector((0, 0, -1)))
            if sample_alt is None or abs(center_alt - sample_alt) > margin_pct * center_alt:
                break

        else: # triggered if no `break` statement 
            return ground_loc
        
    raise ValueError(f'Failed to find flat area {retries=}')

def circular_camera_path(camera_rig, target_obj, rad, alt, duration):
    
    bpy.ops.curve.primitive_bezier_circle_add(
        location=target_obj.location + Vector((0, 0, alt)),
    )
    circle = bpy.context.object
    circle.scale = (rad,) * 3

    follow_path(camera_rig, circle, duration=duration)
    circle.data.driver_add('eval_time').driver.expression = 'frame'

    butil.constrain_object(camera_rig, 'TRACK_TO', target=target_obj)

@gin.configurable
def compose_scene(
    output_folder: Path, 
    terrain: Terrain, 
    scene_seed: int, 

    asset_factory=None, # provided via gin
    grid_rad=1.2, 
    grid_dim=3, #NxN grid
    background='grass',
    camera_circle_radius=8,
    camera_altitude=2,
    circle_duration_sec=25,
    fstop=2,

    asset_scale=(1,1,1),
    asset_offset=(0,0,0),

    **params
):

    lighting.add_lighting()

    if params.get("fancy_clouds", 0):
        kole_clouds.add_kole_clouds()
    
    camera_rigs = cam_util.spawn_camera_rigs()
    cam = cam_util.get_camera(0, 0)

    # find a flat spot on the terrain to do the demo
    terrain_mesh = terrain.coarse_terrain()
    terrain_bvh = bvhtree.BVHTree.FromObject(terrain_mesh, bpy.context.evaluated_depsgraph_get())
    if asset_factory is not None:
        center = find_flat_location(
            terrain_mesh, 
            terrain_bvh, 
            rad=camera_circle_radius * 1.5, 
            alt=camera_altitude * 1.5
        )
    else:
        center = (0, 0, 0)
    # move camera in a circle around that location
    center_obj = butil.spawn_empty('center')
    center_obj.location = center
    circular_camera_path(camera_rigs[0], center_obj, 
                         camera_circle_radius, camera_altitude,
                         duration=circle_duration_sec*bpy.context.scene.render.fps)
    cam.data.dof.use_dof = True
    cam.data.dof.aperture_fstop = fstop
    cam.data.dof.focus_object = center_obj

    # make a grid of locations around the center point
    offs = np.linspace(-grid_rad, grid_rad, grid_dim)
    xs, ys = np.meshgrid(offs, offs)
    locs = np.stack([xs, ys, np.full_like(ys, camera_altitude)], axis=-1).reshape(-1, 3)
    locs += np.array(center)

    # snap all the locations the floor
    for i, l in enumerate(locs):
        floorloc, *_ = terrain_bvh.ray_cast(Vector(l), Vector((0, 0, -1)))
        if floorloc is None:
            raise ValueError('Found a hole in the terain')
        locs[i] = np.array(floorloc + Vector(asset_offset))

    if asset_factory is not None:
        # spawn assets on each location in the grid
        fac = asset_factory(scene_seed)
        col = placement.scatter_placeholders(locs, fac)
        objs, updated_pholders = placement.populate_collection(fac, col)

        for _, o in updated_pholders:
            o.scale = asset_scale

    # apply a procedural backdrop on all visible parts of the terrain
    terrain_inview, *_ = split_inview(terrain_mesh, cam=cam, dist_max=params['inview_distance'], vis_margin=2)
    if background is None:
        pass
    elif background == 'grass':
        grass.apply(terrain_inview)
        rocks.apply(terrain_inview)
    elif background == 'pine_forest':
        pine_needle.apply(terrain_inview)
        pinecone.apply(terrain_inview)
        rocks.apply(terrain_inview)
    elif background == 'TODO ADD MORE OPTIONS HERE':
        pass
    else:
        raise ValueError(f'Unrecognized {background=}')

def main():
    
    parser = argparse.ArgumentParser()
    parser.add_argument('--output_folder', type=Path)
    parser.add_argument('--input_folder', type=Path, default=None)
    parser.add_argument('-s', '--seed', default=None, help="The seed used to generate the scene")
    parser.add_argument('-t', '--task', nargs='+', default=['coarse'],
                        choices=['coarse', 'populate', 'fine_terrain', 'ground_truth', 'render', 'mesh_save'])
    parser.add_argument('-g', '--gin_config', nargs='+', default=['base'],
                        help='Set of config files for gin (separated by spaces) '
                             'e.g. --gin_config file1 file2 (exclude .gin from path)')
    parser.add_argument('-p', '--gin_param', nargs='+', default=[],
                        help='Parameter settings that override config defaults '
                             'e.g. --gin_param module_1.a=2 module_2.b=3')
    parser.add_argument('--task_uniqname', type=str, default=None)
    parser.add_argument('-d', '--debug', action="store_const", dest="loglevel", const=logging.DEBUG, default=logging.INFO)
    parser.add_argument( '-v', '--verbose', action="store_const", dest="loglevel", const=logging.INFO)

    args = parser.parse_args(sys.argv[sys.argv.index("--") + 1:])

    extras = '[%(filename)s:%(lineno)d] ' if args.loglevel == logging.DEBUG else ''
    logging.basicConfig(
        format=f'[%(asctime)s.%(msecs)03d] [%(name)s] [%(levelname)s] {extras}| %(message)s',
        level=args.loglevel,
        datefmt='%H:%M:%S'
    )

    scene_seed = infinigen.apply_scene_seed(args)
    infinigen.apply_gin_configs(args, scene_seed, skip_unknown=True)
    
    infinigen.main(
        compose_scene_func=compose_scene,
        input_folder=args.input_folder, 
        output_folder=args.output_folder, 
        task=args.task, 
        task_uniqname=args.task_uniqname, 
        scene_seed=scene_seed
    )

if __name__ == "__main__":
    main()
worldgen/__init__.py METASEP

worldgen/surfaces/surface_utils.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Mingzhe Wang
# Date Signed: April 25 2023 

import random
import math

from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface

@node_utils.to_nodegroup('nodegroup_norm_value', singleton=False, type='GeometryNodeTree')
def nodegroup_norm_value(nw: NodeWrangler):
    # Code generated using version 2.6.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Attribute', 0.0000),
            ('NodeSocketGeometry', 'Geometry', None)])
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': group_input.outputs["Geometry"], 2: group_input.outputs["Attribute"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Attribute"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_statistic_1.outputs["Max"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math, input_kwargs={0: subtract, 1: subtract_1}, attrs={'operation': 'DIVIDE'})
    
    subtract_2 = nw.new_node(Nodes.Math, input_kwargs={0: divide}, attrs={'operation': 'SUBTRACT'})
    
    multiply = nw.new_node(Nodes.Math, input_kwargs={0: subtract_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    group_output = nw.new_node(Nodes.GroupOutput, input_kwargs={'Value': multiply}, attrs={'is_active_output': True})

@node_utils.to_nodegroup('nodegroup_norm_vec', singleton=False, type='GeometryNodeTree')
def nodegroup_norm_vec(nw: NodeWrangler):
    # Code generated using version 2.6.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Geometry', None),
            ('NodeSocketString', 'Name', ''),
            ('NodeSocketVector', 'Vector', (0.0000, 0.0000, 0.0000))])
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    normvalue = nw.new_node(nodegroup_norm_value().name,
        input_kwargs={'Attribute': separate_xyz_1.outputs["X"], 'Geometry': group_input.outputs["Geometry"]})
    
    normvalue_1 = nw.new_node(nodegroup_norm_value().name,
        input_kwargs={'Attribute': separate_xyz_1.outputs["Y"], 'Geometry': group_input.outputs["Geometry"]})
    
    normvalue_2 = nw.new_node(nodegroup_norm_value().name,
        input_kwargs={'Attribute': separate_xyz_1.outputs["Z"], 'Geometry': group_input.outputs["Geometry"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': normvalue, 'Y': normvalue_1, 'Z': normvalue_2})
    
    store_named_attribute = nw.new_node(Nodes.StoreNamedAttribute,
        input_kwargs={'Geometry': group_input.outputs["Geometry"], 'Name': group_input.outputs["Name"], 2: combine_xyz},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    group_output = nw.new_node(Nodes.GroupOutput, input_kwargs={'Geometry': store_named_attribute}, attrs={'is_active_output': True})


def sample_range(x_min, x_max):
    y = random.random()
    y = y * (x_max - x_min) + x_min
    return y


def sample_ratio(x, sample_min=0.5, sample_max=2):
    if x == 0:
        return x
    neg = 1
    if x < 0:
        x = -x
        neg = -1
    x_min = x * sample_min
    x_max = x * sample_max
    exp = sample_range(math.log(x_min), math.log(x_max))
    return neg * math.exp(exp)


def clip(x, v_min=0, v_max=1):
    return max(min(x, v_max), v_min)


# sample a random rgb color
# if offset is not 0, the color is sampled from [color-offset, color+offset]
def sample_color(color, offset=0, keep_sum=False):
    if keep_sum:
        mean = (color[0]+color[1]+color[2])/3
        offset = min(mean, 1-mean)*random.random()
        idx = random.randint(0, 2)
        f = 1
        pcg = random.random()
        for i in range(3):
            if i == idx:
                color[i] = mean+offset
            else:
                color[i] = mean-offset*(f*pcg+(1-f)*(1-pcg))
                f = 0
        return
        
    for i in range(3):
        if offset == 0:
            color[i] = random.random()
        else:
            color[i] += (random.random() - 0.5) * 2 * offset
        color[i] = clip(color[i])

# generate a random voronoi offset
def geo_voronoi_noise(nw, rand=False, **input_kwargs):
    group_input = nw.new_node(Nodes.GroupInput)

    subdivide_mesh = nw.new_node('GeometryNodeSubdivideMesh',
                                 input_kwargs={'Mesh': group_input.outputs["Geometry"],
                                     'Level': input_kwargs.get('subdivide_mesh_level', 0)})

    position = nw.new_node(Nodes.InputPosition)

    scale = nw.new_node(Nodes.Value)
    scale.outputs["Value"].default_value = input_kwargs.get('scale', 2)

    vector_math = nw.new_node(Nodes.VectorMath, input_kwargs={0: position, 1: scale},
                              attrs={'operation': 'MULTIPLY'})

    noise_texture = nw.new_node(Nodes.NoiseTexture,
                                input_kwargs={'Vector': vector_math.outputs["Vector"], 'Scale': 10.0})
    if rand:
        sample_max = input_kwargs['noise_scale_max'] if 'noise_scale_max' in input_kwargs else 3
        sample_min = input_kwargs['noise_scale_min'] if 'noise_scale_min' in input_kwargs else 1 / sample_max
        noise_texture.inputs["Scale"].default_value = sample_ratio(noise_texture.inputs["Scale"].default_value,
                                                                   sample_min, sample_max)

    mix = nw.new_node(Nodes.MixRGB, input_kwargs={'Fac': 0.8, 'Color1': noise_texture.outputs["Color"],
        'Color2': vector_math.outputs["Vector"]})
    if rand:
        mix.inputs["Fac"].default_value = sample_range(0.7, 0.9)

    voronoi_texture = nw.new_node(Nodes.VoronoiTexture, input_kwargs={'Vector': mix},
                                  attrs={'voronoi_dimensions': '4D'})
    if rand:
        sample_max = input_kwargs['voronoi_scale_max'] if 'voronoi_scale_max' in input_kwargs else 3
        sample_min = input_kwargs[
            'voronoi_scale_min'] if 'voronoi_scale_min' in input_kwargs else 1 / sample_max
        voronoi_texture.inputs["Scale"].default_value = sample_ratio(
            voronoi_texture.inputs["Scale"].default_value, sample_min, sample_max)
        voronoi_texture.inputs['W'].default_value = sample_range(-5, 5)

    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: voronoi_texture.outputs["Distance"]},
        attrs={'operation': 'SUBTRACT'})

    normal = nw.new_node(Nodes.InputNormal)

    vector_math_1 = nw.new_node(Nodes.VectorMath,
                                input_kwargs={0: subtract, 1: normal},
                                attrs={'operation': 'MULTIPLY'})

    offsetscale = nw.new_node(Nodes.Value)
    offsetscale.outputs["Value"].default_value = input_kwargs.get('offsetscale', 0.02)

    vector_math_2 = nw.new_node(Nodes.VectorMath,
                                input_kwargs={0: vector_math_1.outputs["Vector"], 1: offsetscale},
                                attrs={'operation': 'MULTIPLY'})

    set_position = nw.new_node(Nodes.SetPosition, input_kwargs={'Geometry': subdivide_mesh,
        'Offset': vector_math_2.outputs["Vector"]})

    capture_attribute = nw.new_node(Nodes.CaptureAttribute, input_kwargs={'Geometry': set_position,
        1: voronoi_texture.outputs["Distance"]}, attrs={'data_type': 'FLOAT_VECTOR'})

    group_output = nw.new_node(Nodes.GroupOutput,
                               input_kwargs={'Geometry': capture_attribute.outputs["Geometry"],
                                   'Attribute': capture_attribute.outputs["Attribute"]})

worldgen/surfaces/surface_mixing_dev_script.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Lahav Lipson
# Date Signed: May 2 2023

'''
To use this file, do the following:

cd worldgen
blender dev_scene.blend

Then in the blender gui:
- click the 'Scripting' tab
- click the folder button to open this file as a new script
- append some meshes from another blend file, or run some other code to create some objects 
- implement a geonode / material setup using the node wrangler in the functions below
- left/right click the object you want to apply a material to
- click the play button to run the script

'''

import bpy
import gin
import mathutils
from numpy.random import uniform, normal
from nodes.node_wrangler import Nodes, NodeWrangler
from surfaces import surface
from surfaces.templates import dirt, cobble_stone, cracked_ground, sand, mountain
import generate # Necessary to parse gin config files

gin.clear_config()
gin.enter_interactive_mode()
gin.parse_config_files_and_bindings(["config/base.gin"], [])

def right_half(nw: NodeWrangler, **kwargs):
    x = nw.new_node(Nodes.SeparateXYZ, [nw.new_node(Nodes.InputPosition)])
    return nw.new_node(Nodes.Math, [(x, "Y"), 0], attrs={"operation": "GREATER_THAN"})

def left_half(nw: NodeWrangler, **kwargs):
    x = nw.new_node(Nodes.SeparateXYZ, [nw.new_node(Nodes.InputPosition)])
    return nw.new_node(Nodes.Math, [(x, "Y"), 0], attrs={"operation": "LESS_THAN"})

obj = bpy.context.active_object
cracked_ground.apply(obj, selection=surface.write_attribute(obj, right_half))
dirt.apply(obj, selection=surface.write_attribute(obj, left_half))
worldgen/surfaces/surface.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: 
# - Alex Raistrick: primary author
# - Lahav Lipson: Surface mixing
# Date Signed: May 2 2023

import string
from collections import defaultdict
import importlib
from inspect import signature

import bpy
from mathutils import Vector
import gin
import numpy as np
from tqdm import trange

from util import blender as butil
from util.blender import set_geomod_inputs # got moved, left here for import compatibility
from nodes.node_wrangler import NodeWrangler, Nodes, isnode, infer_output_socket, geometry_node_group_empty_new
from nodes import node_info

def remove_materials(obj):
    with butil.SelectObjects(obj):
        obj.active_material_index = 0
        for i in range(len(obj.material_slots)):
            bpy.ops.object.material_slot_remove({'object': obj})


def write_attribute(objs, node_func, name=None, data_type=None, apply=False):
    if name is None:
        name = node_func.__name__

    def attr_writer(nw, **kwargs):
        value = node_func(nw)

        nonlocal data_type
        if data_type is None:
            data_type = node_info.NODETYPE_TO_DATATYPE[infer_output_socket(value).type]

        capture = nw.new_node(Nodes.CaptureAttribute,
                              attrs={'data_type': data_type},
                              input_kwargs={
                                  'Geometry': nw.new_node(Nodes.GroupInput),
                                  'Value': value
                              })
        output = nw.new_node(Nodes.GroupOutput, input_kwargs={
            'Geometry': (capture, 'Geometry'),
            name: (capture, 'Attribute')
        })

    mod = add_geomod(objs, attr_writer, name=f'write_attribute({name})', apply=apply, attributes=[name])
    return name 

def read_attr_data(obj, attr, domain='POINT') -> np.array:
    if isinstance(attr, str):
        attr = obj.data.attributes[attr]

    if domain == 'POINT':
        n = len(obj.data.vertices)
    elif domain == 'EDGE':
        n = len(obj.data.edges)
    elif domain == 'FACE':
        n = len(obj.data.polygons)
    else:
        raise NotImplementedError
    dtype = attr.data_type
    dim = node_info.DATATYPE_DIMS[dtype]
    field = node_info.DATATYPE_FIELDS[dtype]

    data = np.empty(n * dim)
    attr.data.foreach_get(field, data)
    return data.reshape(-1, dim)


def write_attr_data(obj, attr, data: np.array, type='FLOAT', domain='POINT'):
    if isinstance(attr, str):
        if attr in obj.data.attributes:
            attr = obj.data.attributes[attr]
        else:
            attr = obj.data.attributes.new(attr, type, domain)

    field = node_info.DATATYPE_FIELDS[attr.data_type]
    attr.data.foreach_set(field, data.reshape(-1))

def new_attr_data(obj, attr, type, domain, data: np.array):
    assert(isinstance(attr, str))
    assert(attr not in obj.data.attributes)

    obj.data.attributes.new(name=attr, type=type, domain=domain)
    attr = obj.data.attributes[attr]
    field = node_info.DATATYPE_FIELDS[attr.data_type]
    attr.data.foreach_set(field, data.reshape(-1))


def smooth_attribute(obj, name, iters=20, weight=0.05, verbose=False):
    data = read_attr_data(obj, name)

    edges = np.empty(len(obj.data.edges) * 2, dtype=np.int)
    obj.data.edges.foreach_get('vertices', edges)
    edges = edges.reshape(-1, 2)

    r = range(iters) if not verbose else trange(iters)
    for _ in r:
        vertex_weight = np.ones(len(obj.data.vertices))
        data_out = data.copy()

        data_out[edges[:, 0]] += data[edges[:, 1]] * weight
        vertex_weight[edges[:, 0]] += weight

        data_out[edges[:, 1]] += data[edges[:, 0]] * weight
        vertex_weight[edges[:, 1]] += weight

        data = data_out / vertex_weight[:, None]

    write_attr_data(obj, name, data)


def attribute_to_vertex_group(obj, attr, name=None, min_thresh=0, binary=False):
    if name is None:
        name = attr if isinstance(attr, str) else attr.name

    attr_data = read_attr_data(obj, attr)

    if attr_data.shape[-1] != 1:
        raise ValueError(
            f'Could not convert non-scalar attribute {attr} to vertex group, expected 1 data dimension but got {attr_data.shape=}')

    group = obj.vertex_groups.new(name=name)

    if binary:
        group.add(np.where(attr_data > min_thresh)[0], 1.0, 'ADD')
    else:
        for i, v in enumerate(attr_data):
            if v > min_thresh:
                group.add([i], v, 'ADD')

    return group


def eval_argument(nw, argument, default_value=1.0, **kwargs):
    if argument is None:
        # return selection encompassing everything
        v = nw.new_node(Nodes.Value)
        v.outputs[0].default_value = default_value
        return v
    elif callable(argument):
        allowed_keys = list(signature(argument).parameters.keys())[1:]
        return argument(nw, **{k: v for k, v in kwargs.items() if k in allowed_keys})
    elif isinstance(argument, str):
        return nw.expose_input(name=argument, attribute=argument, val=default_value)
    elif isinstance(argument, (float, int)):
        v = nw.new_node(Nodes.Value)
        v.outputs[0].default_value = argument
        return v
    elif isinstance(argument, (tuple, Vector)):
        v = nw.new_node(Nodes.Vector)
        v.vector = argument
        return v
    elif nw.is_socket(argument):
        return argument
    else:
        raise ValueError(f'surface.eval_argument couldnt parse {argument}')


def shaderfunc_to_material(shader_func, *args, name=None, **kwargs):
    '''
    Convert a shader_func(nw) directly to a bpy.data.material

    Used in add_material and transpiler's Nodes.SetMaterial handler
    '''

    if name is None:
        name = shader_func.__name__

    material = bpy.data.materials.new(name=name)
    material.use_nodes = True
    material.node_tree.nodes.remove(material.node_tree.nodes['Principled BSDF'])  # remove the default BSDF

    nw = NodeWrangler(material.node_tree)
    new_node_tree = shader_func(nw, *args, **kwargs)

    if new_node_tree is not None:
        if isinstance(new_node_tree, tuple) and isnode(new_node_tree[1]):
            new_node_tree, volume = new_node_tree
            nw.new_node(Nodes.MaterialOutput, input_kwargs={'Volume': volume})
        nw.new_node(Nodes.MaterialOutput, input_kwargs={'Surface': new_node_tree})

    return material


def seed_generator(size=8, chars=string.ascii_uppercase):
    return ''.join(np.random.choice(list(chars)) for _ in range(size))


def add_material(objs, shader_func, selection=None, input_args=None, input_kwargs=None, name=None, reuse=False):
    if input_args is None:
        input_args = []
    if input_kwargs is None:
        input_kwargs = {}
    if not isinstance(objs, list):
        objs = [objs]

    if selection is None:
        if name is None:
            name = shader_func.__name__
        if (not reuse) and (name in bpy.data.materials):
            name += f"_{seed_generator(8)}"
        material = shaderfunc_to_material(shader_func, *input_args, **input_kwargs)
    elif isinstance(selection, str):

        name = "MixedSurface"
        if name in objs[0].data.materials:
            material = objs[0].data.materials[name]
        else:
            material = bpy.data.materials.new(name=name)
            material.use_nodes = True
            material.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value = (1, 0, 1, 1)  # Set Magenta
            objs[0].active_material = material

        nw = NodeWrangler(material.node_tree)

        new_attribute_node = nw.new_node(Nodes.Attribute, [], {"attribute_name": selection})
        if "Attribute Sum" in material.node_tree.nodes:
            old_attribute_sum_node = material.node_tree.nodes["Attribute Sum"]
            if old_attribute_sum_node.type == "ATTRIBUTE":
                socket_index_old = 2
            else:
                socket_index_old = 0
            new_attribute_sum_node = nw.scalar_add((old_attribute_sum_node, socket_index_old), (new_attribute_node, 2))
            old_attribute_sum_node.name = "Attribute Sum Old"
            new_attribute_sum_node.name = "Attribute Sum"
        else:
            new_attribute_node.name = "Attribute Sum"
            new_attribute_sum_node = new_attribute_node
        # grab a reference to whatever is currently linked to output
        links_to_output = [link for link in nw.links if (link.to_node.bl_idname == Nodes.MaterialOutput)]
        assert len(links_to_output) == 1, links_to_output
        penultimate_node = links_to_output.pop().from_node
        if new_attribute_sum_node.type == "ATTRIBUTE":
            socket_index_new = 2
        else:
            socket_index_new = 0
        selection_weight = nw.divide2(
            (new_attribute_node, 2),
            (new_attribute_sum_node, socket_index_new)
        )

        # spawn in the node tree to mix with it
        new_node_tree = shader_func(nw, **input_kwargs)
        if new_node_tree is None:
            raise ValueError(
                f'{shader_func} returned None while attempting add_material(selection=...). Shaderfunc must return its output to be mixable')
        if isinstance(new_node_tree, tuple) and isnode(new_node_tree[1]):
            new_node_tree, volume = new_node_tree
            nw.new_node(Nodes.MaterialOutput, input_kwargs={'Volume': volume})

        # mix the two together
        mix_shader = nw.new_node(Nodes.MixShader, [selection_weight, penultimate_node, new_node_tree])
        nw.new_node(Nodes.MaterialOutput, input_kwargs={'Surface': mix_shader})
    else:
        raise ValueError(f"{type(selection)=} not handled.")

    for obj in objs:
        obj.active_material = material
    return material

def add_geomod(objs, geo_func,
               name=None, apply=False, reuse=False, input_args=None,
               input_kwargs=None, attributes=None, show_viewport=True, selection=None,
               domains=None, input_attributes=None, ):
    
    if input_args is None:
        input_args = []
    if input_kwargs is None:
        input_kwargs = {}
    if attributes is None:
        attributes = []
    if domains is None:
        domains = ['POINT'] * len(attributes)
    if input_attributes is None:
        input_attributes = [None] * 128

    if name is None:
        name = geo_func.__name__
    if not isinstance(objs, list):
        objs = [objs]
    elif len(objs) == 0:
        return None

    if selection is not None:
        input_kwargs['selection'] = selection

    ng = None
    for obj in objs:

        mod = obj.modifiers.new(name=name, type='NODES')
        mod.show_viewport = False

        if mod is None:
            raise ValueError(f'Attempted to surface.add_geomod({obj=}), yet created modifier was None. '
                             f'Check that {obj.type=} supports geo modifiers')

        mod.show_viewport = show_viewport
        if ng is None:  # Create a unique node_group for the first one only
            if reuse and name in bpy.data.node_groups:
                mod.node_group = bpy.data.node_groups[name]
            else:
                # print("input_kwargs", input_kwargs, geo_func.__name__)
                if mod.node_group == None:
                    group = geometry_node_group_empty_new()
                    mod.node_group = group
                nw = NodeWrangler(mod)
                geo_func(nw, *input_args, **input_kwargs)
            ng = mod.node_group
            ng.name = name
        else:
            mod.node_group = ng

        outputs = mod.node_group.outputs
        identifiers = [outputs[i].identifier for i in range(len(outputs)) if outputs[i].type != 'GEOMETRY']
        if len(identifiers) != len(attributes):
            raise Exception(
                f"has {len(identifiers)} identifiers, but {len(attributes)} attributes. Specifically, {identifiers=} and {attributes=}")
        for id, att_name in zip(identifiers, attributes):
            # attributes are a 1-indexed list, and Geometry is the first element, so we start from 2
            # while f'Output_{i}_attribute_name' not in
            mod[id + '_attribute_name'] = att_name
        os = [outputs[i] for i in range(len(outputs)) if outputs[i].type != 'GEOMETRY']
        for o, domain in zip(os, domains):
            o.attribute_domain = domain

        inputs = mod.node_group.inputs
        if not any(att_name is None for att_name in input_attributes):
            raise Exception('None should be provided for Geometry inputs.')
        for i, att_name in zip(inputs, input_attributes):
            id = i.identifier
            if att_name is not None:
                mod[f'{id}_use_attribute'] = True
                mod[f'{id}_attribute_name'] = att_name

    if apply:
        for obj in objs:
            butil.apply_modifiers(obj, name)
        return None

    return mod


class NoApply:
    @staticmethod
    def apply(objs, *args, **kwargs):
        return objs, []


class Registry:

    def __init__(self):
        self._registry = None

    @staticmethod
    def get_surface(name):
        if name == '':
            return NoApply
        
        prefixes = ['surfaces.templates', 'surfaces.scatters']
        for prefix in prefixes:
            try:
                return importlib.import_module(prefix + '.' + name)
            except ModuleNotFoundError:
                continue

        raise ValueError(f'Could not find {name=} in any of {prefixes}')

    @staticmethod
    def sample_registry(registry):
        mods, probs = zip(*registry)
        return np.random.choice(mods, p=np.array(probs) / sum(probs))

    @gin.configurable('registry')
    def initialize_from_gin(self, smooth_categories=0, **gin_category_info):

        if smooth_categories != 0:
            raise NotImplementedError

        with gin.unlock_config():
            self._registry = defaultdict(list)
            for k, v in gin_category_info.items():
                self._registry[k] = [(self.get_surface(name), weight) for name, weight in v]

    def __call__(self, category_key):
        if self._registry is None:
            raise ValueError(
                f'Surface registry has not been initialized! Have you loaded gin and called .initialize()?'
                'Note, this step cannot happen at module initialization time, as gin is not yet loaded'
            )

        if not category_key in self._registry:
            raise KeyError(
                f'registry recieved request with {category_key=}, but no gin_config for this key was provided. {self._registry.keys()=}')

        return self.sample_registry(self._registry[category_key])        


registry = Registry()

worldgen/surfaces/dev_script.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Alexander Raistrick
# Date Signed: May 30, 2023

'''
To use this file, do the following:

cd worldgen
blender dev_scene.blend

Then in the blender gui:
- click the 'Scripting' tab
- click the folder button to open this file as a new script
- append some meshes from another blend file, or run some other code to create some objects 
- implement a geonode / material setup using the node wrangler in the functions below
- left/right click the object you want to apply a material to
- click the play button to run the script

'''

import bpy
import mathutils
from numpy.random import uniform, normal
from nodes.node_wrangler import Nodes, NodeWrangler
from surfaces import surface

def shader_dev(nw):
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF)
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geo_dev(nw):
    group_input = nw.new_node(Nodes.GroupInput)
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': group_input.outputs["Geometry"]})

def apply(obj):
    surface.add_geomod(obj, geo_dev, apply=False)
    surface.add_material(obj, shader_dev, reuse=False)
apply(bpy.context.active_object)
worldgen/surfaces/__init__.py METASEP

worldgen/surfaces/templates/water.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Zeyu Ma, Alex Raistrick
# Date Signed: June 5 2023

import os

import bpy
import gin
import numpy as np
from mathutils import Vector
from nodes.node_wrangler import Nodes
from numpy.random import normal, uniform
from surfaces import surface
from terrain.assets.ocean import ocean_asset, spatial_size
from terrain.utils import SurfaceTypes, drive_param
from util.math import FixedSeed
from util.random import random_general as rg
from util.organization import Attributes

type = SurfaceTypes.BlenderDisplacement
mod_name = "geo_water"
name = "water"
info = {}

@gin.configurable('geo')
def geo_water(
    nw,
    asset_paths,
    coastal,
    tile_size=40,
    with_waves=True,
    with_ripples=("bool", 0.3),
    waves_animation_speed=("uniform", 0.005, 0.025),
    animate_ripples=True,
    water_scale=("uniform", 4, 6),
    water_detail=("uniform", 5, 10),
    water_height=("uniform", 0.002, 0.02),
    water_dimension=("uniform", 1.0, 1.4),
    water_lacunarity=("uniform", 1.8, 2.0),
    height_modulation_scale=("uniform", 1, 5),
    ripples_lattice=2,
    selection=None
):
    nw.force_input_consistency()
    group_input = nw.new_node(Nodes.GroupInput)
    position0 = nw.new_node("GeometryNodeInputPosition")

    if asset_paths == []:
        with_ripples = rg(with_ripples)
        water_scale_node = nw.new_node(Nodes.Value, label=f"water_scale")
        water_scale_node.outputs[0].default_value = rg(water_scale)
        water_detail_node = nw.new_node(Nodes.Value, label=f"water_detail")
        water_detail_node.outputs[0].default_value = rg(water_detail)
        water_height_node = nw.new_node(Nodes.Value, label=f"water_height")
        water_height = rg(water_height)
        if with_waves:
            water_height_node.outputs[0].default_value = water_height
        else:
            water_height_node.outputs[0].default_value = 0
        ripple_height_node = nw.new_node(Nodes.Value, label=f"ripple_height")
        ripple_height_node.outputs[0].default_value = 0
        if with_ripples:
            water_height_node.outputs[0].default_value *= 0.1
            ripple_height_node.outputs[0].default_value = water_height
        water_height_node = nw.scalar_multiply(water_height_node, nw.scalar_add(0.5, nw.new_node("ShaderNodeTexMusgrave", input_kwargs={"Scale": rg(height_modulation_scale)})))
        water_dimension_node = nw.new_node(Nodes.Value, label=f"water_dimension")
        water_dimension_node.outputs[0].default_value = rg(water_dimension)
        water_lacunarity_node = nw.new_node(Nodes.Value, label=f"water_lacunarity")
        water_lacunarity_node.outputs[0].default_value = rg(water_lacunarity)


        position_shift = nw.new_node(Nodes.Vector, label="wave")
        position_shift.vector = nw.get_position_translation_seed(f"wave")

        animated_position = nw.add(Vector([0, 0, 0]), position0, position_shift)
        if waves_animation_speed is not None:
            drive_param(animated_position.inputs[0], rg(waves_animation_speed), offset=uniform(0, 10), index=1)

        wave0 = nw.new_node("ShaderNodeTexMusgrave", [
            animated_position, None,
            water_scale_node,
            water_detail_node,
            water_dimension_node,
            water_lacunarity_node,
        ])

        # normal_direction = nw.new_node("GeometryNodeInputNormal", [])
        # temporarily assume flat water
        normal_direction = Vector([0, 0, 1])
        waves = []
        for i in range(ripples_lattice):
            position_shift = nw.new_node(Nodes.Vector, label=f"ripple{i}")
            position_shift.vector = nw.get_position_translation_seed(f"ripple{i}")
            position = nw.add(position_shift, position0)
            voronoi = nw.new_node(Nodes.VoronoiTexture, input_kwargs={'Vector': position, 'Scale': 0.1, 'Randomness': 1})
            instance_offset = nw.new_node(
                Nodes.WaveTexture, [nw.sub(position, (voronoi, 2)), 1],
                attrs={'wave_type': 'RINGS', 'rings_direction': 'SPHERICAL'},
            )
            if animate_ripples:
                drive_param(instance_offset.inputs["Phase Offset"], -uniform(0.2, 1), offset=uniform(0, 10))
            edgeweight = nw.new_node(Nodes.VoronoiTexture,
                                        input_kwargs={'Vector': position, 'Scale': 0.1, 'Randomness': 1},
                                        attrs={'feature': 'DISTANCE_TO_EDGE'})
            waves.append(nw.multiply(edgeweight, instance_offset))
        offset = nw.multiply(
            nw.scalar_add(
                nw.scalar_multiply(wave0, water_height_node),
                nw.scalar_multiply(nw.add(*waves), ripple_height_node),
            ),
            normal_direction,
        )
    else:
        # Simple repetitive tiling
        directory = asset_paths[0] / "cache"
        filepath = directory / "disp_0001.exr"
        seq = bpy.data.images.load(str(filepath))
        seq.source = 'SEQUENCE'
        angle = np.random.uniform(0, np.pi * 2)
        position_shift = nw.get_position_translation_seed(f"wave")
        position = nw.add(position0, position_shift)
        position = nw.multiply(nw.new_node(Nodes.VectorRotate, input_kwargs={"Vector": position, "Angle": angle}), [1/tile_size] * 3)
        sampled_disp = nw.new_node(Nodes.ImageTexture, [seq, position])
        drive_param(sampled_disp.inputs["Frame"], 1, 0)
        offset = nw.multiply(sampled_disp, Vector([tile_size / spatial_size, tile_size / spatial_size, -tile_size / spatial_size]))
        offset = nw.new_node(Nodes.VectorRotate, input_kwargs={"Vector": offset, "Angle": -angle})
        filepath = directory / "foam_0001.exr"
        seq = bpy.data.images.load(str(filepath))
        seq.source = 'SEQUENCE'
        foam = nw.new_node(Nodes.ImageTexture, [seq, position])
        drive_param(foam.inputs["Frame"], 1, 0)
        if coastal:
            X = nw.new_node(Nodes.SeparateXYZ, [position0])
            weight1 = nw.scalar_multiply(1 / np.pi, nw.scalar_sub(np.pi / 2, nw.new_node(Nodes.Math, [nw.scalar_multiply(0.1, nw.scalar_add(30, X))], attrs={'operation': 'ARCTANGENT'})))
            weight2 = nw.scalar_add(0.5, nw.scalar_multiply(1 / np.pi, nw.new_node(Nodes.Math, [nw.scalar_multiply(0.1, nw.scalar_add(60, X))], attrs={'operation': 'ARCTANGENT'})))
            offset = nw.multiply(offset, nw.scalar_multiply(weight1, weight2))
            offset = nw.add(offset, nw.multiply(nw.new_node("ShaderNodeTexMusgrave", input_kwargs={"Scale": 1}), [0, 0, 0.03]))
            foam = nw.multiply(foam, weight2)

        group_input = nw.new_node(
            Nodes.CaptureAttribute,
            input_kwargs={
                "Geometry": group_input,
                "Value": foam
            },
            attrs={"data_type": "FLOAT"},
        )

    if selection is not None:
        offset = nw.multiply(offset, surface.eval_argument(nw, selection))

    set_position = nw.new_node(
        Nodes.SetPosition,
        input_kwargs={
            "Geometry": group_input,
            "Offset": offset,
        },
    )
    input_kwargs = {'Geometry': set_position}
    if asset_paths != []:
        input_kwargs["foam"] = (group_input, "Attribute")
    group_output = nw.new_node(Nodes.GroupOutput, input_kwargs=input_kwargs)


@gin.configurable
def shader(
    nw,
    asset_paths,
    coastal,
    color=("color_category", 'water'),
    enable_scatter=True,
    colored=False,
    emissive_foam=False,
    volume_density=("uniform", 0.07, 0.09),
    anisotropy=("clip_gaussian", 0.75, 0.2, 0.5, 1),
    random_seed=0,
):
    nw.force_input_consistency()
    position = nw.new_node('ShaderNodeNewGeometry', [])
    # Code generated using version 2.3.1 of the node_transpiler (partly)
    with FixedSeed(random_seed):
        color = rg(color)
        light_path = nw.new_node(Nodes.LightPath)

        if colored:
            color_of_transparent_bsdf_principled_bsdf = color
        else:
            color_of_transparent_bsdf_principled_bsdf = (1, 1, 1, 1)

        transparent_bsdf = nw.new_node(Nodes.TransparentBSDF, input_kwargs={"Color": color_of_transparent_bsdf_principled_bsdf})
        principled_bsdf = nw.new_node(Nodes.PrincipledBSDF, input_kwargs={
            "Base Color": color_of_transparent_bsdf_principled_bsdf, "Roughness": 0.0, "IOR": 1.33, "Transmission": 1.0
        })
        surface_shader = nw.new_node(Nodes.MixShader, input_kwargs={
            'Fac': nw.scalar_multiply(1.0, light_path.outputs["Is Camera Ray"]),
            1: transparent_bsdf,
            2: principled_bsdf
        })

        if asset_paths != []:
            if emissive_foam:
                foam_bsdf = nw.new_node(Nodes.Emission, input_kwargs={'Strength': 1})
            else:
                foam_bsdf = nw.new_node(Nodes.DiffuseBSDF)
            foam = nw.new_node(Nodes.Attribute, attrs={"attribute_name": "foam"})
            if coastal:
                weight = nw.scalar_multiply(3, nw.scalar_sub2(1, nw.scalar_multiply(5, nw.new_node(Nodes.Attribute, attrs={"attribute_name": Attributes.BoundarySDF}))))
                weight.use_clamp = 1
                interior_weight = nw.scalar_multiply(1 / np.pi, nw.scalar_sub(
                    np.pi / 2,
                    nw.new_node(Nodes.Math, [nw.scalar_multiply(0.1, nw.scalar_add(30, nw.new_node(Nodes.SeparateXYZ, [position])))], attrs={'operation': 'ARCTANGENT'})
                ))
                weight = nw.scalar_add(weight, interior_weight)
                weight.use_clamp = 1
            else:
                weight = 1
            foam = nw.scalar_multiply(foam, weight)
            surface_shader = nw.new_node(Nodes.MixShader, input_kwargs={'Fac': foam, 1: surface_shader, 2: foam_bsdf})
    
        rgb = nw.new_node(Nodes.RGB)
        rgb.outputs[0].default_value = color
        principled_volume = nw.new_node(Nodes.PrincipledVolume, input_kwargs={
            'Color': rgb, 
            'Absorption Color': rgb,
            'Density': rg(volume_density) if enable_scatter else 0,
            'Anisotropy': rg(anisotropy),
        })

        material_output = nw.new_node(Nodes.MaterialOutput, input_kwargs={'Surface': surface_shader, 'Volume': principled_volume})

@gin.configurable("water")
def apply(objs, is_ocean=False, coastal=0, selection=None, **kwargs):
    info["is_ocean"] = is_ocean = rg(is_ocean)
    asset_paths = []
    if is_ocean:
        ocean_folder = kwargs["ocean_folder"]
        (ocean_folder / "cache").mkdir(parents=1, exist_ok=1)
        (ocean_folder / "cache/disp_0001.exr").touch()
        (ocean_folder / "cache/foam_0001.exr").touch()
        asset_paths.append(ocean_folder)
    input_kwargs = {"asset_paths": asset_paths, "coastal": coastal}
    surface.add_geomod(objs, geo_water, selection=selection, input_kwargs=input_kwargs, attributes=["foam"] if is_ocean else None)
    surface.add_material(objs, shader, selection=selection, input_kwargs=input_kwargs)
    if is_ocean:
        (ocean_folder / "cache/disp_0001.exr").unlink()
        (ocean_folder / "cache/foam_0001.exr").unlink()
worldgen/surfaces/templates/succulent.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Beining Han
# Date Signed: June 15, 2023

from numpy.random import uniform, normal , randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface
from nodes.color import hsv2rgba



def shader_green_transition_succulent(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    musgrave_texture_1 = nw.new_node(Nodes.MusgraveTexture,
                                     input_kwargs={'Scale': uniform(5.0, 20.0)})

    colorramp_3 = nw.new_node(Nodes.ColorRamp,
                              input_kwargs={'Fac': musgrave_texture_1})
    colorramp_3.color_ramp.elements[0].position = 0.1182
    colorramp_3.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.7727
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)

    texture_coordinate = nw.new_node(Nodes.TextureCoord)

    mapping = nw.new_node(Nodes.Mapping,
                          input_kwargs={'Vector': texture_coordinate.outputs["Generated"]})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
                               input_kwargs={'Vector': mapping})

    less_than = nw.new_node(Nodes.Math,
                            input_kwargs={0: separate_xyz.outputs["Z"], 1: 0.85},
                            attrs={'operation': 'LESS_THAN'})

    multiply = nw.new_node(Nodes.Math,
                           input_kwargs={0: colorramp_3.outputs["Color"], 1: less_than},
                           attrs={'operation': 'MULTIPLY'})

    multiply_1 = nw.new_node(Nodes.Math,
                             input_kwargs={0: multiply, 1: uniform(2.0, 10.0)},
                             attrs={'operation': 'MULTIPLY'})

    main_hsv_color = (uniform(0.35, 0.42), uniform(0.5, 0.93), uniform(0.20, 0.80))
    main_color = hsv2rgba(main_hsv_color)
    diffuse_color = hsv2rgba((uniform(0.34, 0.43),) + main_hsv_color[1:])
    split_point = uniform(0.82, 0.92)
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
                              input_kwargs={'Fac': separate_xyz.outputs["Z"]})
    colorramp_1.color_ramp.interpolation = "B_SPLINE"
    colorramp_1.color_ramp.elements[0].position = split_point
    colorramp_1.color_ramp.elements[0].color = main_color
    colorramp_1.color_ramp.elements[1].position = split_point + uniform(0.01, 0.05)
    colorramp_1.color_ramp.elements[1].color = (uniform(0.6, 1.0), uniform(0.0, 0.08), uniform(0.0, 0.08), 1.0)
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': colorramp_1.outputs["Color"], 'Subsurface': uniform(0.01, 0.03), 
        'Subsurface Radius': (0.01, 0.1, 0.1), 'Subsurface Color': colorramp_1.outputs["Color"], 
        'Subsurface IOR': 0.0, 'Specular': 0.0, 'Roughness': 2.0, 'Sheen Tint': 0.0, 
        'Clearcoat Roughness': 0.0, 'IOR': 1.3, 'Emission Strength': 0.0})

    diffuse_bsdf_1 = nw.new_node(Nodes.DiffuseBSDF,
                                 input_kwargs={'Color': diffuse_color, 'Roughness': uniform(0.3, 0.8)})

    mix_shader_2 = nw.new_node(Nodes.MixShader,
                               input_kwargs={'Fac': multiply_1, 1: principled_bsdf, 2: diffuse_bsdf_1})

    material_output = nw.new_node(Nodes.MaterialOutput,
                                  input_kwargs={'Surface': mix_shader_2})


def shader_pink_transition_succulent(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    musgrave_texture_1 = nw.new_node(Nodes.MusgraveTexture,
                                     input_kwargs={'Scale': uniform(5.0, 20.0)})

    colorramp_3 = nw.new_node(Nodes.ColorRamp,
                              input_kwargs={'Fac': musgrave_texture_1})
    colorramp_3.color_ramp.elements[0].position = 0.1182
    colorramp_3.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.7727
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)

    texture_coordinate = nw.new_node(Nodes.TextureCoord)

    mapping = nw.new_node(Nodes.Mapping,
                          input_kwargs={'Vector': texture_coordinate.outputs["Generated"]})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
                               input_kwargs={'Vector': mapping})

    less_than = nw.new_node(Nodes.Math,
                            input_kwargs={0: separate_xyz.outputs["Z"], 1: 0.85},
                            attrs={'operation': 'LESS_THAN'})

    multiply = nw.new_node(Nodes.Math,
                           input_kwargs={0: colorramp_3.outputs["Color"], 1: less_than},
                           attrs={'operation': 'MULTIPLY'})

    multiply_1 = nw.new_node(Nodes.Math,
                             input_kwargs={0: multiply, 1: uniform(2.0, 8.0)},
                             attrs={'operation': 'MULTIPLY'})

    main_hsv_color = (uniform(0.93, 0.99), uniform(0.64, 0.90), uniform(0.50, 0.90))
    main_color = hsv2rgba(main_hsv_color)
    diffuse_color = hsv2rgba((uniform(0.93, 1.), ) + main_hsv_color[1:])
    split_point = uniform(0.82, 0.92)
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
                              input_kwargs={'Fac': separate_xyz.outputs["Z"]})
    colorramp_1.color_ramp.interpolation = "B_SPLINE"
    colorramp_1.color_ramp.elements[0].position = split_point
    colorramp_1.color_ramp.elements[0].color = main_color
    colorramp_1.color_ramp.elements[1].position = split_point + uniform(0.01, 0.05)
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': colorramp_1.outputs["Color"], 'Subsurface': uniform(0.01, 0.05), 
        'Subsurface Radius': (0.01, 0.03, 0.03), 'Subsurface Color': colorramp_1.outputs["Color"], 
        'Subsurface IOR': 0.0, 'Specular': 0.0, 'Roughness': 2.0, 'Sheen Tint': 0.0, 
        'Clearcoat Roughness': 0.0, 'IOR': 1.3, 'Emission Strength': 0.0})

    diffuse_bsdf_1 = nw.new_node(Nodes.DiffuseBSDF,
                                 input_kwargs={'Color': diffuse_color, 'Roughness': uniform(0.0, 0.5)})

    mix_shader_2 = nw.new_node(Nodes.MixShader,
                               input_kwargs={'Fac': multiply_1, 1: principled_bsdf, 2: diffuse_bsdf_1})

    material_output = nw.new_node(Nodes.MaterialOutput,
                                  input_kwargs={'Surface': mix_shader_2})


def shader_green_succulent(nw: NodeWrangler):
    musgrave_texture_1 = nw.new_node(Nodes.MusgraveTexture,
                                     input_kwargs={'Scale': uniform(4.0, 15.0)})

    colorramp_3 = nw.new_node(Nodes.ColorRamp,
                              input_kwargs={'Fac': musgrave_texture_1})
    colorramp_3.color_ramp.elements[0].position = 0.1182
    colorramp_3.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.7727
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)

    texture_coordinate = nw.new_node(Nodes.TextureCoord)

    mapping = nw.new_node(Nodes.Mapping,
                          input_kwargs={'Vector': texture_coordinate.outputs["Generated"]})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
                               input_kwargs={'Vector': mapping})

    less_than = nw.new_node(Nodes.Math,
                            input_kwargs={0: separate_xyz.outputs["Z"], 1: 1.0},
                            attrs={'operation': 'LESS_THAN'})

    multiply = nw.new_node(Nodes.Math,
                           input_kwargs={0: colorramp_3.outputs["Color"], 1: less_than},
                           attrs={'operation': 'MULTIPLY'})

    multiply_1 = nw.new_node(Nodes.Math,
                             input_kwargs={0: multiply, 1: uniform(2.0, 8.0)},
                             attrs={'operation': 'MULTIPLY'})

    main_hsv_color = (uniform(0.33, 0.39), uniform(0.5, 0.93), uniform(0.20, 0.70))
    main_color = hsv2rgba(main_hsv_color)
    diffuse_color = hsv2rgba((uniform(0.34, 0.38),) + main_hsv_color[1:])
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
                              input_kwargs={'Fac': separate_xyz.outputs["Z"]})
    colorramp_1.color_ramp.interpolation = "B_SPLINE"
    colorramp_1.color_ramp.elements[0].position = 1.0
    colorramp_1.color_ramp.elements[0].color = main_color
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': colorramp_1.outputs["Color"], 'Subsurface': uniform(0.01, 0.05), 
        'Subsurface Radius': (0.1, 0.1, 0.1), 'Subsurface Color': colorramp_1.outputs["Color"], 
        'Subsurface IOR': 0.0, 'Specular': 0.0, 'Roughness': 2.0, 'Sheen Tint': 0.0, 
        'Clearcoat Roughness': 0.0, 'IOR': 1.3, 'Emission Strength': 0.0})

    diffuse_bsdf_1 = nw.new_node(Nodes.DiffuseBSDF,
                                 input_kwargs={'Color': diffuse_color, 'Roughness': uniform(0.0, 0.5)})

    mix_shader_2 = nw.new_node(Nodes.MixShader,
                               input_kwargs={'Fac': multiply_1, 1: principled_bsdf, 2: diffuse_bsdf_1})

    material_output = nw.new_node(Nodes.MaterialOutput,
                                  input_kwargs={'Surface': mix_shader_2})


def shader_yellow_succulent(nw: NodeWrangler):
    musgrave_texture_1 = nw.new_node(Nodes.MusgraveTexture,
                                     input_kwargs={'Scale': uniform(5.0, 8.0)})

    colorramp_3 = nw.new_node(Nodes.ColorRamp,
                              input_kwargs={'Fac': musgrave_texture_1})
    colorramp_3.color_ramp.elements[0].position = 0.1182
    colorramp_3.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.7727
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)

    texture_coordinate = nw.new_node(Nodes.TextureCoord)

    mapping = nw.new_node(Nodes.Mapping,
                          input_kwargs={'Vector': texture_coordinate.outputs["Generated"]})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
                               input_kwargs={'Vector': mapping})

    less_than = nw.new_node(Nodes.Math,
                            input_kwargs={0: separate_xyz.outputs["Z"], 1: 1.0},
                            attrs={'operation': 'LESS_THAN'})

    multiply = nw.new_node(Nodes.Math,
                           input_kwargs={0: colorramp_3.outputs["Color"], 1: less_than},
                           attrs={'operation': 'MULTIPLY'})

    multiply_1 = nw.new_node(Nodes.Math,
                             input_kwargs={0: multiply, 1: uniform(1.0, 3.0)},
                             attrs={'operation': 'MULTIPLY'})

    main_color = hsv2rgba((uniform(0.1, 0.15), uniform(0.8, 1.0), uniform(0.5, 0.7)))
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
                              input_kwargs={'Fac': separate_xyz.outputs["Z"]})
    colorramp_1.color_ramp.interpolation = "B_SPLINE"
    colorramp_1.color_ramp.elements[0].position = 0.3114
    colorramp_1.color_ramp.elements[0].color = main_color
    colorramp_1.color_ramp.elements[1].position = 0.6864
    colorramp_1.color_ramp.elements[1].color = hsv2rgba((uniform(0.0, 0.06), uniform(0.8, 1.0), uniform(0.5, 0.7)))

    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
                                  input_kwargs={'Base Color': colorramp_1.outputs["Color"], 'Subsurface': 0.01,
                                                'Subsurface Radius': (1.0, 1.0, 1.0),
                                                'Subsurface Color': colorramp_1.outputs["Alpha"], 'Subsurface IOR': 1.3,
                                                'Specular': 0.0, 'Roughness': 2.0, 'Sheen Tint': 0.0,
                                                'Clearcoat Roughness': 0.0, 'IOR': 1.3, 'Emission Strength': 0.0})

    translucent_bsdf = nw.new_node(Nodes.TranslucentBSDF,
                                   input_kwargs={'Color': main_color})

    mix_shader_1 = nw.new_node(Nodes.MixShader,
                               input_kwargs={'Fac': 0.4, 1: principled_bsdf, 2: translucent_bsdf})

    diffuse_bsdf_1 = nw.new_node(Nodes.DiffuseBSDF,
                                 input_kwargs={'Color': main_color,
                                               'Roughness': uniform(0.2, 1.0)})

    mix_shader_2 = nw.new_node(Nodes.MixShader,
                               input_kwargs={'Fac': multiply_1, 1: mix_shader_1, 2: diffuse_bsdf_1})

    material_output = nw.new_node(Nodes.MaterialOutput,
                                  input_kwargs={'Surface': mix_shader_2})


def shader_whitish_green_succulent(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    musgrave_texture_1 = nw.new_node(Nodes.MusgraveTexture,
                                     input_kwargs={'Scale': uniform(5.0, 8.0)})

    colorramp_3 = nw.new_node(Nodes.ColorRamp,
                              input_kwargs={'Fac': musgrave_texture_1})
    colorramp_3.color_ramp.elements[0].position = uniform(0.0, 0.3)
    colorramp_3.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5273
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)

    texture_coordinate = nw.new_node(Nodes.TextureCoord)

    mapping = nw.new_node(Nodes.Mapping,
                          input_kwargs={'Vector': texture_coordinate.outputs["Generated"]})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
                               input_kwargs={'Vector': mapping})

    l = uniform(0.88, 0.98)
    less_than = nw.new_node(Nodes.Math,
                            input_kwargs={0: separate_xyz.outputs["Z"], 1: l - 0.05},
                            attrs={'operation': 'LESS_THAN'})

    multiply = nw.new_node(Nodes.Math,
                           input_kwargs={0: colorramp_3.outputs["Color"], 1: less_than},
                           attrs={'operation': 'MULTIPLY'})

    multiply_1 = nw.new_node(Nodes.Math,
                             input_kwargs={0: multiply, 1: uniform(1.0, 4.0)},
                             attrs={'operation': 'MULTIPLY'})

    main_color = hsv2rgba((uniform(0.23, 0.25), uniform(0.40, 0.60), uniform(0.18, 0.25)))
    colorramp = nw.new_node(Nodes.ColorRamp,
                            input_kwargs={'Fac': separate_xyz.outputs["Z"]})
    colorramp.color_ramp.elements[0].position = l - uniform(0.04, 0.1)
    colorramp.color_ramp.elements[0].color = hsv2rgba((uniform(0.20, 0.38), uniform(0.12, 0.25), uniform(0.50, 0.70)))
    colorramp.color_ramp.elements[1].position = l
    colorramp.color_ramp.elements[1].color = main_color

    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
                                  input_kwargs={'Base Color': colorramp.outputs["Color"], 'Subsurface': 0.01,
                                                'Subsurface Radius': (1.0, 1.0, 1.0),
                                                'Subsurface Color': colorramp.outputs["Color"], 'Subsurface IOR': 1.3,
                                                'Specular': 0.0, 'Roughness': 2.0, 'Sheen Tint': 0.0,
                                                'Clearcoat Roughness': 0.0, 'IOR': 1.3, 'Emission Strength': 0.0})

    translucent_bsdf = nw.new_node(Nodes.TranslucentBSDF,
                                   input_kwargs={'Color': main_color})

    mix_shader_1 = nw.new_node(Nodes.MixShader,
                               input_kwargs={'Fac': 0.7, 1: principled_bsdf, 2: translucent_bsdf})
    diffuse = hsv2rgba((uniform(0.23, 0.25), uniform(0.40, 0.60), uniform(0.10, 0.15)))
    diffuse_bsdf_1 = nw.new_node(Nodes.DiffuseBSDF,
                                 input_kwargs={'Color': diffuse, 'Roughness': 0.5})

    mix_shader_2 = nw.new_node(Nodes.MixShader,
                               input_kwargs={'Fac': multiply_1, 1: mix_shader_1, 2: diffuse_bsdf_1})

    material_output = nw.new_node(Nodes.MaterialOutput,
                                  input_kwargs={'Surface': mix_shader_2})


def apply(obj, selection=None, **kwargs):
    surface.add_material(obj, shader_green_transition_succulent, selection=selection)
worldgen/surfaces/templates/snow.py METASEP
# COPYRIGHT
# adapted from Blender Real Snow add-on https://docs.blender.org/manual/en/latest/addons/object/real_snow.html
# License: GPL

from nodes.node_wrangler import Nodes
from surfaces import surface
from terrain.utils import SurfaceTypes

type = SurfaceTypes.SDFPerturb
mod_name = "geo_snowtexture"
name = "snow"


def shader_snow(nw, subsurface=1.0, **kwargs):
    nw.force_input_consistency()
    position = nw.new_node('ShaderNodeNewGeometry', [])
    combine_xyz = nw.new_node(
        Nodes.CombineXYZ,
        input_kwargs={'X': 0.36, 'Y': 0.46, 'Z': 0.6}
    )
    vector_math = nw.new_node(
        Nodes.VectorMath,
        input_kwargs={0: combine_xyz, 1: (0.5, 0.5, 0.5)},
        attrs={'operation': 'MULTIPLY'}
    )
    mapping = nw.new_node(
        Nodes.Mapping,
        input_kwargs={'Vector': position, 'Scale': (12.0, 12.0, 12.0)}
    )
    voronoi_texture = nw.new_node(
        Nodes.VoronoiTexture,
        input_kwargs={'Vector': mapping, 'Scale': 30.0},
        attrs={'feature': 'N_SPHERE_RADIUS'}
    )
    colorramp = nw.new_node(Nodes.ColorRamp, input_kwargs={'Fac': voronoi_texture.outputs["Radius"]})
    colorramp.color_ramp.elements[0].position = 0.525
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.58
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    principled_bsdf = nw.new_node(
        Nodes.PrincipledBSDF,
        input_kwargs={
            'Base Color': (0.904, 0.904, 0.904, 1.0),
            'Subsurface': subsurface,
            'Subsurface Radius': vector_math.outputs["Vector"],
            'Subsurface Color': (0.904, 0.904, 0.904, 1.0),
            'Specular': 0.224,
            'Roughness': 0.1,
            'Clearcoat': colorramp.outputs["Color"],
            'Clearcoat Roughness': 0.1,
        },
        attrs={'distribution': 'MULTI_GGX'}
    )
    
    return principled_bsdf


def geo_snowtexture(nw, selection=None, **kwargs):
    nw.force_input_consistency()
    group_input = nw.new_node(Nodes.GroupInput)
    normal_dir = nw.new_node(Nodes.InputNormal)
    position0 = nw.new_node(Nodes.InputPosition)
    position = nw.multiply(position0, [12]*3)
    
    noise_texture = nw.new_node(
        Nodes.NoiseTexture,
        input_kwargs={'Vector': position, 'Scale': 12.0, 'Detail': 2}
    )
        
    noise_texture_1 = nw.new_node(
        Nodes.NoiseTexture,
        input_kwargs={'Vector': position, 'Scale': 2.0, 'Detail': 4}
    )
    colorramp_1 = nw.new_node(
        Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]}
    )
    colorramp_1.color_ramp.elements[0].position = 0.069
    colorramp_1.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.757
    colorramp_1.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    noise_texture_2 = nw.new_node(
        Nodes.NoiseTexture,
        input_kwargs={'Vector': position, 'Scale': 1.0, 'Detail': 4}
    )
    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_2.outputs["Fac"]}
    )
    colorramp_2.color_ramp.elements[0].position = 0.069
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 0.757
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    height = nw.scalar_add(
        nw.scalar_multiply(0.6, noise_texture),
        nw.scalar_multiply(0.4, colorramp_1),
        colorramp_2,
    )

    map_range = nw.new_node(
        Nodes.MapRange,
        input_kwargs={'Value': height, 1: 0.0, 2: 2.0, 3: -0.03, 4: 0.03}
    )
    
    modulation = nw.new_node(
        Nodes.NoiseTexture,
        input_kwargs={'Vector': position0, 'Scale': 0.5}
    )
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': modulation}
    )
    colorramp_3.color_ramp.elements[0].position = 0.25
    colorramp_3.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.75
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    

    offset = nw.multiply(normal_dir, map_range, colorramp_3)
    
    if selection is not None:
        offset = nw.multiply(offset, surface.eval_argument(nw, selection))
    
    set_position = nw.new_node(
        Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Geometry"], 'Offset': offset}
    )
    
    group_output = nw.new_node(Nodes.GroupOutput, input_kwargs={'Geometry': set_position})

def apply(objs, selection=None, **kwargs):
    surface.add_geomod(objs, geo_snowtexture, selection=selection)
    surface.add_material(objs, shader_snow, selection=selection, input_kwargs=kwargs)
worldgen/surfaces/templates/horn.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Yihan Wang
# Date Signed: May 30, 2023

import bpy
import mathutils
from numpy.random import uniform, normal, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface

def shader_horn(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    mapping = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate.outputs["Object"], 'Location': (1.7+ uniform(-1, 1) * 0.05, 0.3 + uniform(-1, 1) * 0.05, 0.0 + uniform(-1, 1) * 0.05)})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping, 'Scale': 10.8 + uniform(-1, 1) * 3, 'Detail': 15.0, 'Roughness': 0.7667})
    
    voronoi_texture_1 = nw.new_node(Nodes.VoronoiTexture,
        input_kwargs={'Vector': noise_texture_2.outputs["Fac"], 'Scale': 10.0})
    
    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': voronoi_texture_1.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.4364 + uniform(-1, 1) * 0.05
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 0.58 + uniform(-1, 1) * 0.05
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mapping_2 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate.outputs["Object"]})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_2, 'Scale': 98.9 + uniform(-0.3, 1) * 30, 'Detail': 15.0, 'Roughness': 0.7667})
    
    voronoi_texture = nw.new_node(Nodes.VoronoiTexture,
        input_kwargs={'Vector': noise_texture.outputs["Fac"], 'Scale': 10.0})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': voronoi_texture.outputs["Color"]})
    colorramp.color_ramp.elements[0].position = 0.3089 + uniform(-1, 1) * 0.05
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.673 + uniform(-1, 1) * 0.05
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: colorramp.outputs["Color"]},
        attrs={'operation': 'MULTIPLY'})
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate.outputs["UV"], 'Scale': (1.0, 1.0, 0.0)})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'Scale': 6.4 + uniform(-1, 1) * 1})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_1.color_ramp.elements[0].position = 0.3682 + uniform(-1, 1) * 0.05
    colorramp_1.color_ramp.elements[0].color = (0.3813, 0.2384, 0.1183, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.7864 + uniform(-1, 1) * 0.05
    colorramp_1.color_ramp.elements[1].color = (0.3916, 0.2831, 0.1683, 1.0)
    
    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': multiply.outputs["Vector"], 'Color1': (0.1878, 0.15, 0.0976, 1.0), 'Color2': colorramp_1.outputs["Color"]})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix, 'Roughness': 0.0})
    
    mix_shader = nw.new_node(Nodes.MixShader,
        input_kwargs={'Fac': 0.5917, 1: principled_bsdf})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': mix_shader})



def apply(obj, selection=None, **kwargs):
    surface.add_material(obj, shader_horn, selection=selection)
worldgen/surfaces/templates/grass_blade_texture.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Lahav Lipson, Alexander Raistrick
# Date Signed: May 30, 2023

import bpy
import mathutils
from numpy.random import uniform, normal, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface
import numpy as np

pallete1 = [   ((0.2632, 0.1493, 0.0558, 1.0), 0.0),
    ((0.2695, 0.1585, 0.064, 1.0), 0.058),
    ((0.829, 0.7488, 0.449, 1.0), 0.0718),
    ((0.3486, 0.223, 0.1024, 1.0), 0.0773),
    ((0.3552, 0.2386, 0.1138, 1.0), 0.2099),
    ((0.5925, 0.4391, 0.2677, 1.0), 0.2486),
    ((0.2278, 0.1492, 0.0705, 1.0), 0.2624),
    ((0.4087, 0.2429, 0.1068, 1.0), 0.3149),
    ((0.3037, 0.1832, 0.0586, 1.0), 0.3204),
    ((0.3279, 0.1901, 0.0636, 1.0), 0.3923),
    ((0.604, 0.4648, 0.2181, 1.0), 0.4006),
    ((0.303, 0.204, 0.0733, 1.0), 0.4227),
    ((0.2477, 0.1717, 0.0419, 1.0), 0.4862),
    ((0.2103, 0.1538, 0.0341, 1.0), 0.547),
    ((0.3617, 0.2418, 0.0928, 1.0), 0.5773),
    ((0.2413, 0.1354, 0.038, 1.0), 0.6215),
    ((0.6602, 0.4602, 0.2262, 1.0), 0.6271),
    ((0.3841, 0.251, 0.1021, 1.0), 0.6685),
    ((0.4158, 0.2773, 0.1234, 1.0), 0.6934),
    ((0.4158, 0.2875, 0.1564, 1.0), 0.7624),
    ((0.7427, 0.5479, 0.3642, 1.0), 0.779),
    ((0.2511, 0.1583, 0.0831, 1.0), 0.8094),
    ((0.6233, 0.4074, 0.2138, 1.0), 0.8149),
    ((0.3241, 0.182, 0.076, 1.0), 0.8453),
    ((0.73, 0.4825, 0.2818, 1.0), 0.8619),
    ((0.7319, 0.5246, 0.3017, 1.0), 0.884),
    ((0.2873, 0.1812, 0.0778, 1.0), 0.9088),
    ((0.5537, 0.381, 0.2168, 1.0), 0.9309),
    ((0.3119, 0.1916, 0.0883, 1.0), 0.9558),
    ((0.931, 0.7854, 0.5187, 1.0), 0.9613),
    ((0.9281, 0.7416, 0.4916, 1.0), 1.0)]

pallete2 = [   ((0.3586, 0.3253, 0.1285, 1.0), 0.0),
    ((0.2603, 0.2268, 0.0725, 1.0), 0.0319),
    ((0.2972, 0.2467, 0.0864, 1.0), 0.0957),
    ((0.4891, 0.4373, 0.1874, 1.0), 0.117),
    ((0.3481, 0.3054, 0.1156, 1.0), 0.1383),
    ((0.4084, 0.3708, 0.1488, 1.0), 0.1809),
    ((0.3661, 0.3106, 0.1336, 1.0), 0.2128),
    ((0.6299, 0.5461, 0.2758, 1.0), 0.266),
    ((0.4535, 0.4015, 0.1772, 1.0), 0.2872),
    ((0.5818, 0.5749, 0.2734, 1.0), 0.3085),
    ((0.3063, 0.2933, 0.1009, 1.0), 0.3298),
    ((0.4449, 0.4316, 0.1853, 1.0), 0.3723),
    ((0.2814, 0.3075, 0.1075, 1.0), 0.4043),
    ((0.3078, 0.3569, 0.1202, 1.0), 0.4468),
    ((0.3034, 0.3073, 0.1076, 1.0), 0.5),
    ((0.1296, 0.183, 0.0342, 1.0), 0.5319),
    ((0.2191, 0.2778, 0.0793, 1.0), 0.5638),
    ((0.1282, 0.1593, 0.0378, 1.0), 0.5957),
    ((0.3567, 0.4744, 0.1591, 1.0), 0.6064),
    ((0.1719, 0.2404, 0.0449, 1.0), 0.6277),
    ((0.2168, 0.2639, 0.0755, 1.0), 0.7234),
    ((0.3594, 0.3372, 0.1472, 1.0), 0.7553),
    ((0.1611, 0.1665, 0.0481, 1.0), 0.7872),
    ((0.3238, 0.3161, 0.1372, 1.0), 0.8085),
    ((0.0813, 0.0699, 0.0184, 1.0), 0.8191),
    ((0.2095, 0.2009, 0.0635, 1.0), 0.8723),
    ((0.7108, 0.6485, 0.3301, 1.0), 0.8936),
    ((0.3915, 0.3563, 0.1493, 1.0), 0.9043),
    ((0.1694, 0.1873, 0.0553, 1.0), 0.9574),
    ((0.4335, 0.4064, 0.1848, 1.0), 0.9894),
    ((0.2195, 0.1946, 0.0561, 1.0), 1.0)]

pallete3 = [   ((0.3821, 0.4798, 0.0818, 1.0), 0.0),
    ((0.0858, 0.1301, 0.0193, 1.0), 0.0316),
    ((0.1099, 0.1785, 0.0071, 1.0), 0.0842),
    ((0.8128, 0.9357, 0.197, 1.0), 0.1053),
    ((0.1502, 0.2148, 0.0081, 1.0), 0.1158),
    ((0.391, 0.5164, 0.088, 1.0), 0.1789),
    ((0.0937, 0.136, 0.0077, 1.0), 0.2421),
    ((0.4853, 0.5725, 0.1079, 1.0), 0.2526),
    ((0.149, 0.2143, 0.0111, 1.0), 0.2947),
    ((0.7084, 0.8469, 0.3095, 1.0), 0.3053),
    ((0.0018, 0.008, 0.0, 1.0), 0.3158),
    ((0.9181, 0.9247, 0.4006, 1.0), 0.3263),
    ((0.1496, 0.1989, 0.0209, 1.0), 0.3579),
    ((0.18, 0.2798, 0.0095, 1.0), 0.4211),
    ((0.0971, 0.1541, 0.0068, 1.0), 0.4632),
    ((0.3364, 0.4352, 0.0719, 1.0), 0.4947),
    ((0.1105, 0.1727, 0.0078, 1.0), 0.5579),
    ((0.3493, 0.5321, 0.0443, 1.0), 0.6316),
    ((0.1035, 0.1735, 0.0031, 1.0), 0.6526),
    ((0.6578, 0.7528, 0.1652, 1.0), 0.6737),
    ((0.0797, 0.1192, 0.0077, 1.0), 0.6947),
    ((0.126, 0.191, 0.0137, 1.0), 0.7579),
    ((0.4031, 0.5242, 0.0569, 1.0), 0.8),
    ((0.9708, 0.9771, 0.524, 1.0), 0.8211),
    ((0.0765, 0.1203, 0.0085, 1.0), 0.8316),
    ((0.4879, 0.6171, 0.1039, 1.0), 0.8947),
    ((0.154, 0.2268, 0.0237, 1.0), 0.9158),
    ((0.8421, 0.9664, 0.3916, 1.0), 0.9263),
    ((0.192, 0.2556, 0.0265, 1.0), 0.9474),
    ((0.4264, 0.5593, 0.0509, 1.0), 0.9579),
    ((0.1199, 0.1892, 0.004, 1.0), 1.0)]

pallete4 = [   ((0.0273, 0.0802, 0.0382, 1.0), 0.0),
    ((0.0232, 0.0742, 0.0356, 1.0), 0.0323),
    ((0.1095, 0.2159, 0.1221, 1.0), 0.0645),
    ((0.0296, 0.0865, 0.0319, 1.0), 0.0968),
    ((0.0545, 0.1274, 0.0666, 1.0), 0.129),
    ((0.1106, 0.2139, 0.1332, 1.0), 0.1613),
    ((0.0342, 0.0948, 0.0369, 1.0), 0.2258),
    ((0.0513, 0.1195, 0.0612, 1.0), 0.2581),
    ((0.0182, 0.0558, 0.0222, 1.0), 0.2903),
    ((0.0242, 0.0654, 0.0343, 1.0), 0.3548),
    ((0.0545, 0.1144, 0.0742, 1.0), 0.3871),
    ((0.0195, 0.0503, 0.0235, 1.0), 0.4194),
    ((0.0186, 0.0652, 0.0218, 1.0), 0.4839),
    ((0.0453, 0.1304, 0.0593, 1.0), 0.5484),
    ((0.0844, 0.1845, 0.1329, 1.0), 0.5806),
    ((0.0395, 0.1022, 0.0545, 1.0), 0.6129),
    ((0.0683, 0.1462, 0.0793, 1.0), 0.6452),
    ((0.0265, 0.0726, 0.0265, 1.0), 0.7097),
    ((0.0638, 0.1345, 0.0624, 1.0), 0.7419),
    ((0.017, 0.0631, 0.0173, 1.0), 0.8065),
    ((0.0295, 0.0821, 0.0318, 1.0), 0.8387),
    ((0.0184, 0.0643, 0.0211, 1.0), 0.9032),
    ((0.0298, 0.0866, 0.0336, 1.0), 0.9355),
    ((0.0193, 0.0679, 0.0271, 1.0), 1.0)]

pallete5 = [   ((0.1712, 0.2776, 0.0465, 1.0), 0.0),
    ((0.0596, 0.1252, 0.0085, 1.0), 0.0732),
    ((0.1746, 0.2918, 0.0561, 1.0), 0.0976),
    ((0.0666, 0.1413, 0.007, 1.0), 0.122),
    ((0.1068, 0.2119, 0.0179, 1.0), 0.1463),
    ((0.0924, 0.1889, 0.0124, 1.0), 0.2195),
    ((0.1363, 0.2272, 0.0336, 1.0), 0.2927),
    ((0.0964, 0.1607, 0.0198, 1.0), 0.3171),
    ((0.0938, 0.1642, 0.0263, 1.0), 0.3902),
    ((0.0612, 0.117, 0.0137, 1.0), 0.4146),
    ((0.157, 0.2397, 0.0658, 1.0), 0.439),
    ((0.0213, 0.0497, 0.0023, 1.0), 0.4878),
    ((0.0487, 0.0734, 0.0116, 1.0), 0.5366),
    ((0.0366, 0.0546, 0.006, 1.0), 0.5854),
    ((0.2384, 0.2789, 0.107, 1.0), 0.6098),
    ((0.1384, 0.1946, 0.0482, 1.0), 0.6341),
    ((0.2384, 0.2789, 0.107, 1.0), 0.6585),
    ((0.0408, 0.0628, 0.0031, 1.0), 0.6829),
    ((0.0842, 0.1291, 0.0168, 1.0), 0.7317),
    ((0.0727, 0.1155, 0.0125, 1.0), 0.7561),
    ((0.1238, 0.1865, 0.0352, 1.0), 0.8049),
    ((0.0761, 0.1247, 0.016, 1.0), 0.8537),
    ((0.1389, 0.1985, 0.0443, 1.0), 0.878),
    ((0.0646, 0.1021, 0.0119, 1.0), 0.9512),
    ((0.1329, 0.1812, 0.0395, 1.0), 0.9756),
    ((0.1195, 0.1651, 0.0319, 1.0), 1.0)]

def shader_grass_texture_original(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    coord = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: texture_coordinate.outputs["UV"], 'Scale': uniform(0.02, 0.2)},
        attrs={'operation': 'SCALE'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': coord})
    
    edge_height = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: 6.0, 2: -10.0},
        label='edge height',
        attrs={'operation': 'MULTIPLY_ADD'})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': separate_xyz.outputs["Y"], 'Y': edge_height})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': separate_xyz.outputs["Y"], 'Scale': 25.0, 'Distortion': 8.0, 'Detail Scale': 6.0})
    
    musgrave_texture = nw.new_node(Nodes.MusgraveTexture,
        input_kwargs={'Vector': combine_xyz, 'Scale': 8.0, 'Detail': 5.0, 'Dimension': 0.1, 'Lacunarity': 3.0})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.2, 'Color1': wave_texture.outputs["Color"], 'Color2': musgrave_texture})
    
    
    object_info = nw.new_node(Nodes.ObjectInfo_Shader)
    map_range_1 = nw.new_node(Nodes.MapRange, input_kwargs={0: uniform(), 3: object_info.outputs["Random"], 4: mix_1})
    colorramp = nw.new_node(Nodes.ColorRamp, input_kwargs={'Fac': map_range_1.outputs["Result"]})
    
    pallete = np.random.choice([pallete1, pallete2, pallete3, pallete4, pallete5])
    np.random.shuffle(pallete)
    pallete = pallete[:np.random.randint(4, len(pallete))]
    for _ in range(len(pallete)-2):
        colorramp.color_ramp.elements.new(0)
    assert len(pallete) == len(colorramp.color_ramp.elements)
    for el, (rgba, pos) in zip(colorramp.color_ramp.elements, pallete):
        el.position = pos
        el.color = tuple(rgba)

    rough1, rough2 = uniform(0.2, 0.6, 2)
    roughness = nw.new_node(Nodes.MapRange, [mix_1, 0, 1, rough1, rough2])
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': colorramp.outputs["Color"], 'Roughness': roughness})
    translucent = nw.new_node(Nodes.TranslucentBSDF, [colorramp.outputs["Color"]])
    shader = nw.new_node(Nodes.MixShader, [0.7, principled_bsdf, translucent])
    
    nw.new_node(Nodes.MaterialOutput, input_kwargs={'Surface': shader})



def apply(obj, selection=None, **kwargs):
    surface.add_material(obj, shader_grass_texture_original, selection=selection)
worldgen/surfaces/templates/fish_eye_shader.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Mingzhe Wang
# Date Signed: June 14 2023 

import os, sys
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface

@node_utils.to_nodegroup('nodegroup_rotate2_d_002', singleton=False, type='ShaderNodeTree')
def nodegroup_rotate2_d_002(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.6.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5000),
            ('NodeSocketFloat', 'Value2', 0.5000),
            ('NodeSocketFloat', 'Value', 0.5000)])
    
    multiply = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs[2], 1: 0.0175}, attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math, input_kwargs={0: multiply}, attrs={'operation': 'SINE'})
    
    multiply_1 = nw.new_node(Nodes.Math, input_kwargs={0: sine, 1: group_input}, attrs={'operation': 'MULTIPLY'})
    
    cosine = nw.new_node(Nodes.Math, input_kwargs={0: multiply}, attrs={'operation': 'COSINE'})
    
    multiply_2 = nw.new_node(Nodes.Math, input_kwargs={0: group_input, 1: cosine}, attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math, input_kwargs={0: multiply_1, 1: multiply_2}, attrs={'operation': 'SUBTRACT'})
    
    multiply_3 = nw.new_node(Nodes.Math, input_kwargs={0: group_input, 1: cosine}, attrs={'operation': 'MULTIPLY'})
    
    multiply_4 = nw.new_node(Nodes.Math, input_kwargs={0: group_input, 1: sine}, attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math, input_kwargs={0: multiply_3, 1: multiply_4})
    
    group_output = nw.new_node(Nodes.GroupOutput, input_kwargs={'Value': subtract, 'Value1': add}, attrs={'is_active_output': True})

def shader_eyeball_fish(nw: NodeWrangler):
    # Code generated using version 2.6.3 of the node_transpiler

    attribute_1 = nw.new_node(Nodes.Attribute, attrs={'attribute_name': 'EyeballPosition'})
    
    mapping = nw.new_node(Nodes.Mapping, input_kwargs={'Vector': attribute_1.outputs["Color"]})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture, input_kwargs={'Vector': mapping, 'Scale': 50.0000})
    
    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0200, 'Color1': mapping, 'Color2': noise_texture.outputs["Color"]})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': mix})
    
    value = nw.new_node(Nodes.Value)
    value.outputs[0].default_value = 0.0000
    
    group = nw.new_node(nodegroup_rotate2_d_002().name,
        input_kwargs={0: separate_xyz.outputs["Y"], 'Value2': separate_xyz.outputs["Z"], 2: value})
    
    multiply = nw.new_node(Nodes.Math, input_kwargs={0: separate_xyz.outputs["Z"], 1: 0.3000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_1 = nw.new_node(Nodes.Math, input_kwargs={0: multiply, 1: multiply}, attrs={'operation': 'MULTIPLY'})
    
    multiply_2 = nw.new_node(Nodes.Math, input_kwargs={0: separate_xyz.outputs["Y"], 1: 0.8000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_3 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_2, 1: multiply_2}, attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math, input_kwargs={0: multiply_1, 1: multiply_3})
    
    add_1 = nw.new_node(Nodes.Math, input_kwargs={0: add, 1: 0.6300})
    
    colorramp = nw.new_node(Nodes.ColorRamp, input_kwargs={'Fac': add_1})
    colorramp.color_ramp.elements[0].position = 0.6400
    colorramp.color_ramp.elements[0].color = [1.0000, 1.0000, 1.0000, 1.0000]
    colorramp.color_ramp.elements[1].position = 0.6591
    colorramp.color_ramp.elements[1].color = [0.0000, 0.0000, 0.0000, 1.0000]
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': attribute_1.outputs["Color"], 'Scale': (1.0000, 100.0000, 1.0000)})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.3000, 'Color1': mapping_1, 'Color2': attribute_1.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture, input_kwargs={'Vector': mix_1, 'Scale': 10.0000})
    
    mix_2 = nw.new_node(Nodes.MixRGB, input_kwargs={'Fac': 0.7000, 'Color1': noise_texture_1.outputs["Fac"], 'Color2': mix_1})
    
    voronoi_texture = nw.new_node(Nodes.VoronoiTexture, input_kwargs={'Vector': mix_2, 'Scale': 20.0000})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: voronoi_texture.outputs["Distance"], 1: voronoi_texture.outputs["Distance"], 2: 0.0000},
        attrs={'operation': 'MULTIPLY'})
    
    mapping_2 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': attribute_1.outputs["Color"], 'Scale': (20.0000, 1.0000, 1.0000)})
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.3000, 'Color1': mapping_2, 'Color2': attribute_1.outputs["Color"]})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture, input_kwargs={'Vector': mix_3, 'Scale': 10.0000})
    
    mix_4 = nw.new_node(Nodes.MixRGB, input_kwargs={'Fac': 0.7000, 'Color1': noise_texture_2.outputs["Fac"], 'Color2': mix_3})
    
    voronoi_texture_1 = nw.new_node(Nodes.VoronoiTexture,
        input_kwargs={'Vector': mix_4, 'W': U(-10, 10), 'Scale': 1.0000},
        attrs={'voronoi_dimensions': '4D'})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: voronoi_texture_1.outputs["Distance"], 1: voronoi_texture_1.outputs["Distance"], 2: 0.0000},
        attrs={'operation': 'MULTIPLY'})
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0000, 'Color1': multiply_4, 'Color2': multiply_5},
        attrs={'blend_type': 'OVERLAY'})
    
    bright_contrast = nw.new_node('ShaderNodeBrightContrast', input_kwargs={'Color': mix_5, 'Bright': 0.6000, 'Contrast': 1.5000})
    
    scale1 = U(0.65, 1.2)

    multiply_6 = nw.new_node(Nodes.Math, input_kwargs={0: separate_xyz.outputs["Z"], 1: scale1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_7 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_6, 1: multiply_6}, attrs={'operation': 'MULTIPLY'})
    
    multiply_8 = nw.new_node(Nodes.Math, input_kwargs={0: separate_xyz.outputs["Y"], 1: scale1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_9 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_8, 1: multiply_8}, attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_7, 1: multiply_9})
    
    add_3 = nw.new_node(Nodes.Math, input_kwargs={0: add_2})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp, input_kwargs={'Fac': add_3})
    colorramp_1.color_ramp.elements[0].position = 0.6159
    colorramp_1.color_ramp.elements[0].color = [1.0000, 1.0000, 1.0000, 1.0000]
    colorramp_1.color_ramp.elements[1].position = 0.6591
    colorramp_1.color_ramp.elements[1].color = [0.0000, 0.0000, 0.0000, 1.0000]
    
    colorramp_2 = nw.new_node(Nodes.ColorRamp, input_kwargs={'Fac': colorramp_1.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.0295
    colorramp_2.color_ramp.elements[0].color = [0.0000, 0.0000, 0.0000, 1.0000]
    colorramp_2.color_ramp.elements[1].position = 0.0523
    colorramp_2.color_ramp.elements[1].color = [1.0000, 1.0000, 1.0000, 1.0000]
    
    add_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: bright_contrast, 1: colorramp_2.outputs["Color"]},
        attrs={'use_clamp': True})
    
    scale2 = U(0.6, 0.8)
    multiply_10 = nw.new_node(Nodes.Math, input_kwargs={0: separate_xyz.outputs["Z"], 1: scale2}, attrs={'operation': 'MULTIPLY'})
    
    multiply_11 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_10, 1: multiply_10}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.Math, input_kwargs={0: separate_xyz.outputs["Y"], 1: scale2}, attrs={'operation': 'MULTIPLY'})
    
    multiply_13 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_12, 1: multiply_12}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_11, 1: multiply_13})
    
    add_6 = nw.new_node(Nodes.Math, input_kwargs={0: add_5, 1: 0.1800})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp, input_kwargs={'Fac': add_6})
    colorramp_3.color_ramp.elements[0].position = 0.4773
    colorramp_3.color_ramp.elements[0].color = [1.0000, 1.0000, 1.0000, 1.0000]
    colorramp_3.color_ramp.elements[1].position = 0.6659
    colorramp_3.color_ramp.elements[1].color = [0.0000, 0.0000, 0.0000, 1.0000]
    
    attribute_2 = nw.new_node(Nodes.Attribute, attrs={'attribute_name': 'EyeballPosition'})
    
    noise_texture_3 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': attribute_2.outputs["Color"], 'W': U(-10, 10), 'Scale': 0.5000},
        attrs={'noise_dimensions': '4D'})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp, input_kwargs={'Fac': noise_texture_3.outputs["Color"]})
    colorramp_4.color_ramp.interpolation = "CARDINAL"
    colorramp_4.color_ramp.elements[0].position = 0.3704
    colorramp_4.color_ramp.elements[0].color = [0.9570, 0.9247, 0.2801, 1.0000]
    colorramp_4.color_ramp.elements[1].position = 0.5455
    colorramp_4.color_ramp.elements[1].color = [1.0000, 0.6872, 0.5327, 1.0000]
    sample_color(colorramp_4.color_ramp.elements[0].color)
    sample_color(colorramp_4.color_ramp.elements[1].color)


    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_3.outputs["Color"], 'Color1': (0.7384, 0.5239, 0.2703, 1.0000), 'Color2': colorramp_4.outputs["Color"]})
    sample_color(mix_6.inputs["Color1"].default_value)

    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_1.outputs["Color"], 'Color1': mix_6, 'Color2': (0.0000, 0.0000, 0.0000, 1.0000)})
    
    mix_8 = nw.new_node(Nodes.MixRGB, input_kwargs={'Fac': add_4, 'Color1': (0.0000, 0.0000, 0.0000, 1.0000), 'Color2': mix_7})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': mix_8, 'Color2': (0.0000, 0.0000, 0.0000, 1.0000)})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF, input_kwargs={'Base Color': mix_8, 'Specular': 0.0000, 'Roughness': 0.0000})
    
    glossy_bsdf = nw.new_node('ShaderNodeBsdfGlossy')
    
    mix_shader_1 = nw.new_node(Nodes.MixShader, input_kwargs={'Fac': 0.0200, 1: principled_bsdf, 2: glossy_bsdf})
    
    material_output = nw.new_node(Nodes.MaterialOutput, input_kwargs={'Surface': mix_shader_1}, attrs={'is_active_output': True})


def apply(obj, selection=None, **kwargs):
    surface.add_material(obj, shader_eyeball_fish, selection=selection)
worldgen/surfaces/templates/cobble_stone.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Ankit Goyal, Mingzhe Wang, Zeyu Ma
# Date Signed: June 5 2023

from numpy.random import uniform as U, normal as N
from nodes.node_wrangler import Nodes, NodeWrangler
from surfaces import surface
from util.random import random_color_neighbour
from terrain.utils import SurfaceTypes
from util.math import FixedSeed
import gin

type = SurfaceTypes.SDFPerturb
mod_name = "geo_cobblestone"
name = "cobble_stone"


def shader_cobblestone(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler, and modified
    nw.force_input_consistency()
    stone_color = geo_cobblestone(nw, geometry=False)
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': nw.new_node('ShaderNodeNewGeometry'), 'Scale': N(10, 1.5) / 25, 'W': U(-5, 5)},
        attrs={'noise_dimensions': '4D'})

    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = random_color_neighbour((0.014, 0.013, 0.014, 1.0), 0.2, 0.1, 0.1)
    colorramp_1.color_ramp.elements[1].position = 1.0
    colorramp_1.color_ramp.elements[1].color = random_color_neighbour((0.047, 0.068, 0.069, 1.0), 0.2, 0.1, 0.1)


    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': stone_color.outputs["Color"], 'Color1': (0.0, 0.0, 0.0, 1.0), 'Color2': colorramp_1.outputs["Color"]})

    roughness_low = N(0.25, 0.05)
    roughness_high = N(0.75, 0.05)
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': stone_color.outputs["Color"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (roughness_high, roughness_high, roughness_high, 1.0)
    colorramp.color_ramp.elements[1].position = 1.0
    colorramp.color_ramp.elements[1].color = (roughness_low, roughness_low, roughness_low, 1.0)

    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix, 'Roughness': colorramp.outputs["Color"]})

    return principled_bsdf

@gin.configurable
def geo_cobblestone(nw: NodeWrangler, selection=None, random_seed=0, geometry=True):
    # Code generated using version 2.4.3 of the node_transpiler, and modified
    nw.force_input_consistency()
    if nw.node_group.type == "SHADER":
        position = nw.new_node('ShaderNodeNewGeometry')
        normal = (nw.new_node('ShaderNodeNewGeometry'), 1)
    else:
        position = nw.new_node(Nodes.InputPosition)
        normal = nw.new_node(Nodes.InputNormal)

    with FixedSeed(random_seed):
        # scale of the stone, inversely proportional
        sca_sto = nw.new_value(U(9, 15)/2, "sca_sto")
        # uniformity of the stone, inversely proportional
        uni_sto = nw.new_value(U(0.5, 0.9), "uni_sto")
        # depth of stone
        dep_sto = nw.new_value(U(0.02, 0.04), "dep_sto")


        group_input = nw.new_node(Nodes.GroupInput,
            expose_input=[('NodeSocketGeometry', 'Geometry', None)])

        noise_texture = nw.new_node(Nodes.NoiseTexture,
            input_kwargs={'Vector': position, 'W': nw.new_value(U(-5, 5), "W1"), 'Scale': nw.new_value(N(6.0, 0.5), "Scale1")},
            attrs={'noise_dimensions': '4D'})

        voronoi_texture_2 = nw.new_node(Nodes.VoronoiTexture,
            input_kwargs={'W': nw.new_value(U(-5, 5), "W2"), 'Scale': sca_sto, 'Randomness': uni_sto},
            attrs={'voronoi_dimensions': '4D'})

        noise_texture_3 = nw.new_node(Nodes.NoiseTexture,
            input_kwargs={'Vector': voronoi_texture_2.outputs["Position"], 'Scale': nw.new_value(N(20, 2), "Scale2")})

        colorramp_4 = nw.new_node(Nodes.ColorRamp,
            input_kwargs={'Fac': noise_texture_3.outputs["Fac"]})
        colorramp_4.color_ramp.interpolation = "CONSTANT"
        colorramp_4.color_ramp.elements[0].position = 0.1159
        colorramp_4.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
        colorramp_4.color_ramp.elements[1].position = 0.475
        colorramp_4.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)

        voronoi_texture_1 = nw.new_node(Nodes.VoronoiTexture,
            input_kwargs={'Vector': position, 'W': nw.new_value(U(-5, 5), "W3"), 'Scale': sca_sto, 'Randomness': uni_sto},
            attrs={'voronoi_dimensions': '4D', 'feature': 'DISTANCE_TO_EDGE'})

        multiply = nw.new_node(Nodes.Math,
            input_kwargs={0: 1.5, 1: sca_sto},
            attrs={'operation': 'MULTIPLY'})

        voronoi_texture_3 = nw.new_node(Nodes.VoronoiTexture,
            input_kwargs={'Vector': position, 'W': nw.new_value(U(-5, 5), "W4"), 'Scale': multiply, 'Randomness': uni_sto},
            attrs={'voronoi_dimensions': '4D', 'feature': 'DISTANCE_TO_EDGE'})

        mix_3 = nw.new_node(Nodes.MixRGB,
            input_kwargs={'Fac': colorramp_4.outputs["Color"], 'Color1': voronoi_texture_1.outputs["Distance"], 'Color2': voronoi_texture_3.outputs["Distance"]})

        mix = nw.new_node(Nodes.MixRGB,
            input_kwargs={'Fac': noise_texture.outputs["Fac"], 'Color1': mix_3})

        colorramp = nw.new_node(Nodes.ColorRamp,
            input_kwargs={'Fac': mix}, label="colorramp_VAR")
        colorramp.color_ramp.elements[0].position = U(0.26, 0.29)
        colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
        colorramp.color_ramp.elements[1].position = 0.377
        colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)

        if not geometry: return colorramp

        multiply_1 = nw.new_node(Nodes.VectorMath,
            input_kwargs={0: colorramp.outputs["Color"], 1: normal},
            attrs={'operation': 'MULTIPLY'})

        multiply_2 = nw.new_node(Nodes.VectorMath,
            input_kwargs={0: multiply_1.outputs["Vector"], 1: dep_sto},
            attrs={'operation': 'MULTIPLY'})

        noise_texture_4 = nw.new_node(Nodes.NoiseTexture,
            input_kwargs={'Scale': nw.new_value(N(20, 2), "Scale3"), 'Detail': 10.0, 'Distortion': 2.0})

        subtract = nw.new_node(Nodes.VectorMath,
            input_kwargs={0: noise_texture_4.outputs["Fac"], 1: (0.5, 0.5, 0.5)},
            attrs={'operation': 'SUBTRACT'})

        multiply_5 = nw.new_node(Nodes.VectorMath,
            input_kwargs={0: subtract.outputs["Vector"], 1: normal},
            attrs={'operation': 'MULTIPLY'})

        value_8 = nw.new_value(U(0.01, 0.02), "value_8")

        multiply_6 = nw.new_node(Nodes.VectorMath,
            input_kwargs={0: multiply_5.outputs["Vector"], 1: value_8},
            attrs={'operation': 'MULTIPLY'})

        set_position_1 = nw.new_node(Nodes.SetPosition,
            input_kwargs={'Geometry': group_input, 'Offset': nw.add(multiply_6, multiply_2)})


        group_output = nw.new_node(Nodes.GroupOutput, input_kwargs={'Geometry': set_position_1})


def apply(obj, selection=None, **kwargs):
    surface.add_geomod(obj,geo_cobblestone, selection=selection)
    surface.add_material(obj, shader_cobblestone, selection=selection, reuse=False)
worldgen/surfaces/templates/chitin.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Mingzhe Wang
# Date Signed: April 25 2023 

import os, sys
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform, normal, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category, hsv2rgba
from surfaces import surface

def shader_chitin(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    geometry = nw.new_node('ShaderNodeNewGeometry')
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': geometry.outputs["Pointiness"]})
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements[0].position = 0.4091
    colorramp_1.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.4455
    colorramp_1.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[2].position = 0.5127
    colorramp_1.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    
    colorramp_10 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_1.outputs["Color"]})
    colorramp_10.color_ramp.elements[0].position = 0.0
    colorramp_10.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_10.color_ramp.elements[1].position = 0.2273
    colorramp_10.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': geometry.outputs["Pointiness"]})
    colorramp_4.color_ramp.elements[0].position = 0.4909
    colorramp_4.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.6773
    colorramp_4.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_10.outputs["Color"], 1: colorramp_4.outputs["Color"]},
        attrs={'operation': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': multiply})
    colorramp_3.color_ramp.interpolation = "EASE"
    colorramp_3.color_ramp.elements[0].position = 0.0
    colorramp_3.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.0864
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_3 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz_3.outputs["X"]})
    colorramp_6.color_ramp.elements[0].position = 0.5332
    colorramp_6.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5427
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_2 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'tag_body'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_6.outputs["Color"], 1: attribute_2.outputs["Color"]},
        attrs={'operation': 'MULTIPLY'})
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'tag_head'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: attribute_1.outputs["Color"]},
        attrs={'use_clamp': True})
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (0.0168, 0.0168, 0.0168, 1.0)
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_3.outputs["Color"], 1: colorramp_5.outputs["Color"]},
        attrs={'operation': 'MULTIPLY'})
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'tag_leg'})
    
    invert_1 = nw.new_node('ShaderNodeInvert',
        input_kwargs={'Color': attribute_3.outputs["Color"]})
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_2, 1: invert_1},
        attrs={'operation': 'MULTIPLY'})
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate.outputs["Object"]})
    
    sign = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"]},
        attrs={'operation': 'SIGN'})
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate.outputs["Object"], 'Rotation': (0.0, 0.0, -0.7854), 'Scale': (1.0, 1.0, 0.0)})
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': mapping_1})
    
    mapping = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate.outputs["Object"], 'Rotation': (0.0, 0.0, 0.7854), 'Scale': (1.0, 10.0, 0.0)})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': mapping})
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': sign, 'Color1': separate_xyz_1.outputs["X"], 'Color2': separate_xyz.outputs["X"]})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 10.0, 'Detail': 10.0})
    
    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.2, 'Color1': mix_3, 'Color2': noise_texture.outputs["Fac"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mix, 'W': 1.4, 'Scale': 100.0, 'Detail': 10.0, 'Roughness': 0.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_1.inputs['W'].default_value = sample_range(-2,2)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': multiply_3, 'Color1': (0.0, 0.0, 0.0, 1.0), 'Color2': noise_texture_1.outputs["Fac"]})
    
    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_2})
    colorramp_2.color_ramp.elements[0].position = 0.0
    colorramp_2.color_ramp.elements[0].color = (0.0068, 0.0, 0.0005, 1.0)
    colorramp_2.color_ramp.elements[1].position = 0.9955
    colorramp_2.color_ramp.elements[1].color = (0.1347, 0.0156, 0.0115, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[1].color = hsv2rgba((np.mod(normal(0.2, 0.4), 1), uniform(0, 1), uniform(0.05, 0.5)))
        #for i in range(3):
        #    colorramp_2.color_ramp.elements[1].color[i] /= 7

    invert = nw.new_node('ShaderNodeInvert',
        input_kwargs={'Color': multiply_2})
    
    colorramp_11 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': invert})
    colorramp_11.color_ramp.elements[0].position = 0.3932
    colorramp_11.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_11.color_ramp.elements[1].position = 1.0
    colorramp_11.color_ramp.elements[1].color = (0.5103, 0.5103, 0.5103, 1.0)
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': colorramp_2.outputs["Color"], 'Metallic': 0.7, 'Roughness': colorramp_11.outputs["Color"]},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_chitin(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Geometry', None)])
    
    normal = nw.new_node(Nodes.InputNormal)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 100.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2,2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: -0.5})
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: normal, 1: add},
        attrs={'operation': 'MULTIPLY'})
    
    value = nw.new_node(Nodes.Value)
    value.outputs[0].default_value = 0.001
    
    multiply_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply.outputs["Vector"], 1: value},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Geometry"], 'Offset': multiply_1.outputs["Vector"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': set_position})

def apply(obj, geo_kwargs=None, shader_kwargs=None, **kwargs):
    surface.add_geomod(obj, geometry_chitin, input_kwargs=geo_kwargs)
    surface.add_material(obj, shader_chitin, reuse=False, input_kwargs=shader_kwargs)


if __name__ == "__main__":
    for i in range(1):
        bpy.ops.wm.open_mainfile(filepath='dev_scene_1019.blend')
        #creature(73349, 0).parts(0, factory=QuadrupedBody)
        obj = "creature(36230, 0).parts(0, factory=BeetleBody)"
        #obj = "creature(73349, 0).parts(0, factory=QuadrupedBody)"
        apply(bpy.data.objects[obj], geo_kwargs={'rand': True}, shader_kwargs={'rand': True})
        fn = os.path.join(os.path.abspath(os.curdir), 'dev_scene_test_beetle_attr.blend')
        bpy.ops.wm.save_as_mainfile(filepath=fn)
        #bpy.context.scene.render.filepath = os.path.join('surfaces/surface_thumbnails', 'bone%d.jpg'%(i))
        #bpy.context.scene.render.image_settings.file_format='JPEG'
        #bpy.ops.render.render(write_still=True)

worldgen/surfaces/templates/basic_bsdf.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Alexander Raistrick
# Date Signed: May 30, 2023

import bpy
import mathutils

import numpy as np
from numpy.random import uniform, normal

from nodes.node_wrangler import Nodes, NodeWrangler
from nodes.color import hsv2rgba
from surfaces import surface

def shader_basic_bsdf(nw):

    color = nw.new_node(Nodes.RGB)
    color.outputs[0].default_value = hsv2rgba(uniform(0.05, 0.95, 3))

    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={
            'Base Color': color,
            'Roughness': np.clip(normal(0.6, 0.3), 0.05, 0.95),
            'Metallic': uniform(0, 1) if uniform() < 0.3 else 0,
            'Subsurface': 0 if uniform() < 0.8 else uniform(0, 0.2)
        },
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

    return principled_bsdf

def apply(obj, selection=None, **kwargs):
    surface.add_material(obj, shader_basic_bsdf, reuse=False)
worldgen/surfaces/templates/bark_random.py METASEP
# Copyright (c) Princeton University.
# This source code is licensed under the GPL license found in the LICENSE file in the root directory of this source tree.

# Authors: Yiming Zuo
# Date Signed: Jun 16, 2023

# Code generated using version 2.1.0 of the node_transpiler
from typing import Tuple
import bpy
import mathutils
from numpy.random import uniform, normal
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from surfaces import surface
import numpy as np

from util.math import FixedSeed

@node_utils.to_nodegroup('nodegroup_calc_radius', singleton=True, type='GeometryNodeTree')
def nodegroup_calc_radius(nw):
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Self Location', (0.0, 0.0, 0.0)),
            ('NodeSocketVector', 'Parent Location', (0.0, 0.0, 0.0))])
    
    subtract = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: group_input.outputs["Self Location"], 1: group_input.outputs["Parent Location"]},
        attrs={'operation': 'SUBTRACT'})
    
    normalize = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract.outputs["Vector"]},
        attrs={'operation': 'NORMALIZE'})
    
    position = nw.new_node(Nodes.InputPosition)
    
    subtract_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: position, 1: group_input.outputs["Parent Location"]},
        attrs={'operation': 'SUBTRACT'})
    
    dot_product = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: normalize.outputs["Vector"], 1: subtract_1.outputs["Vector"]},
        attrs={'operation': 'DOT_PRODUCT'})
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: normalize.outputs["Vector"], 1: dot_product.outputs["Value"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: group_input.outputs["Parent Location"], 1: multiply.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add.outputs["Vector"], 1: position},
        attrs={'operation': 'SUBTRACT'})
    
    length = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_2.outputs["Vector"]},
        attrs={'operation': 'LENGTH'})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Radius': length.outputs["Value"]})

@node_utils.to_nodegroup('nodegroup_shader_canonical_coord', singleton=True, type='ShaderNodeTree')
def nodegroup_shader_canonical_coord(nw):
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'scale', 2.0),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'parent_skeleton_loc'})
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'skeleton_loc'})
    
    subtract = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: attribute.outputs["Vector"]},
        attrs={'operation': 'SUBTRACT'})
    
    cross_product = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract.outputs["Vector"], 1: (0.0, 0.0, 1.0)},
        attrs={'operation': 'CROSS_PRODUCT'})
    
    dot_product = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract.outputs["Vector"], 1: (0.0, 0.0, 1.0)},
        attrs={'operation': 'DOT_PRODUCT'})
    
    length = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract.outputs["Vector"]},
        attrs={'operation': 'LENGTH'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: dot_product.outputs["Value"], 1: length.outputs["Value"]},
        attrs={'operation': 'DIVIDE'})
    
    arccosine = nw.new_node(Nodes.Math,
        input_kwargs={0: divide},
        attrs={'operation': 'ARCCOSINE'})
    
    vector_rotate = nw.new_node(Nodes.VectorRotate,
        input_kwargs={'Vector': group_input.outputs["Vector"], 'Center': attribute.outputs["Vector"], 'Axis': cross_product.outputs["Vector"], 'Angle': arccosine})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': separate_xyz.outputs["X"], 'Y': separate_xyz.outputs["Y"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: vector_rotate, 1: combine_xyz},
        attrs={'operation': 'SUBTRACT'})
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: group_input.outputs["scale"]},
        attrs={'operation': 'MULTIPLY'})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Coordinate': multiply.outputs["Vector"]})

@node_utils.to_nodegroup('nodegroup_inject_z_noise_and_scale_001', singleton=True, type='GeometryNodeTree')
def nodegroup_inject_z_noise_and_scale_001(nw):
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Coordinate', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Noise Scale', 2.0),
            ('NodeSocketFloat', 'Noise Amount', 0.5),
            ('NodeSocketFloat', 'Z Multiplier', 0.5)])
    
    separate_xyz_6 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Coordinate"]})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': group_input.outputs["Coordinate"], 'Scale': group_input.outputs["Noise Scale"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input.outputs["Noise Amount"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_6.outputs["Z"], 1: multiply})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: group_input.outputs["Z Multiplier"]},
        attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_6 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': separate_xyz_6.outputs["X"], 'Y': separate_xyz_6.outputs["Y"], 'Z': multiply_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Coordinate': combine_xyz_6})

@node_utils.to_nodegroup('nodegroup_primary_voronoi', singleton=True, type='GeometryNodeTree')
def nodegroup_primary_voronoi(nw):
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Coordinate', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Texture Scale', 20.0),
            ('NodeSocketFloatFactor', 'Randomness', 1.0)])
    
    voronoi_texture_3 = nw.new_node(Nodes.VoronoiTexture,
        input_kwargs={'Vector': group_input.outputs["Coordinate"], 'Scale': group_input.outputs["Texture Scale"], 'Randomness': group_input.outputs["Randomness"]},
        attrs={'feature': 'DISTANCE_TO_EDGE'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': voronoi_texture_3.outputs["Distance"], 2: 0.1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Displacement': map_range.outputs["Result"]})

@node_utils.to_nodegroup('nodegroup_mix', singleton=True, type='GeometryNodeTree')
def nodegroup_mix(nw):
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Input 1', 0.5),
            ('NodeSocketFloat', 'Input 2', 0.5),
            ('NodeSocketFloat', 'Mix Weight', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Input 1"], 1: group_input.outputs["Mix Weight"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: group_input.outputs["Mix Weight"]},
        attrs={'operation': 'SUBTRACT'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Input 2"], 1: subtract},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: multiply_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Value': add})

@node_utils.to_nodegroup('nodegroup_adjust_v', singleton=True, type='ShaderNodeTree')
def nodegroup_adjust_v(nw):
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketColor', 'Color', (0.8, 0.8, 0.8, 1.0)),
            ('NodeSocketFloat', 'V Shift', 0.5)])
    
    separate_hsv = nw.new_node('ShaderNodeSeparateHSV',
        input_kwargs={'Color': group_input.outputs["Color"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_hsv.outputs["V"], 1: group_input.outputs["V Shift"]})
    
    combine_hsv = nw.new_node(Nodes.CombineHSV,
        input_kwargs={'H': separate_hsv.outputs["H"], 'S': separate_hsv.outputs["S"], 'V': add})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Color': combine_hsv})

@node_utils.to_nodegroup('nodegroup_inject_z_noise_and_scale', singleton=True, type='ShaderNodeTree')
def nodegroup_inject_z_noise_and_scale(nw):
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Coordinate', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Noise Scale', 5.0),
            ('NodeSocketFloat', 'Noise Amount', 0.0),
            ('NodeSocketFloat', 'Z Multiplier', 0.5)])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Coordinate"]})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': group_input.outputs["Coordinate"], 'Scale': group_input.outputs["Noise Scale"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: group_input.outputs["Noise Amount"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Z"], 1: multiply})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: group_input.outputs["Z Multiplier"]},
        attrs={'operation': 'MULTIPLY'})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': separate_xyz.outputs["X"], 'Y': separate_xyz.outputs["Y"], 'Z': multiply_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Coordiante': combine_xyz})

@node_utils.to_nodegroup('nodegroup_voronoi', singleton=True, type='ShaderNodeTree')
def nodegroup_voronoi(nw):
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Coordinate', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Texture Scale', 5.0),
            ('NodeSocketFloatFactor', 'Randomness', 1.0)])
    
    voronoi_texture = nw.new_node(Nodes.VoronoiTexture,
        input_kwargs={'Vector': group_input.outputs["Coordinate"], 'Scale': group_input.outputs["Texture Scale"], 'Randomness': group_input.outputs["Randomness"]},
        attrs={'feature': 'DISTANCE_TO_EDGE'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': voronoi_texture.outputs["Distance"], 2: 0.5})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Displacement': map_range.outputs["Result"]})

@node_utils.to_nodegroup('nodegroup_canonical_coord', singleton=True, type='GeometryNodeTree')
def nodegroup_canonical_coord(nw):
    position = nw.new_node(Nodes.InputPosition)
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Self Location', (0.0, 0.0, 0.0)),
            ('NodeSocketVector', 'Parent Location', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'scale', 2.0)])
    
    subtract = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: group_input.outputs["Self Location"], 1: group_input.outputs["Parent Location"]},
        attrs={'operation': 'SUBTRACT'})
    
    cross_product = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract.outputs["Vector"], 1: (0.0, 0.0, 1.0)},
        attrs={'operation': 'CROSS_PRODUCT'})
    
    dot_product = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract.outputs["Vector"], 1: (0.0, 0.0, 1.0)},
        attrs={'operation': 'DOT_PRODUCT'})
    
    length = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract.outputs["Vector"]},
        attrs={'operation': 'LENGTH'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: dot_product.outputs["Value"], 1: length.outputs["Value"]},
        attrs={'operation': 'DIVIDE'})
    
    arccosine = nw.new_node(Nodes.Math,
        input_kwargs={0: divide},
        attrs={'operation': 'ARCCOSINE'})
    
    vector_rotate = nw.new_node(Nodes.VectorRotate,
        input_kwargs={'Vector': position, 'Center': group_input.outputs["Parent Location"], 'Axis': cross_product.outputs["Vector"], 'Angle': arccosine})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Parent Location"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': separate_xyz.outputs["X"], 'Y': separate_xyz.outputs["Y"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: vector_rotate, 1: combine_xyz},
        attrs={'operation': 'SUBTRACT'})
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: group_input.outputs["scale"]},
        attrs={'operation': 'MULTIPLY'})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Coordinate': multiply.outputs["Vector"]})

@node_utils.to_nodegroup('nodegroup_random_bark_geo', singleton=True, type='GeometryNodeTree')
def nodegroup_random_bark_geo(nw):
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Position', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Noise Scale', 2.0),
            ('NodeSocketFloat', 'Noise Amount', 1.0),
            ('NodeSocketFloat', 'Texture Scale', 30.0),
            ('NodeSocketFloatFactor', 'Randomness', 1.0),
            ('NodeSocketFloat', 'Value', 0.05),
            ('NodeSocketFloat', 'Mix Weight', 0.1),
            ('NodeSocketFloat', 'Scale', 15.0),
            ('NodeSocketFloat', 'Detail', 16.0),
            ('NodeSocketFloat', 'Value_1', 2.0),
            ('NodeSocketFloat', 'Z Multiplier', 0.5),
            ('NodeSocketFloat', 'Texture Scale S', 30.0)])

    group_3 = nw.new_node(nodegroup_primary_voronoi().name,
        input_kwargs={'Coordinate': group_input.outputs["Position"], 'Texture Scale': group_input.outputs['Texture Scale S']})
    
    group = nw.new_node(nodegroup_inject_z_noise_and_scale_001().name,
        input_kwargs={'Coordinate': group_input.outputs["Position"], 'Noise Scale': group_input.outputs["Noise Scale"], 'Noise Amount': group_input.outputs["Noise Amount"], 'Z Multiplier': group_input.outputs["Z Multiplier"]})
    
    group_2 = nw.new_node(nodegroup_primary_voronoi().name,
        input_kwargs={'Coordinate': group, 'Texture Scale': group_input.outputs["Texture Scale"], 'Randomness': group_input.outputs["Randomness"]})
    
    group_5 = nw.new_node(nodegroup_mix().name,
        input_kwargs={'Input 1': group_3, 'Input 2': group_2, 'Mix Weight': group_input.outputs["Mix Weight"]})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': group_input.outputs["Position"], 'Scale': group_input.outputs["Value_1"], 'Detail': group_input.outputs["Detail"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: group_input.outputs['Noise Scale']},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: group_5, 1: multiply})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: group_input.outputs["Value"]},
        attrs={'operation': 'MULTIPLY'})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Value': multiply_1})

@node_utils.to_nodegroup('nodegroup_apply_geo_matv2', singleton=True, type='GeometryNodeTree')
def nodegroup_apply_geo_matv2(nw):
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Geometry', None),
            ('NodeSocketFloat', 'Displacement Amount', 0.0),
            ('NodeSocketFloat', 'Displacement Scale', 0.0),
            ('NodeSocketMaterial', 'Material', None)])
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Displacement Amount"], 1: group_input.outputs["Displacement Scale"]},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: normal, 1: multiply},
        attrs={'operation': 'MULTIPLY'})
    
    set_position_1 = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Geometry"], 'Offset': multiply_1.outputs["Vector"]})
    
    set_material = nw.new_node(Nodes.SetMaterial,
        input_kwargs={'Geometry': set_position_1, 'Material': group_input.outputs["Material"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': set_material})

def shader_random_bark_mat(nw, base_color:Tuple, geo_params, selection=None):
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: geo_params['Noise Texture Scale'], 1: 4.0},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': multiply})
    
    map_range_2 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': noise_texture_1.outputs["Fac"], 1: 0.35, 2: 0.4, 3: 0.5, 4: 0.0})
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'initial_position'})

    group_canonical = nw.new_node(nodegroup_shader_canonical_coord().name,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: geo_params['Noise Texture Scale'], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': group_canonical, 'Scale': multiply_1})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': noise_texture.outputs["Fac"], 1: 0.35, 2: 0.4, 3: 0.5, 4: 0.0})
    
    group_2 = nw.new_node(nodegroup_voronoi().name,
        input_kwargs={'Coordinate': group_canonical, 'Texture Scale': geo_params['Secondary Voronoi Scale']})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': group_2, 3: 0.7, 4: 0.0})
    
    group = nw.new_node(nodegroup_inject_z_noise_and_scale().name,
        input_kwargs={'Coordinate': group_canonical, 'Noise Scale': geo_params['Z Noise Scale'], 'Noise Amount': geo_params['Z Noise Amount'], 'Z Multiplier': geo_params['Z Multiplier']})
    
    group_1 = nw.new_node(nodegroup_voronoi().name,
        input_kwargs={'Coordinate': group, 'Texture Scale': geo_params['Primary Voronoi Scale'], 'Randomness': geo_params['Primary Voronoi Randomness']})
    
    rgb_1 = nw.new_node(Nodes.RGB)
    rgb_1.outputs[0].default_value = base_color

    # todo: this value needs to be assigned
    
    group_3 = nw.new_node(nodegroup_adjust_v().name,
        input_kwargs={'Color': rgb_1, 'V Shift': 0.1})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.1, 'Color1': (0.0, 0.0, 0.0, 1.0), 'Color2': group_3})
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': group_1, 'Color1': mix_4, 'Color2': group_3})
    
    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': map_range.outputs["Result"], 'Color1': mix_3, 'Color2': mix_4})
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9, 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': group_3})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': map_range_1.outputs["Result"], 'Color1': mix, 'Color2': mix_6})
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9, 'Color1': (0.0, 0.0, 0.0, 1.0), 'Color2': group_3})
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': map_range_2.outputs["Result"], 'Color1': mix_1, 'Color2': mix_5})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_2, 'Roughness': 0.7})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geo_bark_random(nw, base_color, geo_params, selection=None):
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Geometry', None),
            ('NodeSocketFloat', 'Displacement Scale', geo_params['Displacement Scale']),
            ('NodeSocketFloat', 'Z Noise Scale', geo_params['Z Noise Scale']),
            ('NodeSocketFloat', 'Z Noise Amount', geo_params['Z Noise Amount']),
            ('NodeSocketFloat', 'Z Multiplier', geo_params['Z Multiplier']),
            ('NodeSocketFloat', 'Primary Voronoi Scale', geo_params['Primary Voronoi Scale']),
            ('NodeSocketFloatFactor', 'Primary Voronoi Randomness', geo_params['Primary Voronoi Randomness']),
            ('NodeSocketFloat', 'Secondary Voronoi Mix Weight', geo_params['Secondary Voronoi Mix Weight']),
            ('NodeSocketFloat', 'Secondary Voronoi Scale', geo_params['Secondary Voronoi Scale']),
            ('NodeSocketFloat', 'Noise Texture Scale', geo_params['Noise Texture Scale']),
            ('NodeSocketFloat', 'Noise Texture Detail', geo_params['Noise Texture Detail']),
            ('NodeSocketFloat', 'Noise Texture Weight', geo_params['Noise Texture Weight'])])

    parent_loc = nw.new_node(Nodes.NamedAttribute, ['parent_skeleton_loc'], attrs={'data_type': 'FLOAT_VECTOR'})
    skeleton_loc = nw.new_node(Nodes.NamedAttribute, ['skeleton_loc'], attrs={'data_type': 'FLOAT_VECTOR'})
    
    position = nw.new_node(Nodes.InputPosition)
    
    capture_attribute = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': group_input.outputs["Geometry"], 1: position},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    canonicalcoord = nw.new_node(nodegroup_canonical_coord().name,
        input_kwargs={'Self Location': skeleton_loc, 'Parent Location': parent_loc})

    group_1 = nw.new_node(nodegroup_random_bark_geo().name,
        input_kwargs={'Position': canonicalcoord, 'Noise Scale': group_input.outputs["Z Noise Scale"], 'Noise Amount': group_input.outputs["Z Noise Amount"], 3: group_input.outputs["Primary Voronoi Scale"], 'Randomness': group_input.outputs["Primary Voronoi Randomness"], 5: group_input.outputs["Displacement Scale"], 'Mix Weight': group_input.outputs["Secondary Voronoi Mix Weight"], 'Scale': group_input.outputs["Noise Texture Scale"], 'Detail': group_input.outputs["Noise Texture Detail"], 9: group_input.outputs["Noise Texture Weight"], 'Z Multiplier': group_input.outputs["Z Multiplier"], 11: group_input.outputs["Secondary Voronoi Scale"]})

    calc_radius = nw.new_node(nodegroup_calc_radius().name,
        input_kwargs={'Self Location': skeleton_loc, 'Parent Location': parent_loc})

    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: calc_radius, 1: 3.0},
        attrs={'operation': 'MULTIPLY'})

    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: group_1},
        attrs={'operation': 'MULTIPLY'})
    group = nw.new_node(nodegroup_apply_geo_matv2().name,
        input_kwargs={'Geometry': capture_attribute.outputs["Geometry"], 
                      'Displacement Amount': nw.multiply(multiply_1, surface.eval_argument(nw, selection)), 
                      'Displacement Scale': 0.5, 'Material': surface.shaderfunc_to_material(shader_random_bark_mat, geo_params=geo_params, base_color=base_color)})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': group, 'initial_position': capture_attribute.outputs["Attribute"]})

# https://blender.stackexchange.com/questions/158896/how-set-hex-in-rgb-node-python
def srgb_to_linearrgb(c):
    if   c < 0:       return 0
    elif c < 0.04045: return c/12.92
    else:             return ((c+0.055)/1.055)**2.4

def hex_to_rgb(h, alpha=1):
    r = (h & 0xff0000) >> 16
    g = (h & 0x00ff00) >> 8
    b = (h & 0x0000ff)
    return tuple([srgb_to_linearrgb(c/0xff) for c in (r,g,b)] + [alpha])

def get_random_bark_params(seed):
    with FixedSeed(seed):
        color_factory = [0x4c2f27, 0x69432d, 0x371803, 0x7f4040, 0xcc9576, 0x9e8170, 0x3d2b1f,
        0x8d6a58, 0x8b3325, 0x79443c, 0x88540b, 0x9b5f43, 0x4e3828, 0x4e3828,
        0xc09a6b, 0x944536, 0x3f0110, 0x773c12, 0x6e4e37, 0x5c4033, 0x5c4033,
        0x3c3034, 0x96704c, 0x371b1a, 0x483b32, 0x43141a, 0x471713, 0xc3b090,
        0x6b4423, 0x674d46, 0x5d2e1a, 0x331c1f, 0x7a5640, 0xb99984, 0x71543d,
        0x8f4b28, 0x491a00, 0x836446, 0x7f461b, 0x6a3208, 0x724115, 0xa0522b, 
        0x832a0c, 0x371b1a, 0xc7a373, 0x483b32, 0x635147, 0x664228, 0x5c5248]

        color_factory = [hex_to_rgb(c) for c in color_factory]

        geo_params = {
            'Displacement Scale': np.random.uniform(0.03, 0.07),
            'Z Noise Scale': np.random.uniform(1.0, 3.0),
            'Z Noise Amount': np.random.uniform(0.5, 1.5),
            'Z Multiplier': np.random.uniform(0.1, 0.3),
            'Primary Voronoi Scale': np.random.uniform(20, 40),
            'Primary Voronoi Randomness': np.random.uniform(0.6, 1.0),
            'Secondary Voronoi Mix Weight': np.random.uniform(0.05, 0.2),
            'Secondary Voronoi Scale': np.random.uniform(30, 50),
            'Noise Texture Scale': 15.0,
            'Noise Texture Detail': 16.0,
            'Noise Texture Weight': 2.0}
        color_params = {'Color': color_factory[np.random.randint(len(color_factory))]}

    return geo_params, color_params

def apply(obj, selection=None, **kwargs):

    geo_params, color_params = get_random_bark_params(seed=np.random.randint(1e5))

    surface.add_geomod(obj, geo_bark_random, selection=selection, 
        input_kwargs={'base_color': color_params['Color'], 'geo_params': geo_params}, attributes=['initial_position'])

worldgen/surfaces/templates/fishbody.py METASEP

import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
        scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)
        scales.inputs['Ynoise'].default_value = sample_range(0.1, 0.3)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: -0.5})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add, 1: normal},
        attrs={'operation': 'MULTIPLY'})
    
    value = nw.new_node(Nodes.Value)
    value.outputs[0].default_value = 0.002
    
    multiply_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply.outputs["Vector"], 1: value},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': scales.outputs["Geometry"], 'Offset': multiply_1.outputs["Vector"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': set_position, 
        'attr2': scales.outputs['attr2'],
        'attr5': scales.outputs['attr5']})

@node_utils.to_nodegroup('nodegroup_gradient_color', singleton=False, type='ShaderNodeTree')
def nodegroup_gradient_color(nw: NodeWrangler, **input_args):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5),
        #('NodeSocketColor', 'Color1', (1.0, 1.0, 1.0, 1.0)),
        #('NodeSocketColor', 'Color2', (0.5268, 0.6724, 0.5186, 1.0)),
        #('NodeSocketColor', 'Color3', (0.8055, 0.6284, 0.2728, 1.0)),
        #('NodeSocketColor', 'Color4', (0.838, 0.5269, 0.0338, 1.0)),
        #('NodeSocketColor', 'Color5', (0.0397, 0.0175, 0.0028, 1.0)),
        ('NodeSocketFloat', 'Value1', -0.2)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"], 1: group_input.outputs["Value"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: group_input.outputs["Value1"]})

    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements[0].position = 0.0945
    colorramp_1.color_ramp.elements[0].color = input_args["Color1"]
    colorramp_1.color_ramp.elements[1].position = 0.2045
    colorramp_1.color_ramp.elements[1].color = input_args["Color2"]
    colorramp_1.color_ramp.elements[2].position = 0.3159
    colorramp_1.color_ramp.elements[2].color = input_args["Color3"]
    colorramp_1.color_ramp.elements[3].position = 0.4977
    colorramp_1.color_ramp.elements[3].color = input_args["Color4"]
    colorramp_1.color_ramp.elements[4].position = 0.7568
    colorramp_1.color_ramp.elements[4].color = input_args["Color5"]
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Color': colorramp_1.outputs["Color"]})


@node_utils.to_nodegroup('nodegroup_noise_color', singleton=False, type='ShaderNodeTree')
def nodegroup_noise_color(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    mapping_3 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Scale', 10.0),
            ('NodeSocketColor', 'Color1', (0.7379, 0.2623, 0.0648, 1.0)),
            ('NodeSocketColor', 'Color2', (0.5029, 0.4287, 0.1079, 1.0))])
    
    noise_texture_8 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_3, 'W': U(-5, 5), 'Scale': group_input.outputs["Scale"]},
        attrs={'noise_dimensions': '4D'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_8.outputs["Fac"]})
    colorramp_9.color_ramp.elements[0].position = U(0, 0.5)
    colorramp_9.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 1.0
    colorramp_9.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_9.outputs["Color"], 'Color1': group_input.outputs["Color1"], 'Color2': group_input.outputs["Color2"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={"Color": mix_12})


def shader_stripe_fish(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_6 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    colorramp_11 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': attribute_6.outputs["Color"]})
    colorramp_11.color_ramp.elements[0].position = 0.0
    colorramp_11.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_11.color_ramp.elements[1].position = 0.2909
    colorramp_11.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    mapping_4 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_4, 'Scale': N(10, 2)})
    
    colorramp_10 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_9.outputs["Fac"]})
    colorramp_10.color_ramp.elements[0].position = 0.3773
    colorramp_10.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_10.color_ramp.elements[1].position = 1.0
    x = U(0.1, 0.9)
    colorramp_10.color_ramp.elements[1].color = (x, x, x, 1.0)
    
    mapping_2 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': mapping_2})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["Z"]},
        attrs={'operation': 'SUBTRACT'})
    
    power = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: 4.0 if U()<0.7 else 3.0},
        attrs={'operation': 'POWER'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: power, 1: U(-2, 3)},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: multiply})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': separate_xyz_1.outputs["Y"], 'Z': separate_xyz_1.outputs["Z"]})
    
    reroute = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': combine_xyz})
    
    scale = nw.new_node(Nodes.Value,
        label='scale')
    scale.outputs[0].default_value = max(N(2, 0.6), 0.8)
    
    distortion = nw.new_node(Nodes.Value,
        label='distortion')
    distortion.outputs[0].default_value = N(5, 1)
    
    detail = nw.new_node(Nodes.Value,
        label='detail')
    detail.outputs[0].default_value = 15.0
    
    detailscale = nw.new_node(Nodes.Value,
        label='detailscale')
    detailscale.outputs[0].default_value = U(0.1, 0.8)
    
    offset = nw.new_node(Nodes.Value,
        label='offset')
    offset.outputs[0].default_value = N(1.8, 0.2)
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: offset, 1: -1.0},
        attrs={'operation': 'MULTIPLY'})
    
    wave_texture_2 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': multiply_1})
    
    no_side_stripe = U() > 0.7
    side_stripe_width = U(0.02, 0.1)
    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_2.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0
    colorramp_8.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_8.color_ramp.elements[1].position = side_stripe_width
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture_1 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': offset})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_1.outputs["Color"]})
    colorramp_6.color_ramp.elements[0].position = 0.0
    colorramp_6.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_6.color_ramp.elements[1].position = side_stripe_width
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale})
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = U(0.2, 0.8)
    colorramp_5.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 0.9955
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    if U() < 0.5:
        group_1 = nw.new_node(nodegroup_noise_color().name,
            input_kwargs={"Scale": N(10, 2), "Color1":(U(), U(), U(), 1.0), "Color2": (U(), U(), U(), 1.0)})
    else:
        group_1 = nw.new_node(nodegroup_gradient_color(
                Color1=(U(0.8, 1), U(0.8, 1), U(0.8, 1), 1.0),
                Color2=(U(), U(), U(), 1.0),
                Color3=(U(), U(), U(), 1.0),
                Color4=(U(), U(), U(), 1.0),
                Color5=(U(0, 0.1), U(0, 0.1), U(0, 0.1), 1.0),).name,
            input_kwargs={
                "Value": N(0.5, 0.1),
                "Value1": N(-0.2, 0.1),
            })

infile
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

infile
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

infile
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
infile
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
        scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)
        scales.inputs['Ynoise'].default_value = sample_range(0.1, 0.3)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: -0.5})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add, 1: normal},
        attrs={'operation': 'MULTIPLY'})
    
    value = nw.new_node(Nodes.Value)
    value.outputs[0].default_value = 0.002
    
    multiply_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply.outputs["Vector"], 1: value},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': scales.outputs["Geometry"], 'Offset': multiply_1.outputs["Vector"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': set_position, 
        'attr2': scales.outputs['attr2'],
        'attr5': scales.outputs['attr5']})

@node_utils.to_nodegroup('nodegroup_gradient_color', singleton=False, type='ShaderNodeTree')
def nodegroup_gradient_color(nw: NodeWrangler, **input_args):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5),
        #('NodeSocketColor', 'Color1', (1.0, 1.0, 1.0, 1.0)),
        #('NodeSocketColor', 'Color2', (0.5268, 0.6724, 0.5186, 1.0)),
        #('NodeSocketColor', 'Color3', (0.8055, 0.6284, 0.2728, 1.0)),
        #('NodeSocketColor', 'Color4', (0.838, 0.5269, 0.0338, 1.0)),
        #('NodeSocketColor', 'Color5', (0.0397, 0.0175, 0.0028, 1.0)),
        ('NodeSocketFloat', 'Value1', -0.2)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"], 1: group_input.outputs["Value"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: group_input.outputs["Value1"]})

    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements[0].position = 0.0945
    colorramp_1.color_ramp.elements[0].color = input_args["Color1"]
    colorramp_1.color_ramp.elements[1].position = 0.2045
    colorramp_1.color_ramp.elements[1].color = input_args["Color2"]
    colorramp_1.color_ramp.elements[2].position = 0.3159
    colorramp_1.color_ramp.elements[2].color = input_args["Color3"]
    colorramp_1.color_ramp.elements[3].position = 0.4977
    colorramp_1.color_ramp.elements[3].color = input_args["Color4"]
    colorramp_1.color_ramp.elements[4].position = 0.7568
    colorramp_1.color_ramp.elements[4].color = input_args["Color5"]
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Color': colorramp_1.outputs["Color"]})


@node_utils.to_nodegroup('nodegroup_noise_color', singleton=False, type='ShaderNodeTree')
def nodegroup_noise_color(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    mapping_3 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Scale', 10.0),
            ('NodeSocketColor', 'Color1', (0.7379, 0.2623, 0.0648, 1.0)),
            ('NodeSocketColor', 'Color2', (0.5029, 0.4287, 0.1079, 1.0))])
    
    noise_texture_8 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_3, 'W': U(-5, 5), 'Scale': group_input.outputs["Scale"]},
        attrs={'noise_dimensions': '4D'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_8.outputs["Fac"]})
    colorramp_9.color_ramp.elements[0].position = U(0, 0.5)
    colorramp_9.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 1.0
    colorramp_9.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_9.outputs["Color"], 'Color1': group_input.outputs["Color1"], 'Color2': group_input.outputs["Color2"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={"Color": mix_12})


def shader_stripe_fish(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_6 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    colorramp_11 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': attribute_6.outputs["Color"]})
    colorramp_11.color_ramp.elements[0].position = 0.0
    colorramp_11.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_11.color_ramp.elements[1].position = 0.2909
    colorramp_11.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    mapping_4 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_4, 'Scale': N(10, 2)})
    
    colorramp_10 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_9.outputs["Fac"]})
    colorramp_10.color_ramp.elements[0].position = 0.3773
    colorramp_10.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_10.color_ramp.elements[1].position = 1.0
    x = U(0.1, 0.9)
    colorramp_10.color_ramp.elements[1].color = (x, x, x, 1.0)
    
    mapping_2 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': mapping_2})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["Z"]},
        attrs={'operation': 'SUBTRACT'})
    
    power = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: 4.0 if U()<0.7 else 3.0},
        attrs={'operation': 'POWER'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: power, 1: U(-2, 3)},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: multiply})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': separate_xyz_1.outputs["Y"], 'Z': separate_xyz_1.outputs["Z"]})
    
    reroute = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': combine_xyz})
    
    scale = nw.new_node(Nodes.Value,
        label='scale')
    scale.outputs[0].default_value = max(N(2, 0.6), 0.8)
    
    distortion = nw.new_node(Nodes.Value,
        label='distortion')
    distortion.outputs[0].default_value = N(5, 1)
    
    detail = nw.new_node(Nodes.Value,
        label='detail')
    detail.outputs[0].default_value = 15.0
    
    detailscale = nw.new_node(Nodes.Value,
        label='detailscale')
    detailscale.outputs[0].default_value = U(0.1, 0.8)
    
    offset = nw.new_node(Nodes.Value,
        label='offset')
    offset.outputs[0].default_value = N(1.8, 0.2)
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: offset, 1: -1.0},
        attrs={'operation': 'MULTIPLY'})
    
    wave_texture_2 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': multiply_1})
    
    no_side_stripe = U() > 0.7
    side_stripe_width = U(0.02, 0.1)
    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_2.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0
    colorramp_8.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_8.color_ramp.elements[1].position = side_stripe_width
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture_1 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': offset})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_1.outputs["Color"]})
    colorramp_6.color_ramp.elements[0].position = 0.0
    colorramp_6.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_6.color_ramp.elements[1].position = side_stripe_width
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale})
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = U(0.2, 0.8)
    colorramp_5.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 0.9955
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    if U() < 0.5:
infile
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
        scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)
        scales.inputs['Ynoise'].default_value = sample_range(0.1, 0.3)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: -0.5})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add, 1: normal},
        attrs={'operation': 'MULTIPLY'})
    
    value = nw.new_node(Nodes.Value)
    value.outputs[0].default_value = 0.002
    
    multiply_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply.outputs["Vector"], 1: value},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': scales.outputs["Geometry"], 'Offset': multiply_1.outputs["Vector"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': set_position, 
        'attr2': scales.outputs['attr2'],
        'attr5': scales.outputs['attr5']})

@node_utils.to_nodegroup('nodegroup_gradient_color', singleton=False, type='ShaderNodeTree')
def nodegroup_gradient_color(nw: NodeWrangler, **input_args):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5),
        #('NodeSocketColor', 'Color1', (1.0, 1.0, 1.0, 1.0)),
        #('NodeSocketColor', 'Color2', (0.5268, 0.6724, 0.5186, 1.0)),
        #('NodeSocketColor', 'Color3', (0.8055, 0.6284, 0.2728, 1.0)),
        #('NodeSocketColor', 'Color4', (0.838, 0.5269, 0.0338, 1.0)),
        #('NodeSocketColor', 'Color5', (0.0397, 0.0175, 0.0028, 1.0)),
        ('NodeSocketFloat', 'Value1', -0.2)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"], 1: group_input.outputs["Value"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: group_input.outputs["Value1"]})

    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements[0].position = 0.0945
    colorramp_1.color_ramp.elements[0].color = input_args["Color1"]
    colorramp_1.color_ramp.elements[1].position = 0.2045
    colorramp_1.color_ramp.elements[1].color = input_args["Color2"]
    colorramp_1.color_ramp.elements[2].position = 0.3159
    colorramp_1.color_ramp.elements[2].color = input_args["Color3"]
    colorramp_1.color_ramp.elements[3].position = 0.4977
    colorramp_1.color_ramp.elements[3].color = input_args["Color4"]
    colorramp_1.color_ramp.elements[4].position = 0.7568
    colorramp_1.color_ramp.elements[4].color = input_args["Color5"]
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Color': colorramp_1.outputs["Color"]})


@node_utils.to_nodegroup('nodegroup_noise_color', singleton=False, type='ShaderNodeTree')
def nodegroup_noise_color(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    mapping_3 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Scale', 10.0),
            ('NodeSocketColor', 'Color1', (0.7379, 0.2623, 0.0648, 1.0)),
            ('NodeSocketColor', 'Color2', (0.5029, 0.4287, 0.1079, 1.0))])
    
    noise_texture_8 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_3, 'W': U(-5, 5), 'Scale': group_input.outputs["Scale"]},
        attrs={'noise_dimensions': '4D'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_8.outputs["Fac"]})
    colorramp_9.color_ramp.elements[0].position = U(0, 0.5)
    colorramp_9.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 1.0
    colorramp_9.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_9.outputs["Color"], 'Color1': group_input.outputs["Color1"], 'Color2': group_input.outputs["Color2"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={"Color": mix_12})


def shader_stripe_fish(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_6 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    colorramp_11 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': attribute_6.outputs["Color"]})
    colorramp_11.color_ramp.elements[0].position = 0.0
    colorramp_11.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_11.color_ramp.elements[1].position = 0.2909
    colorramp_11.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    mapping_4 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_4, 'Scale': N(10, 2)})
    
    colorramp_10 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_9.outputs["Fac"]})
    colorramp_10.color_ramp.elements[0].position = 0.3773
    colorramp_10.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_10.color_ramp.elements[1].position = 1.0
    x = U(0.1, 0.9)
    colorramp_10.color_ramp.elements[1].color = (x, x, x, 1.0)
    
    mapping_2 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': mapping_2})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["Z"]},
        attrs={'operation': 'SUBTRACT'})
    
    power = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: 4.0 if U()<0.7 else 3.0},
        attrs={'operation': 'POWER'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: power, 1: U(-2, 3)},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: multiply})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': separate_xyz_1.outputs["Y"], 'Z': separate_xyz_1.outputs["Z"]})
    
    reroute = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': combine_xyz})
    
    scale = nw.new_node(Nodes.Value,
        label='scale')
    scale.outputs[0].default_value = max(N(2, 0.6), 0.8)
    
    distortion = nw.new_node(Nodes.Value,
        label='distortion')
    distortion.outputs[0].default_value = N(5, 1)
    
    detail = nw.new_node(Nodes.Value,
        label='detail')
    detail.outputs[0].default_value = 15.0
    
    detailscale = nw.new_node(Nodes.Value,
        label='detailscale')
    detailscale.outputs[0].default_value = U(0.1, 0.8)
    
    offset = nw.new_node(Nodes.Value,
        label='offset')
    offset.outputs[0].default_value = N(1.8, 0.2)
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: offset, 1: -1.0},
        attrs={'operation': 'MULTIPLY'})
    
    wave_texture_2 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': multiply_1})
    
    no_side_stripe = U() > 0.7
    side_stripe_width = U(0.02, 0.1)
    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_2.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0
    colorramp_8.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_8.color_ramp.elements[1].position = side_stripe_width
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture_1 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': offset})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_1.outputs["Color"]})
    colorramp_6.color_ramp.elements[0].position = 0.0
    colorramp_6.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_6.color_ramp.elements[1].position = side_stripe_width
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale})
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = U(0.2, 0.8)
    colorramp_5.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 0.9955
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    if U() < 0.5:
        group_1 = nw.new_node(nodegroup_noise_color().name,
            input_kwargs={"Scale": N(10, 2), "Color1":(U(), U(), U(), 1.0), "Color2": (U(), U(), U(), 1.0)})
    else:
infile
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

infile
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
        scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)
        scales.inputs['Ynoise'].default_value = sample_range(0.1, 0.3)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: -0.5})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add, 1: normal},
        attrs={'operation': 'MULTIPLY'})
    
    value = nw.new_node(Nodes.Value)
    value.outputs[0].default_value = 0.002
    
    multiply_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply.outputs["Vector"], 1: value},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': scales.outputs["Geometry"], 'Offset': multiply_1.outputs["Vector"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': set_position, 
        'attr2': scales.outputs['attr2'],
        'attr5': scales.outputs['attr5']})

@node_utils.to_nodegroup('nodegroup_gradient_color', singleton=False, type='ShaderNodeTree')
def nodegroup_gradient_color(nw: NodeWrangler, **input_args):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5),
        #('NodeSocketColor', 'Color1', (1.0, 1.0, 1.0, 1.0)),
        #('NodeSocketColor', 'Color2', (0.5268, 0.6724, 0.5186, 1.0)),
        #('NodeSocketColor', 'Color3', (0.8055, 0.6284, 0.2728, 1.0)),
        #('NodeSocketColor', 'Color4', (0.838, 0.5269, 0.0338, 1.0)),
        #('NodeSocketColor', 'Color5', (0.0397, 0.0175, 0.0028, 1.0)),
        ('NodeSocketFloat', 'Value1', -0.2)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"], 1: group_input.outputs["Value"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: group_input.outputs["Value1"]})

    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements[0].position = 0.0945
    colorramp_1.color_ramp.elements[0].color = input_args["Color1"]
    colorramp_1.color_ramp.elements[1].position = 0.2045
    colorramp_1.color_ramp.elements[1].color = input_args["Color2"]
    colorramp_1.color_ramp.elements[2].position = 0.3159
    colorramp_1.color_ramp.elements[2].color = input_args["Color3"]
    colorramp_1.color_ramp.elements[3].position = 0.4977
    colorramp_1.color_ramp.elements[3].color = input_args["Color4"]
    colorramp_1.color_ramp.elements[4].position = 0.7568
    colorramp_1.color_ramp.elements[4].color = input_args["Color5"]
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Color': colorramp_1.outputs["Color"]})


@node_utils.to_nodegroup('nodegroup_noise_color', singleton=False, type='ShaderNodeTree')
def nodegroup_noise_color(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    mapping_3 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Scale', 10.0),
            ('NodeSocketColor', 'Color1', (0.7379, 0.2623, 0.0648, 1.0)),
            ('NodeSocketColor', 'Color2', (0.5029, 0.4287, 0.1079, 1.0))])
    
    noise_texture_8 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_3, 'W': U(-5, 5), 'Scale': group_input.outputs["Scale"]},
        attrs={'noise_dimensions': '4D'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_8.outputs["Fac"]})
    colorramp_9.color_ramp.elements[0].position = U(0, 0.5)
    colorramp_9.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 1.0
    colorramp_9.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_9.outputs["Color"], 'Color1': group_input.outputs["Color1"], 'Color2': group_input.outputs["Color2"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={"Color": mix_12})


def shader_stripe_fish(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_6 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    colorramp_11 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': attribute_6.outputs["Color"]})
    colorramp_11.color_ramp.elements[0].position = 0.0
    colorramp_11.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_11.color_ramp.elements[1].position = 0.2909
    colorramp_11.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    mapping_4 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_4, 'Scale': N(10, 2)})
    
    colorramp_10 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_9.outputs["Fac"]})
    colorramp_10.color_ramp.elements[0].position = 0.3773
    colorramp_10.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_10.color_ramp.elements[1].position = 1.0
    x = U(0.1, 0.9)
    colorramp_10.color_ramp.elements[1].color = (x, x, x, 1.0)
    
    mapping_2 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': mapping_2})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["Z"]},
        attrs={'operation': 'SUBTRACT'})
    
    power = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: 4.0 if U()<0.7 else 3.0},
        attrs={'operation': 'POWER'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: power, 1: U(-2, 3)},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: multiply})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': separate_xyz_1.outputs["Y"], 'Z': separate_xyz_1.outputs["Z"]})
    
    reroute = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': combine_xyz})
    
    scale = nw.new_node(Nodes.Value,
        label='scale')
    scale.outputs[0].default_value = max(N(2, 0.6), 0.8)
    
    distortion = nw.new_node(Nodes.Value,
        label='distortion')
    distortion.outputs[0].default_value = N(5, 1)
    
    detail = nw.new_node(Nodes.Value,
        label='detail')
    detail.outputs[0].default_value = 15.0
    
    detailscale = nw.new_node(Nodes.Value,
        label='detailscale')
    detailscale.outputs[0].default_value = U(0.1, 0.8)
    
    offset = nw.new_node(Nodes.Value,
        label='offset')
    offset.outputs[0].default_value = N(1.8, 0.2)
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: offset, 1: -1.0},
        attrs={'operation': 'MULTIPLY'})
    
    wave_texture_2 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': multiply_1})
    
    no_side_stripe = U() > 0.7
    side_stripe_width = U(0.02, 0.1)
    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_2.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0
    colorramp_8.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_8.color_ramp.elements[1].position = side_stripe_width
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture_1 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': offset})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_1.outputs["Color"]})
    colorramp_6.color_ramp.elements[0].position = 0.0
    colorramp_6.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_6.color_ramp.elements[1].position = side_stripe_width
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale})
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = U(0.2, 0.8)
    colorramp_5.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 0.9955
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    if U() < 0.5:
        group_1 = nw.new_node(nodegroup_noise_color().name,
            input_kwargs={"Scale": N(10, 2), "Color1":(U(), U(), U(), 1.0), "Color2": (U(), U(), U(), 1.0)})
    else:
        group_1 = nw.new_node(nodegroup_gradient_color(
                Color1=(U(0.8, 1), U(0.8, 1), U(0.8, 1), 1.0),
                Color2=(U(), U(), U(), 1.0),
                Color3=(U(), U(), U(), 1.0),
                Color4=(U(), U(), U(), 1.0),
                Color5=(U(0, 0.1), U(0, 0.1), U(0, 0.1), 1.0),).name,
            input_kwargs={
                "Value": N(0.5, 0.1),
                "Value1": N(-0.2, 0.1),
            })

    group = nw.new_node(nodegroup_gradient_color(
            Color1=(U(0.8, 1), U(0.8, 1), U(0.8, 1), 1.0),
            Color2=(U(), U(), U(), 1.0),
            Color3=(U(), U(), U(), 1.0),
            Color4=(U(), U(), U(), 1.0),
            Color5=(U(0, 0.1), U(0, 0.1), U(0, 0.1), 1.0),).name,
        input_kwargs={
            "Value": N(0.5, 0.1),
            "Value1": N(-0.2, 0.1),
        })
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_5.outputs["Color"], 'Color1': group_1, 'Color2': group})
    
    side_stripe_color = (U(), U(), U(), 1.0)
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_6.outputs["Color"], 'Color1': side_stripe_color, 'Color2': mix_8})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_8.outputs["Color"], 'Color1': side_stripe_color, 'Color2': mix_9})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_10.outputs["Color"], 'Color1': mix_10, 'Color2': (U(), U(), U(), 1.0)})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_11.outputs["Color"], 'Color1': mix_11, 'Color2': (U(0, 0.5), U(0, 0.5), U(0, 0.5), 1.0)})
    
    noise_texture_7 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 10.0})
    
    roughness = U(0, 0.5)
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_7.outputs["Fac"]})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.9955
    colorramp_14.color_ramp.elements[1].color = (roughness, roughness, roughness, 1.0)
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_7, 'Metallic': max(0, N(0.2, 0.1)), 'Roughness': colorramp_14.outputs["Color"]})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})


def apply(obj, geo_kwargs=None, shader_kwargs=None, **kwargs):
    attributes = [
        'Color variations',
        'offset2'
    ]
        shader = shader_fish_body_gold
    else:
    surface.add_geomod(obj, geometry_fish_body, input_kwargs=geo_kwargs, attributes=attributes)
    surface.add_material(obj, shader, input_kwargs=shader_kwargs)

if __name__ == "__main__":
    for i in range(1):
        bpy.ops.wm.open_mainfile(filepath='dev_scene_fish_nurb.blend')
        i = 0
        for obj in bpy.data.objects:
            if obj.name.find('Nurb') >= 0:
infile
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
        scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
        scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)
        scales.inputs['Ynoise'].default_value = sample_range(0.1, 0.3)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
        scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)
        scales.inputs['Ynoise'].default_value = sample_range(0.1, 0.3)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: -0.5})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add, 1: normal},
        attrs={'operation': 'MULTIPLY'})
    
    value = nw.new_node(Nodes.Value)
    value.outputs[0].default_value = 0.002
    
    multiply_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply.outputs["Vector"], 1: value},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': scales.outputs["Geometry"], 'Offset': multiply_1.outputs["Vector"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': set_position, 
        'attr2': scales.outputs['attr2'],
        'attr5': scales.outputs['attr5']})

@node_utils.to_nodegroup('nodegroup_gradient_color', singleton=False, type='ShaderNodeTree')
def nodegroup_gradient_color(nw: NodeWrangler, **input_args):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5),
        #('NodeSocketColor', 'Color1', (1.0, 1.0, 1.0, 1.0)),
        #('NodeSocketColor', 'Color2', (0.5268, 0.6724, 0.5186, 1.0)),
        #('NodeSocketColor', 'Color3', (0.8055, 0.6284, 0.2728, 1.0)),
        #('NodeSocketColor', 'Color4', (0.838, 0.5269, 0.0338, 1.0)),
        #('NodeSocketColor', 'Color5', (0.0397, 0.0175, 0.0028, 1.0)),
        ('NodeSocketFloat', 'Value1', -0.2)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"], 1: group_input.outputs["Value"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: group_input.outputs["Value1"]})

    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements[0].position = 0.0945
    colorramp_1.color_ramp.elements[0].color = input_args["Color1"]
    colorramp_1.color_ramp.elements[1].position = 0.2045
    colorramp_1.color_ramp.elements[1].color = input_args["Color2"]
    colorramp_1.color_ramp.elements[2].position = 0.3159
    colorramp_1.color_ramp.elements[2].color = input_args["Color3"]
    colorramp_1.color_ramp.elements[3].position = 0.4977
    colorramp_1.color_ramp.elements[3].color = input_args["Color4"]
    colorramp_1.color_ramp.elements[4].position = 0.7568
    colorramp_1.color_ramp.elements[4].color = input_args["Color5"]
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Color': colorramp_1.outputs["Color"]})


@node_utils.to_nodegroup('nodegroup_noise_color', singleton=False, type='ShaderNodeTree')
def nodegroup_noise_color(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    mapping_3 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Scale', 10.0),
            ('NodeSocketColor', 'Color1', (0.7379, 0.2623, 0.0648, 1.0)),
            ('NodeSocketColor', 'Color2', (0.5029, 0.4287, 0.1079, 1.0))])
    
    noise_texture_8 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_3, 'W': U(-5, 5), 'Scale': group_input.outputs["Scale"]},
        attrs={'noise_dimensions': '4D'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_8.outputs["Fac"]})
    colorramp_9.color_ramp.elements[0].position = U(0, 0.5)
    colorramp_9.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 1.0
    colorramp_9.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_9.outputs["Color"], 'Color1': group_input.outputs["Color1"], 'Color2': group_input.outputs["Color2"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={"Color": mix_12})


def shader_stripe_fish(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_6 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    colorramp_11 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': attribute_6.outputs["Color"]})
    colorramp_11.color_ramp.elements[0].position = 0.0
    colorramp_11.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_11.color_ramp.elements[1].position = 0.2909
    colorramp_11.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    mapping_4 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_4, 'Scale': N(10, 2)})
    
    colorramp_10 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_9.outputs["Fac"]})
    colorramp_10.color_ramp.elements[0].position = 0.3773
    colorramp_10.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_10.color_ramp.elements[1].position = 1.0
    x = U(0.1, 0.9)
    colorramp_10.color_ramp.elements[1].color = (x, x, x, 1.0)
    
    mapping_2 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': mapping_2})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["Z"]},
        attrs={'operation': 'SUBTRACT'})
    
    power = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: 4.0 if U()<0.7 else 3.0},
        attrs={'operation': 'POWER'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: power, 1: U(-2, 3)},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: multiply})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': separate_xyz_1.outputs["Y"], 'Z': separate_xyz_1.outputs["Z"]})
    
    reroute = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': combine_xyz})
    
    scale = nw.new_node(Nodes.Value,
        label='scale')
    scale.outputs[0].default_value = max(N(2, 0.6), 0.8)
    
    distortion = nw.new_node(Nodes.Value,
        label='distortion')
    distortion.outputs[0].default_value = N(5, 1)
    
    detail = nw.new_node(Nodes.Value,
        label='detail')
    detail.outputs[0].default_value = 15.0
    
    detailscale = nw.new_node(Nodes.Value,
        label='detailscale')
    detailscale.outputs[0].default_value = U(0.1, 0.8)
    
    offset = nw.new_node(Nodes.Value,
        label='offset')
    offset.outputs[0].default_value = N(1.8, 0.2)
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: offset, 1: -1.0},
        attrs={'operation': 'MULTIPLY'})
    
    wave_texture_2 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': multiply_1})
    
    no_side_stripe = U() > 0.7
    side_stripe_width = U(0.02, 0.1)
    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_2.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0
    colorramp_8.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_8.color_ramp.elements[1].position = side_stripe_width
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture_1 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': offset})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_1.outputs["Color"]})
    colorramp_6.color_ramp.elements[0].position = 0.0
    colorramp_6.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_6.color_ramp.elements[1].position = side_stripe_width
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale})
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = U(0.2, 0.8)
    colorramp_5.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 0.9955
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    if U() < 0.5:
        group_1 = nw.new_node(nodegroup_noise_color().name,
            input_kwargs={"Scale": N(10, 2), "Color1":(U(), U(), U(), 1.0), "Color2": (U(), U(), U(), 1.0)})
    else:
        group_1 = nw.new_node(nodegroup_gradient_color(
                Color1=(U(0.8, 1), U(0.8, 1), U(0.8, 1), 1.0),
                Color2=(U(), U(), U(), 1.0),
                Color3=(U(), U(), U(), 1.0),
                Color4=(U(), U(), U(), 1.0),
                Color5=(U(0, 0.1), U(0, 0.1), U(0, 0.1), 1.0),).name,
            input_kwargs={
                "Value": N(0.5, 0.1),
                "Value1": N(-0.2, 0.1),
            })

    group = nw.new_node(nodegroup_gradient_color(
            Color1=(U(0.8, 1), U(0.8, 1), U(0.8, 1), 1.0),
            Color2=(U(), U(), U(), 1.0),
            Color3=(U(), U(), U(), 1.0),
            Color4=(U(), U(), U(), 1.0),
            Color5=(U(0, 0.1), U(0, 0.1), U(0, 0.1), 1.0),).name,
        input_kwargs={
            "Value": N(0.5, 0.1),
            "Value1": N(-0.2, 0.1),
        })
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_5.outputs["Color"], 'Color1': group_1, 'Color2': group})
    
    side_stripe_color = (U(), U(), U(), 1.0)
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_6.outputs["Color"], 'Color1': side_stripe_color, 'Color2': mix_8})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_8.outputs["Color"], 'Color1': side_stripe_color, 'Color2': mix_9})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_10.outputs["Color"], 'Color1': mix_10, 'Color2': (U(), U(), U(), 1.0)})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_11.outputs["Color"], 'Color1': mix_11, 'Color2': (U(0, 0.5), U(0, 0.5), U(0, 0.5), 1.0)})
    
    noise_texture_7 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 10.0})
    
    roughness = U(0, 0.5)
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_7.outputs["Fac"]})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.9955
    colorramp_14.color_ramp.elements[1].color = (roughness, roughness, roughness, 1.0)
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_7, 'Metallic': max(0, N(0.2, 0.1)), 'Roughness': colorramp_14.outputs["Color"]})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})


def apply(obj, geo_kwargs=None, shader_kwargs=None, **kwargs):
    attributes = [
        'Color variations',
        'offset2'
    ]
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
        scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)
        scales.inputs['Ynoise'].default_value = sample_range(0.1, 0.3)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: -0.5})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add, 1: normal},
        attrs={'operation': 'MULTIPLY'})
    
    value = nw.new_node(Nodes.Value)
    value.outputs[0].default_value = 0.002
    
    multiply_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply.outputs["Vector"], 1: value},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': scales.outputs["Geometry"], 'Offset': multiply_1.outputs["Vector"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': set_position, 
        'attr2': scales.outputs['attr2'],
        'attr5': scales.outputs['attr5']})

@node_utils.to_nodegroup('nodegroup_gradient_color', singleton=False, type='ShaderNodeTree')
def nodegroup_gradient_color(nw: NodeWrangler, **input_args):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5),
        #('NodeSocketColor', 'Color1', (1.0, 1.0, 1.0, 1.0)),
        #('NodeSocketColor', 'Color2', (0.5268, 0.6724, 0.5186, 1.0)),
        #('NodeSocketColor', 'Color3', (0.8055, 0.6284, 0.2728, 1.0)),
        #('NodeSocketColor', 'Color4', (0.838, 0.5269, 0.0338, 1.0)),
        #('NodeSocketColor', 'Color5', (0.0397, 0.0175, 0.0028, 1.0)),
        ('NodeSocketFloat', 'Value1', -0.2)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"], 1: group_input.outputs["Value"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: group_input.outputs["Value1"]})

    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements[0].position = 0.0945
    colorramp_1.color_ramp.elements[0].color = input_args["Color1"]
    colorramp_1.color_ramp.elements[1].position = 0.2045
    colorramp_1.color_ramp.elements[1].color = input_args["Color2"]
    colorramp_1.color_ramp.elements[2].position = 0.3159
    colorramp_1.color_ramp.elements[2].color = input_args["Color3"]
    colorramp_1.color_ramp.elements[3].position = 0.4977
    colorramp_1.color_ramp.elements[3].color = input_args["Color4"]
    colorramp_1.color_ramp.elements[4].position = 0.7568
    colorramp_1.color_ramp.elements[4].color = input_args["Color5"]
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Color': colorramp_1.outputs["Color"]})


@node_utils.to_nodegroup('nodegroup_noise_color', singleton=False, type='ShaderNodeTree')
def nodegroup_noise_color(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    mapping_3 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Scale', 10.0),
            ('NodeSocketColor', 'Color1', (0.7379, 0.2623, 0.0648, 1.0)),
            ('NodeSocketColor', 'Color2', (0.5029, 0.4287, 0.1079, 1.0))])
    
    noise_texture_8 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_3, 'W': U(-5, 5), 'Scale': group_input.outputs["Scale"]},
        attrs={'noise_dimensions': '4D'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_8.outputs["Fac"]})
    colorramp_9.color_ramp.elements[0].position = U(0, 0.5)
    colorramp_9.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 1.0
    colorramp_9.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_9.outputs["Color"], 'Color1': group_input.outputs["Color1"], 'Color2': group_input.outputs["Color2"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={"Color": mix_12})


def shader_stripe_fish(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_6 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    colorramp_11 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': attribute_6.outputs["Color"]})
    colorramp_11.color_ramp.elements[0].position = 0.0
    colorramp_11.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_11.color_ramp.elements[1].position = 0.2909
    colorramp_11.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    mapping_4 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_4, 'Scale': N(10, 2)})
    
    colorramp_10 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_9.outputs["Fac"]})
    colorramp_10.color_ramp.elements[0].position = 0.3773
    colorramp_10.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_10.color_ramp.elements[1].position = 1.0
    x = U(0.1, 0.9)
    colorramp_10.color_ramp.elements[1].color = (x, x, x, 1.0)
    
    mapping_2 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': mapping_2})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["Z"]},
        attrs={'operation': 'SUBTRACT'})
    
    power = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: 4.0 if U()<0.7 else 3.0},
        attrs={'operation': 'POWER'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: power, 1: U(-2, 3)},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: multiply})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': separate_xyz_1.outputs["Y"], 'Z': separate_xyz_1.outputs["Z"]})
    
    reroute = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': combine_xyz})
    
    scale = nw.new_node(Nodes.Value,
        label='scale')
    scale.outputs[0].default_value = max(N(2, 0.6), 0.8)
    
    distortion = nw.new_node(Nodes.Value,
        label='distortion')
    distortion.outputs[0].default_value = N(5, 1)
    
    detail = nw.new_node(Nodes.Value,
        label='detail')
    detail.outputs[0].default_value = 15.0
    
    detailscale = nw.new_node(Nodes.Value,
        label='detailscale')
    detailscale.outputs[0].default_value = U(0.1, 0.8)
    
    offset = nw.new_node(Nodes.Value,
        label='offset')
    offset.outputs[0].default_value = N(1.8, 0.2)
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: offset, 1: -1.0},
        attrs={'operation': 'MULTIPLY'})
    
    wave_texture_2 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': multiply_1})
    
    no_side_stripe = U() > 0.7
    side_stripe_width = U(0.02, 0.1)
    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_2.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0
    colorramp_8.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_8.color_ramp.elements[1].position = side_stripe_width
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture_1 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': offset})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_1.outputs["Color"]})
    colorramp_6.color_ramp.elements[0].position = 0.0
    colorramp_6.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_6.color_ramp.elements[1].position = side_stripe_width
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale})
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = U(0.2, 0.8)
    colorramp_5.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 0.9955
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    if U() < 0.5:
        group_1 = nw.new_node(nodegroup_noise_color().name,
            input_kwargs={"Scale": N(10, 2), "Color1":(U(), U(), U(), 1.0), "Color2": (U(), U(), U(), 1.0)})
    else:
        group_1 = nw.new_node(nodegroup_gradient_color(
                Color1=(U(0.8, 1), U(0.8, 1), U(0.8, 1), 1.0),
                Color2=(U(), U(), U(), 1.0),
                Color3=(U(), U(), U(), 1.0),
                Color4=(U(), U(), U(), 1.0),
                Color5=(U(0, 0.1), U(0, 0.1), U(0, 0.1), 1.0),).name,
            input_kwargs={
                "Value": N(0.5, 0.1),
                "Value1": N(-0.2, 0.1),
            })

    group = nw.new_node(nodegroup_gradient_color(
            Color1=(U(0.8, 1), U(0.8, 1), U(0.8, 1), 1.0),
            Color2=(U(), U(), U(), 1.0),
            Color3=(U(), U(), U(), 1.0),
            Color4=(U(), U(), U(), 1.0),
            Color5=(U(0, 0.1), U(0, 0.1), U(0, 0.1), 1.0),).name,
        input_kwargs={
            "Value": N(0.5, 0.1),
            "Value1": N(-0.2, 0.1),
        })
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_5.outputs["Color"], 'Color1': group_1, 'Color2': group})
    
    side_stripe_color = (U(), U(), U(), 1.0)
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_6.outputs["Color"], 'Color1': side_stripe_color, 'Color2': mix_8})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_8.outputs["Color"], 'Color1': side_stripe_color, 'Color2': mix_9})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_10.outputs["Color"], 'Color1': mix_10, 'Color2': (U(), U(), U(), 1.0)})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_11.outputs["Color"], 'Color1': mix_11, 'Color2': (U(0, 0.5), U(0, 0.5), U(0, 0.5), 1.0)})
    
    noise_texture_7 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 10.0})
    
    roughness = U(0, 0.5)
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_7.outputs["Fac"]})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.9955
    colorramp_14.color_ramp.elements[1].color = (roughness, roughness, roughness, 1.0)
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_7, 'Metallic': max(0, N(0.2, 0.1)), 'Roughness': colorramp_14.outputs["Color"]})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})


def apply(obj, geo_kwargs=None, shader_kwargs=None, **kwargs):
    attributes = [
        'Color variations',
        'offset2'
    ]
        shader = shader_fish_body_gold
    else:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
        scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)
        scales.inputs['Ynoise'].default_value = sample_range(0.1, 0.3)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: -0.5})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add, 1: normal},
        attrs={'operation': 'MULTIPLY'})
    
    value = nw.new_node(Nodes.Value)
    value.outputs[0].default_value = 0.002
    
    multiply_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply.outputs["Vector"], 1: value},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': scales.outputs["Geometry"], 'Offset': multiply_1.outputs["Vector"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': set_position, 
        'attr2': scales.outputs['attr2'],
        'attr5': scales.outputs['attr5']})

@node_utils.to_nodegroup('nodegroup_gradient_color', singleton=False, type='ShaderNodeTree')
def nodegroup_gradient_color(nw: NodeWrangler, **input_args):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5),
        #('NodeSocketColor', 'Color1', (1.0, 1.0, 1.0, 1.0)),
        #('NodeSocketColor', 'Color2', (0.5268, 0.6724, 0.5186, 1.0)),
        #('NodeSocketColor', 'Color3', (0.8055, 0.6284, 0.2728, 1.0)),
        #('NodeSocketColor', 'Color4', (0.838, 0.5269, 0.0338, 1.0)),
        #('NodeSocketColor', 'Color5', (0.0397, 0.0175, 0.0028, 1.0)),
        ('NodeSocketFloat', 'Value1', -0.2)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"], 1: group_input.outputs["Value"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: group_input.outputs["Value1"]})

    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements.new(0)
    colorramp_1.color_ramp.elements[0].position = 0.0945
    colorramp_1.color_ramp.elements[0].color = input_args["Color1"]
    colorramp_1.color_ramp.elements[1].position = 0.2045
    colorramp_1.color_ramp.elements[1].color = input_args["Color2"]
    colorramp_1.color_ramp.elements[2].position = 0.3159
    colorramp_1.color_ramp.elements[2].color = input_args["Color3"]
    colorramp_1.color_ramp.elements[3].position = 0.4977
    colorramp_1.color_ramp.elements[3].color = input_args["Color4"]
    colorramp_1.color_ramp.elements[4].position = 0.7568
    colorramp_1.color_ramp.elements[4].color = input_args["Color5"]
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Color': colorramp_1.outputs["Color"]})


@node_utils.to_nodegroup('nodegroup_noise_color', singleton=False, type='ShaderNodeTree')
def nodegroup_noise_color(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    mapping_3 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Scale', 10.0),
            ('NodeSocketColor', 'Color1', (0.7379, 0.2623, 0.0648, 1.0)),
            ('NodeSocketColor', 'Color2', (0.5029, 0.4287, 0.1079, 1.0))])
    
    noise_texture_8 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_3, 'W': U(-5, 5), 'Scale': group_input.outputs["Scale"]},
        attrs={'noise_dimensions': '4D'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_8.outputs["Fac"]})
    colorramp_9.color_ramp.elements[0].position = U(0, 0.5)
    colorramp_9.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 1.0
    colorramp_9.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_9.outputs["Color"], 'Color1': group_input.outputs["Color1"], 'Color2': group_input.outputs["Color2"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={"Color": mix_12})


def shader_stripe_fish(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_6 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    colorramp_11 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': attribute_6.outputs["Color"]})
    colorramp_11.color_ramp.elements[0].position = 0.0
    colorramp_11.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_11.color_ramp.elements[1].position = 0.2909
    colorramp_11.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    mapping_4 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_4, 'Scale': N(10, 2)})
    
    colorramp_10 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_9.outputs["Fac"]})
    colorramp_10.color_ramp.elements[0].position = 0.3773
    colorramp_10.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_10.color_ramp.elements[1].position = 1.0
    x = U(0.1, 0.9)
    colorramp_10.color_ramp.elements[1].color = (x, x, x, 1.0)
    
    mapping_2 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': mapping_2})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["Z"]},
        attrs={'operation': 'SUBTRACT'})
    
    power = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: 4.0 if U()<0.7 else 3.0},
        attrs={'operation': 'POWER'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: power, 1: U(-2, 3)},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: multiply})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': separate_xyz_1.outputs["Y"], 'Z': separate_xyz_1.outputs["Z"]})
    
    reroute = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': combine_xyz})
    
    scale = nw.new_node(Nodes.Value,
        label='scale')
    scale.outputs[0].default_value = max(N(2, 0.6), 0.8)
    
    distortion = nw.new_node(Nodes.Value,
        label='distortion')
    distortion.outputs[0].default_value = N(5, 1)
    
    detail = nw.new_node(Nodes.Value,
        label='detail')
    detail.outputs[0].default_value = 15.0
    
    detailscale = nw.new_node(Nodes.Value,
        label='detailscale')
    detailscale.outputs[0].default_value = U(0.1, 0.8)
    
    offset = nw.new_node(Nodes.Value,
        label='offset')
    offset.outputs[0].default_value = N(1.8, 0.2)
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: offset, 1: -1.0},
        attrs={'operation': 'MULTIPLY'})
    
    wave_texture_2 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': multiply_1})
    
    no_side_stripe = U() > 0.7
    side_stripe_width = U(0.02, 0.1)
    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_2.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0
    colorramp_8.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_8.color_ramp.elements[1].position = side_stripe_width
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture_1 = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale, 'Phase Offset': offset})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture_1.outputs["Color"]})
    colorramp_6.color_ramp.elements[0].position = 0.0
    colorramp_6.color_ramp.elements[0].color = (no_side_stripe, no_side_stripe, no_side_stripe, 1.0)
    colorramp_6.color_ramp.elements[1].position = side_stripe_width
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': reroute, 'Scale': scale, 'Distortion': distortion, 'Detail': detail, 'Detail Scale': detailscale})
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = U(0.2, 0.8)
    colorramp_5.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 0.9955
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    if U() < 0.5:
        group_1 = nw.new_node(nodegroup_noise_color().name,
            input_kwargs={"Scale": N(10, 2), "Color1":(U(), U(), U(), 1.0), "Color2": (U(), U(), U(), 1.0)})
    else:
        group_1 = nw.new_node(nodegroup_gradient_color(
                Color1=(U(0.8, 1), U(0.8, 1), U(0.8, 1), 1.0),
                Color2=(U(), U(), U(), 1.0),
                Color3=(U(), U(), U(), 1.0),
                Color4=(U(), U(), U(), 1.0),
                Color5=(U(0, 0.1), U(0, 0.1), U(0, 0.1), 1.0),).name,
            input_kwargs={
                "Value": N(0.5, 0.1),
                "Value1": N(-0.2, 0.1),
            })

    group = nw.new_node(nodegroup_gradient_color(
            Color1=(U(0.8, 1), U(0.8, 1), U(0.8, 1), 1.0),
            Color2=(U(), U(), U(), 1.0),
            Color3=(U(), U(), U(), 1.0),
            Color4=(U(), U(), U(), 1.0),
            Color5=(U(0, 0.1), U(0, 0.1), U(0, 0.1), 1.0),).name,
        input_kwargs={
            "Value": N(0.5, 0.1),
            "Value1": N(-0.2, 0.1),
        })
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_5.outputs["Color"], 'Color1': group_1, 'Color2': group})
    
    side_stripe_color = (U(), U(), U(), 1.0)
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_6.outputs["Color"], 'Color1': side_stripe_color, 'Color2': mix_8})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_8.outputs["Color"], 'Color1': side_stripe_color, 'Color2': mix_9})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_10.outputs["Color"], 'Color1': mix_10, 'Color2': (U(), U(), U(), 1.0)})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_11.outputs["Color"], 'Color1': mix_11, 'Color2': (U(0, 0.5), U(0, 0.5), U(0, 0.5), 1.0)})
    
    noise_texture_7 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 10.0})
    
    roughness = U(0, 0.5)
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_7.outputs["Fac"]})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.9955
    colorramp_14.color_ramp.elements[1].color = (roughness, roughness, roughness, 1.0)
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_7, 'Metallic': max(0, N(0.2, 0.1)), 'Roughness': colorramp_14.outputs["Color"]})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})


def apply(obj, geo_kwargs=None, shader_kwargs=None, **kwargs):
    attributes = [
        'Color variations',
        'offset2'
    ]
        shader = shader_fish_body_gold
    else:
    surface.add_geomod(obj, geometry_fish_body, input_kwargs=geo_kwargs, attributes=attributes)
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
inproject
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
        scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)
        scales.inputs['Ynoise'].default_value = sample_range(0.1, 0.3)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: -0.5})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add, 1: normal},
        attrs={'operation': 'MULTIPLY'})
non_informative
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
random
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
random
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
random
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
        attrs={'clamp': True}
        )

    sine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'SINE'})
    
    cosine_1 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_3}, attrs={'operation': 'COSINE'})
    
    combine_xyz_color = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': sine_1, 'Y': cosine_1, 'Z': 0.0000})

    add_6 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_color.outputs["Vector"], 1: multiply_add}, attrs={'operation': 'DOT_PRODUCT'})
    
    distance_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'DISTANCE'})
    
    add_7 = nw.new_node(Nodes.Math, input_kwargs={0: distance_1.outputs["Value"], 1: 0.0100})
    
    multiply_17 = nw.new_node(Nodes.Math, input_kwargs={0: greater_than_1, 1: add_7}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_2 = nw.new_node(Nodes.Math, input_kwargs={0: add_4, 1: less_than_1, 2: multiply_17}, attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_18 = nw.new_node(Nodes.Math, input_kwargs={0: multiply_add_2, 1: 2.0000}, attrs={'operation': 'MULTIPLY'})
    
    multiply_19 = nw.new_node(Nodes.MapRange, 
        input_kwargs={0: multiply_18, 1: 0.9156, 2: 1.0000, 3: 0.0000, 4: 0.5},
        attrs={'clamp': True}
    )

    subtract_4 = nw.new_node(Nodes.Math, input_kwargs={0: add_6, 1: multiply_19}, attrs={'operation': 'SUBTRACT'})
    
    subtract_5 = nw.new_node(Nodes.Math, input_kwargs={0: subtract_4, 1: 0.0000}, attrs={'operation': 'SUBTRACT'})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply_20 = nw.new_node(Nodes.VectorMath, input_kwargs={0: subtract_5, 1: normal}, attrs={'operation': 'MULTIPLY'})
    
    multiply_21 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply_20.outputs["Vector"], 1: group_input.outputs["Offset"]},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': group_input.outputs["Mesh"], 'Offset': multiply_21.outputs["Vector"]})
    
    capture_attribute_1 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': set_position, 1: multiply_add_1},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    capture_attribute_4 = nw.new_node(Nodes.CaptureAttribute,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 1: multiply_19},
        attrs={'data_type': 'FLOAT_VECTOR'})
    
    separate_xyz_7 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': capture_attribute_1.outputs["Attribute"]})
    
    attribute_statistic = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["X"]})
    
    subtract_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["X"], 1: attribute_statistic.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_8, 1: attribute_statistic.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    attribute_statistic_1 = nw.new_node(Nodes.AttributeStatistic,
        input_kwargs={'Geometry': capture_attribute_1.outputs["Geometry"], 2: separate_xyz_7.outputs["Y"]})
    
    subtract_9 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_7.outputs["Y"], 1: attribute_statistic_1.outputs["Min"]},
        attrs={'operation': 'SUBTRACT'})
    
    divide_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_9, 1: attribute_statistic_1.outputs["Range"]},
        attrs={'operation': 'DIVIDE'})
    
    combine_xyz_3 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': divide, 'Y': divide_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': capture_attribute_4.outputs["Geometry"], 
                'attr2': combine_xyz_3, 
                'attr5': capture_attribute_4.outputs["Attribute"]})

def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    mapping_1 = nw.new_node(Nodes.Mapping,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    noise_texture_6 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': mapping_1, 'W': 0.8, 'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)

    colorramp_15 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_15.color_ramp.elements[0].position = 0.3523
    colorramp_15.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_15.color_ramp.elements[1].position = 0.3727
    colorramp_15.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_3 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_3.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    texture_coordinate_5 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_5.outputs["Normal"]})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Z"], 1: 0.5})
    if rand:
        add.inputs[1].default_value = sample_range(0.45, 0.6)
    
    colorramp_14 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': add})
    colorramp_14.color_ramp.elements[0].position = 0.0
    colorramp_14.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_14.color_ramp.elements[1].position = 0.2341
    colorramp_14.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"]},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["X"], 1: multiply},
        attrs={'operation': 'SUBTRACT'})
    
    map_range = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': subtract, 1: -0.2})
    
    colorramp_12 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_12.color_ramp.elements[0].position = 0.0
    colorramp_12.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_12.color_ramp.elements[1].position = 0.2518
    colorramp_12.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    texture_coordinate_3 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_3.outputs["Generated"]})
    
    invert_1 = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_1.outputs["X"], 1: 0.57},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute, 1: 0.4},
        attrs={'operation': 'MULTIPLY'})
    
    map_range_1 = nw.new_node(Nodes.MapRange,
        input_kwargs={'Value': multiply_1})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: invert_1, 1: map_range_1.outputs["Result"]},
        attrs={'operation': 'SUBTRACT'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_2, 1: 0.1})
    
    colorramp_13 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': map_range.outputs["Result"]})
    colorramp_13.color_ramp.elements[0].position = 0.0
    colorramp_13.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_13.color_ramp.elements[1].position = 0.6727
    colorramp_13.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate_2 = nw.new_node(Nodes.TextureCoord)
    
    noise_texture_9 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate_2.outputs["Generated"]})
    
    mix_7 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture_9.outputs["Color"], 'Color2': texture_coordinate_2.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix_7, 'Scale': 2.5, 'Distortion': 1.3, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 0.2})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_8 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_8.color_ramp.elements[0].position = 0.0795
    colorramp_8.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_8.color_ramp.elements[1].position = 1.0
    colorramp_8.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)

    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_8.outputs["Color"], 1: -0.5})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add_2, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)

    add_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_10 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_13.outputs["Color"], 'Color2': add_3},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_9 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_10})
    colorramp_9.color_ramp.elements.new(0)
    colorramp_9.color_ramp.elements[0].position = 0.0
    colorramp_9.color_ramp.elements[0].color = (0.0179, 0.0119, 0.0, 1.0)
    colorramp_9.color_ramp.elements[1].position = 0.2318
    colorramp_9.color_ramp.elements[1].color = (0.1972, 0.1213, 0.0148, 1.0)
    colorramp_9.color_ramp.elements[2].position = 1.0
    colorramp_9.color_ramp.elements[2].color = (0.0, 0.0, 0.0, 1.0)
    if rand:
        sample_color(colorramp_9.color_ramp.elements[1].color)
        colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 3.0})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture.outputs["Fac"]})
    colorramp_3.color_ramp.elements[0].position = 0.2614
    colorramp_3.color_ramp.elements[0].color = (0.0059, 0.0028, 0.0002, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5795
    colorramp_3.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_5 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_9.outputs["Color"], 'Color2': colorramp_3.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_9 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': add_1, 'Color1': (0.021, 0.0158, 0.0026, 1.0), 'Color2': mix_5})
    
    mix_8 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_12.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_9})
    
    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_6.outputs["Fac"]})
    colorramp_4.color_ramp.elements[0].position = 0.2455
    colorramp_4.color_ramp.elements[0].color = (0.0642, 0.0339, 0.006, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.4886
    colorramp_4.color_ramp.elements[1].color = (0.1224, 0.3306, 0.261, 1.0)
    
    mix_6 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.0, 'Color1': mix_8, 'Color2': colorramp_4.outputs["Color"]},
        attrs={'blend_type': 'ADD'})
    
    mix_11 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_14.outputs["Color"], 'Color1': (0.4072, 0.4072, 0.4072, 1.0), 'Color2': mix_5})
    
    colorramp_7 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_7.color_ramp.elements[0].position = 0.0
    colorramp_7.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_7.color_ramp.elements[1].position = 0.7682
    colorramp_7.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': mix_11, 'Color2': colorramp_7.outputs["Color"]})
    
    mix_12 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4})
    if rand:
        sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)

    principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf_1})

def shader_fish_body_gold(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute.outputs["Vector"]})
    
    colorramp = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp.color_ramp.elements[0].position = 0.0
    colorramp.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp.color_ramp.elements[1].position = 0.4209
    colorramp.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    attribute_1 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'offset2'})
    
    greater_than = nw.new_node(Nodes.Math,
        input_kwargs={0: attribute_1.outputs["Vector"], 1: 0.01},
        attrs={'operation': 'GREATER_THAN'})
    
    colorramp_1 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': separate_xyz.outputs["X"]})
    colorramp_1.color_ramp.elements[0].position = 0.0
    colorramp_1.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_1.color_ramp.elements[1].position = 0.8659
    colorramp_1.color_ramp.elements[1].color = (0.0685, 0.0685, 0.0685, 1.0)
    
    texture_coordinate = nw.new_node(Nodes.TextureCoord)
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': texture_coordinate.outputs["Generated"], 'W': 1.1861},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    mix = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.9042, 'Color1': noise_texture.outputs["Color"], 'Color2': texture_coordinate.outputs["Generated"]})
    
    wave_texture = nw.new_node(Nodes.WaveTexture,
        input_kwargs={'Vector': mix, 'Scale': 1.0062, 'Distortion': 2.7139, 'Detail': 0.0, 'Detail Roughness': 0.0, 'Phase Offset': 8.0064})
    if rand:
        wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)
        wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)
        wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)

    colorramp_2 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': wave_texture.outputs["Color"]})
    colorramp_2.color_ramp.elements[0].position = 0.1254
    colorramp_2.color_ramp.elements[0].color = (0.0, 0.0, 0.0, 1.0)
    colorramp_2.color_ramp.elements[1].position = 1.0
    colorramp_2.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    if rand:
        colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: colorramp_2.outputs["Color"], 1: -0.0})
    
    divide = nw.new_node(Nodes.Math,
        input_kwargs={0: add, 1: 2.0},
        attrs={'operation': 'DIVIDE'})
    
    texture_coordinate_1 = nw.new_node(Nodes.TextureCoord)
    
    separate_xyz_1 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': texture_coordinate_1.outputs["Generated"]})
    
    invert = nw.new_node(Nodes.Invert,
        input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})
    if rand:
        invert.inputs['Fac'].default_value = sample_range(0.5, 1)
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: divide, 1: invert})
    
    mix_1 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 1.0, 'Color1': colorramp_1.outputs["Color"], 'Color2': add_1},
        attrs={'blend_type': 'MULTIPLY'})
    
    colorramp_3 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': mix_1})
    colorramp_3.color_ramp.elements.new(0)
    colorramp_3.color_ramp.elements[0].position = 0.0091
    colorramp_3.color_ramp.elements[0].color = (0.9254, 0.0164, 0.0, 1.0)
    colorramp_3.color_ramp.elements[1].position = 0.5136
    colorramp_3.color_ramp.elements[1].color = (1.0, 0.2384, 0.0027, 1.0)
    colorramp_3.color_ramp.elements[2].position = 1.0
    colorramp_3.color_ramp.elements[2].color = (1.0, 0.1073, 0.0738, 1.0)
    if rand:
        for e in colorramp_3.color_ramp.elements:
            sample_color(e.color, offset=0.05)
        colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)

    colorramp_4 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': greater_than})
    colorramp_4.color_ramp.elements[0].position = 0.0
    colorramp_4.color_ramp.elements[0].color = (1.0, 1.0, 1.0, 1.0)
    colorramp_4.color_ramp.elements[1].position = 0.7682
    colorramp_4.color_ramp.elements[1].color = (0.0228, 0.0165, 0.0, 1.0)
    
    colorramp_5 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': colorramp_4.outputs["Color"]})
    colorramp_5.color_ramp.elements[0].position = 0.0
    colorramp_5.color_ramp.elements[0].color = (1.0, 0.0817, 0.0, 1.0)
    colorramp_5.color_ramp.elements[1].position = 1.0
    colorramp_5.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_2 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': greater_than, 'Color1': colorramp_3.outputs["Color"], 'Color2': colorramp_5.outputs["Color"]})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 20.0})
    
    colorramp_6 = nw.new_node(Nodes.ColorRamp,
        input_kwargs={'Fac': noise_texture_1.outputs["Fac"]})
    colorramp_6.color_ramp.elements[0].position = 0.2614
    colorramp_6.color_ramp.elements[0].color = (1.0, 0.2402, 0.0026, 1.0)
    colorramp_6.color_ramp.elements[1].position = 0.5795
    colorramp_6.color_ramp.elements[1].color = (1.0, 1.0, 1.0, 1.0)
    
    mix_3 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': 0.75, 'Color1': mix_2, 'Color2': colorramp_6.outputs["Color"]},
        attrs={'blend_type': 'MULTIPLY'})
    
    mix_4 = nw.new_node(Nodes.MixRGB,
        input_kwargs={'Fac': colorramp.outputs["Color"], 'Color1': (1.0, 1.0, 1.0, 1.0), 'Color2': mix_3})
    
    principled_bsdf = nw.new_node(Nodes.PrincipledBSDF,
        input_kwargs={'Base Color': mix_4, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.5, 'Specular': 0.5273, 'Roughness': 0.1, 'IOR': 1.69},
        attrs={'subsurface_method': 'BURLEY'})
    
    material_output = nw.new_node(Nodes.MaterialOutput,
        input_kwargs={'Surface': principled_bsdf})

def geometry_fish_body(nw: NodeWrangler, rand=True, **input_kwargs):
    # Code generated using version 2.4.3 of the node_transpiler
    group_input = nw.new_node(Nodes.GroupInput)

    UV = nw.new_node(nodegroup_UV().name, 
        input_kwargs={'Vector': nw.expose_input('UVMap', attribute='UVMap', dtype='NodeSocketVector')})

    scales = nw.new_node(nodegroup_scales().name,
        input_kwargs={'Mesh': group_input, 'Vector': UV, 'Scale': 6, 'Xscale': 0.3, 'Yscale': 12.0, 'Offset': 0.002})
    if rand:
        scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)
        scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)
        scales.inputs['Yscale'].default_value = sample_range(8, 12)
        scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)
        scales.inputs['Ynoise'].default_value = sample_range(0.1, 0.3)

    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Scale': 50.0},
        attrs={'noise_dimensions': '4D'})
    if rand:
        noise_texture.inputs['W'].default_value = sample_range(-2, 2)

    add = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: -0.5})
    
    normal = nw.new_node(Nodes.InputNormal)
    
    multiply = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add, 1: normal},
        attrs={'operation': 'MULTIPLY'})
    
    value = nw.new_node(Nodes.Value)
    value.outputs[0].default_value = 0.002
    
    multiply_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: multiply.outputs["Vector"], 1: value},
        attrs={'operation': 'MULTIPLY'})
    
    set_position = nw.new_node(Nodes.SetPosition,
        input_kwargs={'Geometry': scales.outputs["Geometry"], 'Offset': multiply_1.outputs["Vector"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Geometry': set_position, 
        'attr2': scales.outputs['attr2'],
        'attr5': scales.outputs['attr5']})

@node_utils.to_nodegroup('nodegroup_gradient_color', singleton=False, type='ShaderNodeTree')
def nodegroup_gradient_color(nw: NodeWrangler, **input_args):
    # Code generated using version 2.4.3 of the node_transpiler

    attribute_5 = nw.new_node(Nodes.Attribute,
        attrs={'attribute_name': 'Color variations'})
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': attribute_5.outputs["Vector"]})
    
    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5),
        #('NodeSocketColor', 'Color1', (1.0, 1.0, 1.0, 1.0)),
        #('NodeSocketColor', 'Color2', (0.5268, 0.6724, 0.5186, 1.0)),
        #('NodeSocketColor', 'Color3', (0.8055, 0.6284, 0.2728, 1.0)),
        #('NodeSocketColor', 'Color4', (0.838, 0.5269, 0.0338, 1.0)),
        #('NodeSocketColor', 'Color5', (0.0397, 0.0175, 0.0028, 1.0)),
        ('NodeSocketFloat', 'Value1', -0.2)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz.outputs["Y"], 1: group_input.outputs["Value"]},
random
import numpy as np
import math as ma
from surfaces.surface_utils import clip, sample_range, sample_ratio, sample_color, geo_voronoi_noise
import bpy
import mathutils
from numpy.random import uniform as U, normal as N, randint
from nodes.node_wrangler import Nodes, NodeWrangler
from nodes import node_utils
from nodes.color import color_category
from surfaces import surface


@node_utils.to_nodegroup('nodegroup_node_grid', singleton=False, type='GeometryNodeTree')
def nodegroup_node_grid(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketFloat', 'Value', 0.5)])
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: group_input.outputs["Value"], 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    floor = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply, 1: 2.0},
        attrs={'operation': 'FLOOR'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: floor},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1})
    
    trunc = nw.new_node(Nodes.Math,
        input_kwargs={0: add},
        attrs={'operation': 'TRUNC'})
    
    trunc_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1},
        attrs={'operation': 'TRUNC'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: trunc_1})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'floor1': trunc, 'floor2': add_1})


@node_utils.to_nodegroup('nodegroup_node_group', singleton=False, type='GeometryNodeTree')
def nodegroup_UV(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0))])
    
    separate_xyz = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: 0.75, 1: separate_xyz.outputs["X"]},
        attrs={'operation': 'SUBTRACT'})
    
    absolute = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract},
        attrs={'operation': 'ABSOLUTE'})
    
    subtract_1 = nw.new_node(Nodes.Math,
        input_kwargs={1: absolute},
        attrs={'operation': 'SUBTRACT'})
    
    absolute_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract_1},
        attrs={'operation': 'ABSOLUTE'})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: absolute_1, 1: 2.0},
        attrs={'operation': 'MULTIPLY'})
    
    subtract_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: 1.0, 1: multiply},
        attrs={'operation': 'SUBTRACT', 'use_clamp': True})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': subtract_2, 'Y': separate_xyz.outputs["Y"]})
    
    group_output = nw.new_node(Nodes.GroupOutput,
        input_kwargs={'Vector': combine_xyz})

@node_utils.to_nodegroup('nodegroup_scales', singleton=False, type='GeometryNodeTree')
def nodegroup_scales(nw: NodeWrangler):
    # Code generated using version 2.4.3 of the node_transpiler

    group_input = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    #subdivide_mesh = nw.new_node(Nodes.SubdivideMesh,
    #    input_kwargs={'Mesh': group_input.outputs["Mesh"]})
    
    separate_xyz_2 = nw.new_node(Nodes.SeparateXYZ,
        input_kwargs={'Vector': group_input.outputs["Vector"]})
    
    multiply = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["X"], 1: 10.0},
        attrs={'operation': 'MULTIPLY'})
    
    reroute_2 = nw.new_node(Nodes.Reroute,
        input_kwargs={'Input': multiply})
    
    angle = nw.new_node(Nodes.Value,
        label='Angle')
    angle.outputs[0].default_value = 0.0
    
    cosine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'COSINE'})
    
    multiply_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    sine = nw.new_node(Nodes.Math,
        input_kwargs={0: angle},
        attrs={'operation': 'SINE'})
    
    multiply_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    subtract = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_1, 1: multiply_2},
        attrs={'operation': 'SUBTRACT'})
    
    group_input_2 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_3 = nw.new_node(Nodes.Math,
        input_kwargs={0: subtract, 1: group_input_2.outputs["Xscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_2 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_4 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_2.outputs["Fac"], 1: group_input_2.outputs["Xnoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_3, 1: multiply_4})
    
    multiply_5 = nw.new_node(Nodes.Math,
        input_kwargs={0: reroute_2, 1: sine},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_6 = nw.new_node(Nodes.Math,
        input_kwargs={0: separate_xyz_2.outputs["Y"], 1: cosine},
        attrs={'operation': 'MULTIPLY'})
    
    add_1 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_5, 1: multiply_6})
    
    multiply_7 = nw.new_node(Nodes.Math,
        input_kwargs={0: add_1, 1: group_input_2.outputs["Yscale"]},
        attrs={'operation': 'MULTIPLY'})
    
    noise_texture_1 = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'W': 0.8, 'Scale': 10.0},
        attrs={'noise_dimensions': '4D'})
    
    multiply_8 = nw.new_node(Nodes.Math,
        input_kwargs={0: noise_texture_1.outputs["Fac"], 1: group_input_2.outputs["Ynoise"]},
        attrs={'operation': 'MULTIPLY'})
    
    add_2 = nw.new_node(Nodes.Math,
        input_kwargs={0: multiply_7, 1: multiply_8})
    
    combine_xyz_2 = nw.new_node(Nodes.CombineXYZ,
        input_kwargs={'X': add, 'Y': add_2})
    
    group_input_1 = nw.new_node(Nodes.GroupInput,
        expose_input=[('NodeSocketGeometry', 'Mesh', None),
            ('NodeSocketVector', 'Vector', (0.0, 0.0, 0.0)),
            ('NodeSocketFloat', 'Scale', 40.0),
            ('NodeSocketFloat', 'Xscale', 1.0),
            ('NodeSocketFloat', 'Yscale', 1.0),
            ('NodeSocketFloat', 'Xnoise', 0.02),
            ('NodeSocketFloat', 'Ynoise', 0.02),
            ('NodeSocketFloat', 'Offset', 0.0002)])
    
    multiply_8 = nw.new_node(Nodes.VectorMath, input_kwargs={0: combine_xyz_2, 1: group_input_1.outputs["Scale"]}, attrs={'operation': 'MULTIPLY'})

    separate_xyz = nw.new_node(Nodes.SeparateXYZ, input_kwargs={'Vector': multiply_8})
    
    nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})
    
    greater_than = nw.new_node(Nodes.Compare,
        input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]},
        attrs={'operation': 'LESS_THAN'})

    less_than = nw.new_node(Nodes.Compare, input_kwargs={0: nodegrid.outputs["floor1"], 1: separate_xyz.outputs["Y"]})

    nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})
    
    combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor2"], 'Y': nodegrid.outputs["floor1"]})
    
    multiply_9 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    combine_xyz_1 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': nodegrid_1.outputs["floor1"], 'Y': nodegrid.outputs["floor2"]})
    
    multiply_10 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    add_3 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_9.outputs["Vector"], 1: multiply_10.outputs["Vector"]})
    
    subtract_1 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'SUBTRACT'})
    
    distance = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_3}, attrs={'operation': 'DISTANCE'})
    
    add_4 = nw.new_node(Nodes.Math, input_kwargs={0: distance.outputs["Value"], 1: 0.0100})
    
    less_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000}, attrs={'operation': 'LESS_THAN'})
    
    greater_than_1 = nw.new_node(Nodes.Compare, input_kwargs={0: add_4, 1: 0.5000})
    
    multiply_11 = nw.new_node(Nodes.VectorMath, input_kwargs={0: less_than, 1: combine_xyz_1}, attrs={'operation': 'MULTIPLY'})
    
    multiply_12 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than, 1: combine_xyz}, attrs={'operation': 'MULTIPLY'})
    
    add_5 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_11.outputs["Vector"], 1: multiply_12.outputs["Vector"]})
    
    subtract_2 = nw.new_node(Nodes.VectorMath, input_kwargs={0: multiply_8, 1: add_5}, attrs={'operation': 'SUBTRACT'})
    
    multiply_13 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: greater_than_1, 1: subtract_2.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY'})
    
    _multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: subtract_1.outputs["Vector"], 1: less_than_1, 2: multiply_13.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    multiply_add = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: _multiply_add, 1: (1, -1, 1)},
        attrs={'operation': 'MULTIPLY'})
    
    multiply_14 = nw.new_node(Nodes.VectorMath, input_kwargs={0: greater_than_1, 1: add_5}, attrs={'operation': 'MULTIPLY'})
    
    multiply_add_1 = nw.new_node(Nodes.VectorMath,
        input_kwargs={0: add_3, 1: less_than_1, 2: multiply_14.outputs["Vector"]},
        attrs={'operation': 'MULTIPLY_ADD'})
    
    noise_texture = nw.new_node(Nodes.NoiseTexture,
        input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},
        attrs={'noise_dimensions': '4D'})
    
    subtract_3 = nw.new_node(Nodes.MapRange,
        input_kwargs={0: noise_texture.outputs["Fac"], 1: 0.26, 2: 0.74, 3: -0.5, 4: 0.5},
random
    group = nw.new_node(nodegroup_gradient_color(     UV = nw.new_node(nodegroup_UV().name,      scales = nw.new_node(nodegroup_scales().name,     nodegrid = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["Y"]})         group_1 = nw.new_node(nodegroup_noise_color().name,         group_1 = nw.new_node(nodegroup_gradient_color(     nodegrid_1 = nw.new_node(nodegroup_node_grid().name, input_kwargs={'Value': separate_xyz.outputs["X"]})                 apply(obj, geo_kwargs={'rand': True}, shader_kwargs={'rand': True, 'stripefish':True})         colorramp_9.color_ramp.elements[1].position = sample_range(0.1, 0.9)         invert.inputs['Fac'].default_value = sample_range(0.5, 1)         add.inputs[1].default_value = sample_range(0.45, 0.6)         input_kwargs={'Vector': multiply_add_1, 'W': sample_range(-10, 10), 'Scale': 33.0000},             sample_color(e.color, offset=0.05)         colorramp_3.color_ramp.elements[1].position = sample_range(0.2, 0.8)         sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True)         scales.inputs['Scale'].default_value = sample_ratio(6, 2/3, 3/2)         scales.inputs['Xscale'].default_value = sample_range(0.2, 0.3)         scales.inputs['Yscale'].default_value = sample_range(8, 12)         scales.inputs['Xnoise'].default_value = sample_range(0.1, 0.3)         scales.inputs['Ynoise'].default_value = sample_range(0.1, 0.3)         wave_texture.inputs['Scale'].default_value = sample_ratio(2, 0.5, 2)         wave_texture.inputs['Phase Offset'].default_value = sample_range(0, 10)         wave_texture.inputs['Distortion'].default_value = sample_range(0, 3)         noise_texture.inputs['W'].default_value = sample_range(-2, 2)         colorramp_8.color_ramp.elements[0].position = sample_range(0, 0.2)         noise_texture_6.inputs['W'].default_value = sample_range(-2, 2)         colorramp_2.color_ramp.elements[0].position = sample_range(0, 0.2)         shader = shader_fish_body_gold     surface.add_geomod(obj, geometry_fish_body, input_kwargs=geo_kwargs, attributes=attributes)     surface.add_material(obj, shader, input_kwargs=shader_kwargs)         sample_color(colorramp_9.color_ramp.elements[1].color)     divide = nw.new_node(Nodes.Math,         input_kwargs={0: angle},         input_kwargs={'Fac': 0.5593, 'Color': separate_xyz_1.outputs["Z"]})         attrs={'operation': 'MULTIPLY'})         attrs={'clamp': True}