// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.

#ifndef toolx_sg_text_freetype_marker
#define toolx_sg_text_freetype_marker

#include "text_freetype"

namespace toolx {
namespace sg {

class text_freetype_marker : public text_freetype {
  TOOLS_NODE(text_freetype_marker,toolx::sg::text_freetype_marker,text_freetype)
public:
  virtual bool draw_in_frame_buffer() const {return true;}

  virtual void render(tools::sg::render_action& a_action) {
   {bool _color_touched = color_touched(a_action.state());
    bool _char_height_touched = char_height_touched(a_action.state());
    if(touched()||_color_touched||_char_height_touched) {
      update_sg(a_action.out(),font.touched(),a_action.state());
      reset_touched();
    }}

    const tools::sg::state& state = a_action.state();

    a_action.set_lighting(false); //Same logic as Inventor SoLightModel.model = BASE_COLOR.
    a_action.set_depth_test(false);

         if(m_wndg==wndg_ccw) a_action.set_winding(tools::sg::winding_ccw);
    else if(m_wndg==wndg_cw) a_action.set_winding(tools::sg::winding_cw);

    float x,y,z;
    a_action.projected_origin(x,y,z);
    float zz = 0;

    a_action.load_matrices_to_identity();
    
   {tools::mat4f _mtx;
    _mtx.set_translate(x,y,zz);
    if(!m_bitmaps.size()) {
      if(state.m_ww) _mtx.mul_scale(float(state.m_wh)/float(state.m_ww),1,1);
    }
    a_action.load_model_matrix(_mtx);}
    
    ///////////////////////////////////////////////////////////
    /// lines /////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
   {tools_vforcit(line_t,m_lines,it) {
      const line_t& item = *it;
      size_t pos = item.first;
      size_t num = item.second;
      if(!num) continue;
      const float* data = tools::vec_data<float>(m_xys)+pos;
      a_action.draw_vertex_array_xy(tools::gl::line_strip(),num*2,data);
    }}

    ///////////////////////////////////////////////////////////
    /// triangles /////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
   {tools_vforcit(gl_triangle_t,m_triangles,it) {
      const std::pair<GLUenum,triangle_t>& item = *it;
      size_t pos = item.second.first;
      size_t num = item.second.second;
      if(!num) continue;
      //a_out << "toolx::sg::text_freetype_marker::render :"
      //      << " num points " << num
      //      << std::endl;

      const float* data = tools::vec_data<float>(m_xys)+pos;
      a_action.draw_vertex_array_xy((*it).first,num*2,data);
    }}

    ///////////////////////////////////////////////////////////
    /// bitmap ////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    if(m_bitmaps.size()) {
#if defined(ANDROID) /*|| TARGET_OS_IPHONE*/
      // we do not have transparent texture here (see also gl/tex_img() that does img/4-bytes => img/3-bytes) :
     {tools::sg::state& _state = a_action.state();
      tools::colorf old_color = _state.m_color;
      _state.m_color = tools::colorf_white();
      a_action.color4f(_state.m_color);
      m_bitmaps.render(a_action);
      _state.m_color = old_color;
      a_action.color4f(_state.m_color);}
#else
      m_bitmaps.render(a_action);
#endif
    }

    ///////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    a_action.load_matrices_from_state();

    a_action.set_depth_test(state.m_GL_DEPTH_TEST);
    a_action.set_lighting(state.m_GL_LIGHTING);
    a_action.set_winding(state.m_winding);

  }

  virtual void pick(tools::sg::pick_action& a_action) {
    const tools::sg::state& state = a_action.state();
    
   {bool _char_height_touched = char_height_touched(a_action.state());
    if(touched()||_char_height_touched) {
      update_sg(a_action.out(),font.touched(),a_action.state());
      reset_touched();
    }}

    float x,y,z;
    a_action.projected_origin(x,y,z);
    float zz = 0;

    a_action.set_matrices_to_identity();

    a_action.model_matrix().set_translate(x,y,zz);
    if(!m_bitmaps.size()) {
      if(state.m_ww) a_action.model_matrix().mul_scale(float(state.m_wh)/float(state.m_ww),1,1);
    }  
    
    ///////////////////////////////////////////////////////////
    /// lines /////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
   {tools_vforcit(line_t,m_lines,it) {
      const line_t& item = *it;
      size_t pos = item.first;
      size_t num = item.second;
      if(!num) continue;

      const float* data = tools::vec_data<float>(m_xys)+pos;
      float* vp = _trans2(num,data,x,y);
      if(!vp) continue;

      if(a_action.add__line_strip_xy(*this,2*num,vp,true)) {
        delete [] vp;
        a_action.set_matrices_from_state();
        return;
      }

      delete [] vp;
    }}


    ///////////////////////////////////////////////////////////
    /// triangles /////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
   {tools_vforcit(gl_triangle_t,m_triangles,it) {
      const std::pair<GLUenum,triangle_t>& item = *it;
      size_t pos = item.second.first;
      size_t num = item.second.second;
      if(!num) continue;

      const float* data = tools::vec_data<float>(m_xys)+pos;
      float* vp = _trans2(num,data,x,y);
      if(!vp) continue;
      if(a_action.add__primitive_xy(*this,item.first,2*num,vp,true)){
        delete [] vp;
        a_action.set_matrices_from_state();
        return;
      }
      delete [] vp;
    }}

    ///////////////////////////////////////////////////////////
    /// bitmap ////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    if(m_bitmaps.size()) {
      m_bitmaps.pick(a_action);
    }

    ///////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    a_action.set_matrices_from_state();
  }

  virtual void bbox(tools::sg::bbox_action& a_action) {
   {bool _char_height_touched = char_height_touched(a_action.state());
    if(touched()||_char_height_touched) {
      update_sg(a_action.out(),font.touched(),a_action.state());
      reset_touched();
    }}
    a_action.add_one_point(0,0,0);
/*
   {tools_vforcit(line_t,m_lines,it) {
      const line_t& item = *it;
      size_t num = item.second;
      const float* data = tools::vec_data<float>(m_xys)+item.first;

      float px,py,pz;
      float* pos = (float*)data;
      for(size_t index=0;index<num;index++) {
        px = *pos;pos++;
        py = *pos;pos++;
        pz = 0;
        a_action.add_one_point(px,py,pz);
      }

    }}

    ///////////////////////////////////////////////////////////
    /// triangles /////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
   {tools_vforcit(gl_triangle_t,m_triangles,it) {
      const std::pair<GLUenum,triangle_t>& item = *it;
      size_t num = item.second.second;
      const float* data = tools::vec_data<float>(m_xys)+item.second.first;

      float px,py,pz;
      float* pos = (float*)data;
      for(size_t index=0;index<num;index++) {
        px = *pos;pos++;
        py = *pos;pos++;
        pz = 0;
        a_action.add_one_point(px,py,pz);
      }
    }}
    
    ///////////////////////////////////////////////////////////
    /// bitmap ////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    m_bitmaps.bbox(a_action);
*/
  }

public:
  text_freetype_marker():parent(){
    height = 10; //pixels
  }
  virtual ~text_freetype_marker(){}
public:
  text_freetype_marker(const text_freetype_marker& a_from):parent(a_from) {}
  text_freetype_marker& operator=(const text_freetype_marker& a_from){parent::operator=(a_from);return *this;}
protected:
  void update_sg(std::ostream& a_out,bool a_load_font,const tools::sg::state& a_state) {
    if(!a_state.m_wh) {parent::update_sg(a_out,a_load_font);return;}
    float sy = 2.0f*float(height.value())/float(a_state.m_wh); //in [-1,1]
    float old_height = height.value();
    height.value_no_cmp(sy);
    //update_what what = lines;
    //if(modeling==tools::sg::font_filled) what = faces_and_lines;
    parent::update_sg(a_out,a_load_font);
    height.value_no_cmp(old_height);
  }

  float* _trans2(size_t a_num,const float* a_data,float a_x,float a_y) {
    float* vp = new float[a_num*2];
    if(!vp) return 0;
    float* pos = vp;
    float* pda = (float*)a_data;
    for(size_t index=0;index<a_num;index++){
      *pos = *pda + a_x;pos++;pda++;
      *pos = *pda + a_y;pos++;pda++;
    }
    return vp;
  }
};

}}

#endif

