Cleanup: typo in last commit
[blender.git] / source / blender / collada / Materials.cpp
index d6ed0e2859af2282ed474827506d9626d2d9d06b..3b2c68ef95e48f8d68f372c5f4c5eafca3418c39 100644 (file)
 
 #include "Materials.h"
 
-MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map) :
-       mContext(C),
-       material(ma),
-       effect(nullptr),
-       key_image_map(&key_image_map)
+MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map)
+    : mContext(C), material(ma), effect(nullptr), key_image_map(&key_image_map)
 {
-       ntree = prepare_material_nodetree();
-       setShaderType();
+  bNodeTree *new_ntree = prepare_material_nodetree();
+  setShaderType();
+  if (new_ntree) {
+    shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
+    output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
+    add_link(shader_node, 0, output_node, 0);
+  }
 }
 
-MaterialNode::MaterialNode(bContext *C, COLLADAFW::EffectCommon *ef, Material *ma, UidImageMap &uid_image_map) :
-       mContext(C),
-       material(ma),
-       effect(ef),
-       uid_image_map(&uid_image_map)
+MaterialNode::MaterialNode(bContext *C,
+                           COLLADAFW::EffectCommon *ef,
+                           Material *ma,
+                           UidImageMap &uid_image_map)
+    : mContext(C), material(ma), effect(ef), uid_image_map(&uid_image_map)
 {
-       ntree = prepare_material_nodetree();
-       setShaderType();
+  prepare_material_nodetree();
+  setShaderType();
 
-       std::map<std::string, bNode *> nmap;
+  std::map<std::string, bNode *> nmap;
 #if 0
-       nmap["main"] = add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300);
-       nmap["emission"] = add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission");
-       nmap["add"] = add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400);
-       nmap["transparent"] = add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200);
-       nmap["mix"] = add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency");
-       nmap["out"] = add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300);
-       nmap["out"]->flag &= ~NODE_SELECT;
-
-       add_link(ntree, nmap["emission"], 0, nmap["add"], 0);
-       add_link(ntree, nmap["main"], 0, nmap["add"], 1);
-       add_link(ntree, nmap["add"], 0, nmap["mix"], 1);
-       add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2);
-
-       add_link(ntree, nmap["mix"], 0, nmap["out"], 0);
-       // experimental, probably not used.
-       make_group(C, ntree, nmap);
+  nmap["main"] = add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300);
+  nmap["emission"] = add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission");
+  nmap["add"] = add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400);
+  nmap["transparent"] = add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200);
+  nmap["mix"] = add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency");
+  nmap["out"] = add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300);
+  nmap["out"]->flag &= ~NODE_SELECT;
+
+  add_link(ntree, nmap["emission"], 0, nmap["add"], 0);
+  add_link(ntree, nmap["main"], 0, nmap["add"], 1);
+  add_link(ntree, nmap["add"], 0, nmap["mix"], 1);
+  add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2);
+
+  add_link(ntree, nmap["mix"], 0, nmap["out"], 0);
+  // experimental, probably not used.
+  make_group(C, ntree, nmap);
 #else
-       shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
-       output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
-       add_link(shader_node, 0, output_node, 0);
+  shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
+  output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
+  add_link(shader_node, 0, output_node, 0);
 #endif
 }
 
 void MaterialNode::setShaderType()
 {
 #if 0
-       COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
-       // Currently we only support PBR based shaders
-       // TODO: simulate the effects with PBR
-
-       // blinn
-       if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
-               ma->spec_shader = MA_SPEC_BLINN;
-               ma->spec = ef->getShininess().getFloatValue();
-       }
-       // phong
-       else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
-               ma->spec_shader = MA_SPEC_PHONG;
-               ma->har = ef->getShininess().getFloatValue();
-       }
-       // lambert
-       else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
-               ma->diff_shader = MA_DIFF_LAMBERT;
-       }
-       // default - lambert
-       else {
-               ma->diff_shader = MA_DIFF_LAMBERT;
-               fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
-       }
+  COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
+  // Currently we only support PBR based shaders
+  // TODO: simulate the effects with PBR
+
+  // blinn
+  if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
+    ma->spec_shader = MA_SPEC_BLINN;
+    ma->spec = ef->getShininess().getFloatValue();
+  }
+  // phong
+  else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
+    ma->spec_shader = MA_SPEC_PHONG;
+    ma->har = ef->getShininess().getFloatValue();
+  }
+  // lambert
+  else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
+    ma->diff_shader = MA_DIFF_LAMBERT;
+  }
+  // default - lambert
+  else {
+    ma->diff_shader = MA_DIFF_LAMBERT;
+    fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
+  }
 #endif
 }
 
+// returns null if material already has a node tree
 bNodeTree *MaterialNode::prepare_material_nodetree()
 {
-       if (material->nodetree == NULL) {
-               material->nodetree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree");
-               material->use_nodes = true;
-       }
-       return material->nodetree;
+  if (material->nodetree) {
+    ntree = material->nodetree;
+    return NULL;
+  }
+
+  material->nodetree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree");
+  material->use_nodes = true;
+  ntree = material->nodetree;
+  return ntree;
 }
 
 bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label)
 {
-       bNode *node = nodeAddStaticNode(mContext, ntree, node_type);
-       if (node) {
-               if (label.length() > 0) {
-                       strcpy(node->label, label.c_str());
-               }
-               node->locx = locx;
-               node->locy = locy;
-               node->flag |= NODE_SELECT;
-       }
-       node_map[label] = node;
-       return node;
+  bNode *node = nodeAddStaticNode(mContext, ntree, node_type);
+  if (node) {
+    if (label.length() > 0) {
+      strcpy(node->label, label.c_str());
+    }
+    node->locx = locx;
+    node->locy = locy;
+    node->flag |= NODE_SELECT;
+  }
+  node_map[label] = node;
+  return node;
 }
 
 void MaterialNode::add_link(bNode *from_node, int from_index, bNode *to_node, int to_index)
 {
-       bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
-       bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
+  bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
+  bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
 
-       nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
+  nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
 }
 
-void MaterialNode::set_reflectivity(float val)
+void MaterialNode::set_reflectivity(COLLADAFW::FloatOrParam &val)
 {
-       material->metallic = val;
-       bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_METALLIC);
-       *(float *)socket->default_value = val;
+  float reflectivity = val.getFloatValue();
+  if (reflectivity >= 0) {
+    bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Metallic");
+    ((bNodeSocketValueFloat *)socket->default_value)->value = reflectivity;
+    material->metallic = reflectivity;
+  }
 }
 
-void MaterialNode::set_ior(float val)
+#if 0
+// needs rework to be done for 2.81
+void MaterialNode::set_shininess(COLLADAFW::FloatOrParam &val)
 {
-       bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_IOR);
-       *(float *)socket->default_value = val;
+  float roughness = val.getFloatValue();
+  if (roughness >= 0) {
+    bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Roughness");
+    ((bNodeSocketValueFloat *)socket->default_value)->value = roughness;
+  }
 }
+#endif
 
-void MaterialNode::set_diffuse(COLLADAFW::ColorOrTexture &cot, std::string label)
+void MaterialNode::set_ior(COLLADAFW::FloatOrParam &val)
 {
-       int locy = -300 * (node_map.size()-2);
-       if (cot.isColor()) {
-               COLLADAFW::Color col = cot.getColor();
-               bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_DIFFUSE);
-               float *fcol = (float *)socket->default_value;
-
-               fcol[0] = material->r = col.getRed();
-               fcol[1] = material->g = col.getGreen();
-               fcol[2] = material->b = col.getBlue();
-               fcol[3] = material->a = col.getAlpha();
-       }
-       else if (cot.isTexture()) {
-               bNode *texture_node = add_texture_node(cot, -300, locy, label);
-               if (texture_node != NULL) {
-                       add_link(texture_node, 0, shader_node, 0);
-               }
-       }
+  float ior = val.getFloatValue();
+  if (ior < 0) {
+    fprintf(stderr,
+            "IOR of negative value is not allowed for materials (using Blender default value "
+            "instead)");
+    return;
+  }
+
+  bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "IOR");
+  ((bNodeSocketValueFloat *)socket->default_value)->value = ior;
 }
 
-Image *MaterialNode::get_diffuse_image()
+void MaterialNode::set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode,
+                             COLLADAFW::ColorOrTexture &cot,
+                             COLLADAFW::FloatOrParam &val)
 {
-       bNode *shader = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
-       if (shader == nullptr) {
-               return nullptr;
-       }
-
-       bNodeSocket *in_socket = (bNodeSocket *)BLI_findlink(&shader->inputs, BC_PBR_DIFFUSE);
-       if (in_socket == nullptr) {
-               return nullptr;
-       }
-
-       bNodeLink *link = in_socket->link;
-       if (link == nullptr) {
-               return nullptr;
-       }
-
-       bNode *texture = link->fromnode;
-       if (texture == nullptr) {
-               return nullptr;
-       }
-
-       if (texture->type != SH_NODE_TEX_IMAGE) {
-               return nullptr;
-       }
+  /*  Handling the alpha value according to the Collada 1.4 reference guide
+   *  see page 7-5 Determining Transparency (Opacity)
+   */
+
+  if (effect == nullptr) {
+    return;
+  }
+
+  if (cot.isColor() || !cot.isValid()) {
+    // transparent_cot is either a color or not defined
+
+    float transparent_alpha;
+    if (cot.isValid()) {
+      COLLADAFW::Color col = cot.getColor();
+      transparent_alpha = col.getAlpha();
+    }
+    else {
+      // no transparent color defined
+      transparent_alpha = 1;
+    }
+
+    float transparency_alpha = val.getFloatValue();
+    if (transparency_alpha < 0) {
+      // transparency is not defined
+      transparency_alpha = 1;  // set to opaque
+    }
+
+    float alpha = transparent_alpha * transparency_alpha;
+    if (mode == COLLADAFW::EffectCommon::RGB_ZERO) {
+      alpha = 1 - alpha;
+    }
+
+    bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Alpha");
+    ((bNodeSocketValueFloat *)socket->default_value)->value = alpha;
+  }
+  else if (cot.isTexture()) {
+    int locy = -300 * (node_map.size() - 2);
+    add_texture_node(cot, -300, locy, "Alpha");
+  }
+}
 
-       Image *image = (Image *)texture->id;
-       return image;
+void MaterialNode::set_diffuse(COLLADAFW::ColorOrTexture &cot)
+{
+  int locy = -300 * (node_map.size() - 2);
+  if (cot.isColor()) {
+    COLLADAFW::Color col = cot.getColor();
+    bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Base Color");
+    float *fcol = (float *)socket->default_value;
+
+    fcol[0] = material->r = col.getRed();
+    fcol[1] = material->g = col.getGreen();
+    fcol[2] = material->b = col.getBlue();
+    fcol[3] = material->a = col.getAlpha();
+  }
+  else if (cot.isTexture()) {
+    bNode *texture_node = add_texture_node(cot, -300, locy, "Base Color");
+    if (texture_node != NULL) {
+      add_link(texture_node, 0, shader_node, 0);
+    }
+  }
+}
 
+Image *MaterialNode::get_diffuse_image()
+{
+  bNode *shader = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
+  if (shader == nullptr) {
+    return nullptr;
+  }
+
+  bNodeSocket *in_socket = nodeFindSocket(shader, SOCK_IN, "Base Color");
+  if (in_socket == nullptr) {
+    return nullptr;
+  }
+
+  bNodeLink *link = in_socket->link;
+  if (link == nullptr) {
+    return nullptr;
+  }
+
+  bNode *texture = link->fromnode;
+  if (texture == nullptr) {
+    return nullptr;
+  }
+
+  if (texture->type != SH_NODE_TEX_IMAGE) {
+    return nullptr;
+  }
+
+  Image *image = (Image *)texture->id;
+  return image;
 }
 
 static bNodeSocket *set_color(bNode *node, COLLADAFW::Color col)
 {
-               bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->outputs, 0);
-               float *fcol = (float *)socket->default_value;
-               fcol[0] = col.getRed();
-               fcol[1] = col.getGreen();
-               fcol[2] = col.getBlue();
+  bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->outputs, 0);
+  float *fcol = (float *)socket->default_value;
+  fcol[0] = col.getRed();
+  fcol[1] = col.getGreen();
+  fcol[2] = col.getBlue();
 
-               return socket;
+  return socket;
 }
 
-void MaterialNode::set_ambient(COLLADAFW::ColorOrTexture &cot, std::string label)
+void MaterialNode::set_ambient(COLLADAFW::ColorOrTexture &cot)
 {
-       int locy = -300 * (node_map.size() - 2);
-       if (cot.isColor()) {
-               COLLADAFW::Color col = cot.getColor();
-               bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
-               set_color(node, col);
-               // TODO: Connect node
-       }
-       // texture
-       else if (cot.isTexture()) {
-               add_texture_node(cot, -300, locy, label);
-               // TODO: Connect node
-       }
+  int locy = -300 * (node_map.size() - 2);
+  if (cot.isColor()) {
+    COLLADAFW::Color col = cot.getColor();
+    bNode *node = add_node(SH_NODE_RGB, -300, locy, "Ambient");
+    set_color(node, col);
+    // TODO: Connect node
+  }
+  // texture
+  else if (cot.isTexture()) {
+    add_texture_node(cot, -300, locy, "Ambient");
+    // TODO: Connect node
+  }
 }
-void MaterialNode::set_reflective(COLLADAFW::ColorOrTexture &cot, std::string label)
+
+void MaterialNode::set_reflective(COLLADAFW::ColorOrTexture &cot)
 {
-       int locy = -300 * (node_map.size() - 2);
-       if (cot.isColor()) {
-               COLLADAFW::Color col = cot.getColor();
-               bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
-               set_color(node, col);
-               // TODO: Connect node
-       }
-       // texture
-       else if (cot.isTexture()) {
-               add_texture_node(cot, -300, locy, label);
-               // TODO: Connect node
-       }
+  int locy = -300 * (node_map.size() - 2);
+  if (cot.isColor()) {
+    COLLADAFW::Color col = cot.getColor();
+    bNode *node = add_node(SH_NODE_RGB, -300, locy, "Reflective");
+    set_color(node, col);
+    // TODO: Connect node
+  }
+  // texture
+  else if (cot.isTexture()) {
+    add_texture_node(cot, -300, locy, "Reflective");
+    // TODO: Connect node
+  }
 }
 
-void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot, std::string label)
+void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot)
 {
-       int locy = -300 * (node_map.size() - 2);
-       if (cot.isColor()) {
-               COLLADAFW::Color col = cot.getColor();
-               bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
-               set_color(node, col);
-               // TODO: Connect node
-       }
-       // texture
-       else if (cot.isTexture()) {
-               add_texture_node(cot, -300, locy, label);
-               // TODO: Connect node
-       }
+  int locy = -300 * (node_map.size() - 2);
+  if (cot.isColor()) {
+    COLLADAFW::Color col = cot.getColor();
+    bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Emission");
+    float *fcol = (float *)socket->default_value;
+
+    fcol[0] = col.getRed();
+    fcol[1] = col.getGreen();
+    fcol[2] = col.getBlue();
+    fcol[3] = col.getAlpha();
+  }
+  else if (cot.isTexture()) {
+    bNode *texture_node = add_texture_node(cot, -300, locy, "Emission");
+    if (texture_node != NULL) {
+      add_link(texture_node, 0, shader_node, 0);
+    }
+  }
 }
 
-void MaterialNode::set_opacity(COLLADAFW::ColorOrTexture &cot, std::string label)
+void MaterialNode::set_opacity(COLLADAFW::ColorOrTexture &cot)
 {
-       if (effect == nullptr) {
-               return;
-       }
-
-       int locy = -300 * (node_map.size() - 2);
-       if (cot.isColor()) {
-               COLLADAFW::Color col = effect->getTransparent().getColor();
-               float alpha = effect->getTransparency().getFloatValue();
-
-               if (col.isValid()) {
-                       alpha *= col.getAlpha(); // Assuming A_ONE opaque mode
-               }
-               if (col.isValid() || alpha < 1.0) {
-                       // not sure what to do here
-               }
-
-               bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
-               set_color(node, col);
-               // TODO: Connect node
-       }
-       // texture
-       else if (cot.isTexture()) {
-               add_texture_node(cot, -300, locy, label);
-               // TODO: Connect node
-       }
+  if (effect == nullptr) {
+    return;
+  }
+
+  int locy = -300 * (node_map.size() - 2);
+  if (cot.isColor()) {
+    COLLADAFW::Color col = effect->getTransparent().getColor();
+    float alpha = effect->getTransparency().getFloatValue();
+
+    if (col.isValid()) {
+      alpha *= col.getAlpha();  // Assuming A_ONE opaque mode
+    }
+
+    bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Alpha");
+    ((bNodeSocketValueFloat *)socket->default_value)->value = alpha;
+  }
+  // texture
+  else if (cot.isTexture()) {
+    add_texture_node(cot, -300, locy, "Alpha");
+    // TODO: Connect node
+  }
 }
 
-void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot, std::string label)
+void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot)
 {
-       int locy = -300 * (node_map.size() - 2);
-       if (cot.isColor()) {
-               COLLADAFW::Color col = cot.getColor();
-               material->specr = col.getRed();
-               material->specg = col.getGreen();
-               material->specb = col.getBlue();
-
-               bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
-               set_color(node, col);
-               // TODO: Connect node
-       }
-       // texture
-       else if (cot.isTexture()) {
-               add_texture_node(cot, -300, locy, label);
-               // TODO: Connect node
-       }
+  int locy = -300 * (node_map.size() - 2);
+  if (cot.isColor()) {
+    COLLADAFW::Color col = cot.getColor();
+    bNode *node = add_node(SH_NODE_RGB, -300, locy, "Specular");
+    set_color(node, col);
+    // TODO: Connect node
+  }
+  // texture
+  else if (cot.isTexture()) {
+    add_texture_node(cot, -300, locy, "Specular");
+    // TODO: Connect node
+  }
 }
 
-bNode *MaterialNode::add_texture_node(COLLADAFW::ColorOrTexture &cot, int locx, int locy, std::string label)
+bNode *MaterialNode::add_texture_node(COLLADAFW::ColorOrTexture &cot,
+                                      int locx,
+                                      int locy,
+                                      std::string label)
 {
-       if (effect == nullptr) {
-               return nullptr;
-       }
-
-       UidImageMap &image_map = *uid_image_map;
+  if (effect == nullptr) {
+    return nullptr;
+  }
 
-       COLLADAFW::Texture ctex = cot.getTexture();
+  UidImageMap &image_map = *uid_image_map;
 
-       COLLADAFW::SamplerPointerArray& samp_array = effect->getSamplerPointerArray();
-       COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()];
+  COLLADAFW::Texture ctex = cot.getTexture();
 
-       const COLLADAFW::UniqueId& ima_uid = sampler->getSourceImage();
+  COLLADAFW::SamplerPointerArray &samp_array = effect->getSamplerPointerArray();
+  COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()];
 
-       if (image_map.find(ima_uid) == image_map.end()) {
-               fprintf(stderr, "Couldn't find an image by UID.\n");
-               return NULL;
-       }
+  const COLLADAFW::UniqueId &ima_uid = sampler->getSourceImage();
 
-       Image *ima = image_map[ima_uid];
-       bNode *texture_node = add_node(SH_NODE_TEX_IMAGE, locx, locy, label);
-       texture_node->id = &ima->id;
-       return texture_node;
+  if (image_map.find(ima_uid) == image_map.end()) {
+    fprintf(stderr, "Couldn't find an image by UID.\n");
+    return NULL;
+  }
 
+  Image *ima = image_map[ima_uid];
+  bNode *texture_node = add_node(SH_NODE_TEX_IMAGE, locx, locy, label);
+  texture_node->id = &ima->id;
+  return texture_node;
 }