diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index 10bcbf6..8c0d405 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -455,6 +455,9 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug else if(string_iequals(node.name(), "noise_texture")) { snode = new NoiseTextureNode(); } + else if(string_iequals(node.name(), "gabor_texture")) { + snode = new GaborTextureNode(); + } else if(string_iequals(node.name(), "checker_texture")) { snode = new CheckerTextureNode(); } diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 6175c8e..9c52015 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -629,6 +629,12 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen get_tex_mapping(&noise->tex_mapping, b_noise_node.texture_mapping()); node = noise; } + else if (b_node.is_a(&RNA_ShaderNodeTexGabor)) { + BL::ShaderNodeTexGabor b_gabor_node(b_node); + GaborTextureNode *gabor = new GaborTextureNode(); + get_tex_mapping(&gabor->tex_mapping, b_gabor_node.texture_mapping()); + node = gabor; + } else if (b_node.is_a(&RNA_ShaderNodeTexMusgrave)) { BL::ShaderNodeTexMusgrave b_musgrave_node(b_node); MusgraveTextureNode *musgrave = new MusgraveTextureNode(); diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 96c7cef..8d80765 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -147,6 +147,7 @@ CCL_NAMESPACE_END #include "svm_blackbody.h" #include "svm_closure.h" #include "svm_noisetex.h" +#include "svm_gabortex.h" #include "svm_convert.h" #include "svm_displace.h" #include "svm_fresnel.h" @@ -256,6 +257,9 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade case NODE_TEX_NOISE: svm_node_tex_noise(kg, sd, stack, node, &offset); break; + case NODE_TEX_GABOR: + svm_node_tex_gabor(kg, sd, stack, node, &offset); + break; case NODE_TEX_VORONOI: svm_node_tex_voronoi(kg, sd, stack, node, &offset); break; diff --git a/intern/cycles/kernel/svm/svm_gabortex.h b/intern/cycles/kernel/svm/svm_gabortex.h new file mode 100644 index 0000000..8ba1d9f --- /dev/null +++ b/intern/cycles/kernel/svm/svm_gabortex.h @@ -0,0 +1,59 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +CCL_NAMESPACE_BEGIN + +/* Gabor */ + +ccl_device_inline float svm_gabor(float3 p, float scale, float seed, float impulses) +{ + float3 vec = p * scale; + + GaborParams gp; + setup_gabor_parameters(gp, impulses); + + return min(max(gabor_grid(gp, vec, seed) * 0.5f + 0.5f, 0.0f), 1.0f); +} + +ccl_device void svm_node_tex_gabor(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint co_offset, scale_offset, seed_offset, impulse_offset, fac_offset, color_offset; + + decode_node_uchar4(node.y, &co_offset, &scale_offset, &seed_offset, &impulse_offset); + + uint4 node2 = read_node(kg, offset); + + float scale = stack_load_float_default(stack, scale_offset, node2.x); + float seed = stack_load_float_default(stack, seed_offset, node2.y); + float impulses = stack_load_float_default(stack, impulse_offset, node2.z); + float3 co = stack_load_float3(stack, co_offset); + + float fac = svm_gabor(co, scale, seed, impulses); + + float3 color = make_float3(fac, + svm_gabor(make_float3(co.y, co.x, co.z), scale, seed, impulses), + svm_gabor(make_float3(co.y, co.z, co.x), scale, seed, impulses)); + + decode_node_uchar4(node.z, &color_offset, &fac_offset, NULL, NULL); + + if(stack_valid(fac_offset)) + stack_store_float(stack, fac_offset, fac); + if(stack_valid(color_offset)) + stack_store_float3(stack, color_offset, color); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h index 282ad19..b0552de 100644 --- a/intern/cycles/kernel/svm/svm_noise.h +++ b/intern/cycles/kernel/svm/svm_noise.h @@ -5,7 +5,7 @@ * All Rights Reserved. * * Modifications Copyright 2011, Blender Foundation. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: @@ -32,12 +32,13 @@ CCL_NAMESPACE_BEGIN -#ifndef __KERNEL_SSE2__ +/* Used by Perlin and Gabor */ ccl_device int quick_floor(float x) { return float_to_int(x) - ((x < 0) ? 1 : 0); } -#else + +#ifdef __KERNEL_SSE2__ ccl_device_inline __m128i quick_floor_sse(const __m128& x) { __m128i b = _mm_cvttps_epi32(x); @@ -384,5 +385,175 @@ ccl_device float psnoise(float3 p, float3 pperiod) } #endif +/* GABOR NOISE +* +* For further details of Gabor Noise Method please see +* http://www.gabornoise.com/ +* +*/ + +ccl_device uint cellhash(int cell[3], int seed) +{ + // define macros +#define rot(x,k) (((x)<<(k) | ((x)>>(32-(k))))) +#define final(a,b,c) +#define mix(a,b,c) \ + { \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + + // hash data + int a, b, c; + a = b = c = 3735928588; + + // Put a,b,c in to cell array + a += cell[0]; + b += cell[1]; + c += cell[2]; + mix(a,b,c); + a+=seed; + final(a,b,c); + + return c; + +#undef rot +#undef mix +#undef final +} + +ccl_device void rng_seed(int &rng, int cell[3], int seed) +{ + int chash = cellhash(cell, seed); + if(chash == 0) + chash = 1; + rng = chash * 3039177861; +} + +ccl_device void rng_next(int &rng) +{ + rng *= 3039177861; +} + +ccl_device float rng_uniform(int &rng) +{ + static const float int_max_inv = 1.0f / (float)(0x7FFFFFFF); + float res = (float)rng * int_max_inv * 0.5f + 0.5f; + rng_next(rng); + return res; +} + +ccl_device int rng_poisson(int &rng, float mean) +{ + float g = exp(-mean); + int em = 0; + float t = rng_uniform(rng); + while (t > g) + { + ++em; + t *=rng_uniform(rng); + } + return em; +} + +struct GaborParams { + float weight; + float impulses; + float radius, radius2, radius3, radius_inv; + float a; + float bandwidth; + float lambda, sqrt_lambda_inv; +}; + + +ccl_device void setup_gabor_parameters(GaborParams &gp, float impulses) +{ + /* Only Impulses is user controllable, we might expose more later */ + float sqrt_pi_over_ln2 = sqrtf(M_PI_F / M_LN2); + float frequency = 2.0; + float truncate = 0.02f; + float bandwidth_pow = 2.0f; /* powf(2.0f, gp.bandwidth) */ + + gp.impulses = impulses; + gp.weight = 1.0f; + gp.bandwidth = 1.0; + gp.a = frequency * ((bandwidth_pow - 1.0f) / (bandwidth_pow + 1.0f)) * sqrt_pi_over_ln2; + + gp.radius = sqrtf(-log(truncate) / M_PI_F) / gp.a; + gp.radius_inv = 1.0f / gp.radius; + gp.radius2 = gp.radius * gp.radius; + gp.radius3 = gp.radius2 * gp.radius; + + gp.lambda = impulses / ((1.33333f * M_PI_F) * gp.radius3); + gp.sqrt_lambda_inv = 1.0f / sqrtf(gp.lambda); +} + +ccl_device float gabor_kernel(float weight, float3 omega, float phi, float bandwidth, float3 vector) +{ + float g = exp(-M_PI_F * (bandwidth * bandwidth) * dot(vector, vector)); + float h = cos(M_2PI_F * dot(omega, vector) + phi); + return weight * g * h; +} + + +ccl_device void gabor_sample(GaborParams &gp, int &rng, float3 &omega, float &phi) +{ + float cos_omega_p = rng_uniform(rng) * 2.0f - 1.0f; + float sin_omega_p = sqrtf(1.0f - cos_omega_p*cos_omega_p); + float omega_t = M_2PI_F * rng_uniform(rng); + float sin_omega_t = sin(omega_t); + float cos_omega_t = cos(omega_t); + omega = normalize(make_float3(cos_omega_t*sin_omega_p, sin_omega_t*sin_omega_p, cos_omega_p)); + phi = M_2PI_F * rng_uniform(rng); +} + + +ccl_device float gabor_cell(GaborParams gp, int c_i[3], float3 x_c_i, int seed) +{ + int rng; + rng_seed(rng, c_i, seed); + int num_impulses = rng_poisson(rng, gp.impulses); + float sum = 0.0f; + for (int i = 0; i < num_impulses; ++i) { + float xrand = rng_uniform(rng); + float yrand = rng_uniform(rng); + float zrand = rng_uniform(rng); + float3 x_k_i = (x_c_i - make_float3(xrand, yrand, zrand)) * gp.radius; + float3 omega; + float phi; + gabor_sample(gp, rng, omega, phi); + + if(dot(x_k_i, x_k_i) < gp.radius2) { + sum += gabor_kernel(gp.weight, omega, phi, gp.a, x_k_i); + } + } + return sum; +} + + +ccl_device float gabor_grid(GaborParams gp, float3 x_g, int seed) +{ + float x_g_0 = x_g.x - floorf(x_g.x); + float x_g_1 = x_g.y - floorf(x_g.y); + float x_g_2 = x_g.z - floorf(x_g.z); + float3 x_c = make_float3(x_g_0, x_g_1, x_g_2); + int cell[3] = { quick_floor(x_g.x), quick_floor(x_g.y), quick_floor(x_g.z) }; + float sum = 0.0f; + for (int k = -1; k <= 1; k++) { + for (int j = -1; j <= 1; j++) { + for (int i = -1; i <= 1; i++) { + int c_i[3] = { cell[0] + i, cell[1] + j, cell[2] + k }; + float3 x_c_i = x_c - make_float3(i, j, k); + sum += gabor_cell(gp, c_i, x_c_i, seed); + } + } + } + return sum * gp.sqrt_lambda_inv; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index ad5e1ea..5b0ed9f 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -59,6 +59,7 @@ typedef enum NodeType { NODE_TEX_WAVE, NODE_TEX_MAGIC, NODE_TEX_NOISE, + NODE_TEX_GABOR, NODE_SHADER_JUMP, NODE_SET_DISPLACEMENT, NODE_GEOMETRY_BUMP_DX, diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index af6fca2..bb86ff6 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -783,6 +783,66 @@ void NoiseTextureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_noise_texture"); } +/* Gabor Texture */ + +GaborTextureNode::GaborTextureNode() +: TextureNode("gabor_texture") +{ + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); + add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Seed", SHADER_SOCKET_FLOAT, 2.0f); + add_input("Impulses", SHADER_SOCKET_FLOAT, 0.0f); + + add_output("Color", SHADER_SOCKET_COLOR); + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void GaborTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *impulses_in = input("Impulses"); + ShaderInput *seed_in = input("Seed"); + ShaderInput *scale_in = input("Scale"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *fac_out = output("Fac"); + + if(vector_in->link) compiler.stack_assign(vector_in); + if(scale_in->link) compiler.stack_assign(scale_in); + if(seed_in->link) compiler.stack_assign(seed_in); + if(impulses_in->link) compiler.stack_assign(impulses_in); + + int vector_offset = vector_in->stack_offset; + + if(!tex_mapping.skip()) { + vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR); + tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset); + } + + if(!fac_out->links.empty()) + compiler.stack_assign(fac_out); + if(!color_out->links.empty()) + compiler.stack_assign(color_out); + + compiler.add_node(NODE_TEX_GABOR, + compiler.encode_uchar4(vector_offset, scale_in->stack_offset, seed_in->stack_offset, impulses_in->stack_offset), + compiler.encode_uchar4(color_out->stack_offset, fac_out->stack_offset)); + compiler.add_node( + __float_as_int(scale_in->value.x), + __float_as_int(seed_in->value.x), + __float_as_int(impulses_in->value.x)); + + if(vector_offset != vector_in->stack_offset) + compiler.stack_clear_offset(vector_in->type, vector_offset); +} + +void GaborTextureNode::compile(OSLCompiler& compiler) +{ + tex_mapping.compile(compiler); + + compiler.add(this, "node_gabor_texture"); +} + + /* Voronoi Texture */ static ShaderEnum voronoi_coloring_init() diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 86c4f49..9cdeea6 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -134,6 +134,11 @@ public: SHADER_NODE_CLASS(NoiseTextureNode) }; +class GaborTextureNode : public TextureNode { +public: + SHADER_NODE_CLASS(GaborTextureNode) +}; + class VoronoiTextureNode : public TextureNode { public: SHADER_NODE_CLASS(VoronoiTextureNode) diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 6ade491..5ce8bea 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -201,6 +201,7 @@ shader_node_categories = [ NodeItem("ShaderNodeTexEnvironment"), NodeItem("ShaderNodeTexSky"), NodeItem("ShaderNodeTexNoise"), + NodeItem("ShaderNodeTexGabor"), NodeItem("ShaderNodeTexWave"), NodeItem("ShaderNodeTexVoronoi"), NodeItem("ShaderNodeTexMusgrave"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 59ea921..b026b0e 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -744,6 +744,7 @@ struct ShadeResult; #define SH_NODE_COMBHSV 184 #define SH_NODE_BSDF_HAIR 185 #define SH_NODE_LAMP 186 +#define SH_NODE_TEX_GABOR 187 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index d622556..e1934aa 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3542,6 +3542,7 @@ static void registerShaderNodes(void) register_node_type_sh_tex_magic(); register_node_type_sh_tex_checker(); register_node_type_sh_tex_brick(); + register_node_type_sh_tex_gabor(); } static void registerTextureNodes(void) diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 19ef6d0..fadb94f 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -2334,6 +2334,12 @@ void node_tex_noise(vec3 co, float scale, float detail, float distortion, out ve fac = 1.0; } +void node_tex_gabor(vec3 co, float scale, float seed, float impulses, out vec4 color, out float fac) +{ + color = vec4(1.0); + fac = 1.0; +} + void node_tex_sky(vec3 co, out vec4 color) { color = vec4(1.0); diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index cd9595d..647eecf 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -754,6 +754,10 @@ typedef struct NodeTexNoise { NodeTexBase base; } NodeTexNoise; +typedef struct NodeTexGabor { + NodeTexBase base; +} NodeTexGabor; + typedef struct NodeTexVoronoi { NodeTexBase base; int coloring; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index d893a8c..4f47f44 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3494,6 +3494,12 @@ static void def_sh_tex_noise(StructRNA *srna) def_sh_tex(srna); } +static void def_sh_tex_gabor(StructRNA *srna) +{ + RNA_def_struct_sdna_from(srna, "NodeTexGabor", "storage"); + def_sh_tex(srna); +} + static void def_sh_tex_checker(StructRNA *srna) { RNA_def_struct_sdna_from(srna, "NodeTexChecker", "storage"); diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 16671e8..9c04d7e 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -189,6 +189,7 @@ set(SRC shader/nodes/node_shader_tex_checker.c shader/nodes/node_shader_tex_coord.c shader/nodes/node_shader_tex_environment.c + shader/nodes/node_shader_tex_gabor.c shader/nodes/node_shader_tex_gradient.c shader/nodes/node_shader_tex_image.c shader/nodes/node_shader_tex_magic.c diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 0f388a8..55ef0d2 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -127,6 +127,7 @@ void register_node_type_sh_tex_musgrave(void); void register_node_type_sh_tex_noise(void); void register_node_type_sh_tex_checker(void); void register_node_type_sh_bump(void); +void register_node_type_sh_tex_gabor(void); #endif diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index f7f7118..33f0c56 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -107,6 +107,7 @@ DefNode( ShaderNode, SH_NODE_SCRIPT, def_sh_script, "SC DefNode( ShaderNode, SH_NODE_TEX_IMAGE, def_sh_tex_image, "TEX_IMAGE", TexImage, "Image Texture", "" ) DefNode( ShaderNode, SH_NODE_TEX_ENVIRONMENT, def_sh_tex_environment, "TEX_ENVIRONMENT", TexEnvironment, "Environment Texture","" ) DefNode( ShaderNode, SH_NODE_TEX_SKY, def_sh_tex_sky, "TEX_SKY", TexSky, "Sky Texture", "" ) +DefNode( ShaderNode, SH_NODE_TEX_GABOR, def_sh_tex_gabor, "TEX_GABOR", TexGabor, "Gabor Texture", "" ) DefNode( ShaderNode, SH_NODE_TEX_GRADIENT, def_sh_tex_gradient, "TEX_GRADIENT", TexGradient, "Gradient Texture", "" ) DefNode( ShaderNode, SH_NODE_TEX_NOISE, def_sh_tex_noise, "TEX_NOISE", TexNoise, "Noise Texture", "" ) DefNode( ShaderNode, SH_NODE_TEX_MAGIC, def_sh_tex_magic, "TEX_MAGIC", TexMagic, "Magic Texture", "" ) diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gabor.c b/source/blender/nodes/shader/nodes/node_shader_tex_gabor.c new file mode 100644 index 0000000..5d59c23 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_tex_gabor.c @@ -0,0 +1,79 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../node_shader_util.h" + +/* **************** Gabor ******************** */ + +static bNodeSocketTemplate sh_node_tex_gabor_in[] = { + { SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f}, + { SOCK_FLOAT, 1, N_("Seed"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 16.0f}, + { SOCK_FLOAT, 1, N_("Impulses"), 1.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f}, + { -1, 0, "" } +}; + +static bNodeSocketTemplate sh_node_tex_gabor_out[] = { + { SOCK_RGBA, 0, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 0, N_("Fac"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static void node_shader_init_tex_gabor(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeTexGabor *tex = MEM_callocN(sizeof(NodeTexGabor), "NodeTexGabor"); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); + default_color_mapping(&tex->base.color_mapping); + + node->storage = tex; +} + +static int node_shader_gpu_tex_gabor(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, + GPUNodeStack *out) +{ + if (!in[0].link) + in[0].link = GPU_attribute(CD_ORCO, ""); + + node_shader_gpu_tex_mapping(mat, node, in, out); + + return GPU_stack_link(mat, "node_tex_gabor", in, out); +} + +/* node type definition */ +void register_node_type_sh_tex_gabor(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_TEX_GABOR, "Gabor Texture", NODE_CLASS_TEXTURE, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, sh_node_tex_gabor_in, sh_node_tex_gabor_out); + node_type_init(&ntype, node_shader_init_tex_gabor); + node_type_storage(&ntype, "NodeTexGabor", node_free_standard_storage, node_copy_standard_storage); + node_type_gpu(&ntype, node_shader_gpu_tex_gabor); + + nodeRegisterType(&ntype); +}