source code

class QuadElem : public SingleForwardBoxableFaceCollection

{

public:

  QuadElem(Point p1, Point p2, Point p3, Point p4) : p1(p1), p2(p2), p3(p3), p4(p4) { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 1; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const

  {

    if (point==0) return p1;

    if (point==1) return p2;

    if (point==2) return p3;

    return p4;

  }

  virtual Vector PointNormal(int face, int point) const

  {

    Vector u_x = p2-p1;

    Vector u_y = p3-p1;

    return Vector::CrossProduct(u_x, u_y);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    if (point==0) {

      p.x = 0;

      p.y = 0;

    }

    if (point==1) {

      p.x = 1;

      p.y = 0;

    }

    if (point==2) {

      p.x = 1;

      p.y = 1;

    }

    if (point==3) {

      p.x = 0;

      p.y = 1;

    }



    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p1,p2,p3,p4;

};

EXPORT GameApi::P GameApi::PolygonApi::quad_z(float x1, float x2,

{

  Point pp1 = Point(x1,y1,z);

  Point pp2 = Point(x2,y1,z);

  Point pp3 = Point(x2,y2,z);

  Point pp4 = Point(x1,y2,z);

  FaceCollection *coll = new QuadElem(pp1,pp2,pp3,pp4);

  return add_polygon(e,coll,1);

}

class QuadElem : public SingleForwardBoxableFaceCollection

{

public:

  QuadElem(Point p1, Point p2, Point p3, Point p4) : p1(p1), p2(p2), p3(p3), p4(p4) { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 1; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const

  {

    if (point==0) return p1;

    if (point==1) return p2;

    if (point==2) return p3;

    return p4;

  }

  virtual Vector PointNormal(int face, int point) const

  {

    Vector u_x = p2-p1;

    Vector u_y = p3-p1;

    return Vector::CrossProduct(u_x, u_y);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    if (point==0) {

      p.x = 0;

      p.y = 0;

    }

    if (point==1) {

      p.x = 1;

      p.y = 0;

    }

    if (point==2) {

      p.x = 1;

      p.y = 1;

    }

    if (point==3) {

      p.x = 0;

      p.y = 1;

    }



    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p1,p2,p3,p4;

};

EXPORT GameApi::P GameApi::PolygonApi::quad_z(float x1, float x2,

{

  Point pp1 = Point(x1,y1,z);

  Point pp2 = Point(x2,y1,z);

  Point pp3 = Point(x2,y2,z);

  Point pp4 = Point(x1,y2,z);

  FaceCollection *coll = new QuadElem(pp1,pp2,pp3,pp4);

  return add_polygon(e,coll,1);

}

template<class C>

class ConstantBitmap : public Bitmap<C>

{

public:

  ConstantBitmap(C c, int x, int y) : c(c), x(x), y(y) { }

  void Prepare() { }



  int SizeX() const { return x; }

  int SizeY() const { return y; }

  C Map(int , int ) const

  {

    return c;

  }

private:

  C c;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::newbitmap(int sx, int sy, unsigned int color)

{

  ::Bitmap<Color> *b = new ConstantBitmap<Color>(Color(color), sx,sy);

  BitmapColorHandle *handle = new BitmapColorHandle;

  handle->bm = b;

  BM bm = add_bitmap(e, handle);

  return bm;

  

}

class ConstantBitmap_Color : public Bitmap<Color>

{

public:

  ConstantBitmap_Color(Color c, int x, int y) : c(c), x(x), y(y) { }

  void Prepare() { }



  int SizeX() const { return x; }

  int SizeY() const { return y; }

  Color Map(int , int ) const

  {

    return c;

  }

private:

  Color c;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::newbitmap(int sx, int sy, unsigned int color)

{

  ::Bitmap<Color> *b = new ConstantBitmap_Color(Color(color), sx,sy);

  BitmapColorHandle *handle = new BitmapColorHandle;

  handle->bm = b;

  BM bm = add_bitmap(e, handle);

  return bm;

  

}

class FontInterfaceImpl : public FontInterface

{

public:

  FontInterfaceImpl(GameApi::Env &e, void *priv_, std::string ttf_filename, std::string homepage, int sx, int sy);

  virtual int Top(long idx) const;

  virtual int SizeX(long idx) const;

  virtual int SizeY(long idx) const;

  virtual int Map(long idx, int x, int y) const;



  void gen_glyph_data(long idx);

private:

  GameApi::Env &e;

  std::string ttf_filename;

  std::string homepage;

  int sx,sy;

  mutable std::map<long, GlyphData*> glyph_data;

  void *priv_;

  void *priv;

  int state;

  long old_idx;

  mutable pthread_mutex_t mutex;

  std::string key;

};

GameApi::FI GameApi::FontApi::load_font(std::string ttf_filename, int sx, int sy)

{

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  void *priv_ = (void*)&env->lib;

  return add_font_interface(e, new FontInterfaceImpl(e, priv_, ttf_filename, gameapi_homepageurl, sx,sy));

}

class FontInterfaceImpl : public FontInterface

{

public:

  FontInterfaceImpl(GameApi::Env &e, void *priv_, std::string ttf_filename, std::string homepage, int sx, int sy);

  virtual int Top(long idx) const;

  virtual int SizeX(long idx) const;

  virtual int SizeY(long idx) const;

  virtual int Map(long idx, int x, int y) const;



  void gen_glyph_data(long idx);

private:

  GameApi::Env &e;

  std::string ttf_filename;

  std::string homepage;

  int sx,sy;

  mutable std::map<long, GlyphData*> glyph_data;

  void *priv_;

  void *priv;

  int state;

  long old_idx;

  mutable pthread_mutex_t mutex;

  std::string key;

};

GameApi::FI GameApi::FontApi::load_font(std::string ttf_filename, int sx, int sy)

{

#ifdef HAS_FREETYPE

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  void *priv_ = (void*)&env->lib;

  return add_font_interface(e, new FontInterfaceImpl(e, priv_, ttf_filename, gameapi_homepageurl, sx,sy));

#else

  std::cout << "WARNING: FREETYPE LIBRARY MISSING!" << std::endl;

  GameApi::FI fi;

  fi.id = 0;

  return fi;

#endif

}

class BitmapPrepareCache2 : public Bitmap<Color>

{

public:

  BitmapPrepareCache2(GameApi::Env &e, std::string id, Bitmap<Color> *bm) : e(e), id(id), bm(bm) { }

  void Prepare()

  {

    if (bitmap_find_data(id)!=-1) {

      return;

    }

    bm->Prepare();

    GameApi::BM num = add_color_bitmap2(e, bm);

    bitmap_prepare_cache_data.push_back(std::make_pair(id,num.id));

  }

  Bitmap<Color> *get_bm() const

  {

    int num = bitmap_find_data(id);

    if (num==-1) { const_cast<BitmapPrepareCache2*>(this)->Prepare(); num=bitmap_find_data(id); }

    GameApi::BM bm2;

    bm2.id = num;

    BitmapHandle *handle = find_bitmap(e, bm2);

    Bitmap<Color> *bbm = find_color_bitmap(handle);

    return bbm;

  }

  virtual int SizeX() const { return get_bm()->SizeX(); }

  virtual int SizeY() const { return get_bm()->SizeY(); }

  virtual Color Map(int x, int y) const

  {

    return get_bm()->Map(x,y);

  }

private:

  GameApi::Env &e;

  std::string id;

  Bitmap<Color> *bm;

};

GameApi::BM GameApi::FontApi::draw_text_string(FI font, std::string str, int x_gap, int empty_line_height)

{

  std::cout << "draw_text_string: " << str << std::endl;

  int s = str.size();

  std::vector<GI> glyphs;

  for(int i=0;i<s;i++)

    {

      GI glyph = choose_glyph_from_font(font, (long)(str[i]));

      glyphs.push_back(glyph);

    }

  SD sd = draw_text_string_sd(glyphs, str, x_gap, empty_line_height);

  BM bm = string_display_to_bitmap(sd,0);

  //BitmapHandle *bbm = find_bitmap(e, bm);

  //Bitmap<Color> *bbm1 = find_color_bitmap(bbm);

  //Bitmap<Color> *bbm2 = new BitmapPrepareCache2(e, str, bbm1);

  //BitmapColorHandle *handle = new BitmapColorHandle;

  //handle->bm = bbm2;

  //BM bm2 = add_bitmap(e,handle);



  return bm;

}

class BitmapPrepareCache2 : public Bitmap<Color>

{

public:

  BitmapPrepareCache2(GameApi::Env &e, std::string id, Bitmap<Color> *bm) : e(e), id(id), bm(bm) { }

  void Prepare()

  {

    if (bitmap_find_data(id)!=-1) {

      return;

    }

    bm->Prepare();

    GameApi::BM num = add_color_bitmap2(e, bm);

    bitmap_prepare_cache_data.push_back(std::make_pair(id,num.id));

  }

  Bitmap<Color> *get_bm() const

  {

    int num = bitmap_find_data(id);

    if (num==-1) { const_cast<BitmapPrepareCache2*>(this)->Prepare(); num=bitmap_find_data(id); }

    GameApi::BM bm2;

    bm2.id = num;

    BitmapHandle *handle = find_bitmap(e, bm2);

    Bitmap<Color> *bbm = find_color_bitmap(handle);

    return bbm;

  }

  virtual int SizeX() const { return get_bm()->SizeX(); }

  virtual int SizeY() const { return get_bm()->SizeY(); }

  virtual Color Map(int x, int y) const

  {

    return get_bm()->Map(x,y);

  }

private:

  GameApi::Env &e;

  std::string id;

  Bitmap<Color> *bm;

};

GameApi::BM GameApi::FontApi::draw_text_string(FI font, std::string str, int x_gap, int empty_line_height)

{

  std::cout << "draw_text_string: " << str << std::endl;

  int s = str.size();

  std::vector<GI> glyphs;

  for(int i=0;i<s;i++)

    {

      GI glyph = choose_glyph_from_font(font, (long)(str[i]));

      glyphs.push_back(glyph);

    }

  SD sd = draw_text_string_sd(glyphs, str, x_gap, empty_line_height);

  BM bm = string_display_to_bitmap(sd,0);

  //BitmapHandle *bbm = find_bitmap(e, bm);

  //Bitmap<Color> *bbm1 = find_color_bitmap(bbm);

  //Bitmap<Color> *bbm2 = new BitmapPrepareCache2(e, str, bbm1);

  //BitmapColorHandle *handle = new BitmapColorHandle;

  //handle->bm = bbm2;

  //BM bm2 = add_bitmap(e,handle);



  return bm;

}

class BorderBitmap : public Bitmap<Color>

{

public:

  BorderBitmap(Bitmap<Color> &next, 

	       Color left, Color right, Color top, Color bottom,

	       int left_border, int right_border, int top_border, int bottom_border) : next(next), left(left), right(right), top(top), bottom(bottom),

										       left_border(left_border), right_border(right_border),

										       top_border(top_border), bottom_border(bottom_border) { }

  void Prepare() { next.Prepare(); }



  virtual int SizeX() const { return left_border + next.SizeX() + right_border; }

  virtual int SizeY() const { return top_border + next.SizeY() + bottom_border; }

  virtual Color Map(int x, int y) const

  {

    if (x < left_border) return left;

    if (y < top_border) return top;

    if (x > SizeX()-right_border) return right;

    if (y > SizeY()-bottom_border) return bottom;

    return next.Map(x-left_border, y-top_border);

  }



private:

  Bitmap<Color> &next;

  Color left, right, top, bottom;

  int left_border, right_border, top_border, bottom_border;

};

GameApi::BM GameApi::BitmapApi::border(BM bm, int left, int right, int top, int bottom)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  ::Bitmap<Color> *b2 = find_color_bitmap(handle);

  ::Bitmap<Color> *b3 = new BorderBitmap(*b2, Color::Transparent(),Color::Transparent(),Color::Transparent(),Color::Transparent(),

					 left, right, top, bottom);

  BitmapColorHandle *handle2 = new BitmapColorHandle;

  handle2->bm = b3;

  BM bm2 = add_bitmap(e, handle2);

  return bm2;

}

class BorderBitmap : public Bitmap<Color>

{

public:

  BorderBitmap(Bitmap<Color> &next, 

	       Color left, Color right, Color top, Color bottom,

	       int left_border, int right_border, int top_border, int bottom_border) : next(next), left(left), right(right), top(top), bottom(bottom),

										       left_border(left_border), right_border(right_border),

										       top_border(top_border), bottom_border(bottom_border) { }

  void Prepare() { next.Prepare(); }



  virtual int SizeX() const { return left_border + next.SizeX() + right_border; }

  virtual int SizeY() const { return top_border + next.SizeY() + bottom_border; }

  virtual Color Map(int x, int y) const

  {

    if (x < left_border) return left;

    if (y < top_border) return top;

    if (x > SizeX()-right_border) return right;

    if (y > SizeY()-bottom_border) return bottom;

    return next.Map(x-left_border, y-top_border);

  }



private:

  Bitmap<Color> &next;

  Color left, right, top, bottom;

  int left_border, right_border, top_border, bottom_border;

};

GameApi::BM GameApi::BitmapApi::border(BM bm, int left, int right, int top, int bottom)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  ::Bitmap<Color> *b2 = find_color_bitmap(handle);

  ::Bitmap<Color> *b3 = new BorderBitmap(*b2, Color::Transparent(),Color::Transparent(),Color::Transparent(),Color::Transparent(),

					 left, right, top, bottom);

  BitmapColorHandle *handle2 = new BitmapColorHandle;

  handle2->bm = b3;

  BM bm2 = add_bitmap(e, handle2);

  return bm2;

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_y(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, false, true);



  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_y(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, false, true);



  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class TextureMaterial : public MaterialForward

{

public:

  TextureMaterial(GameApi::EveryApi &ev, GameApi::BM bm, float mix) : ev(ev), bm(bm), mix(mix) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::ML I17=ev.polygon_api.render_vertex_array_ml(ev,I16);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17, mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml_fade(ev,I16,pta, flip, start_time, end_time);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }



private:

  GameApi::EveryApi &ev;

  GameApi::BM bm;

  float mix;

};

EXPORT GameApi::MT GameApi::MaterialsApi::texture(EveryApi &ev, BM bm, float mix)

{

  return add_material(e, new TextureMaterial(ev, bm,mix));

}

class TextureMaterial : public MaterialForward

{

public:

  TextureMaterial(GameApi::EveryApi &ev, GameApi::BM bm, float mix) : ev(ev), bm(bm), mix(mix) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::ML I17=ev.polygon_api.render_vertex_array_ml(ev,I16);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17, mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml_fade(ev,I16,pta, flip, start_time, end_time);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }



private:

  GameApi::EveryApi &ev;

  GameApi::BM bm;

  float mix;

};

EXPORT GameApi::MT GameApi::MaterialsApi::texture(EveryApi &ev, BM bm, float mix)

{

  return add_material(e, new TextureMaterial(ev, bm,mix));

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind(P p, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = mat2->mat(p.id);

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind(P p, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = 0;

  if (mat2) {

    val = mat2->mat(p.id);

  }

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class SphereElem : public SingleForwardBoxableFaceCollection

{

public:

  SphereElem(int numfaces, int numfaces2) :  numfaces(numfaces), numfaces2(numfaces2), center(Point(0.0,0.0,0.0)), radius(1.0) { }

  SphereElem(Point center, float radius, int numfaces1, int numfaces2);

  virtual void SetBox(Matrix b) { /*box = b; inverted=false; */}

  void Prepare() {}

  virtual int NumFaces() const;

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    p-=center;

    Vector v = p;

    //if (!inverted) { boxinv=Matrix::Inverse(box); inverted=true; }

    Point pp = v;

    

    return pp.x*pp.x+pp.y*pp.y+pp.z*pp.z<radius*radius; 

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    Point p = v;

    p-=center;

    Vector vv = p;

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    return -vv; /*-center*/;

  }

private:

  //Matrix box;

  //mutable Matrix boxinv;

  int numfaces;

  int numfaces2;

  Point center;

  float radius;

  //mutable bool inverted;

};

EXPORT GameApi::P GameApi::PolygonApi::sphere(PT center, float radius, int numfaces1, int numfaces2)

{

    Point *p = find_point(e,center);

    FaceCollection *coll = new SphereElem(*p, radius, numfaces1, numfaces2);

    return add_polygon(e, coll,1);

}

class SphereElem : public SingleForwardBoxableFaceCollection

{

public:

  SphereElem(int numfaces, int numfaces2) :  numfaces(numfaces), numfaces2(numfaces2), center(Point(0.0,0.0,0.0)), radius(1.0) { }

  SphereElem(Point center, float radius, int numfaces1, int numfaces2);

  virtual void SetBox(Matrix b) { /*box = b; inverted=false; */}

  void Prepare() {}

  virtual int NumFaces() const;

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    p-=center;

    Vector v = p;

    //if (!inverted) { boxinv=Matrix::Inverse(box); inverted=true; }

    Point pp = v;

    

    return pp.x*pp.x+pp.y*pp.y+pp.z*pp.z<radius*radius; 

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    Point p = v;

    p-=center;

    Vector vv = p;

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    return -vv; /*-center*/;

  }

private:

  //Matrix box;

  //mutable Matrix boxinv;

  int numfaces;

  int numfaces2;

  Point center;

  float radius;

  //mutable bool inverted;

};

EXPORT GameApi::P GameApi::PolygonApi::sphere(PT center, float radius, int numfaces1, int numfaces2)

{

    Point *p = find_point(e,center);

    FaceCollection *coll = new SphereElem(*p, radius, numfaces1, numfaces2);

    return add_polygon(e, coll,1);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

class OrElem2 : public FaceCollection

{

public:

  OrElem2(FaceCollection *coll1, FaceCollection *coll2) : coll1(coll1), coll2(coll2),s(0),s2(0) { }

  void Prepare() {

    coll1->Prepare();

    coll2->Prepare();

    s = coll1->NumFaces();

    s2 = coll1->NumTextures();

  }

  int get_index(int face) const

  {

    if (face<s) { return face; }

    return face-s;

  }

  FaceCollection *get_elem(int face) const {

    if (face<s) return coll1;

    return coll2;

  }

  int get_index2(int face) const

  {

    if (face<s2) { return face; }

    return face-s2;

  }

  FaceCollection *get_elem2(int face) const {

    if (face<s2) return coll1;

    return coll2;

  }

  virtual int NumFaces() const { return coll1->NumFaces()+coll2->NumFaces(); }

  virtual int NumPoints(int face) const

  {

    return get_elem(face)->NumPoints(get_index(face));

  }

  virtual Point FacePoint(int face, int point) const

  {

    return get_elem(face)->FacePoint(get_index(face), point);

  }

  virtual Vector PointNormal(int face, int point) const

  {

    return get_elem(face)->PointNormal(get_index(face), point);

  }

  virtual float Attrib(int face, int point, int id) const

  {

    return get_elem(face)->Attrib(get_index(face), point,id);

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return get_elem(face)->AttribI(get_index(face), point,id);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return get_elem(face)->Color(get_index(face), point);

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    return get_elem(face)->TexCoord(get_index(face), point);

  }

  virtual float TexCoord3(int face, int point) const {

    return get_elem(face)->TexCoord3(get_index(face), point);



  }

  virtual Point EndFacePoint(int face, int point) const {

    return get_elem(face)->EndFacePoint(get_index(face), point);

  }

  virtual Vector EndPointNormal(int face, int point) const {

    return get_elem(face)->EndPointNormal(get_index(face), point);

  }

  virtual float EndAttrib(int face, int point, int id) const {

    return get_elem(face)->EndAttrib(get_index(face), point,id);

  }

  virtual int EndAttribI(int face, int point, int id) const {

    return get_elem(face)->EndAttribI(get_index(face), point,id);

  }

  virtual unsigned int EndColor(int face, int point) const {

    return get_elem(face)->EndColor(get_index(face), point);

  }

  virtual Point2d EndTexCoord(int face, int point) const {

    return get_elem(face)->EndTexCoord(get_index(face), point);

  }

  virtual float EndTexCoord3(int face, int point) const {

    return get_elem(face)->EndTexCoord3(get_index(face), point);

  }



  virtual float Duration() const { return 1.0; }



  virtual int NumTextures() const { return coll1->NumTextures() + coll2->NumTextures(); }

  virtual void GenTexture(int num) {

    get_elem2(num)->GenTexture(get_index2(num));

  }

  virtual BufferRef TextureBuf(int num) const {

    return get_elem2(num)->TextureBuf(get_index2(num));

  }

  virtual int FaceTexture(int face) const {

    return get_elem(face)->FaceTexture(get_index(face));



  }



private:

  FaceCollection *coll1;

  FaceCollection *coll2;

  int s;

  int s2;

};

EXPORT GameApi::P GameApi::PolygonApi::or_elem(P p1, P p2)

{

  FaceCollection *pp1 = find_facecoll(e, p1);

  FaceCollection *pp2 = find_facecoll(e, p2);

  //OrElem<FaceCollection> *coll = new OrElem<FaceCollection>;

  //coll->push_back(pp1);

  //coll->push_back(pp2);

  //coll->update_faces_cache();

  FaceCollection *coll = new OrElem2(pp1,pp2);

  return add_polygon2(e, coll,1);

}

class OrElem2 : public FaceCollection

{

public:

  OrElem2(FaceCollection *coll1, FaceCollection *coll2) : coll1(coll1), coll2(coll2),s(0),s2(0) { }

  void Prepare() {

    coll1->Prepare();

    coll2->Prepare();

    s = coll1->NumFaces();

    s2 = coll1->NumTextures();

  }

  int get_index(int face) const

  {

    if (face<s) { return face; }

    return face-s;

  }

  FaceCollection *get_elem(int face) const {

    if (face<s) return coll1;

    return coll2;

  }

  int get_index2(int face) const

  {

    if (face<s2) { return face; }

    return face-s2;

  }

  FaceCollection *get_elem2(int face) const {

    if (face<s2) return coll1;

    return coll2;

  }

  virtual int NumFaces() const { return coll1->NumFaces()+coll2->NumFaces(); }

  virtual int NumPoints(int face) const

  {

    return get_elem(face)->NumPoints(get_index(face));

  }

  virtual Point FacePoint(int face, int point) const

  {

    return get_elem(face)->FacePoint(get_index(face), point);

  }

  virtual Vector PointNormal(int face, int point) const

  {

    return get_elem(face)->PointNormal(get_index(face), point);

  }

  virtual float Attrib(int face, int point, int id) const

  {

    return get_elem(face)->Attrib(get_index(face), point,id);

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return get_elem(face)->AttribI(get_index(face), point,id);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return get_elem(face)->Color(get_index(face), point);

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    return get_elem(face)->TexCoord(get_index(face), point);

  }

  virtual float TexCoord3(int face, int point) const {

    return get_elem(face)->TexCoord3(get_index(face), point);



  }

  virtual Point EndFacePoint(int face, int point) const {

    return get_elem(face)->EndFacePoint(get_index(face), point);

  }

  virtual Vector EndPointNormal(int face, int point) const {

    return get_elem(face)->EndPointNormal(get_index(face), point);

  }

  virtual float EndAttrib(int face, int point, int id) const {

    return get_elem(face)->EndAttrib(get_index(face), point,id);

  }

  virtual int EndAttribI(int face, int point, int id) const {

    return get_elem(face)->EndAttribI(get_index(face), point,id);

  }

  virtual unsigned int EndColor(int face, int point) const {

    return get_elem(face)->EndColor(get_index(face), point);

  }

  virtual Point2d EndTexCoord(int face, int point) const {

    return get_elem(face)->EndTexCoord(get_index(face), point);

  }

  virtual float EndTexCoord3(int face, int point) const {

    return get_elem(face)->EndTexCoord3(get_index(face), point);

  }



  virtual float Duration() const { return 1.0; }



  virtual int NumTextures() const { return coll1->NumTextures() + coll2->NumTextures(); }

  virtual void GenTexture(int num) {

    get_elem2(num)->GenTexture(get_index2(num));

  }

  virtual BufferRef TextureBuf(int num) const {

    return get_elem2(num)->TextureBuf(get_index2(num));

  }

  virtual int FaceTexture(int face) const {

    return get_elem(face)->FaceTexture(get_index(face));



  }



private:

  FaceCollection *coll1;

  FaceCollection *coll2;

  int s;

  int s2;

};

EXPORT GameApi::P GameApi::PolygonApi::or_elem(P p1, P p2)

{

  FaceCollection *pp1 = find_facecoll(e, p1);

  FaceCollection *pp2 = find_facecoll(e, p2);

  //OrElem<FaceCollection> *coll = new OrElem<FaceCollection>;

  //coll->push_back(pp1);

  //coll->push_back(pp2);

  //coll->update_faces_cache();

  FaceCollection *coll = new OrElem2(pp1,pp2);

  return add_polygon2(e, coll,1);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class SphereElem : public SingleForwardBoxableFaceCollection

{

public:

  SphereElem(int numfaces, int numfaces2) :  numfaces(numfaces), numfaces2(numfaces2), center(Point(0.0,0.0,0.0)), radius(1.0) { }

  SphereElem(Point center, float radius, int numfaces1, int numfaces2);

  virtual void SetBox(Matrix b) { /*box = b; inverted=false; */}

  void Prepare() {}

  virtual int NumFaces() const;

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    p-=center;

    Vector v = p;

    //if (!inverted) { boxinv=Matrix::Inverse(box); inverted=true; }

    Point pp = v;

    

    return pp.x*pp.x+pp.y*pp.y+pp.z*pp.z<radius*radius; 

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    Point p = v;

    p-=center;

    Vector vv = p;

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    return -vv; /*-center*/;

  }

private:

  //Matrix box;

  //mutable Matrix boxinv;

  int numfaces;

  int numfaces2;

  Point center;

  float radius;

  //mutable bool inverted;

};

EXPORT GameApi::P GameApi::PolygonApi::sphere(PT center, float radius, int numfaces1, int numfaces2)

{

    Point *p = find_point(e,center);

    FaceCollection *coll = new SphereElem(*p, radius, numfaces1, numfaces2);

    return add_polygon(e, coll,1);

}

class SphereElem : public SingleForwardBoxableFaceCollection

{

public:

  SphereElem(int numfaces, int numfaces2) :  numfaces(numfaces), numfaces2(numfaces2), center(Point(0.0,0.0,0.0)), radius(1.0) { }

  SphereElem(Point center, float radius, int numfaces1, int numfaces2);

  virtual void SetBox(Matrix b) { /*box = b; inverted=false; */}

  void Prepare() {}

  virtual int NumFaces() const;

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    p-=center;

    Vector v = p;

    //if (!inverted) { boxinv=Matrix::Inverse(box); inverted=true; }

    Point pp = v;

    

    return pp.x*pp.x+pp.y*pp.y+pp.z*pp.z<radius*radius; 

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    Point p = v;

    p-=center;

    Vector vv = p;

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    return -vv; /*-center*/;

  }

private:

  //Matrix box;

  //mutable Matrix boxinv;

  int numfaces;

  int numfaces2;

  Point center;

  float radius;

  //mutable bool inverted;

};

EXPORT GameApi::P GameApi::PolygonApi::sphere(PT center, float radius, int numfaces1, int numfaces2)

{

    Point *p = find_point(e,center);

    FaceCollection *coll = new SphereElem(*p, radius, numfaces1, numfaces2);

    return add_polygon(e, coll,1);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

class OrElem2 : public FaceCollection

{

public:

  OrElem2(FaceCollection *coll1, FaceCollection *coll2) : coll1(coll1), coll2(coll2),s(0),s2(0) { }

  void Prepare() {

    coll1->Prepare();

    coll2->Prepare();

    s = coll1->NumFaces();

    s2 = coll1->NumTextures();

  }

  int get_index(int face) const

  {

    if (face<s) { return face; }

    return face-s;

  }

  FaceCollection *get_elem(int face) const {

    if (face<s) return coll1;

    return coll2;

  }

  int get_index2(int face) const

  {

    if (face<s2) { return face; }

    return face-s2;

  }

  FaceCollection *get_elem2(int face) const {

    if (face<s2) return coll1;

    return coll2;

  }

  virtual int NumFaces() const { return coll1->NumFaces()+coll2->NumFaces(); }

  virtual int NumPoints(int face) const

  {

    return get_elem(face)->NumPoints(get_index(face));

  }

  virtual Point FacePoint(int face, int point) const

  {

    return get_elem(face)->FacePoint(get_index(face), point);

  }

  virtual Vector PointNormal(int face, int point) const

  {

    return get_elem(face)->PointNormal(get_index(face), point);

  }

  virtual float Attrib(int face, int point, int id) const

  {

    return get_elem(face)->Attrib(get_index(face), point,id);

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return get_elem(face)->AttribI(get_index(face), point,id);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return get_elem(face)->Color(get_index(face), point);

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    return get_elem(face)->TexCoord(get_index(face), point);

  }

  virtual float TexCoord3(int face, int point) const {

    return get_elem(face)->TexCoord3(get_index(face), point);



  }

  virtual Point EndFacePoint(int face, int point) const {

    return get_elem(face)->EndFacePoint(get_index(face), point);

  }

  virtual Vector EndPointNormal(int face, int point) const {

    return get_elem(face)->EndPointNormal(get_index(face), point);

  }

  virtual float EndAttrib(int face, int point, int id) const {

    return get_elem(face)->EndAttrib(get_index(face), point,id);

  }

  virtual int EndAttribI(int face, int point, int id) const {

    return get_elem(face)->EndAttribI(get_index(face), point,id);

  }

  virtual unsigned int EndColor(int face, int point) const {

    return get_elem(face)->EndColor(get_index(face), point);

  }

  virtual Point2d EndTexCoord(int face, int point) const {

    return get_elem(face)->EndTexCoord(get_index(face), point);

  }

  virtual float EndTexCoord3(int face, int point) const {

    return get_elem(face)->EndTexCoord3(get_index(face), point);

  }



  virtual float Duration() const { return 1.0; }



  virtual int NumTextures() const { return coll1->NumTextures() + coll2->NumTextures(); }

  virtual void GenTexture(int num) {

    get_elem2(num)->GenTexture(get_index2(num));

  }

  virtual BufferRef TextureBuf(int num) const {

    return get_elem2(num)->TextureBuf(get_index2(num));

  }

  virtual int FaceTexture(int face) const {

    return get_elem(face)->FaceTexture(get_index(face));



  }



private:

  FaceCollection *coll1;

  FaceCollection *coll2;

  int s;

  int s2;

};

EXPORT GameApi::P GameApi::PolygonApi::or_elem(P p1, P p2)

{

  FaceCollection *pp1 = find_facecoll(e, p1);

  FaceCollection *pp2 = find_facecoll(e, p2);

  //OrElem<FaceCollection> *coll = new OrElem<FaceCollection>;

  //coll->push_back(pp1);

  //coll->push_back(pp2);

  //coll->update_faces_cache();

  FaceCollection *coll = new OrElem2(pp1,pp2);

  return add_polygon2(e, coll,1);

}

class OrElem2 : public FaceCollection

{

public:

  OrElem2(FaceCollection *coll1, FaceCollection *coll2) : coll1(coll1), coll2(coll2),s(0),s2(0) { }

  void Prepare() {

    coll1->Prepare();

    coll2->Prepare();

    s = coll1->NumFaces();

    s2 = coll1->NumTextures();

  }

  int get_index(int face) const

  {

    if (face<s) { return face; }

    return face-s;

  }

  FaceCollection *get_elem(int face) const {

    if (face<s) return coll1;

    return coll2;

  }

  int get_index2(int face) const

  {

    if (face<s2) { return face; }

    return face-s2;

  }

  FaceCollection *get_elem2(int face) const {

    if (face<s2) return coll1;

    return coll2;

  }

  virtual int NumFaces() const { return coll1->NumFaces()+coll2->NumFaces(); }

  virtual int NumPoints(int face) const

  {

    return get_elem(face)->NumPoints(get_index(face));

  }

  virtual Point FacePoint(int face, int point) const

  {

    return get_elem(face)->FacePoint(get_index(face), point);

  }

  virtual Vector PointNormal(int face, int point) const

  {

    return get_elem(face)->PointNormal(get_index(face), point);

  }

  virtual float Attrib(int face, int point, int id) const

  {

    return get_elem(face)->Attrib(get_index(face), point,id);

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return get_elem(face)->AttribI(get_index(face), point,id);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return get_elem(face)->Color(get_index(face), point);

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    return get_elem(face)->TexCoord(get_index(face), point);

  }

  virtual float TexCoord3(int face, int point) const {

    return get_elem(face)->TexCoord3(get_index(face), point);



  }

  virtual Point EndFacePoint(int face, int point) const {

    return get_elem(face)->EndFacePoint(get_index(face), point);

  }

  virtual Vector EndPointNormal(int face, int point) const {

    return get_elem(face)->EndPointNormal(get_index(face), point);

  }

  virtual float EndAttrib(int face, int point, int id) const {

    return get_elem(face)->EndAttrib(get_index(face), point,id);

  }

  virtual int EndAttribI(int face, int point, int id) const {

    return get_elem(face)->EndAttribI(get_index(face), point,id);

  }

  virtual unsigned int EndColor(int face, int point) const {

    return get_elem(face)->EndColor(get_index(face), point);

  }

  virtual Point2d EndTexCoord(int face, int point) const {

    return get_elem(face)->EndTexCoord(get_index(face), point);

  }

  virtual float EndTexCoord3(int face, int point) const {

    return get_elem(face)->EndTexCoord3(get_index(face), point);

  }



  virtual float Duration() const { return 1.0; }



  virtual int NumTextures() const { return coll1->NumTextures() + coll2->NumTextures(); }

  virtual void GenTexture(int num) {

    get_elem2(num)->GenTexture(get_index2(num));

  }

  virtual BufferRef TextureBuf(int num) const {

    return get_elem2(num)->TextureBuf(get_index2(num));

  }

  virtual int FaceTexture(int face) const {

    return get_elem(face)->FaceTexture(get_index(face));



  }



private:

  FaceCollection *coll1;

  FaceCollection *coll2;

  int s;

  int s2;

};

EXPORT GameApi::P GameApi::PolygonApi::or_elem(P p1, P p2)

{

  FaceCollection *pp1 = find_facecoll(e, p1);

  FaceCollection *pp2 = find_facecoll(e, p2);

  //OrElem<FaceCollection> *coll = new OrElem<FaceCollection>;

  //coll->push_back(pp1);

  //coll->push_back(pp2);

  //coll->update_faces_cache();

  FaceCollection *coll = new OrElem2(pp1,pp2);

  return add_polygon2(e, coll,1);

}

EXPORT GameApi::P GameApi::PolygonApi::translate(P orig, float dx, float dy, float dz)

{

  return translate_1(orig, dx,dy,dz);

}

EXPORT GameApi::P GameApi::PolygonApi::translate(P orig, float dx, float dy, float dz)

{

  return translate_1(orig, dx,dy,dz);

}

class OrElem2 : public FaceCollection

{

public:

  OrElem2(FaceCollection *coll1, FaceCollection *coll2) : coll1(coll1), coll2(coll2),s(0),s2(0) { }

  void Prepare() {

    coll1->Prepare();

    coll2->Prepare();

    s = coll1->NumFaces();

    s2 = coll1->NumTextures();

  }

  int get_index(int face) const

  {

    if (face<s) { return face; }

    return face-s;

  }

  FaceCollection *get_elem(int face) const {

    if (face<s) return coll1;

    return coll2;

  }

  int get_index2(int face) const

  {

    if (face<s2) { return face; }

    return face-s2;

  }

  FaceCollection *get_elem2(int face) const {

    if (face<s2) return coll1;

    return coll2;

  }

  virtual int NumFaces() const { return coll1->NumFaces()+coll2->NumFaces(); }

  virtual int NumPoints(int face) const

  {

    return get_elem(face)->NumPoints(get_index(face));

  }

  virtual Point FacePoint(int face, int point) const

  {

    return get_elem(face)->FacePoint(get_index(face), point);

  }

  virtual Vector PointNormal(int face, int point) const

  {

    return get_elem(face)->PointNormal(get_index(face), point);

  }

  virtual float Attrib(int face, int point, int id) const

  {

    return get_elem(face)->Attrib(get_index(face), point,id);

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return get_elem(face)->AttribI(get_index(face), point,id);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return get_elem(face)->Color(get_index(face), point);

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    return get_elem(face)->TexCoord(get_index(face), point);

  }

  virtual float TexCoord3(int face, int point) const {

    return get_elem(face)->TexCoord3(get_index(face), point);



  }

  virtual Point EndFacePoint(int face, int point) const {

    return get_elem(face)->EndFacePoint(get_index(face), point);

  }

  virtual Vector EndPointNormal(int face, int point) const {

    return get_elem(face)->EndPointNormal(get_index(face), point);

  }

  virtual float EndAttrib(int face, int point, int id) const {

    return get_elem(face)->EndAttrib(get_index(face), point,id);

  }

  virtual int EndAttribI(int face, int point, int id) const {

    return get_elem(face)->EndAttribI(get_index(face), point,id);

  }

  virtual unsigned int EndColor(int face, int point) const {

    return get_elem(face)->EndColor(get_index(face), point);

  }

  virtual Point2d EndTexCoord(int face, int point) const {

    return get_elem(face)->EndTexCoord(get_index(face), point);

  }

  virtual float EndTexCoord3(int face, int point) const {

    return get_elem(face)->EndTexCoord3(get_index(face), point);

  }



  virtual float Duration() const { return 1.0; }



  virtual int NumTextures() const { return coll1->NumTextures() + coll2->NumTextures(); }

  virtual void GenTexture(int num) {

    get_elem2(num)->GenTexture(get_index2(num));

  }

  virtual BufferRef TextureBuf(int num) const {

    return get_elem2(num)->TextureBuf(get_index2(num));

  }

  virtual int FaceTexture(int face) const {

    return get_elem(face)->FaceTexture(get_index(face));



  }



private:

  FaceCollection *coll1;

  FaceCollection *coll2;

  int s;

  int s2;

};

EXPORT GameApi::P GameApi::PolygonApi::or_elem(P p1, P p2)

{

  FaceCollection *pp1 = find_facecoll(e, p1);

  FaceCollection *pp2 = find_facecoll(e, p2);

  //OrElem<FaceCollection> *coll = new OrElem<FaceCollection>;

  //coll->push_back(pp1);

  //coll->push_back(pp2);

  //coll->update_faces_cache();

  FaceCollection *coll = new OrElem2(pp1,pp2);

  return add_polygon2(e, coll,1);

}

class OrElem2 : public FaceCollection

{

public:

  OrElem2(FaceCollection *coll1, FaceCollection *coll2) : coll1(coll1), coll2(coll2),s(0),s2(0) { }

  void Prepare() {

    coll1->Prepare();

    coll2->Prepare();

    s = coll1->NumFaces();

    s2 = coll1->NumTextures();

  }

  int get_index(int face) const

  {

    if (face<s) { return face; }

    return face-s;

  }

  FaceCollection *get_elem(int face) const {

    if (face<s) return coll1;

    return coll2;

  }

  int get_index2(int face) const

  {

    if (face<s2) { return face; }

    return face-s2;

  }

  FaceCollection *get_elem2(int face) const {

    if (face<s2) return coll1;

    return coll2;

  }

  virtual int NumFaces() const { return coll1->NumFaces()+coll2->NumFaces(); }

  virtual int NumPoints(int face) const

  {

    return get_elem(face)->NumPoints(get_index(face));

  }

  virtual Point FacePoint(int face, int point) const

  {

    return get_elem(face)->FacePoint(get_index(face), point);

  }

  virtual Vector PointNormal(int face, int point) const

  {

    return get_elem(face)->PointNormal(get_index(face), point);

  }

  virtual float Attrib(int face, int point, int id) const

  {

    return get_elem(face)->Attrib(get_index(face), point,id);

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return get_elem(face)->AttribI(get_index(face), point,id);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return get_elem(face)->Color(get_index(face), point);

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    return get_elem(face)->TexCoord(get_index(face), point);

  }

  virtual float TexCoord3(int face, int point) const {

    return get_elem(face)->TexCoord3(get_index(face), point);



  }

  virtual Point EndFacePoint(int face, int point) const {

    return get_elem(face)->EndFacePoint(get_index(face), point);

  }

  virtual Vector EndPointNormal(int face, int point) const {

    return get_elem(face)->EndPointNormal(get_index(face), point);

  }

  virtual float EndAttrib(int face, int point, int id) const {

    return get_elem(face)->EndAttrib(get_index(face), point,id);

  }

  virtual int EndAttribI(int face, int point, int id) const {

    return get_elem(face)->EndAttribI(get_index(face), point,id);

  }

  virtual unsigned int EndColor(int face, int point) const {

    return get_elem(face)->EndColor(get_index(face), point);

  }

  virtual Point2d EndTexCoord(int face, int point) const {

    return get_elem(face)->EndTexCoord(get_index(face), point);

  }

  virtual float EndTexCoord3(int face, int point) const {

    return get_elem(face)->EndTexCoord3(get_index(face), point);

  }



  virtual float Duration() const { return 1.0; }



  virtual int NumTextures() const { return coll1->NumTextures() + coll2->NumTextures(); }

  virtual void GenTexture(int num) {

    get_elem2(num)->GenTexture(get_index2(num));

  }

  virtual BufferRef TextureBuf(int num) const {

    return get_elem2(num)->TextureBuf(get_index2(num));

  }

  virtual int FaceTexture(int face) const {

    return get_elem(face)->FaceTexture(get_index(face));



  }



private:

  FaceCollection *coll1;

  FaceCollection *coll2;

  int s;

  int s2;

};

EXPORT GameApi::P GameApi::PolygonApi::or_elem(P p1, P p2)

{

  FaceCollection *pp1 = find_facecoll(e, p1);

  FaceCollection *pp2 = find_facecoll(e, p2);

  //OrElem<FaceCollection> *coll = new OrElem<FaceCollection>;

  //coll->push_back(pp1);

  //coll->push_back(pp2);

  //coll->update_faces_cache();

  FaceCollection *coll = new OrElem2(pp1,pp2);

  return add_polygon2(e, coll,1);

}

class RecalculateNormals : public ForwardFaceCollection

{

public:

  RecalculateNormals(FaceCollection &coll) : ForwardFaceCollection(coll) { }

  Vector PointNormal(int face, int point) const 

  { 

    Point p1 = FacePoint(face, 0);

    Point p2 = FacePoint(face, 1);

    Point p3 = FacePoint(face, 2);

    Vector v = -Vector::CrossProduct(p2-p1,p3-p1);

    return v / v.Dist();

  }

};

EXPORT GameApi::P GameApi::PolygonApi::recalculate_normals(P orig)

{

  FaceCollection *coll = find_facecoll(e, orig);

  FaceCollection *coll2 = new RecalculateNormals(*coll);

  return add_polygon(e, coll2, 1);

}

class RecalculateNormals : public ForwardFaceCollection

{

public:

  RecalculateNormals(FaceCollection &coll) : ForwardFaceCollection(coll) { }

  Vector PointNormal(int face, int point) const 

  { 

    Point p1 = FacePoint(face, 0);

    Point p2 = FacePoint(face, 1);

    Point p3 = FacePoint(face, 2);

    Vector v = -Vector::CrossProduct(p2-p1,p3-p1);

    return v / v.Dist();

  }

};

EXPORT GameApi::P GameApi::PolygonApi::recalculate_normals(P orig)

{

  FaceCollection *coll = find_facecoll(e, orig);

  FaceCollection *coll2 = new RecalculateNormals(*coll);

  return add_polygon(e, coll2, 1);

}

class SmoothNormals2 : public ForwardFaceCollection

{

public:

  SmoothNormals2(FaceCollection *coll) : ForwardFaceCollection(*coll), coll(coll) { }

  struct Data { Data() : v{0.01,0.01,0.01}, count(0) { } Vector v; int count; };

  

  virtual void Prepare() {

    coll->Prepare();



    int s = coll->NumFaces();

    //int count = 0;

    for(int i=0;i<s;i++) {

      int s2 = coll->NumPoints(i);

      for(int j=0;j<s2;j++) {

	Point p = coll->FacePoint(i,j);

	Point p1 = coll->FacePoint(i,(j+1)%s2);

	Point p2 = coll->FacePoint(i,(j+2)%s2);

	Point p3 = coll->FacePoint(i,(j+3)%s2);

	//Point p4 = coll->FacePoint(i,(j+3)%s2);

	//float area = Vector::DotProduct(coll->PointNormal(i,j),Vector::CrossProduct(p1,p2) + Vector::CrossProduct(p2,p3) + Vector::CrossProduct(p3,p4))/2.0;

	float a1 = Vector::Angle(p2-p1,p3-p1);

	//float a2 = Vector::Angle(p3-p2,p1-p2);

	//float a3 = Vector::Angle(p1-p3,p2-p3);

	Data &v = mymap[key(p)];

	Vector n = coll->PointNormal(i,j);

	if (std::isnormal(a1)) {

	  v.v+=n*a1;

	//v.v+=a2*n;

	//v.v+=a3*n;

	  v.count++;

	}

      }

    }

  }

  std::tuple<int,int,int> key(Point p) const

  {

    return std::make_tuple(int(p.x*100.0),int(p.y*100.0),int(p.z*100.0));

  }

  virtual Vector PointNormal(int face, int point) const

  {

    Point p = coll->FacePoint(face,point);

    Data v = mymap[key(p)];

    if (v.count==1) { return coll->PointNormal(face,point); }

    if (v.count==0) v.count++;

    Vector vv = v.v/float(v.count);

    float dist = vv.Dist();

    //if (dist<0.01) { vv=Vector(1.0,0.0,0.0); dist=1.0; }

    return (vv)/dist;

  }

private:

  FaceCollection *coll;

  mutable std::map<std::tuple<int,int,int>, Data> mymap;

};

GameApi::P GameApi::PolygonApi::smooth_normals2(P p) {

GameApi::P GameApi::PolygonApi::smooth_normals2(P p) {

  FaceCollection *coll = find_facecoll(e, p);

  return add_polygon2(e, new SmoothNormals2(coll),1);

}

class SmoothNormals2 : public ForwardFaceCollection

{

public:

  SmoothNormals2(FaceCollection *coll) : ForwardFaceCollection(*coll), coll(coll) { }

  struct Data { Data() : v{0.01,0.01,0.01}, count(0) { } Vector v; int count; };

  

  virtual void Prepare() {

    coll->Prepare();



    int s = coll->NumFaces();

    //int count = 0;

    for(int i=0;i<s;i++) {

      int s2 = coll->NumPoints(i);

      for(int j=0;j<s2;j++) {

	Point p = coll->FacePoint(i,j);

	Point p1 = coll->FacePoint(i,(j+1)%s2);

	Point p2 = coll->FacePoint(i,(j+2)%s2);

	Point p3 = coll->FacePoint(i,(j+3)%s2);

	//Point p4 = coll->FacePoint(i,(j+3)%s2);

	//float area = Vector::DotProduct(coll->PointNormal(i,j),Vector::CrossProduct(p1,p2) + Vector::CrossProduct(p2,p3) + Vector::CrossProduct(p3,p4))/2.0;

	float a1 = Vector::Angle(p2-p1,p3-p1);

	//float a2 = Vector::Angle(p3-p2,p1-p2);

	//float a3 = Vector::Angle(p1-p3,p2-p3);

	Data &v = mymap[key(p)];

	Vector n = coll->PointNormal(i,j);

	if (std::isnormal(a1)) {

	  v.v+=n*a1;

	//v.v+=a2*n;

	//v.v+=a3*n;

	  v.count++;

	}

      }

    }

  }

  std::tuple<int,int,int> key(Point p) const

  {

    return std::make_tuple(int(p.x*100.0),int(p.y*100.0),int(p.z*100.0));

  }

  virtual Vector PointNormal(int face, int point) const

  {

    Point p = coll->FacePoint(face,point);

    Data v = mymap[key(p)];

    if (v.count==1) { return coll->PointNormal(face,point); }

    if (v.count==0) v.count++;

    Vector vv = v.v/float(v.count);

    float dist = vv.Dist();

    //if (dist<0.01) { vv=Vector(1.0,0.0,0.0); dist=1.0; }

    return (vv)/dist;

  }

private:

  FaceCollection *coll;

  mutable std::map<std::tuple<int,int,int>, Data> mymap;

};

GameApi::P GameApi::PolygonApi::smooth_normals2(P p) {

GameApi::P GameApi::PolygonApi::smooth_normals2(P p) {

  FaceCollection *coll = find_facecoll(e, p);

  return add_polygon2(e, new SmoothNormals2(coll),1);

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind(P p, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = mat2->mat(p.id);

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind(P p, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = 0;

  if (mat2) {

    val = mat2->mat(p.id);

  }

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

class ArrayMainLoop : public MainLoopItem

{

public:

  ArrayMainLoop(GameApi::Env &env, GameApi::EveryApi &ev, std::vector<MainLoopItem*> vec) : env(env), ev(ev), vec(vec) { }

  void Prepare() {

    int s = vec.size();

    for(int i=0;i<s;i++) vec[i]->Prepare();

  }

  void execute(MainLoopEnv &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	MainLoopEnv ee = e;



	// here's a block needed to distribute in_MV to different cases.

	int id = vec[i]->shader_id();

	if (id!=-1) {

	  GameApi::SH sh;

	  sh.id = id;

	  GameApi::M m = add_matrix2( env, e.in_MV);

	  ev.shader_api.use(sh);

	  ev.shader_api.set_var(sh, "in_MV", m);

	}

	vec[i]->execute(ee);

      }

  }

  void handle_event(MainLoopEvent &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	vec[i]->handle_event(e);

      }

  }

#if 0

  int shader_id() { 

    int s = vec.size();

    for(int i=s-1;i>=0;i--)

      {

	if (vec[i]->shader_id()!=-1) return vec[i]->shader_id();

      }

    return -1; 

  }

#endif

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  std::vector<MainLoopItem*> vec;

};

EXPORT GameApi::ML GameApi::MainLoopApi::array_ml(std::vector<ML> vec)

{

  std::vector<MainLoopItem*> vec2;

  int s = vec.size();

  for(int i=0;i<s;i++)

    {

      //std::cout << "array_ml id: " << vec[i].id << std::endl;

      vec2.push_back(find_main_loop(e,vec[i]));

    }

  return add_main_loop(e, new ArrayMainLoop(vec2));

}

class ArrayMainLoop : public MainLoopItem

{

public:

  ArrayMainLoop(GameApi::Env &env, GameApi::EveryApi &ev, std::vector<MainLoopItem*> vec) : env(env), ev(ev), vec(vec) { }

  void Prepare() {

    int s = vec.size();

    for(int i=0;i<s;i++) vec[i]->Prepare();

  }

  void execute(MainLoopEnv &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	MainLoopEnv ee = e;



	// here's a block needed to distribute in_MV to different cases.

	int id = vec[i]->shader_id();

	if (id!=-1) {

	  GameApi::SH sh;

	  sh.id = id;

	  GameApi::M m = add_matrix2( env, e.in_MV);

	  ev.shader_api.use(sh);

	  ev.shader_api.set_var(sh, "in_MV", m);

	}

	vec[i]->execute(ee);

      }

  }

  void handle_event(MainLoopEvent &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	vec[i]->handle_event(e);

      }

  }

#if 0

  int shader_id() { 

    int s = vec.size();

    for(int i=s-1;i>=0;i--)

      {

	if (vec[i]->shader_id()!=-1) return vec[i]->shader_id();

      }

    return -1; 

  }

#endif

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  std::vector<MainLoopItem*> vec;

};

EXPORT GameApi::ML GameApi::MainLoopApi::array_ml(GameApi::EveryApi &ev, std::vector<ML> vec)

{

  std::vector<MainLoopItem*> vec2;

  int s = vec.size();

  for(int i=0;i<s;i++)

    {

      //std::cout << "array_ml id: " << vec[i].id << std::endl;

      vec2.push_back(find_main_loop(e,vec[i]));

    }

  return add_main_loop(e, new ArrayMainLoop(e,ev,vec2));

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class QuadElem : public SingleForwardBoxableFaceCollection

{

public:

  QuadElem(Point p1, Point p2, Point p3, Point p4) : p1(p1), p2(p2), p3(p3), p4(p4) { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 1; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const

  {

    if (point==0) return p1;

    if (point==1) return p2;

    if (point==2) return p3;

    return p4;

  }

  virtual Vector PointNormal(int face, int point) const

  {

    Vector u_x = p2-p1;

    Vector u_y = p3-p1;

    return Vector::CrossProduct(u_x, u_y);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    if (point==0) {

      p.x = 0;

      p.y = 0;

    }

    if (point==1) {

      p.x = 1;

      p.y = 0;

    }

    if (point==2) {

      p.x = 1;

      p.y = 1;

    }

    if (point==3) {

      p.x = 0;

      p.y = 1;

    }



    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p1,p2,p3,p4;

};

EXPORT GameApi::P GameApi::PolygonApi::quad_z(float x1, float x2,

{

  Point pp1 = Point(x1,y1,z);

  Point pp2 = Point(x2,y1,z);

  Point pp3 = Point(x2,y2,z);

  Point pp4 = Point(x1,y2,z);

  FaceCollection *coll = new QuadElem(pp1,pp2,pp3,pp4);

  return add_polygon(e,coll,1);

}

class QuadElem : public SingleForwardBoxableFaceCollection

{

public:

  QuadElem(Point p1, Point p2, Point p3, Point p4) : p1(p1), p2(p2), p3(p3), p4(p4) { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 1; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const

  {

    if (point==0) return p1;

    if (point==1) return p2;

    if (point==2) return p3;

    return p4;

  }

  virtual Vector PointNormal(int face, int point) const

  {

    Vector u_x = p2-p1;

    Vector u_y = p3-p1;

    return Vector::CrossProduct(u_x, u_y);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    if (point==0) {

      p.x = 0;

      p.y = 0;

    }

    if (point==1) {

      p.x = 1;

      p.y = 0;

    }

    if (point==2) {

      p.x = 1;

      p.y = 1;

    }

    if (point==3) {

      p.x = 0;

      p.y = 1;

    }



    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p1,p2,p3,p4;

};

EXPORT GameApi::P GameApi::PolygonApi::quad_z(float x1, float x2,

{

  Point pp1 = Point(x1,y1,z);

  Point pp2 = Point(x2,y1,z);

  Point pp3 = Point(x2,y2,z);

  Point pp4 = Point(x1,y2,z);

  FaceCollection *coll = new QuadElem(pp1,pp2,pp3,pp4);

  return add_polygon(e,coll,1);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class LineCurve : public Curve<Point>

{

public:

  LineCurve(Point p1, Point p2) : p1(p1), p2(p2) {}

  float Size() const {

    return 1.0;

  }

  Point Index(float p) const

  {

    return Point((1.0-p)*Vector(p1) + p*Vector(p2));

  }

private:

  Point p1,p2;

};

EXPORT GameApi::C GameApi::CurveApi::line(PT p1, PT p2)

{

  Point *pp1 = find_point(e, p1);

  Point *pp2 = find_point(e, p2);

  return add_curve(e, new LineCurve(*pp1, *pp2));

}

class LineCurve : public Curve<Point>

{

public:

  LineCurve(Point p1, Point p2) : p1(p1), p2(p2) {}

  float Size() const {

    return 1.0;

  }

  Point Index(float p) const

  {

    return Point((1.0-p)*Vector(p1) + p*Vector(p2));

  }

private:

  Point p1,p2;

};

EXPORT GameApi::C GameApi::CurveApi::line(PT p1, PT p2)

{

  Point *pp1 = find_point(e, p1);

  Point *pp2 = find_point(e, p2);

  return add_curve(e, new LineCurve(*pp1, *pp2));

}

class SampleCurve : public PointsApiPoints

{

public:

  SampleCurve(Curve<Point> *c, int num_points) : c(c), num_points(num_points) { }

  int NumPoints() const { return num_points+1; }

  Point Pos(int i) const

  {

    float val = float(i);

    val/=float(num_points);

    val*=c->Size();

    return c->Index(val);

  }

  unsigned int Color(int i) const

  {

    return 0xffffffff;

  }

private:

  Curve<Point> *c;

  int num_points;

  float start,end;

};

EXPORT GameApi::PTS GameApi::CurveApi::sample(C curve, int num_samples)

{

  Curve<Point> *c = find_curve(e, curve);

  return add_points_api_points(e, new SampleCurve(c,num_samples));

}

class SampleMatrixCurve2 : public MatrixArray

{

public:

  SampleMatrixCurve2(Curve<Matrix> *c, int num_points) : c(c), num_points(num_points) { }

  int Size() const { return num_points; }

  Matrix Index(int i) const

  {

    float val = float(i);

    val/=float(num_points);

    val*=c->Size();

    return c->Index(val);

  }

  unsigned int Color(int i) const

  {

    return 0xffffffff;

  }

private:

  Curve<Matrix> *c;

  int num_points;

};

EXPORT GameApi::MS GameApi::MatrixCurveApi::sample(MC m_curve, int num)

{

  Curve<Matrix> *c = find_matrix_curve(e, m_curve);

  return add_matrix_array(e, new SampleMatrixCurve2(c,num));

}

class SampleCurve : public PointsApiPoints

{

public:

  SampleCurve(Curve<Point> *c, int num_points) : c(c), num_points(num_points) { }

  int NumPoints() const { return num_points+1; }

  Point Pos(int i) const

  {

    float val = float(i);

    val/=float(num_points);

    val*=c->Size();

    return c->Index(val);

  }

  unsigned int Color(int i) const

  {

    return 0xffffffff;

  }

private:

  Curve<Point> *c;

  int num_points;

  float start,end;

};

EXPORT GameApi::PTS GameApi::CurveApi::sample(C curve, int num_samples)

{

  Curve<Point> *c = find_curve(e, curve);

  return add_points_api_points(e, new SampleCurve(c,num_samples));

}

class SampleMatrixCurve2 : public MatrixArray

{

public:

  SampleMatrixCurve2(Curve<Matrix> *c, int num_points) : c(c), num_points(num_points) { }

  int Size() const { return num_points; }

  Matrix Index(int i) const

  {

    float val = float(i);

    val/=float(num_points);

    val*=c->Size();

    return c->Index(val);

  }

  unsigned int Color(int i) const

  {

    return 0xffffffff;

  }

private:

  Curve<Matrix> *c;

  int num_points;

};

EXPORT GameApi::MS GameApi::MatrixCurveApi::sample(MC m_curve, int num)

{

  Curve<Matrix> *c = find_matrix_curve(e, m_curve);

  return add_matrix_array(e, new SampleMatrixCurve2(c,num));

}

template<class C>

class ConstantBitmap : public Bitmap<C>

{

public:

  ConstantBitmap(C c, int x, int y) : c(c), x(x), y(y) { }

  void Prepare() { }



  int SizeX() const { return x; }

  int SizeY() const { return y; }

  C Map(int , int ) const

  {

    return c;

  }

private:

  C c;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::newbitmap(int sx, int sy, unsigned int color)

{

  ::Bitmap<Color> *b = new ConstantBitmap<Color>(Color(color), sx,sy);

  BitmapColorHandle *handle = new BitmapColorHandle;

  handle->bm = b;

  BM bm = add_bitmap(e, handle);

  return bm;

  

}

class ConstantBitmap_Color : public Bitmap<Color>

{

public:

  ConstantBitmap_Color(Color c, int x, int y) : c(c), x(x), y(y) { }

  void Prepare() { }



  int SizeX() const { return x; }

  int SizeY() const { return y; }

  Color Map(int , int ) const

  {

    return c;

  }

private:

  Color c;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::newbitmap(int sx, int sy, unsigned int color)

{

  ::Bitmap<Color> *b = new ConstantBitmap_Color(Color(color), sx,sy);

  BitmapColorHandle *handle = new BitmapColorHandle;

  handle->bm = b;

  BM bm = add_bitmap(e, handle);

  return bm;

  

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class GradientBitmap2 : public Bitmap<Color>

{

public:

  GradientBitmap2(Point2d pos_1, Point2d pos_2, unsigned int color_1, unsigned int color_2, int sx, int sy) : pos_1(pos_1), pos_2(pos_2), color_1(color_1), color_2(color_2), sx(sx), sy(sy) { 

    u_x = Point(pos_2.x, pos_2.y, 0.0)-Point(pos_1.x, pos_1.y, 0.0);

    v = u_x.Dist();

    v = v*v;

  }

  void Prepare() { }

  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  virtual Color Map(int x, int y) const

  {

    //std::cout << "gradient" << std::endl;

    Vector u = Point(x, y, 0.0)-Point(pos_1.x, pos_1.y, 0.0);

    float val = Vector::DotProduct(u, u_x);

    val /= v;

    //val /= v; 

    // now [0.0 .. 1.0]

    if (val<0.0) return 0;

    if (val>1.0) return 0;

    return Color(Color::CubicInterpolate(color_1, color_2, val));

  }



private:

  Point2d pos_1;

  Point2d pos_2;

  unsigned int color_1;

  unsigned int color_2;

  int sx,sy;

  Vector u_x;

  float v;

};

EXPORT GameApi::BM GameApi::BitmapApi::gradient(PT pos_1, PT pos_2, unsigned int color_1, unsigned int color_2, int sx, int sy)

{

  Point *pos_1a = find_point(e, pos_1);

  Point *pos_2a = find_point(e, pos_2);

  Point2d pos_1b = { pos_1a->x, pos_1a->y };

  Point2d pos_2b = { pos_2a->x, pos_2a->y };

  return add_color_bitmap2(e, new GradientBitmap2(pos_1b, pos_2b, color_1, color_2, sx,sy));

}

class GradientBitmap2 : public Bitmap<Color>

{

public:

  GradientBitmap2(Point2d pos_1, Point2d pos_2, unsigned int color_1, unsigned int color_2, int sx, int sy) : pos_1(pos_1), pos_2(pos_2), color_1(color_1), color_2(color_2), sx(sx), sy(sy) { 

    u_x = Point(pos_2.x, pos_2.y, 0.0)-Point(pos_1.x, pos_1.y, 0.0);

    v = u_x.Dist();

    v = v*v;

  }

  void Prepare() { }

  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  virtual Color Map(int x, int y) const

  {

    //std::cout << "gradient" << std::endl;

    Vector u = Point(x, y, 0.0)-Point(pos_1.x, pos_1.y, 0.0);

    float val = Vector::DotProduct(u, u_x);

    val /= v;

    //val /= v; 

    // now [0.0 .. 1.0]

    if (val<0.0) return 0;

    if (val>1.0) return 0;

    return Color(Color::CubicInterpolate(color_1, color_2, val));

  }



private:

  Point2d pos_1;

  Point2d pos_2;

  unsigned int color_1;

  unsigned int color_2;

  int sx,sy;

  Vector u_x;

  float v;

};

EXPORT GameApi::BM GameApi::BitmapApi::gradient(PT pos_1, PT pos_2, unsigned int color_1, unsigned int color_2, int sx, int sy)

{

  Point *pos_1a = find_point(e, pos_1);

  Point *pos_2a = find_point(e, pos_2);

  Point2d pos_1b = { pos_1a->x, pos_1a->y };

  Point2d pos_2b = { pos_2a->x, pos_2a->y };

  return add_color_bitmap2(e, new GradientBitmap2(pos_1b, pos_2b, color_1, color_2, sx,sy));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_x(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, true, false);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_x(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, true, false);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

template<class C>

class RepeatBitmap : public Bitmap<C>

{

public:

  RepeatBitmap(Bitmap<C> &bm, int times_x, int times_y) : bm(bm), times_x(times_x), times_y(times_y) { }

  void Prepare() { bm.Prepare(); }



  int SizeX() const { return times_x*bm.SizeX(); }

  int SizeY() const { return times_y*bm.SizeY(); }

  C Map(int x, int y) const

  {

    int xx = x % bm.SizeX();

    int yy = y % bm.SizeY();

    return bm.Map(xx,yy);

  }

private:

  Bitmap<C> &bm;

  int times_x, times_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::repeat_bitmap(BM orig, int xcount, int ycount)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  if (!chandle) return add_bitmap(e,0);

  RepeatBitmap<Color> *rep = new RepeatBitmap<Color>(*chandle->bm, xcount, ycount);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

template<class C>

class RepeatBitmap : public Bitmap<C>

{

public:

  RepeatBitmap(Bitmap<C> &bm, int times_x, int times_y) : bm(bm), times_x(times_x), times_y(times_y) { }

  void Prepare() { bm.Prepare(); }



  int SizeX() const { return times_x*bm.SizeX(); }

  int SizeY() const { return times_y*bm.SizeY(); }

  C Map(int x, int y) const

  {

    int xx = x % bm.SizeX();

    int yy = y % bm.SizeY();

    return bm.Map(xx,yy);

  }

private:

  Bitmap<C> &bm;

  int times_x, times_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::repeat_bitmap(BM orig, int xcount, int ycount)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  if (!chandle) return add_bitmap(e,0);

  RepeatBitmap<Color> *rep = new RepeatBitmap<Color>(*chandle->bm, xcount, ycount);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class PartCircleBoolBitmap : public Bitmap<bool>

{

public:

  PartCircleBoolBitmap(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad) : sx(sx), sy(sy), x(x), y(y), sa(start_angle), ea(end_angle), sr(start_rad), er(end_rad) { }

  void Prepare() { }



  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  

  bool Map(int ax, int ay) const

  {

    ax-=x;

    ay-=y;

    float r = sqrtf(float(ax)*float(ax)+float(ay)*float(ay));

    float angle = atan2f(float(ay),float(ax));

    if (angle<sa || angle>ea) return false;

    if (r<sr || r>er) return false;

    return true;

  }

private:

  int sx,sy;

  float x,y;

  float sa,ea;

  float sr,er;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::part_circle(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad)

{

  return add_bool_bitmap(e, new PartCircleBoolBitmap(sx,sy, x,y,start_angle,end_angle, start_rad, end_rad));

}

class PartCircleBoolBitmap : public Bitmap<bool>

{

public:

  PartCircleBoolBitmap(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad) : sx(sx), sy(sy), x(x), y(y), sa(start_angle), ea(end_angle), sr(start_rad), er(end_rad) { }

  void Prepare() { }



  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  

  bool Map(int ax, int ay) const

  {

    ax-=x;

    ay-=y;

    float r = sqrtf(float(ax)*float(ax)+float(ay)*float(ay));

    float angle = atan2f(float(ay),float(ax));

    if (angle<sa || angle>ea) return false;

    if (r<sr || r>er) return false;

    return true;

  }

private:

  int sx,sy;

  float x,y;

  float sa,ea;

  float sr,er;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::part_circle(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad)

{

  return add_bool_bitmap(e, new PartCircleBoolBitmap(sx,sy, x,y,start_angle,end_angle, start_rad, end_rad));

}

class PartCircleBoolBitmap : public Bitmap<bool>

{

public:

  PartCircleBoolBitmap(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad) : sx(sx), sy(sy), x(x), y(y), sa(start_angle), ea(end_angle), sr(start_rad), er(end_rad) { }

  void Prepare() { }



  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  

  bool Map(int ax, int ay) const

  {

    ax-=x;

    ay-=y;

    float r = sqrtf(float(ax)*float(ax)+float(ay)*float(ay));

    float angle = atan2f(float(ay),float(ax));

    if (angle<sa || angle>ea) return false;

    if (r<sr || r>er) return false;

    return true;

  }

private:

  int sx,sy;

  float x,y;

  float sa,ea;

  float sr,er;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::part_circle(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad)

{

  return add_bool_bitmap(e, new PartCircleBoolBitmap(sx,sy, x,y,start_angle,end_angle, start_rad, end_rad));

}

class PartCircleBoolBitmap : public Bitmap<bool>

{

public:

  PartCircleBoolBitmap(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad) : sx(sx), sy(sy), x(x), y(y), sa(start_angle), ea(end_angle), sr(start_rad), er(end_rad) { }

  void Prepare() { }



  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  

  bool Map(int ax, int ay) const

  {

    ax-=x;

    ay-=y;

    float r = sqrtf(float(ax)*float(ax)+float(ay)*float(ay));

    float angle = atan2f(float(ay),float(ax));

    if (angle<sa || angle>ea) return false;

    if (r<sr || r>er) return false;

    return true;

  }

private:

  int sx,sy;

  float x,y;

  float sa,ea;

  float sr,er;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::part_circle(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad)

{

  return add_bool_bitmap(e, new PartCircleBoolBitmap(sx,sy, x,y,start_angle,end_angle, start_rad, end_rad));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

template<class C>

class RepeatBitmap : public Bitmap<C>

{

public:

  RepeatBitmap(Bitmap<C> &bm, int times_x, int times_y) : bm(bm), times_x(times_x), times_y(times_y) { }

  void Prepare() { bm.Prepare(); }



  int SizeX() const { return times_x*bm.SizeX(); }

  int SizeY() const { return times_y*bm.SizeY(); }

  C Map(int x, int y) const

  {

    int xx = x % bm.SizeX();

    int yy = y % bm.SizeY();

    return bm.Map(xx,yy);

  }

private:

  Bitmap<C> &bm;

  int times_x, times_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::repeat_bitmap(BM orig, int xcount, int ycount)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  if (!chandle) return add_bitmap(e,0);

  RepeatBitmap<Color> *rep = new RepeatBitmap<Color>(*chandle->bm, xcount, ycount);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

template<class C>

class RepeatBitmap : public Bitmap<C>

{

public:

  RepeatBitmap(Bitmap<C> &bm, int times_x, int times_y) : bm(bm), times_x(times_x), times_y(times_y) { }

  void Prepare() { bm.Prepare(); }



  int SizeX() const { return times_x*bm.SizeX(); }

  int SizeY() const { return times_y*bm.SizeY(); }

  C Map(int x, int y) const

  {

    int xx = x % bm.SizeX();

    int yy = y % bm.SizeY();

    return bm.Map(xx,yy);

  }

private:

  Bitmap<C> &bm;

  int times_x, times_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::repeat_bitmap(BM orig, int xcount, int ycount)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  if (!chandle) return add_bitmap(e,0);

  RepeatBitmap<Color> *rep = new RepeatBitmap<Color>(*chandle->bm, xcount, ycount);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BlitBitmapClassMasked2 : public Bitmap<Color>

{

public:

  BlitBitmapClassMasked2(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y, Bitmap<bool> &mask) : bm(bm), bm2(bm2), x(x), y(y), mask(mask) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

    mask.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    bool val = false;

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	c2 = bm2.Map(xx-x, yy-y);

	val = mask.Map(xx-x,yy-y);

	}

    if (!val) {

      return c1;

    }

    else

      {

	return c2;

      }

  }  

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

  Bitmap<bool> &mask;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap_bb(BM bg, BM orig, int x, int y, BB mask)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  BoolBitmap *handle3 = find_bool_bitmap(e, mask);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  Bitmap<bool> *bm3 = handle3->bitmap;

  return add_color_bitmap(e, new BlitBitmapClassMasked2(*bm1, *bm2, x,y, *bm3));

}

class BlitBitmapClassMasked2 : public Bitmap<Color>

{

public:

  BlitBitmapClassMasked2(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y, Bitmap<bool> &mask) : bm(bm), bm2(bm2), x(x), y(y), mask(mask) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

    mask.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    bool val = false;

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	c2 = bm2.Map(xx-x, yy-y);

	val = mask.Map(xx-x,yy-y);

	}

    if (!val) {

      return c1;

    }

    else

      {

	return c2;

      }

  }  

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

  Bitmap<bool> &mask;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap_bb(BM bg, BM orig, int x, int y, BB mask)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  BoolBitmap *handle3 = find_bool_bitmap(e, mask);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  Bitmap<bool> *bm3 = handle3->bitmap;

  return add_color_bitmap(e, new BlitBitmapClassMasked2(*bm1, *bm2, x,y, *bm3));

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_y(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, false, true);



  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_y(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, false, true);



  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class TextureMaterial : public MaterialForward

{

public:

  TextureMaterial(GameApi::EveryApi &ev, GameApi::BM bm, float mix) : ev(ev), bm(bm), mix(mix) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::ML I17=ev.polygon_api.render_vertex_array_ml(ev,I16);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17, mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml_fade(ev,I16,pta, flip, start_time, end_time);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }



private:

  GameApi::EveryApi &ev;

  GameApi::BM bm;

  float mix;

};

EXPORT GameApi::MT GameApi::MaterialsApi::texture(EveryApi &ev, BM bm, float mix)

{

  return add_material(e, new TextureMaterial(ev, bm,mix));

}

class TextureMaterial : public MaterialForward

{

public:

  TextureMaterial(GameApi::EveryApi &ev, GameApi::BM bm, float mix) : ev(ev), bm(bm), mix(mix) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::ML I17=ev.polygon_api.render_vertex_array_ml(ev,I16);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17, mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml_fade(ev,I16,pta, flip, start_time, end_time);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }



private:

  GameApi::EveryApi &ev;

  GameApi::BM bm;

  float mix;

};

EXPORT GameApi::MT GameApi::MaterialsApi::texture(EveryApi &ev, BM bm, float mix)

{

  return add_material(e, new TextureMaterial(ev, bm,mix));

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind_inst(P p, PTS pts, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = mat2->mat_inst(p.id,pts.id);

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind_inst(P p, PTS pts, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = 0;

  if (mat2) {

    val = mat2->mat_inst(p.id,pts.id);

  }

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class QuadElem : public SingleForwardBoxableFaceCollection

{

public:

  QuadElem(Point p1, Point p2, Point p3, Point p4) : p1(p1), p2(p2), p3(p3), p4(p4) { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 1; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const

  {

    if (point==0) return p1;

    if (point==1) return p2;

    if (point==2) return p3;

    return p4;

  }

  virtual Vector PointNormal(int face, int point) const

  {

    Vector u_x = p2-p1;

    Vector u_y = p3-p1;

    return Vector::CrossProduct(u_x, u_y);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    if (point==0) {

      p.x = 0;

      p.y = 0;

    }

    if (point==1) {

      p.x = 1;

      p.y = 0;

    }

    if (point==2) {

      p.x = 1;

      p.y = 1;

    }

    if (point==3) {

      p.x = 0;

      p.y = 1;

    }



    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p1,p2,p3,p4;

};

EXPORT GameApi::P GameApi::PolygonApi::quad_z(float x1, float x2,

{

  Point pp1 = Point(x1,y1,z);

  Point pp2 = Point(x2,y1,z);

  Point pp3 = Point(x2,y2,z);

  Point pp4 = Point(x1,y2,z);

  FaceCollection *coll = new QuadElem(pp1,pp2,pp3,pp4);

  return add_polygon(e,coll,1);

}

class QuadElem : public SingleForwardBoxableFaceCollection

{

public:

  QuadElem(Point p1, Point p2, Point p3, Point p4) : p1(p1), p2(p2), p3(p3), p4(p4) { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 1; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const

  {

    if (point==0) return p1;

    if (point==1) return p2;

    if (point==2) return p3;

    return p4;

  }

  virtual Vector PointNormal(int face, int point) const

  {

    Vector u_x = p2-p1;

    Vector u_y = p3-p1;

    return Vector::CrossProduct(u_x, u_y);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    if (point==0) {

      p.x = 0;

      p.y = 0;

    }

    if (point==1) {

      p.x = 1;

      p.y = 0;

    }

    if (point==2) {

      p.x = 1;

      p.y = 1;

    }

    if (point==3) {

      p.x = 0;

      p.y = 1;

    }



    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p1,p2,p3,p4;

};

EXPORT GameApi::P GameApi::PolygonApi::quad_z(float x1, float x2,

{

  Point pp1 = Point(x1,y1,z);

  Point pp2 = Point(x2,y1,z);

  Point pp3 = Point(x2,y2,z);

  Point pp4 = Point(x1,y2,z);

  FaceCollection *coll = new QuadElem(pp1,pp2,pp3,pp4);

  return add_polygon(e,coll,1);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class LineCurve : public Curve<Point>

{

public:

  LineCurve(Point p1, Point p2) : p1(p1), p2(p2) {}

  float Size() const {

    return 1.0;

  }

  Point Index(float p) const

  {

    return Point((1.0-p)*Vector(p1) + p*Vector(p2));

  }

private:

  Point p1,p2;

};

EXPORT GameApi::C GameApi::CurveApi::line(PT p1, PT p2)

{

  Point *pp1 = find_point(e, p1);

  Point *pp2 = find_point(e, p2);

  return add_curve(e, new LineCurve(*pp1, *pp2));

}

class LineCurve : public Curve<Point>

{

public:

  LineCurve(Point p1, Point p2) : p1(p1), p2(p2) {}

  float Size() const {

    return 1.0;

  }

  Point Index(float p) const

  {

    return Point((1.0-p)*Vector(p1) + p*Vector(p2));

  }

private:

  Point p1,p2;

};

EXPORT GameApi::C GameApi::CurveApi::line(PT p1, PT p2)

{

  Point *pp1 = find_point(e, p1);

  Point *pp2 = find_point(e, p2);

  return add_curve(e, new LineCurve(*pp1, *pp2));

}

class SampleCurve : public PointsApiPoints

{

public:

  SampleCurve(Curve<Point> *c, int num_points) : c(c), num_points(num_points) { }

  int NumPoints() const { return num_points+1; }

  Point Pos(int i) const

  {

    float val = float(i);

    val/=float(num_points);

    val*=c->Size();

    return c->Index(val);

  }

  unsigned int Color(int i) const

  {

    return 0xffffffff;

  }

private:

  Curve<Point> *c;

  int num_points;

  float start,end;

};

EXPORT GameApi::PTS GameApi::CurveApi::sample(C curve, int num_samples)

{

  Curve<Point> *c = find_curve(e, curve);

  return add_points_api_points(e, new SampleCurve(c,num_samples));

}

class SampleMatrixCurve2 : public MatrixArray

{

public:

  SampleMatrixCurve2(Curve<Matrix> *c, int num_points) : c(c), num_points(num_points) { }

  int Size() const { return num_points; }

  Matrix Index(int i) const

  {

    float val = float(i);

    val/=float(num_points);

    val*=c->Size();

    return c->Index(val);

  }

  unsigned int Color(int i) const

  {

    return 0xffffffff;

  }

private:

  Curve<Matrix> *c;

  int num_points;

};

EXPORT GameApi::MS GameApi::MatrixCurveApi::sample(MC m_curve, int num)

{

  Curve<Matrix> *c = find_matrix_curve(e, m_curve);

  return add_matrix_array(e, new SampleMatrixCurve2(c,num));

}

class SampleCurve : public PointsApiPoints

{

public:

  SampleCurve(Curve<Point> *c, int num_points) : c(c), num_points(num_points) { }

  int NumPoints() const { return num_points+1; }

  Point Pos(int i) const

  {

    float val = float(i);

    val/=float(num_points);

    val*=c->Size();

    return c->Index(val);

  }

  unsigned int Color(int i) const

  {

    return 0xffffffff;

  }

private:

  Curve<Point> *c;

  int num_points;

  float start,end;

};

EXPORT GameApi::PTS GameApi::CurveApi::sample(C curve, int num_samples)

{

  Curve<Point> *c = find_curve(e, curve);

  return add_points_api_points(e, new SampleCurve(c,num_samples));

}

class SampleMatrixCurve2 : public MatrixArray

{

public:

  SampleMatrixCurve2(Curve<Matrix> *c, int num_points) : c(c), num_points(num_points) { }

  int Size() const { return num_points; }

  Matrix Index(int i) const

  {

    float val = float(i);

    val/=float(num_points);

    val*=c->Size();

    return c->Index(val);

  }

  unsigned int Color(int i) const

  {

    return 0xffffffff;

  }

private:

  Curve<Matrix> *c;

  int num_points;

};

EXPORT GameApi::MS GameApi::MatrixCurveApi::sample(MC m_curve, int num)

{

  Curve<Matrix> *c = find_matrix_curve(e, m_curve);

  return add_matrix_array(e, new SampleMatrixCurve2(c,num));

}

template<class C>

class ConstantBitmap : public Bitmap<C>

{

public:

  ConstantBitmap(C c, int x, int y) : c(c), x(x), y(y) { }

  void Prepare() { }



  int SizeX() const { return x; }

  int SizeY() const { return y; }

  C Map(int , int ) const

  {

    return c;

  }

private:

  C c;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::newbitmap(int sx, int sy, unsigned int color)

{

  ::Bitmap<Color> *b = new ConstantBitmap<Color>(Color(color), sx,sy);

  BitmapColorHandle *handle = new BitmapColorHandle;

  handle->bm = b;

  BM bm = add_bitmap(e, handle);

  return bm;

  

}

class ConstantBitmap_Color : public Bitmap<Color>

{

public:

  ConstantBitmap_Color(Color c, int x, int y) : c(c), x(x), y(y) { }

  void Prepare() { }



  int SizeX() const { return x; }

  int SizeY() const { return y; }

  Color Map(int , int ) const

  {

    return c;

  }

private:

  Color c;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::newbitmap(int sx, int sy, unsigned int color)

{

  ::Bitmap<Color> *b = new ConstantBitmap_Color(Color(color), sx,sy);

  BitmapColorHandle *handle = new BitmapColorHandle;

  handle->bm = b;

  BM bm = add_bitmap(e, handle);

  return bm;

  

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class GradientBitmap2 : public Bitmap<Color>

{

public:

  GradientBitmap2(Point2d pos_1, Point2d pos_2, unsigned int color_1, unsigned int color_2, int sx, int sy) : pos_1(pos_1), pos_2(pos_2), color_1(color_1), color_2(color_2), sx(sx), sy(sy) { 

    u_x = Point(pos_2.x, pos_2.y, 0.0)-Point(pos_1.x, pos_1.y, 0.0);

    v = u_x.Dist();

    v = v*v;

  }

  void Prepare() { }

  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  virtual Color Map(int x, int y) const

  {

    //std::cout << "gradient" << std::endl;

    Vector u = Point(x, y, 0.0)-Point(pos_1.x, pos_1.y, 0.0);

    float val = Vector::DotProduct(u, u_x);

    val /= v;

    //val /= v; 

    // now [0.0 .. 1.0]

    if (val<0.0) return 0;

    if (val>1.0) return 0;

    return Color(Color::CubicInterpolate(color_1, color_2, val));

  }



private:

  Point2d pos_1;

  Point2d pos_2;

  unsigned int color_1;

  unsigned int color_2;

  int sx,sy;

  Vector u_x;

  float v;

};

EXPORT GameApi::BM GameApi::BitmapApi::gradient(PT pos_1, PT pos_2, unsigned int color_1, unsigned int color_2, int sx, int sy)

{

  Point *pos_1a = find_point(e, pos_1);

  Point *pos_2a = find_point(e, pos_2);

  Point2d pos_1b = { pos_1a->x, pos_1a->y };

  Point2d pos_2b = { pos_2a->x, pos_2a->y };

  return add_color_bitmap2(e, new GradientBitmap2(pos_1b, pos_2b, color_1, color_2, sx,sy));

}

class GradientBitmap2 : public Bitmap<Color>

{

public:

  GradientBitmap2(Point2d pos_1, Point2d pos_2, unsigned int color_1, unsigned int color_2, int sx, int sy) : pos_1(pos_1), pos_2(pos_2), color_1(color_1), color_2(color_2), sx(sx), sy(sy) { 

    u_x = Point(pos_2.x, pos_2.y, 0.0)-Point(pos_1.x, pos_1.y, 0.0);

    v = u_x.Dist();

    v = v*v;

  }

  void Prepare() { }

  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  virtual Color Map(int x, int y) const

  {

    //std::cout << "gradient" << std::endl;

    Vector u = Point(x, y, 0.0)-Point(pos_1.x, pos_1.y, 0.0);

    float val = Vector::DotProduct(u, u_x);

    val /= v;

    //val /= v; 

    // now [0.0 .. 1.0]

    if (val<0.0) return 0;

    if (val>1.0) return 0;

    return Color(Color::CubicInterpolate(color_1, color_2, val));

  }



private:

  Point2d pos_1;

  Point2d pos_2;

  unsigned int color_1;

  unsigned int color_2;

  int sx,sy;

  Vector u_x;

  float v;

};

EXPORT GameApi::BM GameApi::BitmapApi::gradient(PT pos_1, PT pos_2, unsigned int color_1, unsigned int color_2, int sx, int sy)

{

  Point *pos_1a = find_point(e, pos_1);

  Point *pos_2a = find_point(e, pos_2);

  Point2d pos_1b = { pos_1a->x, pos_1a->y };

  Point2d pos_2b = { pos_2a->x, pos_2a->y };

  return add_color_bitmap2(e, new GradientBitmap2(pos_1b, pos_2b, color_1, color_2, sx,sy));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

class TriBoolBitmap : public Bitmap<bool>

{

public:

  TriBoolBitmap(Bitmap<bool> *bb, Point2d p0, Point2d p1, Point2d p2) : bb(bb), p0(p0), p1(p1), p2(p2) { }

  void Prepare() {

    float A = (-p1.y * p2.x + p0.y*(-p1.x + p2.x) + p0.x*(p1.y - p2.y) + p1.x*p2.y);

    if (A<=0.0f)

      {

	std::swap(p0,p2);

      }

  }

  int SizeX() const { return bb->SizeX(); }

  int SizeY() const { return bb->SizeY(); }

  bool Map(int x, int y) const

  {

    Point2d p = { float(x),float(y) };

    float s = (p0.y*p2.x - p0.x*p2.y + (p2.y-p0.y)*p.x + (p0.x-p2.x)*p.y);

    float t = (p0.x*p1.y - p0.y*p1.x + (p0.y-p1.y)*p.x + (p1.x-p0.x)*p.y);

    if (s<= 0.0 || t<=0.0) return false;

    float A = (-p1.y * p2.x + p0.y*(-p1.x+p2.x) + p0.x*(p1.y-p2.y) + p1.x*p2.y);

    return (s+t)<A;



  }

private:

  Bitmap<bool> *bb;

  Point2d p0,p1,p2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::tri(BB orig, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y)

{

  Bitmap<bool> *bb = find_bool_bitmap(e, orig)->bitmap;

  Point2d p1 = { p1_x, p1_y };

  Point2d p2 = { p2_x, p2_y };

  Point2d p3 = { p3_x, p3_y };

  return add_bool_bitmap(e, new TriBoolBitmap(bb, p1,p2,p3));

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_x(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, true, false);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_x(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, true, false);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

template<class C>

class RepeatBitmap : public Bitmap<C>

{

public:

  RepeatBitmap(Bitmap<C> &bm, int times_x, int times_y) : bm(bm), times_x(times_x), times_y(times_y) { }

  void Prepare() { bm.Prepare(); }



  int SizeX() const { return times_x*bm.SizeX(); }

  int SizeY() const { return times_y*bm.SizeY(); }

  C Map(int x, int y) const

  {

    int xx = x % bm.SizeX();

    int yy = y % bm.SizeY();

    return bm.Map(xx,yy);

  }

private:

  Bitmap<C> &bm;

  int times_x, times_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::repeat_bitmap(BM orig, int xcount, int ycount)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  if (!chandle) return add_bitmap(e,0);

  RepeatBitmap<Color> *rep = new RepeatBitmap<Color>(*chandle->bm, xcount, ycount);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

template<class C>

class RepeatBitmap : public Bitmap<C>

{

public:

  RepeatBitmap(Bitmap<C> &bm, int times_x, int times_y) : bm(bm), times_x(times_x), times_y(times_y) { }

  void Prepare() { bm.Prepare(); }



  int SizeX() const { return times_x*bm.SizeX(); }

  int SizeY() const { return times_y*bm.SizeY(); }

  C Map(int x, int y) const

  {

    int xx = x % bm.SizeX();

    int yy = y % bm.SizeY();

    return bm.Map(xx,yy);

  }

private:

  Bitmap<C> &bm;

  int times_x, times_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::repeat_bitmap(BM orig, int xcount, int ycount)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  if (!chandle) return add_bitmap(e,0);

  RepeatBitmap<Color> *rep = new RepeatBitmap<Color>(*chandle->bm, xcount, ycount);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class PartCircleBoolBitmap : public Bitmap<bool>

{

public:

  PartCircleBoolBitmap(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad) : sx(sx), sy(sy), x(x), y(y), sa(start_angle), ea(end_angle), sr(start_rad), er(end_rad) { }

  void Prepare() { }



  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  

  bool Map(int ax, int ay) const

  {

    ax-=x;

    ay-=y;

    float r = sqrtf(float(ax)*float(ax)+float(ay)*float(ay));

    float angle = atan2f(float(ay),float(ax));

    if (angle<sa || angle>ea) return false;

    if (r<sr || r>er) return false;

    return true;

  }

private:

  int sx,sy;

  float x,y;

  float sa,ea;

  float sr,er;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::part_circle(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad)

{

  return add_bool_bitmap(e, new PartCircleBoolBitmap(sx,sy, x,y,start_angle,end_angle, start_rad, end_rad));

}

class PartCircleBoolBitmap : public Bitmap<bool>

{

public:

  PartCircleBoolBitmap(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad) : sx(sx), sy(sy), x(x), y(y), sa(start_angle), ea(end_angle), sr(start_rad), er(end_rad) { }

  void Prepare() { }



  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  

  bool Map(int ax, int ay) const

  {

    ax-=x;

    ay-=y;

    float r = sqrtf(float(ax)*float(ax)+float(ay)*float(ay));

    float angle = atan2f(float(ay),float(ax));

    if (angle<sa || angle>ea) return false;

    if (r<sr || r>er) return false;

    return true;

  }

private:

  int sx,sy;

  float x,y;

  float sa,ea;

  float sr,er;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::part_circle(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad)

{

  return add_bool_bitmap(e, new PartCircleBoolBitmap(sx,sy, x,y,start_angle,end_angle, start_rad, end_rad));

}

class PartCircleBoolBitmap : public Bitmap<bool>

{

public:

  PartCircleBoolBitmap(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad) : sx(sx), sy(sy), x(x), y(y), sa(start_angle), ea(end_angle), sr(start_rad), er(end_rad) { }

  void Prepare() { }



  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  

  bool Map(int ax, int ay) const

  {

    ax-=x;

    ay-=y;

    float r = sqrtf(float(ax)*float(ax)+float(ay)*float(ay));

    float angle = atan2f(float(ay),float(ax));

    if (angle<sa || angle>ea) return false;

    if (r<sr || r>er) return false;

    return true;

  }

private:

  int sx,sy;

  float x,y;

  float sa,ea;

  float sr,er;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::part_circle(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad)

{

  return add_bool_bitmap(e, new PartCircleBoolBitmap(sx,sy, x,y,start_angle,end_angle, start_rad, end_rad));

}

class PartCircleBoolBitmap : public Bitmap<bool>

{

public:

  PartCircleBoolBitmap(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad) : sx(sx), sy(sy), x(x), y(y), sa(start_angle), ea(end_angle), sr(start_rad), er(end_rad) { }

  void Prepare() { }



  virtual int SizeX() const { return sx; }

  virtual int SizeY() const { return sy; }

  

  bool Map(int ax, int ay) const

  {

    ax-=x;

    ay-=y;

    float r = sqrtf(float(ax)*float(ax)+float(ay)*float(ay));

    float angle = atan2f(float(ay),float(ax));

    if (angle<sa || angle>ea) return false;

    if (r<sr || r>er) return false;

    return true;

  }

private:

  int sx,sy;

  float x,y;

  float sa,ea;

  float sr,er;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::part_circle(int sx, int sy, float x, float y, float start_angle, float end_angle, float start_rad, float end_rad)

{

  return add_bool_bitmap(e, new PartCircleBoolBitmap(sx,sy, x,y,start_angle,end_angle, start_rad, end_rad));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

class NotBitmap : public Bitmap<bool>

{

public:

  NotBitmap(Bitmap<bool> &bm) : bm(bm) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  bool Map(int x, int y) const { return !bm.Map(x,y); }

private:

  Bitmap<bool> &bm;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::not_bitmap(BB b)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, b)->bitmap;

  return add_bool_bitmap(e, new NotBitmap(*bm));

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

template<class C>

class RepeatBitmap : public Bitmap<C>

{

public:

  RepeatBitmap(Bitmap<C> &bm, int times_x, int times_y) : bm(bm), times_x(times_x), times_y(times_y) { }

  void Prepare() { bm.Prepare(); }



  int SizeX() const { return times_x*bm.SizeX(); }

  int SizeY() const { return times_y*bm.SizeY(); }

  C Map(int x, int y) const

  {

    int xx = x % bm.SizeX();

    int yy = y % bm.SizeY();

    return bm.Map(xx,yy);

  }

private:

  Bitmap<C> &bm;

  int times_x, times_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::repeat_bitmap(BM orig, int xcount, int ycount)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  if (!chandle) return add_bitmap(e,0);

  RepeatBitmap<Color> *rep = new RepeatBitmap<Color>(*chandle->bm, xcount, ycount);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

template<class C>

class RepeatBitmap : public Bitmap<C>

{

public:

  RepeatBitmap(Bitmap<C> &bm, int times_x, int times_y) : bm(bm), times_x(times_x), times_y(times_y) { }

  void Prepare() { bm.Prepare(); }



  int SizeX() const { return times_x*bm.SizeX(); }

  int SizeY() const { return times_y*bm.SizeY(); }

  C Map(int x, int y) const

  {

    int xx = x % bm.SizeX();

    int yy = y % bm.SizeY();

    return bm.Map(xx,yy);

  }

private:

  Bitmap<C> &bm;

  int times_x, times_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::repeat_bitmap(BM orig, int xcount, int ycount)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  if (!chandle) return add_bitmap(e,0);

  RepeatBitmap<Color> *rep = new RepeatBitmap<Color>(*chandle->bm, xcount, ycount);

  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class EquivalenceClassColorBitmap : public Bitmap<bool>

{

public:

  EquivalenceClassColorBitmap(Bitmap<Color> &bm, Color val) : bm(bm), val(val) { }

  void Prepare() { 

    bm.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual bool Map(int x, int y) const

  {

    Color c = bm.Map(x,y);

    return c.r==val.r && c.g==val.g && c.b == val.b;

  }

  

private:

  Bitmap<Color> &bm;

  Color val;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::from_bitmaps_color(BM bm, int r, int g, int b)

{

  BitmapHandle *handle = find_bitmap(e, bm);

  Bitmap<Color> *color_bm = find_color_bitmap(handle);

  return add_bool_bitmap(e,new EquivalenceClassColorBitmap(*color_bm, Color(r,g,b)));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BoolBitmapSprite : public Bitmap<bool>

{

public:

  BoolBitmapSprite(Bitmap<bool> &bg, Bitmap<bool> &sprite, float x, float y, float mult_x, float mult_y) : bg(bg), sprite(sprite), x(x), y(y), mult_x(mult_x), mult_y(mult_y) { }

  void Prepare() { bg.Prepare(); sprite.Prepare(); }



  int SizeX() const {return bg.SizeX(); }

  int SizeY() const {return bg.SizeY(); }

  bool Map(int mx, int my) const {

    float xx = mx - x;

    float yy = my - y;

    xx /= mult_x;

    yy /= mult_y; 

    if (xx >= 0.0 && xx < sprite.SizeX())

      if (yy >= 0.0 && yy < sprite.SizeY())

	{

	  bool b = sprite.Map(xx,yy);

	  if (!b) { return bg.Map(mx,my); }

	  return true;

	}

    return bg.Map(mx,my);

  }

private:

  Bitmap<bool> &bg;

  Bitmap<bool> &sprite;

  float x,y,mult_x, mult_y;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::sprite(BB bg, BB sprite, float x, float y, float mult_x, float mult_y)

{

  Bitmap<bool> *bg_1 = find_bool_bitmap(e,bg)->bitmap;

  Bitmap<bool> *sprite_1 = find_bool_bitmap(e,sprite)->bitmap;

  return add_bool_bitmap(e, new BoolBitmapSprite(*bg_1, *sprite_1, x, y, mult_x, mult_y));

}

class BlitBitmapClassMasked2 : public Bitmap<Color>

{

public:

  BlitBitmapClassMasked2(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y, Bitmap<bool> &mask) : bm(bm), bm2(bm2), x(x), y(y), mask(mask) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

    mask.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    bool val = false;

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	c2 = bm2.Map(xx-x, yy-y);

	val = mask.Map(xx-x,yy-y);

	}

    if (!val) {

      return c1;

    }

    else

      {

	return c2;

      }

  }  

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

  Bitmap<bool> &mask;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap_bb(BM bg, BM orig, int x, int y, BB mask)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  BoolBitmap *handle3 = find_bool_bitmap(e, mask);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  Bitmap<bool> *bm3 = handle3->bitmap;

  return add_color_bitmap(e, new BlitBitmapClassMasked2(*bm1, *bm2, x,y, *bm3));

}

class BlitBitmapClassMasked2 : public Bitmap<Color>

{

public:

  BlitBitmapClassMasked2(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y, Bitmap<bool> &mask) : bm(bm), bm2(bm2), x(x), y(y), mask(mask) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

    mask.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    bool val = false;

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	c2 = bm2.Map(xx-x, yy-y);

	val = mask.Map(xx-x,yy-y);

	}

    if (!val) {

      return c1;

    }

    else

      {

	return c2;

      }

  }  

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

  Bitmap<bool> &mask;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap_bb(BM bg, BM orig, int x, int y, BB mask)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  BoolBitmap *handle3 = find_bool_bitmap(e, mask);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  Bitmap<bool> *bm3 = handle3->bitmap;

  return add_color_bitmap(e, new BlitBitmapClassMasked2(*bm1, *bm2, x,y, *bm3));

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_y(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, false, true);



  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_y(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, false, true);



  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class TextureMaterial : public MaterialForward

{

public:

  TextureMaterial(GameApi::EveryApi &ev, GameApi::BM bm, float mix) : ev(ev), bm(bm), mix(mix) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::ML I17=ev.polygon_api.render_vertex_array_ml(ev,I16);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17, mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml_fade(ev,I16,pta, flip, start_time, end_time);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }



private:

  GameApi::EveryApi &ev;

  GameApi::BM bm;

  float mix;

};

EXPORT GameApi::MT GameApi::MaterialsApi::texture(EveryApi &ev, BM bm, float mix)

{

  return add_material(e, new TextureMaterial(ev, bm,mix));

}

class TextureMaterial : public MaterialForward

{

public:

  TextureMaterial(GameApi::EveryApi &ev, GameApi::BM bm, float mix) : ev(ev), bm(bm), mix(mix) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::ML I17=ev.polygon_api.render_vertex_array_ml(ev,I16);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17, mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml(ev,I16,pta);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P I10=p; //ev.polygon_api.cube(0.0,100.0,0.0,100.0,0.0,100.0);

    //GameApi::P I11=ev.polygon_api.texcoord_manual(I10,0,0,1,0,1,1,0,1);

    GameApi::VA I12=ev.polygon_api.create_vertex_array(I10,true);

    GameApi::BM I13=bm; //ev.bitmap_api.chessboard(20,20,2,2,ffffffff,ff888888);

    GameApi::TX I14=ev.texture_api.tex_bitmap(I13);

    GameApi::TXID I15=ev.texture_api.prepare(I14);

    GameApi::VA I16=ev.texture_api.bind(I12,I15);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    GameApi::ML I17=ev.materials_api.render_instanced2_ml_fade(ev,I16,pta, flip, start_time, end_time);

    GameApi::ML I18=ev.polygon_api.texture_shader(ev, I17,mix);

    return I18;

  }



private:

  GameApi::EveryApi &ev;

  GameApi::BM bm;

  float mix;

};

EXPORT GameApi::MT GameApi::MaterialsApi::texture(EveryApi &ev, BM bm, float mix)

{

  return add_material(e, new TextureMaterial(ev, bm,mix));

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind_inst(P p, PTS pts, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = mat2->mat_inst(p.id,pts.id);

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind_inst(P p, PTS pts, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = 0;

  if (mat2) {

    val = mat2->mat_inst(p.id,pts.id);

  }

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class DepthFunc : public MainLoopItem

{

public:

  DepthFunc(MainLoopItem *next, int i) : next(next),i(i) {}

  void Prepare() {next->Prepare(); }

  virtual void execute(MainLoopEnv &e) {

    switch(i) {

    case 0: g_low->ogl->glDepthFunc(Low_GL_LEQUAL); break;

    case 1: g_low->ogl->glDepthFunc(Low_GL_EQUAL); break;

    case 2: g_low->ogl->glDepthFunc(Low_GL_ALWAYS); break;

    case 3: g_low->ogl->glDepthFunc(Low_GL_LESS); break;

    case 4: g_low->ogl->glDepthFunc(Low_GL_GREATER); break;

    case 5: g_low->ogl->glDepthFunc(Low_GL_GEQUAL); break;

    };

    next->execute(e);

    g_low->ogl->glDepthFunc(Low_GL_LEQUAL);

  }

  virtual void handle_event(MainLoopEvent &e) {

    next->handle_event(e);

  }

  virtual int shader_id() { return next->shader_id(); }

private:

  MainLoopItem *next;

  int i;

};

GameApi::ML GameApi::MainLoopApi::depthfunc(ML ml, int val)

{

  MainLoopItem *next = find_main_loop(e,ml);

  return add_main_loop(e, new DepthFunc(next,val));

}

class DepthFunc : public MainLoopItem

{

public:

  DepthFunc(MainLoopItem *next, int i) : next(next),i(i) {}

  void Prepare() {next->Prepare(); }

  virtual void execute(MainLoopEnv &e) {

    switch(i) {

    case 0: g_low->ogl->glDepthFunc(Low_GL_LEQUAL); break;

    case 1: g_low->ogl->glDepthFunc(Low_GL_EQUAL); break;

    case 2: g_low->ogl->glDepthFunc(Low_GL_ALWAYS); break;

    case 3: g_low->ogl->glDepthFunc(Low_GL_LESS); break;

    case 4: g_low->ogl->glDepthFunc(Low_GL_GREATER); break;

    case 5: g_low->ogl->glDepthFunc(Low_GL_GEQUAL); break;

    };

    next->execute(e);

    g_low->ogl->glDepthFunc(Low_GL_LEQUAL);

  }

  virtual void handle_event(MainLoopEvent &e) {

    next->handle_event(e);

  }

  virtual int shader_id() { return next->shader_id(); }

private:

  MainLoopItem *next;

  int i;

};

GameApi::ML GameApi::MainLoopApi::depthfunc(ML ml, int val)

{

  MainLoopItem *next = find_main_loop(e,ml);

  return add_main_loop(e, new DepthFunc(next,val));

}

class BlendFunc : public MainLoopItem

{

public:

  BlendFunc(MainLoopItem *next, int i, int i2) : next(next),i(i),i2(i2) {}

  void Prepare() {next->Prepare(); }

  virtual void execute(MainLoopEnv &e) {

    Low_GLenum s = Low_GL_SRC_COLOR;

    Low_GLenum d = Low_GL_ONE_MINUS_SRC_COLOR;

    switch(i) {

    case 0: s=Low_GL_ZERO; break;

    case 1: s=Low_GL_ONE; break;

    case 2: s=Low_GL_SRC_COLOR; break;

    case 3: s=Low_GL_ONE_MINUS_SRC_COLOR; break;

    case 4: s=Low_GL_DST_COLOR; break;

    case 5: s=Low_GL_ONE_MINUS_DST_COLOR; break;

    case 6: s=Low_GL_SRC_ALPHA; break;

    case 7: s=Low_GL_ONE_MINUS_SRC_ALPHA; break;

    case 8: s=Low_GL_DST_ALPHA; break;

    case 9: s=Low_GL_ONE_MINUS_DST_ALPHA; break;

    case 10: s=Low_GL_CONSTANT_COLOR; break;

    case 11: s=Low_GL_ONE_MINUS_CONSTANT_COLOR; break;

    case 12: s=Low_GL_CONSTANT_ALPHA; break;

    };



    switch(i2) {

    case 0: d=Low_GL_ZERO; break;

    case 1: d=Low_GL_ONE; break;

    case 2: d=Low_GL_SRC_COLOR; break;

    case 3: d=Low_GL_ONE_MINUS_SRC_COLOR; break;

    case 4: d=Low_GL_DST_COLOR; break;

    case 5: d=Low_GL_ONE_MINUS_DST_COLOR; break;

    case 6: d=Low_GL_SRC_ALPHA; break;

    case 7: d=Low_GL_ONE_MINUS_SRC_ALPHA; break;

    case 8: d=Low_GL_DST_ALPHA; break;

    case 9: d=Low_GL_ONE_MINUS_DST_ALPHA; break;

    case 10: d=Low_GL_CONSTANT_COLOR; break;

    case 11: d=Low_GL_ONE_MINUS_CONSTANT_COLOR; break;

    case 12: d=Low_GL_CONSTANT_ALPHA; break;

    };

    g_low->ogl->glBlendFunc(s,d);

    next->execute(e);

    g_low->ogl->glBlendFunc(Low_GL_SRC_ALPHA,Low_GL_ONE_MINUS_SRC_ALPHA);

  }

  virtual void handle_event(MainLoopEvent &e) {

    next->handle_event(e);

  }

  virtual int shader_id() { return next->shader_id(); }

private:

  MainLoopItem *next;

  int i,i2;

};

GameApi::ML GameApi::MainLoopApi::blendfunc(ML ml, int val, int val2)

{

  MainLoopItem *next = find_main_loop(e,ml);

  return add_main_loop(e, new BlendFunc(next,val,val2));

}

class BlendFunc : public MainLoopItem

{

public:

  BlendFunc(MainLoopItem *next, int i, int i2) : next(next),i(i),i2(i2) {}

  void Prepare() {next->Prepare(); }

  virtual void execute(MainLoopEnv &e) {

    Low_GLenum s = Low_GL_SRC_COLOR;

    Low_GLenum d = Low_GL_ONE_MINUS_SRC_COLOR;

    switch(i) {

    case 0: s=Low_GL_ZERO; break;

    case 1: s=Low_GL_ONE; break;

    case 2: s=Low_GL_SRC_COLOR; break;

    case 3: s=Low_GL_ONE_MINUS_SRC_COLOR; break;

    case 4: s=Low_GL_DST_COLOR; break;

    case 5: s=Low_GL_ONE_MINUS_DST_COLOR; break;

    case 6: s=Low_GL_SRC_ALPHA; break;

    case 7: s=Low_GL_ONE_MINUS_SRC_ALPHA; break;

    case 8: s=Low_GL_DST_ALPHA; break;

    case 9: s=Low_GL_ONE_MINUS_DST_ALPHA; break;

    case 10: s=Low_GL_CONSTANT_COLOR; break;

    case 11: s=Low_GL_ONE_MINUS_CONSTANT_COLOR; break;

    case 12: s=Low_GL_CONSTANT_ALPHA; break;

    };



    switch(i2) {

    case 0: d=Low_GL_ZERO; break;

    case 1: d=Low_GL_ONE; break;

    case 2: d=Low_GL_SRC_COLOR; break;

    case 3: d=Low_GL_ONE_MINUS_SRC_COLOR; break;

    case 4: d=Low_GL_DST_COLOR; break;

    case 5: d=Low_GL_ONE_MINUS_DST_COLOR; break;

    case 6: d=Low_GL_SRC_ALPHA; break;

    case 7: d=Low_GL_ONE_MINUS_SRC_ALPHA; break;

    case 8: d=Low_GL_DST_ALPHA; break;

    case 9: d=Low_GL_ONE_MINUS_DST_ALPHA; break;

    case 10: d=Low_GL_CONSTANT_COLOR; break;

    case 11: d=Low_GL_ONE_MINUS_CONSTANT_COLOR; break;

    case 12: d=Low_GL_CONSTANT_ALPHA; break;

    };

    g_low->ogl->glBlendFunc(s,d);

    next->execute(e);

    g_low->ogl->glBlendFunc(Low_GL_SRC_ALPHA,Low_GL_ONE_MINUS_SRC_ALPHA);

  }

  virtual void handle_event(MainLoopEvent &e) {

    next->handle_event(e);

  }

  virtual int shader_id() { return next->shader_id(); }

private:

  MainLoopItem *next;

  int i,i2;

};

GameApi::ML GameApi::MainLoopApi::blendfunc(ML ml, int val, int val2)

{

  MainLoopItem *next = find_main_loop(e,ml);

  return add_main_loop(e, new BlendFunc(next,val,val2));

}

class ArrayMainLoop : public MainLoopItem

{

public:

  ArrayMainLoop(GameApi::Env &env, GameApi::EveryApi &ev, std::vector<MainLoopItem*> vec) : env(env), ev(ev), vec(vec) { }

  void Prepare() {

    int s = vec.size();

    for(int i=0;i<s;i++) vec[i]->Prepare();

  }

  void execute(MainLoopEnv &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	MainLoopEnv ee = e;



	// here's a block needed to distribute in_MV to different cases.

	int id = vec[i]->shader_id();

	if (id!=-1) {

	  GameApi::SH sh;

	  sh.id = id;

	  GameApi::M m = add_matrix2( env, e.in_MV);

	  ev.shader_api.use(sh);

	  ev.shader_api.set_var(sh, "in_MV", m);

	}

	vec[i]->execute(ee);

      }

  }

  void handle_event(MainLoopEvent &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	vec[i]->handle_event(e);

      }

  }

#if 0

  int shader_id() { 

    int s = vec.size();

    for(int i=s-1;i>=0;i--)

      {

	if (vec[i]->shader_id()!=-1) return vec[i]->shader_id();

      }

    return -1; 

  }

#endif

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  std::vector<MainLoopItem*> vec;

};

EXPORT GameApi::ML GameApi::MainLoopApi::array_ml(std::vector<ML> vec)

{

  std::vector<MainLoopItem*> vec2;

  int s = vec.size();

  for(int i=0;i<s;i++)

    {

      //std::cout << "array_ml id: " << vec[i].id << std::endl;

      vec2.push_back(find_main_loop(e,vec[i]));

    }

  return add_main_loop(e, new ArrayMainLoop(vec2));

}

class ArrayMainLoop : public MainLoopItem

{

public:

  ArrayMainLoop(GameApi::Env &env, GameApi::EveryApi &ev, std::vector<MainLoopItem*> vec) : env(env), ev(ev), vec(vec) { }

  void Prepare() {

    int s = vec.size();

    for(int i=0;i<s;i++) vec[i]->Prepare();

  }

  void execute(MainLoopEnv &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	MainLoopEnv ee = e;



	// here's a block needed to distribute in_MV to different cases.

	int id = vec[i]->shader_id();

	if (id!=-1) {

	  GameApi::SH sh;

	  sh.id = id;

	  GameApi::M m = add_matrix2( env, e.in_MV);

	  ev.shader_api.use(sh);

	  ev.shader_api.set_var(sh, "in_MV", m);

	}

	vec[i]->execute(ee);

      }

  }

  void handle_event(MainLoopEvent &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	vec[i]->handle_event(e);

      }

  }

#if 0

  int shader_id() { 

    int s = vec.size();

    for(int i=s-1;i>=0;i--)

      {

	if (vec[i]->shader_id()!=-1) return vec[i]->shader_id();

      }

    return -1; 

  }

#endif

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  std::vector<MainLoopItem*> vec;

};

EXPORT GameApi::ML GameApi::MainLoopApi::array_ml(GameApi::EveryApi &ev, std::vector<ML> vec)

{

  std::vector<MainLoopItem*> vec2;

  int s = vec.size();

  for(int i=0;i<s;i++)

    {

      //std::cout << "array_ml id: " << vec[i].id << std::endl;

      vec2.push_back(find_main_loop(e,vec[i]));

    }

  return add_main_loop(e, new ArrayMainLoop(e,ev,vec2));

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

class BitmapCircle : public Bitmap<bool>

{

public:

  BitmapCircle(Point2d center, float radius, int sx, int sy) : center(center), radius(radius), sx(sx), sy(sy) { }

  void Prepare() { }



  int SizeX() const { return sx; }

  int SizeY() const { return sy; }

  bool Map(int x, int y) const

  {

    float xx = x;

    float yy = y;

    xx -= center.x;

    yy -= center.y;

    return xx*xx+yy*yy < radius*radius;

  }

private:

  Point2d center;

  float radius;

  int sx, sy;

};

class OrBitmap : public Bitmap<bool>

{

public:

  OrBitmap(Bitmap<bool> &bm1, Bitmap<bool> &bm2) : bm1(bm1), bm2(bm2) { }

  void Prepare() { 

    bm1.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm1.SizeX(); }

  virtual int SizeY() const { return bm1.SizeY(); }

  bool Map(int x, int y) const { return bm1.Map(x,y)||bm2.Map(x,y); }

private:

  Bitmap<bool> &bm1;

  Bitmap<bool> &bm2;

};

EXPORT GameApi::BB GameApi::BoolBitmapApi::circle(BB bg, float center_x, float center_y, float radius)

{

  Bitmap<bool> *bm = find_bool_bitmap(e, bg)->bitmap;

  Point2d center = { center_x, center_y };

  Bitmap<bool> *circle = new BitmapCircle(center, radius, bm->SizeX(), bm->SizeY());

  Bitmap<bool> *orbitmap = new OrBitmap(*bm, *circle);

  ::EnvImpl *env = ::EnvImpl::Environment(&e);

  env->deletes.push_back(std::shared_ptr<void>(circle));

  return add_bool_bitmap(e, orbitmap);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

EXPORT GameApi::BM GameApi::BoolBitmapApi::to_bitmap(BB bools,

{

  return to_bitmap_1(bools, true_r, true_g, true_b, true_a,

		     false_r, false_g, false_b, false_a);

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class BlitBitmapClass : public Bitmap<Color>

{

public:

  BlitBitmapClass(Bitmap<Color> &bm, Bitmap<Color> &bm2, int x, int y) : bm(bm), bm2(bm2), x(x), y(y) { }

  void Prepare() { 

    bm.Prepare();

    bm2.Prepare();

  }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int xx, int yy) const

  {

    Color c1 = bm.Map(xx,yy);

    Color c2(0,0,0,0);

    if (xx>=x && xx<x+bm2.SizeX())

      if (yy>=y && yy<y+bm2.SizeY())

	{

	  //std::cout << "Test" << x <<" " << y << ":" << xx << " " << yy << std::endl;

	c2 = bm2.Map(xx-x, yy-y);

	}

    Color res = Color::Interpolate(c1,c2,c2.alpha/255.0);

    //std::cout << res.r << res.b << res.g << res.alpha << std::endl;

    return res;

  } 

private:

  Bitmap<Color> &bm;

  Bitmap<Color> &bm2;

  int x,y;

};

EXPORT GameApi::BM GameApi::BitmapApi::blitbitmap(BM bg, BM orig, int x, int y)

{

  BitmapHandle *handle = find_bitmap(e, bg);

  BitmapHandle *handle2 = find_bitmap(e, orig);

  Bitmap<Color> *bm1 = find_color_bitmap(handle);

  Bitmap<Color> *bm2 = find_color_bitmap(handle2);

  return add_color_bitmap(e, new BlitBitmapClass(*bm1, *bm2, x,y));

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_y(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, false, true);



  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

class FlipBitmap : public Bitmap<Color>

{

public:

  FlipBitmap(Bitmap<Color> &bm, bool x, bool y) : bm(bm), flip_x(x), flip_y(y) { }

  void Prepare() { bm.Prepare(); }



  virtual int SizeX() const { return bm.SizeX(); }

  virtual int SizeY() const { return bm.SizeY(); }

  virtual Color Map(int x, int y) const

  {

    int xx = x;

    int yy = y;

    if (flip_x) {

      xx = SizeX()-x-1;

    }

    if (flip_y) {

      yy = SizeY()-y-1;

    }

    return bm.Map(xx,yy);

  }



private:

  Bitmap<Color> &bm;

  bool flip_x, flip_y;

};

EXPORT GameApi::BM GameApi::BitmapApi::flip_y(BM orig)

{

  BitmapHandle *handle = find_bitmap(e, orig);

  BitmapColorHandle *chandle = dynamic_cast<BitmapColorHandle*>(handle);

  Bitmap<Color> *rep = new FlipBitmap(*chandle->bm, false, true);



  BitmapColorHandle *chandle2 = new BitmapColorHandle;

  chandle2->bm = rep;

  return add_bitmap(e,chandle2);

}

EXPORT GameApi::ML GameApi::PolygonApi::sprite_render(EveryApi &ev, BM bm, float start_x, float end_x, float start_y, float end_y, float z)

{

  GameApi::P I1=ev.polygon_api.quad_z(start_x,end_x,start_y,end_y,z);

  GameApi::BM I2=bm; 

  GameApi::MT I3=ev.materials_api.texture(ev,I2,1.0);

  GameApi::ML I4=ev.materials_api.bind(I1,I3);

  return I4;

}

EXPORT GameApi::ML GameApi::PolygonApi::sprite_render(EveryApi &ev, BM bm, float start_x, float end_x, float start_y, float end_y, float z)

{

  GameApi::P I1=ev.polygon_api.quad_z(start_x,end_x,start_y,end_y,z);

  GameApi::BM I2=bm; 

  GameApi::MT I3=ev.materials_api.texture(ev,I2,1.0);

  GameApi::ML I4=ev.materials_api.bind(I1,I3);

  return I4;

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::scale2(MN next, float sx, float sy, float sz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Scale(sx,sy,sz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::scale2(MN next, float sx, float sy, float sz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Scale(sx,sy,sz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class TurnTo2d : public MainLoopItem

{

public:

  TurnTo2d(GameApi::EveryApi &ev, MainLoopItem *next, Point2d tl, Point2d br) : ev(ev), next(next), tl(tl), br(br) {

  }

  void handle_event(MainLoopEvent &e)

  {

    next->handle_event(e);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &e)

  {

    static int inside_it = false;

    if (inside_it) { 

    g_low->ogl->glDisable(Low_GL_DEPTH_TEST);

      next->execute(e); 

    g_low->ogl->glEnable(Low_GL_DEPTH_TEST);

      return; 

    }



    inside_it = true;

    tl.x = e.screen_x;

    tl.y = e.screen_y;

    br.x = e.screen_width;

    br.y = e.screen_height;

    screen_x = ev.mainloop_api.get_screen_sx();

    screen_y = ev.mainloop_api.get_screen_sy();

    corner_x = ev.mainloop_api.get_corner_x();

    corner_y = ev.mainloop_api.get_corner_y();

    rect_sx = ev.mainloop_api.get_screen_rect_sx();

    rect_sy = ev.mainloop_api.get_screen_rect_sy();





  	float scale_x = 1.0;

	float scale_y = 1.0;

	if (g_event_screen_y!=-1) {

	  scale_x = float(g_event_screen_x)/float(screen_x);

	  scale_y = float(g_event_screen_y)/float(screen_y);

	}





    GameApi::SH sh = { e.sh_texture_2d };

    ev.shader_api.use(sh);

    ev.mainloop_api.switch_to_3d(false, sh, screen_x, screen_y);

    g_low->ogl->glViewport((corner_x+tl.x)*scale_x,(screen_y-corner_y-(br.y-tl.y))*scale_y, (br.x-tl.x)*scale_x, (br.y-tl.y)*scale_y);



    g_low->ogl->glDisable(Low_GL_DEPTH_TEST);

    //int old_sh = e.sh_texture;

    MainLoopEnv ee = e;

    ee.sh_texture = e.sh_texture_2d;

    ee.in_MV = Matrix::Identity();

    //ee.env = e.env * Matrix::Translate(0.0,0.0,400.0);

    ee.is_2d = true;

    next->execute(ee);

    //e.sh_texture = old_sh;

    g_low->ogl->glEnable(Low_GL_DEPTH_TEST);

    ev.mainloop_api.switch_to_3d(true, sh, screen_x, screen_y);

    g_low->ogl->glViewport(corner_x*scale_x,(screen_y-corner_y-rect_sy)*scale_y,rect_sx*scale_x, rect_sy*scale_y);

    inside_it = false;

  }



private:

  GameApi::EveryApi &ev;

  MainLoopItem *next;

  Point2d tl,br;

  int screen_x, screen_y;

  int corner_x, corner_y;

  int rect_sx, rect_sy;

};

EXPORT GameApi::ML GameApi::SpriteApi::turn_to_2d(EveryApi &ev, ML ml, float tl_x, float tl_y, float br_x, float br_y)

{

  MainLoopItem *next = find_main_loop(e, ml);

  Point2d tl = { tl_x, tl_y };

  Point2d br = { br_x, br_y };

  return add_main_loop(e, new TurnTo2d(ev,next,tl,br));

}

class TurnTo2d : public MainLoopItem

{

public:

  TurnTo2d(GameApi::EveryApi &ev, MainLoopItem *next, Point2d tl, Point2d br) : ev(ev), next(next), tl(tl), br(br) {

  }

  void handle_event(MainLoopEvent &e)

  {

    next->handle_event(e);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &e)

  {

    static int inside_it = false;

    if (inside_it) { 

    g_low->ogl->glDisable(Low_GL_DEPTH_TEST);

      next->execute(e); 

    g_low->ogl->glEnable(Low_GL_DEPTH_TEST);

      return; 

    }



    inside_it = true;

    tl.x = e.screen_x;

    tl.y = e.screen_y;

    br.x = e.screen_width;

    br.y = e.screen_height;

    screen_x = ev.mainloop_api.get_screen_sx();

    screen_y = ev.mainloop_api.get_screen_sy();

    corner_x = ev.mainloop_api.get_corner_x();

    corner_y = ev.mainloop_api.get_corner_y();

    rect_sx = ev.mainloop_api.get_screen_rect_sx();

    rect_sy = ev.mainloop_api.get_screen_rect_sy();





  	float scale_x = 1.0;

	float scale_y = 1.0;

	if (g_event_screen_y!=-1) {

	  scale_x = float(g_event_screen_x)/float(screen_x);

	  scale_y = float(g_event_screen_y)/float(screen_y);

	}





    GameApi::SH sh = { e.sh_texture_2d };

    ev.shader_api.use(sh);

    ev.mainloop_api.switch_to_3d(false, sh, screen_x, screen_y);

    g_low->ogl->glViewport((corner_x+tl.x)*scale_x,(screen_y-corner_y-(br.y-tl.y))*scale_y, (br.x-tl.x)*scale_x, (br.y-tl.y)*scale_y);



    g_low->ogl->glDisable(Low_GL_DEPTH_TEST);

    //int old_sh = e.sh_texture;

    MainLoopEnv ee = e;

    ee.sh_texture = e.sh_texture_2d;

    ee.in_MV = Matrix::Identity();

    //ee.env = e.env * Matrix::Translate(0.0,0.0,400.0);

    ee.is_2d = true;

    next->execute(ee);

    //e.sh_texture = old_sh;

    g_low->ogl->glEnable(Low_GL_DEPTH_TEST);

    ev.mainloop_api.switch_to_3d(true, sh, screen_x, screen_y);

    g_low->ogl->glViewport(corner_x*scale_x,(screen_y-corner_y-rect_sy)*scale_y,rect_sx*scale_x, rect_sy*scale_y);

    inside_it = false;

  }



private:

  GameApi::EveryApi &ev;

  MainLoopItem *next;

  Point2d tl,br;

  int screen_x, screen_y;

  int corner_x, corner_y;

  int rect_sx, rect_sy;

};

EXPORT GameApi::ML GameApi::SpriteApi::turn_to_2d(EveryApi &ev, ML ml, float tl_x, float tl_y, float br_x, float br_y)

{

  MainLoopItem *next = find_main_loop(e, ml);

  Point2d tl = { tl_x, tl_y };

  Point2d br = { br_x, br_y };

  return add_main_loop(e, new TurnTo2d(ev,next,tl,br));

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(float start_x, float end_x,

{

  Point p111(start_x, start_y, start_z);

  Point p112(start_x, start_y, end_z);

  Point p121(start_x, end_y, start_z);

  Point p122(start_x, end_y, end_z);

  Point p211(end_x, start_y, start_z);

  Point p212(end_x, start_y, end_z);

  Point p221(end_x, end_y, start_z);

  Point p222(end_x, end_y, end_z);

  

  FaceCollection *coll = new CubeElem(p111,p112,p121,p122,

				      p211,p212,p221,p222);

  return add_polygon2(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(PT *p)

{

  Point *p111 = find_point(e,p[0]);

  Point *p112 = find_point(e,p[1]);

  Point *p121 = find_point(e,p[2]);

  Point *p122 = find_point(e,p[3]);

  Point *p211 = find_point(e,p[4]);

  Point *p212 = find_point(e,p[5]);

  Point *p221 = find_point(e,p[6]);

  Point *p222 = find_point(e,p[7]);

  

  FaceCollection *coll = new CubeElem(*p111,*p112,*p121,*p122,

				      *p211,*p212,*p221,*p222);

  return add_polygon(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(float start_x, float end_x,

{

  Point p111(start_x, start_y, start_z);

  Point p112(start_x, start_y, end_z);

  Point p121(start_x, end_y, start_z);

  Point p122(start_x, end_y, end_z);

  Point p211(end_x, start_y, start_z);

  Point p212(end_x, start_y, end_z);

  Point p221(end_x, end_y, start_z);

  Point p222(end_x, end_y, end_z);

  

  FaceCollection *coll = new CubeElem(p111,p112,p121,p122,

				      p211,p212,p221,p222);

  return add_polygon2(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(PT *p)

{

  Point *p111 = find_point(e,p[0]);

  Point *p112 = find_point(e,p[1]);

  Point *p121 = find_point(e,p[2]);

  Point *p122 = find_point(e,p[3]);

  Point *p211 = find_point(e,p[4]);

  Point *p212 = find_point(e,p[5]);

  Point *p221 = find_point(e,p[6]);

  Point *p222 = find_point(e,p[7]);

  

  FaceCollection *coll = new CubeElem(*p111,*p112,*p121,*p122,

				      *p211,*p212,*p221,*p222);

  return add_polygon(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(float start_x, float end_x,

{

  Point p111(start_x, start_y, start_z);

  Point p112(start_x, start_y, end_z);

  Point p121(start_x, end_y, start_z);

  Point p122(start_x, end_y, end_z);

  Point p211(end_x, start_y, start_z);

  Point p212(end_x, start_y, end_z);

  Point p221(end_x, end_y, start_z);

  Point p222(end_x, end_y, end_z);

  

  FaceCollection *coll = new CubeElem(p111,p112,p121,p122,

				      p211,p212,p221,p222);

  return add_polygon2(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(PT *p)

{

  Point *p111 = find_point(e,p[0]);

  Point *p112 = find_point(e,p[1]);

  Point *p121 = find_point(e,p[2]);

  Point *p122 = find_point(e,p[3]);

  Point *p211 = find_point(e,p[4]);

  Point *p212 = find_point(e,p[5]);

  Point *p221 = find_point(e,p[6]);

  Point *p222 = find_point(e,p[7]);

  

  FaceCollection *coll = new CubeElem(*p111,*p112,*p121,*p122,

				      *p211,*p212,*p221,*p222);

  return add_polygon(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(float start_x, float end_x,

{

  Point p111(start_x, start_y, start_z);

  Point p112(start_x, start_y, end_z);

  Point p121(start_x, end_y, start_z);

  Point p122(start_x, end_y, end_z);

  Point p211(end_x, start_y, start_z);

  Point p212(end_x, start_y, end_z);

  Point p221(end_x, end_y, start_z);

  Point p222(end_x, end_y, end_z);

  

  FaceCollection *coll = new CubeElem(p111,p112,p121,p122,

				      p211,p212,p221,p222);

  return add_polygon2(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(PT *p)

{

  Point *p111 = find_point(e,p[0]);

  Point *p112 = find_point(e,p[1]);

  Point *p121 = find_point(e,p[2]);

  Point *p122 = find_point(e,p[3]);

  Point *p211 = find_point(e,p[4]);

  Point *p212 = find_point(e,p[5]);

  Point *p221 = find_point(e,p[6]);

  Point *p222 = find_point(e,p[7]);

  

  FaceCollection *coll = new CubeElem(*p111,*p112,*p121,*p122,

				      *p211,*p212,*p221,*p222);

  return add_polygon(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(float start_x, float end_x,

{

  Point p111(start_x, start_y, start_z);

  Point p112(start_x, start_y, end_z);

  Point p121(start_x, end_y, start_z);

  Point p122(start_x, end_y, end_z);

  Point p211(end_x, start_y, start_z);

  Point p212(end_x, start_y, end_z);

  Point p221(end_x, end_y, start_z);

  Point p222(end_x, end_y, end_z);

  

  FaceCollection *coll = new CubeElem(p111,p112,p121,p122,

				      p211,p212,p221,p222);

  return add_polygon2(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(PT *p)

{

  Point *p111 = find_point(e,p[0]);

  Point *p112 = find_point(e,p[1]);

  Point *p121 = find_point(e,p[2]);

  Point *p122 = find_point(e,p[3]);

  Point *p211 = find_point(e,p[4]);

  Point *p212 = find_point(e,p[5]);

  Point *p221 = find_point(e,p[6]);

  Point *p222 = find_point(e,p[7]);

  

  FaceCollection *coll = new CubeElem(*p111,*p112,*p121,*p122,

				      *p211,*p212,*p221,*p222);

  return add_polygon(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(float start_x, float end_x,

{

  Point p111(start_x, start_y, start_z);

  Point p112(start_x, start_y, end_z);

  Point p121(start_x, end_y, start_z);

  Point p122(start_x, end_y, end_z);

  Point p211(end_x, start_y, start_z);

  Point p212(end_x, start_y, end_z);

  Point p221(end_x, end_y, start_z);

  Point p222(end_x, end_y, end_z);

  

  FaceCollection *coll = new CubeElem(p111,p112,p121,p122,

				      p211,p212,p221,p222);

  return add_polygon2(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(PT *p)

{

  Point *p111 = find_point(e,p[0]);

  Point *p112 = find_point(e,p[1]);

  Point *p121 = find_point(e,p[2]);

  Point *p122 = find_point(e,p[3]);

  Point *p211 = find_point(e,p[4]);

  Point *p212 = find_point(e,p[5]);

  Point *p221 = find_point(e,p[6]);

  Point *p222 = find_point(e,p[7]);

  

  FaceCollection *coll = new CubeElem(*p111,*p112,*p121,*p122,

				      *p211,*p212,*p221,*p222);

  return add_polygon(e, coll,1);  

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

class ConeElem : public SingleForwardBoxableFaceCollection

{

public:

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2);

  ConeElem(int numfaces, Point p1, Point p2, float rad1, float rad2, Plane pl1_, Plane pl2_);

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return numfaces; }

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    Point2d p;

    p.x = 0;

    p.y = 0;

    return p;

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    return false;

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Point p;

    switch(point)

      {

      case 0: case 3: p=p1; break;

      case 1: case 2: p=p2; break;

      };

    Vector v = FacePoint(face, point);

    Vector center = p;

    return v-center;

  }

private:

  //Matrix box;

  int numfaces;

  Point p1, p2;

  float rad1, rad2;

  LineProperties lp;

  NormalizedPlane pl1, pl2;

  Point2d pp = { 0.0, 0.0 };

  Circle c1,c2;

  PlaneCurveIn3d curve1,curve2;

  SampleCurve3d sample1, sample2;

};

EXPORT GameApi::P GameApi::PolygonApi::cone(int numfaces, PT p1, PT p2, float rad1, float rad2)

{

    Point *pp1 = find_point(e,p1);

    Point *pp2 = find_point(e,p2);

    FaceCollection *coll = new ConeElem(numfaces, *pp1, *pp2, rad1, rad2);

    return add_polygon(e, coll,1);

}

class OrElem2 : public FaceCollection

{

public:

  OrElem2(FaceCollection *coll1, FaceCollection *coll2) : coll1(coll1), coll2(coll2),s(0),s2(0) { }

  void Prepare() {

    coll1->Prepare();

    coll2->Prepare();

    s = coll1->NumFaces();

    s2 = coll1->NumTextures();

  }

  int get_index(int face) const

  {

    if (face<s) { return face; }

    return face-s;

  }

  FaceCollection *get_elem(int face) const {

    if (face<s) return coll1;

    return coll2;

  }

  int get_index2(int face) const

  {

    if (face<s2) { return face; }

    return face-s2;

  }

  FaceCollection *get_elem2(int face) const {

    if (face<s2) return coll1;

    return coll2;

  }

  virtual int NumFaces() const { return coll1->NumFaces()+coll2->NumFaces(); }

  virtual int NumPoints(int face) const

  {

    return get_elem(face)->NumPoints(get_index(face));

  }

  virtual Point FacePoint(int face, int point) const

  {

    return get_elem(face)->FacePoint(get_index(face), point);

  }

  virtual Vector PointNormal(int face, int point) const

  {

    return get_elem(face)->PointNormal(get_index(face), point);

  }

  virtual float Attrib(int face, int point, int id) const

  {

    return get_elem(face)->Attrib(get_index(face), point,id);

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return get_elem(face)->AttribI(get_index(face), point,id);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return get_elem(face)->Color(get_index(face), point);

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    return get_elem(face)->TexCoord(get_index(face), point);

  }

  virtual float TexCoord3(int face, int point) const {

    return get_elem(face)->TexCoord3(get_index(face), point);



  }

  virtual Point EndFacePoint(int face, int point) const {

    return get_elem(face)->EndFacePoint(get_index(face), point);

  }

  virtual Vector EndPointNormal(int face, int point) const {

    return get_elem(face)->EndPointNormal(get_index(face), point);

  }

  virtual float EndAttrib(int face, int point, int id) const {

    return get_elem(face)->EndAttrib(get_index(face), point,id);

  }

  virtual int EndAttribI(int face, int point, int id) const {

    return get_elem(face)->EndAttribI(get_index(face), point,id);

  }

  virtual unsigned int EndColor(int face, int point) const {

    return get_elem(face)->EndColor(get_index(face), point);

  }

  virtual Point2d EndTexCoord(int face, int point) const {

    return get_elem(face)->EndTexCoord(get_index(face), point);

  }

  virtual float EndTexCoord3(int face, int point) const {

    return get_elem(face)->EndTexCoord3(get_index(face), point);

  }



  virtual float Duration() const { return 1.0; }



  virtual int NumTextures() const { return coll1->NumTextures() + coll2->NumTextures(); }

  virtual void GenTexture(int num) {

    get_elem2(num)->GenTexture(get_index2(num));

  }

  virtual BufferRef TextureBuf(int num) const {

    return get_elem2(num)->TextureBuf(get_index2(num));

  }

  virtual int FaceTexture(int face) const {

    return get_elem(face)->FaceTexture(get_index(face));



  }



private:

  FaceCollection *coll1;

  FaceCollection *coll2;

  int s;

  int s2;

};

EXPORT GameApi::P GameApi::PolygonApi::or_elem(P p1, P p2)

{

  FaceCollection *pp1 = find_facecoll(e, p1);

  FaceCollection *pp2 = find_facecoll(e, p2);

  //OrElem<FaceCollection> *coll = new OrElem<FaceCollection>;

  //coll->push_back(pp1);

  //coll->push_back(pp2);

  //coll->update_faces_cache();

  FaceCollection *coll = new OrElem2(pp1,pp2);

  return add_polygon2(e, coll,1);

}

class OrElem2 : public FaceCollection

{

public:

  OrElem2(FaceCollection *coll1, FaceCollection *coll2) : coll1(coll1), coll2(coll2),s(0),s2(0) { }

  void Prepare() {

    coll1->Prepare();

    coll2->Prepare();

    s = coll1->NumFaces();

    s2 = coll1->NumTextures();

  }

  int get_index(int face) const

  {

    if (face<s) { return face; }

    return face-s;

  }

  FaceCollection *get_elem(int face) const {

    if (face<s) return coll1;

    return coll2;

  }

  int get_index2(int face) const

  {

    if (face<s2) { return face; }

    return face-s2;

  }

  FaceCollection *get_elem2(int face) const {

    if (face<s2) return coll1;

    return coll2;

  }

  virtual int NumFaces() const { return coll1->NumFaces()+coll2->NumFaces(); }

  virtual int NumPoints(int face) const

  {

    return get_elem(face)->NumPoints(get_index(face));

  }

  virtual Point FacePoint(int face, int point) const

  {

    return get_elem(face)->FacePoint(get_index(face), point);

  }

  virtual Vector PointNormal(int face, int point) const

  {

    return get_elem(face)->PointNormal(get_index(face), point);

  }

  virtual float Attrib(int face, int point, int id) const

  {

    return get_elem(face)->Attrib(get_index(face), point,id);

  }

  virtual int AttribI(int face, int point, int id) const

  {

    return get_elem(face)->AttribI(get_index(face), point,id);

  }

  virtual unsigned int Color(int face, int point) const

  {

    return get_elem(face)->Color(get_index(face), point);

  }

  virtual Point2d TexCoord(int face, int point) const

  {

    return get_elem(face)->TexCoord(get_index(face), point);

  }

  virtual float TexCoord3(int face, int point) const {

    return get_elem(face)->TexCoord3(get_index(face), point);



  }

  virtual Point EndFacePoint(int face, int point) const {

    return get_elem(face)->EndFacePoint(get_index(face), point);

  }

  virtual Vector EndPointNormal(int face, int point) const {

    return get_elem(face)->EndPointNormal(get_index(face), point);

  }

  virtual float EndAttrib(int face, int point, int id) const {

    return get_elem(face)->EndAttrib(get_index(face), point,id);

  }

  virtual int EndAttribI(int face, int point, int id) const {

    return get_elem(face)->EndAttribI(get_index(face), point,id);

  }

  virtual unsigned int EndColor(int face, int point) const {

    return get_elem(face)->EndColor(get_index(face), point);

  }

  virtual Point2d EndTexCoord(int face, int point) const {

    return get_elem(face)->EndTexCoord(get_index(face), point);

  }

  virtual float EndTexCoord3(int face, int point) const {

    return get_elem(face)->EndTexCoord3(get_index(face), point);

  }



  virtual float Duration() const { return 1.0; }



  virtual int NumTextures() const { return coll1->NumTextures() + coll2->NumTextures(); }

  virtual void GenTexture(int num) {

    get_elem2(num)->GenTexture(get_index2(num));

  }

  virtual BufferRef TextureBuf(int num) const {

    return get_elem2(num)->TextureBuf(get_index2(num));

  }

  virtual int FaceTexture(int face) const {

    return get_elem(face)->FaceTexture(get_index(face));



  }



private:

  FaceCollection *coll1;

  FaceCollection *coll2;

  int s;

  int s2;

};

EXPORT GameApi::P GameApi::PolygonApi::or_elem(P p1, P p2)

{

  FaceCollection *pp1 = find_facecoll(e, p1);

  FaceCollection *pp2 = find_facecoll(e, p2);

  //OrElem<FaceCollection> *coll = new OrElem<FaceCollection>;

  //coll->push_back(pp1);

  //coll->push_back(pp2);

  //coll->update_faces_cache();

  FaceCollection *coll = new OrElem2(pp1,pp2);

  return add_polygon2(e, coll,1);

}

GameApi::P GameApi::PolygonApi::disc(EveryApi &ev, int numfaces, float center_x, float center_y, float center_z, float normal_x, float normal_y, float normal_z, float radius)

{

  PT center = ev.point_api.point(center_x, center_y, center_z);

  V normal = ev.vector_api.vector(normal_x, normal_y, normal_z);

  V tiny_normal = ev.vector_api.mul(normal, 0.001);

  PT center_2 = ev.point_api.move(center, tiny_normal);

  return ev.polygon_api.cone(numfaces, center, center_2, radius, 0.0001);

}

GameApi::P GameApi::PolygonApi::disc(EveryApi &ev, int numfaces, float center_x, float center_y, float center_z, float normal_x, float normal_y, float normal_z, float radius)

{

  PT center = ev.point_api.point(center_x, center_y, center_z);

  V normal = ev.vector_api.vector(normal_x, normal_y, normal_z);

  V tiny_normal = ev.vector_api.mul(normal, 0.001);

  PT center_2 = ev.point_api.move(center, tiny_normal);

  return ev.polygon_api.cone(numfaces, center, center_2, radius, 0.0001);

}

GameApi::P GameApi::PolygonApi::disc(EveryApi &ev, int numfaces, float center_x, float center_y, float center_z, float normal_x, float normal_y, float normal_z, float radius)

{

  PT center = ev.point_api.point(center_x, center_y, center_z);

  V normal = ev.vector_api.vector(normal_x, normal_y, normal_z);

  V tiny_normal = ev.vector_api.mul(normal, 0.001);

  PT center_2 = ev.point_api.move(center, tiny_normal);

  return ev.polygon_api.cone(numfaces, center, center_2, radius, 0.0001);

}

GameApi::P GameApi::PolygonApi::disc(EveryApi &ev, int numfaces, float center_x, float center_y, float center_z, float normal_x, float normal_y, float normal_z, float radius)

{

  PT center = ev.point_api.point(center_x, center_y, center_z);

  V normal = ev.vector_api.vector(normal_x, normal_y, normal_z);

  V tiny_normal = ev.vector_api.mul(normal, 0.001);

  PT center_2 = ev.point_api.move(center, tiny_normal);

  return ev.polygon_api.cone(numfaces, center, center_2, radius, 0.0001);

}

EXPORT GameApi::P GameApi::PolygonApi::or_array2(std::vector<P> vec)

{

  if (vec.size()>0)

    return or_array(&vec[0],vec.size());

  return empty();

}

EXPORT GameApi::P GameApi::PolygonApi::or_array2(std::vector<P> vec)

{

  if (vec.size()>0)

    return or_array(&vec[0],vec.size());

  return empty();

}

class RecalculateNormals : public ForwardFaceCollection

{

public:

  RecalculateNormals(FaceCollection &coll) : ForwardFaceCollection(coll) { }

  Vector PointNormal(int face, int point) const 

  { 

    Point p1 = FacePoint(face, 0);

    Point p2 = FacePoint(face, 1);

    Point p3 = FacePoint(face, 2);

    Vector v = -Vector::CrossProduct(p2-p1,p3-p1);

    return v / v.Dist();

  }

};

EXPORT GameApi::P GameApi::PolygonApi::recalculate_normals(P orig)

{

  FaceCollection *coll = find_facecoll(e, orig);

  FaceCollection *coll2 = new RecalculateNormals(*coll);

  return add_polygon(e, coll2, 1);

}

class RecalculateNormals : public ForwardFaceCollection

{

public:

  RecalculateNormals(FaceCollection &coll) : ForwardFaceCollection(coll) { }

  Vector PointNormal(int face, int point) const 

  { 

    Point p1 = FacePoint(face, 0);

    Point p2 = FacePoint(face, 1);

    Point p3 = FacePoint(face, 2);

    Vector v = -Vector::CrossProduct(p2-p1,p3-p1);

    return v / v.Dist();

  }

};

EXPORT GameApi::P GameApi::PolygonApi::recalculate_normals(P orig)

{

  FaceCollection *coll = find_facecoll(e, orig);

  FaceCollection *coll2 = new RecalculateNormals(*coll);

  return add_polygon(e, coll2, 1);

}

class SmoothNormals2 : public ForwardFaceCollection

{

public:

  SmoothNormals2(FaceCollection *coll) : ForwardFaceCollection(*coll), coll(coll) { }

  struct Data { Data() : v{0.01,0.01,0.01}, count(0) { } Vector v; int count; };

  

  virtual void Prepare() {

    coll->Prepare();



    int s = coll->NumFaces();

    //int count = 0;

    for(int i=0;i<s;i++) {

      int s2 = coll->NumPoints(i);

      for(int j=0;j<s2;j++) {

	Point p = coll->FacePoint(i,j);

	Point p1 = coll->FacePoint(i,(j+1)%s2);

	Point p2 = coll->FacePoint(i,(j+2)%s2);

	Point p3 = coll->FacePoint(i,(j+3)%s2);

	//Point p4 = coll->FacePoint(i,(j+3)%s2);

	//float area = Vector::DotProduct(coll->PointNormal(i,j),Vector::CrossProduct(p1,p2) + Vector::CrossProduct(p2,p3) + Vector::CrossProduct(p3,p4))/2.0;

	float a1 = Vector::Angle(p2-p1,p3-p1);

	//float a2 = Vector::Angle(p3-p2,p1-p2);

	//float a3 = Vector::Angle(p1-p3,p2-p3);

	Data &v = mymap[key(p)];

	Vector n = coll->PointNormal(i,j);

	if (std::isnormal(a1)) {

	  v.v+=n*a1;

	//v.v+=a2*n;

	//v.v+=a3*n;

	  v.count++;

	}

      }

    }

  }

  std::tuple<int,int,int> key(Point p) const

  {

    return std::make_tuple(int(p.x*100.0),int(p.y*100.0),int(p.z*100.0));

  }

  virtual Vector PointNormal(int face, int point) const

  {

    Point p = coll->FacePoint(face,point);

    Data v = mymap[key(p)];

    if (v.count==1) { return coll->PointNormal(face,point); }

    if (v.count==0) v.count++;

    Vector vv = v.v/float(v.count);

    float dist = vv.Dist();

    //if (dist<0.01) { vv=Vector(1.0,0.0,0.0); dist=1.0; }

    return (vv)/dist;

  }

private:

  FaceCollection *coll;

  mutable std::map<std::tuple<int,int,int>, Data> mymap;

};

GameApi::P GameApi::PolygonApi::smooth_normals2(P p) {

GameApi::P GameApi::PolygonApi::smooth_normals2(P p) {

  FaceCollection *coll = find_facecoll(e, p);

  return add_polygon2(e, new SmoothNormals2(coll),1);

}

class SmoothNormals2 : public ForwardFaceCollection

{

public:

  SmoothNormals2(FaceCollection *coll) : ForwardFaceCollection(*coll), coll(coll) { }

  struct Data { Data() : v{0.01,0.01,0.01}, count(0) { } Vector v; int count; };

  

  virtual void Prepare() {

    coll->Prepare();



    int s = coll->NumFaces();

    //int count = 0;

    for(int i=0;i<s;i++) {

      int s2 = coll->NumPoints(i);

      for(int j=0;j<s2;j++) {

	Point p = coll->FacePoint(i,j);

	Point p1 = coll->FacePoint(i,(j+1)%s2);

	Point p2 = coll->FacePoint(i,(j+2)%s2);

	Point p3 = coll->FacePoint(i,(j+3)%s2);

	//Point p4 = coll->FacePoint(i,(j+3)%s2);

	//float area = Vector::DotProduct(coll->PointNormal(i,j),Vector::CrossProduct(p1,p2) + Vector::CrossProduct(p2,p3) + Vector::CrossProduct(p3,p4))/2.0;

	float a1 = Vector::Angle(p2-p1,p3-p1);

	//float a2 = Vector::Angle(p3-p2,p1-p2);

	//float a3 = Vector::Angle(p1-p3,p2-p3);

	Data &v = mymap[key(p)];

	Vector n = coll->PointNormal(i,j);

	if (std::isnormal(a1)) {

	  v.v+=n*a1;

	//v.v+=a2*n;

	//v.v+=a3*n;

	  v.count++;

	}

      }

    }

  }

  std::tuple<int,int,int> key(Point p) const

  {

    return std::make_tuple(int(p.x*100.0),int(p.y*100.0),int(p.z*100.0));

  }

  virtual Vector PointNormal(int face, int point) const

  {

    Point p = coll->FacePoint(face,point);

    Data v = mymap[key(p)];

    if (v.count==1) { return coll->PointNormal(face,point); }

    if (v.count==0) v.count++;

    Vector vv = v.v/float(v.count);

    float dist = vv.Dist();

    //if (dist<0.01) { vv=Vector(1.0,0.0,0.0); dist=1.0; }

    return (vv)/dist;

  }

private:

  FaceCollection *coll;

  mutable std::map<std::tuple<int,int,int>, Data> mymap;

};

GameApi::P GameApi::PolygonApi::smooth_normals2(P p) {

GameApi::P GameApi::PolygonApi::smooth_normals2(P p) {

  FaceCollection *coll = find_facecoll(e, p);

  return add_polygon2(e, new SmoothNormals2(coll),1);

}

class PhongMaterial : public MaterialForward

{

public:

  PhongMaterial(GameApi::EveryApi &ev, Material *next, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow) : ev(ev), next(next), light_dir_x(light_dir_x), light_dir_y(light_dir_y), light_dir_z(light_dir_z), ambient(ambient), highlight(highlight), pow(pow) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat(p0.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst(p0.id, pts.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst2(p0.id, pta.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst_fade(p0.id, pts.id, flip, start_time, end_time);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float light_dir_x, light_dir_y, light_dir_z;

  unsigned int ambient, highlight;

  float pow;

};

EXPORT GameApi::MT GameApi::MaterialsApi::phong(EveryApi &ev, MT nxt, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new PhongMaterial(ev, mat, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow));

}

class PhongMaterial : public MaterialForward

{

public:

  PhongMaterial(GameApi::EveryApi &ev, Material *next, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow) : ev(ev), next(next), light_dir_x(light_dir_x), light_dir_y(light_dir_y), light_dir_z(light_dir_z), ambient(ambient), highlight(highlight), pow(pow) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat(p0.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst(p0.id, pts.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst2(p0.id, pta.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst_fade(p0.id, pts.id, flip, start_time, end_time);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float light_dir_x, light_dir_y, light_dir_z;

  unsigned int ambient, highlight;

  float pow;

};

EXPORT GameApi::MT GameApi::MaterialsApi::phong(EveryApi &ev, MT nxt, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new PhongMaterial(ev, mat, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow));

}

class WebMaterial : public MaterialForward

{

public:

  WebMaterial(GameApi::EveryApi &ev, Material *next, float val, float linewidth, unsigned int color) : ev(ev),next(next),val(val),linewidth(linewidth),color(color) {}

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_ml2(ev,I4);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat(I8.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    g_low->ogl->glLineWidth(linewidth);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml3(ev,I4,pts);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst(I8.id,pts.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    //GameApi::ML I12=ev.mainloop_api.prepare_pts(I11,pts);

    return I11;

  }



  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    g_low->ogl->glLineWidth(linewidth);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst2(I8.id,pta.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);



    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst_fade(I8.id,pts.id, flip, start_time, end_time);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float val;

  float linewidth;

  unsigned int color;

};

EXPORT GameApi::MT GameApi::MaterialsApi::web(EveryApi &ev, MT nxt, float val, float linewidth, unsigned int color)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new WebMaterial(ev,mat,val,linewidth,color));

}

EXPORT GameApi::ML GameApi::MaterialsApi::web(EveryApi &ev, P p)

{



  // TODO: this might require std::function<ML(ev,P)> parameter, but

  // builder can't do it yet.



  P I2=p;

LI I3=ev.lines_api.from_polygon(I2);

LI I4=ev.lines_api.change_color(I3,0xff000000);

LLA I5=ev.lines_api.prepare(I4);

ML I6=ev.lines_api.render_ml(ev,I5);

 P I8=p; 

VA I9=ev.polygon_api.create_vertex_array(I8,true);

ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

ML I11=ev.mainloop_api.array_ml(std::vector<ML>{I6,I10});

 return I11;

}

class WebMaterial : public MaterialForward

{

public:

  WebMaterial(GameApi::EveryApi &ev, Material *next, float val, float linewidth, unsigned int color) : ev(ev),next(next),val(val),linewidth(linewidth),color(color) {}

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_ml2(ev,I4);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat(I8.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    g_low->ogl->glLineWidth(linewidth);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml3(ev,I4,pts);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst(I8.id,pts.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    //GameApi::ML I12=ev.mainloop_api.prepare_pts(I11,pts);

    return I11;

  }



  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    g_low->ogl->glLineWidth(linewidth);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst2(I8.id,pta.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);



    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst_fade(I8.id,pts.id, flip, start_time, end_time);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float val;

  float linewidth;

  unsigned int color;

};

EXPORT GameApi::MT GameApi::MaterialsApi::web(EveryApi &ev, MT nxt, float val, float linewidth, unsigned int color)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new WebMaterial(ev,mat,val,linewidth,color));

}

EXPORT GameApi::ML GameApi::MaterialsApi::web(EveryApi &ev, P p)

{



  // TODO: this might require std::function<ML(ev,P)> parameter, but

  // builder can't do it yet.



  P I2=p;

LI I3=ev.lines_api.from_polygon(I2);

LI I4=ev.lines_api.change_color(I3,0xff000000);

LLA I5=ev.lines_api.prepare(I4);

ML I6=ev.lines_api.render_ml(ev,I5);

 P I8=p; 

VA I9=ev.polygon_api.create_vertex_array(I8,true);

ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

 ML I11=ev.mainloop_api.array_ml(ev,std::vector<ML>{I6,I10});

 return I11;

}

class WebMaterial : public MaterialForward

{

public:

  WebMaterial(GameApi::EveryApi &ev, Material *next, float val, float linewidth, unsigned int color) : ev(ev),next(next),val(val),linewidth(linewidth),color(color) {}

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_ml2(ev,I4);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat(I8.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    g_low->ogl->glLineWidth(linewidth);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml3(ev,I4,pts);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst(I8.id,pts.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    //GameApi::ML I12=ev.mainloop_api.prepare_pts(I11,pts);

    return I11;

  }



  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    g_low->ogl->glLineWidth(linewidth);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst2(I8.id,pta.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);



    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst_fade(I8.id,pts.id, flip, start_time, end_time);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float val;

  float linewidth;

  unsigned int color;

};

EXPORT GameApi::MT GameApi::MaterialsApi::web(EveryApi &ev, MT nxt, float val, float linewidth, unsigned int color)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new WebMaterial(ev,mat,val,linewidth,color));

}

EXPORT GameApi::ML GameApi::MaterialsApi::web(EveryApi &ev, P p)

{



  // TODO: this might require std::function<ML(ev,P)> parameter, but

  // builder can't do it yet.



  P I2=p;

LI I3=ev.lines_api.from_polygon(I2);

LI I4=ev.lines_api.change_color(I3,0xff000000);

LLA I5=ev.lines_api.prepare(I4);

ML I6=ev.lines_api.render_ml(ev,I5);

 P I8=p; 

VA I9=ev.polygon_api.create_vertex_array(I8,true);

ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

ML I11=ev.mainloop_api.array_ml(std::vector<ML>{I6,I10});

 return I11;

}

class WebMaterial : public MaterialForward

{

public:

  WebMaterial(GameApi::EveryApi &ev, Material *next, float val, float linewidth, unsigned int color) : ev(ev),next(next),val(val),linewidth(linewidth),color(color) {}

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_ml2(ev,I4);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat(I8.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    g_low->ogl->glLineWidth(linewidth);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml3(ev,I4,pts);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst(I8.id,pts.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    //GameApi::ML I12=ev.mainloop_api.prepare_pts(I11,pts);

    return I11;

  }



  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    g_low->ogl->glLineWidth(linewidth);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst2(I8.id,pta.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);



    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst_fade(I8.id,pts.id, flip, start_time, end_time);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float val;

  float linewidth;

  unsigned int color;

};

EXPORT GameApi::MT GameApi::MaterialsApi::web(EveryApi &ev, MT nxt, float val, float linewidth, unsigned int color)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new WebMaterial(ev,mat,val,linewidth,color));

}

EXPORT GameApi::ML GameApi::MaterialsApi::web(EveryApi &ev, P p)

{



  // TODO: this might require std::function<ML(ev,P)> parameter, but

  // builder can't do it yet.



  P I2=p;

LI I3=ev.lines_api.from_polygon(I2);

LI I4=ev.lines_api.change_color(I3,0xff000000);

LLA I5=ev.lines_api.prepare(I4);

ML I6=ev.lines_api.render_ml(ev,I5);

 P I8=p; 

VA I9=ev.polygon_api.create_vertex_array(I8,true);

ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

 ML I11=ev.mainloop_api.array_ml(ev,std::vector<ML>{I6,I10});

 return I11;

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind(P p, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = mat2->mat(p.id);

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind(P p, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = 0;

  if (mat2) {

    val = mat2->mat(p.id);

  }

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class SphereElem : public SingleForwardBoxableFaceCollection

{

public:

  SphereElem(int numfaces, int numfaces2) :  numfaces(numfaces), numfaces2(numfaces2), center(Point(0.0,0.0,0.0)), radius(1.0) { }

  SphereElem(Point center, float radius, int numfaces1, int numfaces2);

  virtual void SetBox(Matrix b) { /*box = b; inverted=false; */}

  void Prepare() {}

  virtual int NumFaces() const;

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    p-=center;

    Vector v = p;

    //if (!inverted) { boxinv=Matrix::Inverse(box); inverted=true; }

    Point pp = v;

    

    return pp.x*pp.x+pp.y*pp.y+pp.z*pp.z<radius*radius; 

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    Point p = v;

    p-=center;

    Vector vv = p;

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    return -vv; /*-center*/;

  }

private:

  //Matrix box;

  //mutable Matrix boxinv;

  int numfaces;

  int numfaces2;

  Point center;

  float radius;

  //mutable bool inverted;

};

EXPORT GameApi::P GameApi::PolygonApi::sphere(PT center, float radius, int numfaces1, int numfaces2)

{

    Point *p = find_point(e,center);

    FaceCollection *coll = new SphereElem(*p, radius, numfaces1, numfaces2);

    return add_polygon(e, coll,1);

}

class SphereElem : public SingleForwardBoxableFaceCollection

{

public:

  SphereElem(int numfaces, int numfaces2) :  numfaces(numfaces), numfaces2(numfaces2), center(Point(0.0,0.0,0.0)), radius(1.0) { }

  SphereElem(Point center, float radius, int numfaces1, int numfaces2);

  virtual void SetBox(Matrix b) { /*box = b; inverted=false; */}

  void Prepare() {}

  virtual int NumFaces() const;

  virtual int NumPoints(int face) const { return 4; }

  virtual Point FacePoint(int face, int point) const;

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }



  virtual float Attrib(int face, int point, int id) const

  {

    return 0.0;

  }

  virtual bool Inside(Point p) const 

  {

    p-=center;

    Vector v = p;

    //if (!inverted) { boxinv=Matrix::Inverse(box); inverted=true; }

    Point pp = v;

    

    return pp.x*pp.x+pp.y*pp.y+pp.z*pp.z<radius*radius; 

  }



  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    Point p = v;

    p-=center;

    Vector vv = p;

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    return -vv; /*-center*/;

  }

private:

  //Matrix box;

  //mutable Matrix boxinv;

  int numfaces;

  int numfaces2;

  Point center;

  float radius;

  //mutable bool inverted;

};

EXPORT GameApi::P GameApi::PolygonApi::sphere(PT center, float radius, int numfaces1, int numfaces2)

{

    Point *p = find_point(e,center);

    FaceCollection *coll = new SphereElem(*p, radius, numfaces1, numfaces2);

    return add_polygon(e, coll,1);

}

class PhongMaterial : public MaterialForward

{

public:

  PhongMaterial(GameApi::EveryApi &ev, Material *next, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow) : ev(ev), next(next), light_dir_x(light_dir_x), light_dir_y(light_dir_y), light_dir_z(light_dir_z), ambient(ambient), highlight(highlight), pow(pow) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat(p0.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst(p0.id, pts.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst2(p0.id, pta.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst_fade(p0.id, pts.id, flip, start_time, end_time);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float light_dir_x, light_dir_y, light_dir_z;

  unsigned int ambient, highlight;

  float pow;

};

EXPORT GameApi::MT GameApi::MaterialsApi::phong(EveryApi &ev, MT nxt, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new PhongMaterial(ev, mat, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow));

}

class PhongMaterial : public MaterialForward

{

public:

  PhongMaterial(GameApi::EveryApi &ev, Material *next, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow) : ev(ev), next(next), light_dir_x(light_dir_x), light_dir_y(light_dir_y), light_dir_z(light_dir_z), ambient(ambient), highlight(highlight), pow(pow) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat(p0.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst(p0.id, pts.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst2(p0.id, pta.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst_fade(p0.id, pts.id, flip, start_time, end_time);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float light_dir_x, light_dir_y, light_dir_z;

  unsigned int ambient, highlight;

  float pow;

};

EXPORT GameApi::MT GameApi::MaterialsApi::phong(EveryApi &ev, MT nxt, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new PhongMaterial(ev, mat, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow));

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind_inst(P p, PTS pts, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = mat2->mat_inst(p.id,pts.id);

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind_inst(P p, PTS pts, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = 0;

  if (mat2) {

    val = mat2->mat_inst(p.id,pts.id);

  }

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

class ArrayMainLoop : public MainLoopItem

{

public:

  ArrayMainLoop(GameApi::Env &env, GameApi::EveryApi &ev, std::vector<MainLoopItem*> vec) : env(env), ev(ev), vec(vec) { }

  void Prepare() {

    int s = vec.size();

    for(int i=0;i<s;i++) vec[i]->Prepare();

  }

  void execute(MainLoopEnv &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	MainLoopEnv ee = e;



	// here's a block needed to distribute in_MV to different cases.

	int id = vec[i]->shader_id();

	if (id!=-1) {

	  GameApi::SH sh;

	  sh.id = id;

	  GameApi::M m = add_matrix2( env, e.in_MV);

	  ev.shader_api.use(sh);

	  ev.shader_api.set_var(sh, "in_MV", m);

	}

	vec[i]->execute(ee);

      }

  }

  void handle_event(MainLoopEvent &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	vec[i]->handle_event(e);

      }

  }

#if 0

  int shader_id() { 

    int s = vec.size();

    for(int i=s-1;i>=0;i--)

      {

	if (vec[i]->shader_id()!=-1) return vec[i]->shader_id();

      }

    return -1; 

  }

#endif

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  std::vector<MainLoopItem*> vec;

};

EXPORT GameApi::ML GameApi::MainLoopApi::array_ml(std::vector<ML> vec)

{

  std::vector<MainLoopItem*> vec2;

  int s = vec.size();

  for(int i=0;i<s;i++)

    {

      //std::cout << "array_ml id: " << vec[i].id << std::endl;

      vec2.push_back(find_main_loop(e,vec[i]));

    }

  return add_main_loop(e, new ArrayMainLoop(vec2));

}

class ArrayMainLoop : public MainLoopItem

{

public:

  ArrayMainLoop(GameApi::Env &env, GameApi::EveryApi &ev, std::vector<MainLoopItem*> vec) : env(env), ev(ev), vec(vec) { }

  void Prepare() {

    int s = vec.size();

    for(int i=0;i<s;i++) vec[i]->Prepare();

  }

  void execute(MainLoopEnv &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	MainLoopEnv ee = e;



	// here's a block needed to distribute in_MV to different cases.

	int id = vec[i]->shader_id();

	if (id!=-1) {

	  GameApi::SH sh;

	  sh.id = id;

	  GameApi::M m = add_matrix2( env, e.in_MV);

	  ev.shader_api.use(sh);

	  ev.shader_api.set_var(sh, "in_MV", m);

	}

	vec[i]->execute(ee);

      }

  }

  void handle_event(MainLoopEvent &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	vec[i]->handle_event(e);

      }

  }

#if 0

  int shader_id() { 

    int s = vec.size();

    for(int i=s-1;i>=0;i--)

      {

	if (vec[i]->shader_id()!=-1) return vec[i]->shader_id();

      }

    return -1; 

  }

#endif

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  std::vector<MainLoopItem*> vec;

};

EXPORT GameApi::ML GameApi::MainLoopApi::array_ml(GameApi::EveryApi &ev, std::vector<ML> vec)

{

  std::vector<MainLoopItem*> vec2;

  int s = vec.size();

  for(int i=0;i<s;i++)

    {

      //std::cout << "array_ml id: " << vec[i].id << std::endl;

      vec2.push_back(find_main_loop(e,vec[i]));

    }

  return add_main_loop(e, new ArrayMainLoop(e,ev,vec2));

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(float start_x, float end_x,

{

  Point p111(start_x, start_y, start_z);

  Point p112(start_x, start_y, end_z);

  Point p121(start_x, end_y, start_z);

  Point p122(start_x, end_y, end_z);

  Point p211(end_x, start_y, start_z);

  Point p212(end_x, start_y, end_z);

  Point p221(end_x, end_y, start_z);

  Point p222(end_x, end_y, end_z);

  

  FaceCollection *coll = new CubeElem(p111,p112,p121,p122,

				      p211,p212,p221,p222);

  return add_polygon2(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(PT *p)

{

  Point *p111 = find_point(e,p[0]);

  Point *p112 = find_point(e,p[1]);

  Point *p121 = find_point(e,p[2]);

  Point *p122 = find_point(e,p[3]);

  Point *p211 = find_point(e,p[4]);

  Point *p212 = find_point(e,p[5]);

  Point *p221 = find_point(e,p[6]);

  Point *p222 = find_point(e,p[7]);

  

  FaceCollection *coll = new CubeElem(*p111,*p112,*p121,*p122,

				      *p211,*p212,*p221,*p222);

  return add_polygon(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(float start_x, float end_x,

{

  Point p111(start_x, start_y, start_z);

  Point p112(start_x, start_y, end_z);

  Point p121(start_x, end_y, start_z);

  Point p122(start_x, end_y, end_z);

  Point p211(end_x, start_y, start_z);

  Point p212(end_x, start_y, end_z);

  Point p221(end_x, end_y, start_z);

  Point p222(end_x, end_y, end_z);

  

  FaceCollection *coll = new CubeElem(p111,p112,p121,p122,

				      p211,p212,p221,p222);

  return add_polygon2(e, coll,1);  

}

class CubeElem : public SingleForwardBoxableFaceCollection, public CoordSource

{

public:

  CubeElem() : p111(Point(-1.0,-1.0,-1.0)),

	       p112(Point(-1.0,-1.0,1.0)),

	       p121(Point(-1.0,1.0,-1.0)),

	       p122(Point(-1.0,1.0,1.0)),

	       p211(Point(1.0,-1.0,-1.0)),

	       p212(Point(1.0,-1.0,1.0)),

	       p221(Point(1.0,1.0,-1.0)),

	       p222(Point(1.0,1.0,1.0)) { }

  CubeElem(Point p111,

	   Point p112,

	   Point p121,

	   Point p122,

	   Point p211,

	   Point p212,

	   Point p221,

	   Point p222) : p111(p111), p112(p112), p121(p121),

			 p122(p122), p211(p211), p212(p212),

			 p221(p221), p222(p222) { }

  virtual Coords coord() const

  {

    Coords c;

    c.center = Point(0.0,0.0,0.0);

    c.u_x = Vector(1.0,0.0,0.0);

    c.u_y = Vector(0.0,1.0,0.0);

    c.u_z = Vector(0.0,0.0,1.0);

    return c;

  }

  void Prepare() { }

  virtual void SetBox(Matrix b) { /*box = b;*/ }

  virtual int NumFaces() const { return 6; }

  virtual int NumPoints(int face) const { return 4; }

  //virtual int Texture(int face) const { return face; }

  //virtual Point2d TexCoord(int face, int point) const;

  virtual Point FacePoint(int face, int point) const;

  virtual Vector PointNormal(int face, int point) const

  {

    Vector v = FacePoint(face, point);

    //Vector center = Vector(box.matrix[3], box.matrix[7], box.matrix[11]);

    //v.Normalize();

    return v; /*-center;*/

  }

  virtual unsigned int Color(int face, int point) const

  {

    return Color::White().Pixel();

  }

  virtual Point2d TexCoord(int face, int point) const;

  virtual int AttribI(int face, int point, int id) const

  {

    return 0;

  }

  virtual float Attrib(int face, int point, int id) const

  {

    switch(id)

      {

      case AttrCenterX: return 0.0; //box.matrix[3];

      case AttrCenterY: return 0.0; //box.matrix[7];

      case AttrCenterZ: return 0.0; //box.matrix[11];

      }

    return 0.0;

  }



private:

  Point p111;

  Point p112;

  Point p121;

  Point p122;

  Point p211;

  Point p212;

  Point p221;

  Point p222;

  //Matrix box;

};

EXPORT GameApi::P GameApi::PolygonApi::cube(PT *p)

{

  Point *p111 = find_point(e,p[0]);

  Point *p112 = find_point(e,p[1]);

  Point *p121 = find_point(e,p[2]);

  Point *p122 = find_point(e,p[3]);

  Point *p211 = find_point(e,p[4]);

  Point *p212 = find_point(e,p[5]);

  Point *p221 = find_point(e,p[6]);

  Point *p222 = find_point(e,p[7]);

  

  FaceCollection *coll = new CubeElem(*p111,*p112,*p121,*p122,

				      *p211,*p212,*p221,*p222);

  return add_polygon(e, coll,1);  

}

class PhongMaterial : public MaterialForward

{

public:

  PhongMaterial(GameApi::EveryApi &ev, Material *next, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow) : ev(ev), next(next), light_dir_x(light_dir_x), light_dir_y(light_dir_y), light_dir_z(light_dir_z), ambient(ambient), highlight(highlight), pow(pow) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat(p0.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst(p0.id, pts.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst2(p0.id, pta.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst_fade(p0.id, pts.id, flip, start_time, end_time);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float light_dir_x, light_dir_y, light_dir_z;

  unsigned int ambient, highlight;

  float pow;

};

EXPORT GameApi::MT GameApi::MaterialsApi::phong(EveryApi &ev, MT nxt, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new PhongMaterial(ev, mat, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow));

}

class PhongMaterial : public MaterialForward

{

public:

  PhongMaterial(GameApi::EveryApi &ev, Material *next, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow) : ev(ev), next(next), light_dir_x(light_dir_x), light_dir_y(light_dir_y), light_dir_z(light_dir_z), ambient(ambient), highlight(highlight), pow(pow) { }

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat(p0.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;

  }

  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst(p0.id, pts.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst2(p0.id, pta.id);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }

  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    GameApi::P p0 = ev.polygon_api.recalculate_normals(p);

    //GameApi::P p00 = ev.polygon_api.smooth_normals2(p0);

    //GameApi::P p1 = ev.polygon_api.color(p0, 0xff000000);

    GameApi::ML ml;

    ml.id = next->mat_inst_fade(p0.id, pts.id, flip, start_time, end_time);

    GameApi::ML sh = ev.polygon_api.phong_shader(ev, ml, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow);

    return sh;



  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float light_dir_x, light_dir_y, light_dir_z;

  unsigned int ambient, highlight;

  float pow;

};

EXPORT GameApi::MT GameApi::MaterialsApi::phong(EveryApi &ev, MT nxt, float light_dir_x, float light_dir_y, float light_dir_z, unsigned int ambient, unsigned int highlight, float pow)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new PhongMaterial(ev, mat, light_dir_x, light_dir_y, light_dir_z, ambient, highlight, pow));

}

class WebMaterial : public MaterialForward

{

public:

  WebMaterial(GameApi::EveryApi &ev, Material *next, float val, float linewidth, unsigned int color) : ev(ev),next(next),val(val),linewidth(linewidth),color(color) {}

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_ml2(ev,I4);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat(I8.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    g_low->ogl->glLineWidth(linewidth);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml3(ev,I4,pts);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst(I8.id,pts.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    //GameApi::ML I12=ev.mainloop_api.prepare_pts(I11,pts);

    return I11;

  }



  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    g_low->ogl->glLineWidth(linewidth);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst2(I8.id,pta.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);



    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst_fade(I8.id,pts.id, flip, start_time, end_time);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float val;

  float linewidth;

  unsigned int color;

};

EXPORT GameApi::MT GameApi::MaterialsApi::web(EveryApi &ev, MT nxt, float val, float linewidth, unsigned int color)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new WebMaterial(ev,mat,val,linewidth,color));

}

EXPORT GameApi::ML GameApi::MaterialsApi::web(EveryApi &ev, P p)

{



  // TODO: this might require std::function<ML(ev,P)> parameter, but

  // builder can't do it yet.



  P I2=p;

LI I3=ev.lines_api.from_polygon(I2);

LI I4=ev.lines_api.change_color(I3,0xff000000);

LLA I5=ev.lines_api.prepare(I4);

ML I6=ev.lines_api.render_ml(ev,I5);

 P I8=p; 

VA I9=ev.polygon_api.create_vertex_array(I8,true);

ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

ML I11=ev.mainloop_api.array_ml(std::vector<ML>{I6,I10});

 return I11;

}

class WebMaterial : public MaterialForward

{

public:

  WebMaterial(GameApi::EveryApi &ev, Material *next, float val, float linewidth, unsigned int color) : ev(ev),next(next),val(val),linewidth(linewidth),color(color) {}

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_ml2(ev,I4);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat(I8.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    g_low->ogl->glLineWidth(linewidth);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml3(ev,I4,pts);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst(I8.id,pts.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    //GameApi::ML I12=ev.mainloop_api.prepare_pts(I11,pts);

    return I11;

  }



  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    g_low->ogl->glLineWidth(linewidth);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst2(I8.id,pta.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);



    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst_fade(I8.id,pts.id, flip, start_time, end_time);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float val;

  float linewidth;

  unsigned int color;

};

EXPORT GameApi::MT GameApi::MaterialsApi::web(EveryApi &ev, MT nxt, float val, float linewidth, unsigned int color)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new WebMaterial(ev,mat,val,linewidth,color));

}

EXPORT GameApi::ML GameApi::MaterialsApi::web(EveryApi &ev, P p)

{



  // TODO: this might require std::function<ML(ev,P)> parameter, but

  // builder can't do it yet.



  P I2=p;

LI I3=ev.lines_api.from_polygon(I2);

LI I4=ev.lines_api.change_color(I3,0xff000000);

LLA I5=ev.lines_api.prepare(I4);

ML I6=ev.lines_api.render_ml(ev,I5);

 P I8=p; 

VA I9=ev.polygon_api.create_vertex_array(I8,true);

ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

 ML I11=ev.mainloop_api.array_ml(ev,std::vector<ML>{I6,I10});

 return I11;

}

class WebMaterial : public MaterialForward

{

public:

  WebMaterial(GameApi::EveryApi &ev, Material *next, float val, float linewidth, unsigned int color) : ev(ev),next(next),val(val),linewidth(linewidth),color(color) {}

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_ml2(ev,I4);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat(I8.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    g_low->ogl->glLineWidth(linewidth);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml3(ev,I4,pts);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst(I8.id,pts.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    //GameApi::ML I12=ev.mainloop_api.prepare_pts(I11,pts);

    return I11;

  }



  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    g_low->ogl->glLineWidth(linewidth);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst2(I8.id,pta.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);



    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst_fade(I8.id,pts.id, flip, start_time, end_time);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float val;

  float linewidth;

  unsigned int color;

};

EXPORT GameApi::MT GameApi::MaterialsApi::web(EveryApi &ev, MT nxt, float val, float linewidth, unsigned int color)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new WebMaterial(ev,mat,val,linewidth,color));

}

EXPORT GameApi::ML GameApi::MaterialsApi::web(EveryApi &ev, P p)

{



  // TODO: this might require std::function<ML(ev,P)> parameter, but

  // builder can't do it yet.



  P I2=p;

LI I3=ev.lines_api.from_polygon(I2);

LI I4=ev.lines_api.change_color(I3,0xff000000);

LLA I5=ev.lines_api.prepare(I4);

ML I6=ev.lines_api.render_ml(ev,I5);

 P I8=p; 

VA I9=ev.polygon_api.create_vertex_array(I8,true);

ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

ML I11=ev.mainloop_api.array_ml(std::vector<ML>{I6,I10});

 return I11;

}

class WebMaterial : public MaterialForward

{

public:

  WebMaterial(GameApi::EveryApi &ev, Material *next, float val, float linewidth, unsigned int color) : ev(ev),next(next),val(val),linewidth(linewidth),color(color) {}

  virtual GameApi::ML mat2(GameApi::P p) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_ml2(ev,I4);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat(I8.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat2_inst(GameApi::P p, GameApi::PTS pts) const

  {

    g_low->ogl->glLineWidth(linewidth);

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml3(ev,I4,pts);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst(I8.id,pts.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    //GameApi::ML I12=ev.mainloop_api.prepare_pts(I11,pts);

    return I11;

  }



  virtual GameApi::ML mat2_inst2(GameApi::P p, GameApi::PTA pta) const

  {

    //GameApi::PTA pta = ev.points_api.prepare(pts);

    g_low->ogl->glLineWidth(linewidth);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);

    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst2(I8.id,pta.id);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



  virtual GameApi::ML mat_inst_fade(GameApi::P p, GameApi::PTS pts, bool flip, float start_time, float end_time) const

  {

    g_low->ogl->glLineWidth(linewidth);

    GameApi::PTA pta = ev.points_api.prepare(pts);

    

    GameApi::P I2=p;

    GameApi::P I2b = ev.polygon_api.recalculate_normals(I2);

    GameApi::P I2a = ev.lines_api.p_towards_normal(I2b, val);

    GameApi::LI I3=ev.lines_api.from_polygon(I2a);

    GameApi::LI I4=ev.lines_api.change_color(I3,color);

    //GameApi::LI I5=ev.lines_api.line_pos_mult(val,I4);



    //GameApi::LLA I5=ev.lines_api.prepare(I4);

    GameApi::ML I6=ev.lines_api.render_inst_ml2(ev,I4,pta);

    GameApi::P I8=p; 

    //VA I9=ev.polygon_api.create_vertex_array(I8,true);

    //ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

    GameApi::ML I10;

    I10.id = next->mat_inst_fade(I8.id,pts.id, flip, start_time, end_time);

    GameApi::ML I11=ev.mainloop_api.array_ml(ev,std::vector<GameApi::ML>{I6,I10});

    return I11;

  }



private:

  GameApi::EveryApi &ev;

  Material *next;

  float val;

  float linewidth;

  unsigned int color;

};

EXPORT GameApi::MT GameApi::MaterialsApi::web(EveryApi &ev, MT nxt, float val, float linewidth, unsigned int color)

{

  Material *mat = find_material(e, nxt);

  return add_material(e, new WebMaterial(ev,mat,val,linewidth,color));

}

EXPORT GameApi::ML GameApi::MaterialsApi::web(EveryApi &ev, P p)

{



  // TODO: this might require std::function<ML(ev,P)> parameter, but

  // builder can't do it yet.



  P I2=p;

LI I3=ev.lines_api.from_polygon(I2);

LI I4=ev.lines_api.change_color(I3,0xff000000);

LLA I5=ev.lines_api.prepare(I4);

ML I6=ev.lines_api.render_ml(ev,I5);

 P I8=p; 

VA I9=ev.polygon_api.create_vertex_array(I8,true);

ML I10=ev.polygon_api.render_vertex_array_ml(ev,I9);

 ML I11=ev.mainloop_api.array_ml(ev,std::vector<ML>{I6,I10});

 return I11;

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind(P p, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = mat2->mat(p.id);

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

EXPORT GameApi::ML GameApi::MaterialsApi::bind(P p, MT mat)

{

  Material *mat2 = find_material(e, mat);

  int val = 0;

  if (mat2) {

    val = mat2->mat(p.id);

  }

  GameApi::ML ml;

  ml.id = val;

  return ml;

}

class RotateMovement : public Movement

{

public:

public:

  RotateMovement(Movement *next, float start_time, float end_time,

		 float p_x, float p_y, float p_z,

		float v_x, float v_y, float v_z, float angle)

    : next(next), start_time(start_time), end_time(end_time),

      p_x(p_x), p_y(p_y), p_z(p_z),

      v_x(v_x), v_y(v_y), v_z(v_z), angle(angle) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix m) { }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { return next->get_whole_matrix(time, delta_time); }

    if (time>=end_time) { return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), angle)*next->get_whole_matrix(time, delta_time); }

    float d = time - start_time;

    d/=(end_time-start_time); // [0..1]

    return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), d*angle)*next->get_whole_matrix(time, delta_time);

  }

private:

  Movement *next;

  float start_time, end_time;

  float p_x,p_y,p_z;

  float v_x,v_y,v_z;

  float angle;

};

EXPORT GameApi::MN GameApi::MovementNode::rotate(MN next, float start_time, float end_time,

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new RotateMovement(nxt, start_time, end_time,

					p_x,p_y,p_z,v_x, v_y, v_z, angle));

}

class RotateMovement : public Movement

{

public:

public:

  RotateMovement(Movement *next, float start_time, float end_time,

		 float p_x, float p_y, float p_z,

		float v_x, float v_y, float v_z, float angle)

    : next(next), start_time(start_time), end_time(end_time),

      p_x(p_x), p_y(p_y), p_z(p_z),

      v_x(v_x), v_y(v_y), v_z(v_z), angle(angle) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix m) { }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { return next->get_whole_matrix(time, delta_time); }

    if (time>=end_time) { return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), angle)*next->get_whole_matrix(time, delta_time); }

    float d = time - start_time;

    d/=(end_time-start_time); // [0..1]

    return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), d*angle)*next->get_whole_matrix(time, delta_time);

  }

private:

  Movement *next;

  float start_time, end_time;

  float p_x,p_y,p_z;

  float v_x,v_y,v_z;

  float angle;

};

EXPORT GameApi::MN GameApi::MovementNode::rotate(MN next, float start_time, float end_time, float p_x, float p_y, float p_z, float v_x, float v_y, float v_z, float angle)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new RotateMovement(nxt, start_time, end_time,

					p_x,p_y,p_z,v_x, v_y, v_z, angle));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class ArrayMainLoop : public MainLoopItem

{

public:

  ArrayMainLoop(GameApi::Env &env, GameApi::EveryApi &ev, std::vector<MainLoopItem*> vec) : env(env), ev(ev), vec(vec) { }

  void Prepare() {

    int s = vec.size();

    for(int i=0;i<s;i++) vec[i]->Prepare();

  }

  void execute(MainLoopEnv &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	MainLoopEnv ee = e;



	// here's a block needed to distribute in_MV to different cases.

	int id = vec[i]->shader_id();

	if (id!=-1) {

	  GameApi::SH sh;

	  sh.id = id;

	  GameApi::M m = add_matrix2( env, e.in_MV);

	  ev.shader_api.use(sh);

	  ev.shader_api.set_var(sh, "in_MV", m);

	}

	vec[i]->execute(ee);

      }

  }

  void handle_event(MainLoopEvent &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	vec[i]->handle_event(e);

      }

  }

#if 0

  int shader_id() { 

    int s = vec.size();

    for(int i=s-1;i>=0;i--)

      {

	if (vec[i]->shader_id()!=-1) return vec[i]->shader_id();

      }

    return -1; 

  }

#endif

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  std::vector<MainLoopItem*> vec;

};

EXPORT GameApi::ML GameApi::MainLoopApi::array_ml(std::vector<ML> vec)

{

  std::vector<MainLoopItem*> vec2;

  int s = vec.size();

  for(int i=0;i<s;i++)

    {

      //std::cout << "array_ml id: " << vec[i].id << std::endl;

      vec2.push_back(find_main_loop(e,vec[i]));

    }

  return add_main_loop(e, new ArrayMainLoop(vec2));

}

class ArrayMainLoop : public MainLoopItem

{

public:

  ArrayMainLoop(GameApi::Env &env, GameApi::EveryApi &ev, std::vector<MainLoopItem*> vec) : env(env), ev(ev), vec(vec) { }

  void Prepare() {

    int s = vec.size();

    for(int i=0;i<s;i++) vec[i]->Prepare();

  }

  void execute(MainLoopEnv &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	MainLoopEnv ee = e;



	// here's a block needed to distribute in_MV to different cases.

	int id = vec[i]->shader_id();

	if (id!=-1) {

	  GameApi::SH sh;

	  sh.id = id;

	  GameApi::M m = add_matrix2( env, e.in_MV);

	  ev.shader_api.use(sh);

	  ev.shader_api.set_var(sh, "in_MV", m);

	}

	vec[i]->execute(ee);

      }

  }

  void handle_event(MainLoopEvent &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	vec[i]->handle_event(e);

      }

  }

#if 0

  int shader_id() { 

    int s = vec.size();

    for(int i=s-1;i>=0;i--)

      {

	if (vec[i]->shader_id()!=-1) return vec[i]->shader_id();

      }

    return -1; 

  }

#endif

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  std::vector<MainLoopItem*> vec;

};

EXPORT GameApi::ML GameApi::MainLoopApi::array_ml(GameApi::EveryApi &ev, std::vector<ML> vec)

{

  std::vector<MainLoopItem*> vec2;

  int s = vec.size();

  for(int i=0;i<s;i++)

    {

      //std::cout << "array_ml id: " << vec[i].id << std::endl;

      vec2.push_back(find_main_loop(e,vec[i]));

    }

  return add_main_loop(e, new ArrayMainLoop(e,ev,vec2));

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::scale2(MN next, float sx, float sy, float sz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Scale(sx,sy,sz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::scale2(MN next, float sx, float sy, float sz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Scale(sx,sy,sz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::rotatez(MN next, float angle)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::ZRotation(angle)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::rotatez(MN next, float angle)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::ZRotation(angle)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::rotatex(MN next, float angle)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::XRotation(angle)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::rotatex(MN next, float angle)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::XRotation(angle)));  

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class RotateMovement : public Movement

{

public:

public:

  RotateMovement(Movement *next, float start_time, float end_time,

		 float p_x, float p_y, float p_z,

		float v_x, float v_y, float v_z, float angle)

    : next(next), start_time(start_time), end_time(end_time),

      p_x(p_x), p_y(p_y), p_z(p_z),

      v_x(v_x), v_y(v_y), v_z(v_z), angle(angle) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix m) { }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { return next->get_whole_matrix(time, delta_time); }

    if (time>=end_time) { return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), angle)*next->get_whole_matrix(time, delta_time); }

    float d = time - start_time;

    d/=(end_time-start_time); // [0..1]

    return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), d*angle)*next->get_whole_matrix(time, delta_time);

  }

private:

  Movement *next;

  float start_time, end_time;

  float p_x,p_y,p_z;

  float v_x,v_y,v_z;

  float angle;

};

EXPORT GameApi::MN GameApi::MovementNode::rotate(MN next, float start_time, float end_time,

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new RotateMovement(nxt, start_time, end_time,

					p_x,p_y,p_z,v_x, v_y, v_z, angle));

}

class RotateMovement : public Movement

{

public:

public:

  RotateMovement(Movement *next, float start_time, float end_time,

		 float p_x, float p_y, float p_z,

		float v_x, float v_y, float v_z, float angle)

    : next(next), start_time(start_time), end_time(end_time),

      p_x(p_x), p_y(p_y), p_z(p_z),

      v_x(v_x), v_y(v_y), v_z(v_z), angle(angle) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix m) { }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { return next->get_whole_matrix(time, delta_time); }

    if (time>=end_time) { return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), angle)*next->get_whole_matrix(time, delta_time); }

    float d = time - start_time;

    d/=(end_time-start_time); // [0..1]

    return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), d*angle)*next->get_whole_matrix(time, delta_time);

  }

private:

  Movement *next;

  float start_time, end_time;

  float p_x,p_y,p_z;

  float v_x,v_y,v_z;

  float angle;

};

EXPORT GameApi::MN GameApi::MovementNode::rotate(MN next, float start_time, float end_time, float p_x, float p_y, float p_z, float v_x, float v_y, float v_z, float angle)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new RotateMovement(nxt, start_time, end_time,

					p_x,p_y,p_z,v_x, v_y, v_z, angle));

}

class TempKeyActivateML : public MainLoopItem

{

public:

  TempKeyActivateML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN nm, int key, float duration) : e(e), ev(ev), next(next), mn(nm),key(key), duration(duration)

  { 

    start_time = 0.0; //ev.mainloop_api.get_time();

    start_time2 = 0.0;

    anim_pos = 0.0;

    collect = ev.matrix_api.identity();

    anim_ongoing = false;

    anim_ongoing2 = false;

    key_pressed = false;

    key_canceled=false;

    start_anim_chain = false;

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &eve)

  {

    Movement *move = find_move(e, mn);

    move->event(eve);



    bool start_anim = false;

    bool start_anim2 = false;

    int ch = eve.ch;

#ifdef EMSCRIPTEN

    if (ch>=4 && ch<=29) { ch = ch - 4; ch=ch+'a'; }

    if (ch==39) ch='0';

    if (ch>=30 && ch<=38) { ch = ch-30; ch=ch+'1'; }

#endif

    if (eve.type==0x300 && ch == key && !anim_ongoing && !anim_ongoing2 && !key_pressed) { start_anim = true; } else if (eve.type==0x300 && ch==key && !key_pressed)

      {

	key_canceled=true;

      }

    if (eve.type==0x300 && ch == key) { key_pressed = true; }

    if (eve.type==0x301 && ch == key && !anim_ongoing2 && !key_canceled) { key_pressed = false;  start_anim2 = true; } 

    if (eve.type==0x301 && ch==key) { key_canceled=false;

      //if (!anim_ongoing && !anim_ongoing2 && anim_pos>0.0) {

      //	anim_pos = duration;

      //	start_anim2 = true;

      //}

    }



    if (start_anim) {

      start_anim_chain = false;

      //std::cout << "start_anim" << std::endl;

      anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

      start_anim = false;

    }

    if (start_anim2 && !start_anim_chain) {

      start_anim_chain = true;

      //std::cout << "start_anim2" << std::endl;

      anim_ongoing = false;

      anim_ongoing2 = true; 

      start_time2 = ev.mainloop_api.get_time();  

      anim_pos_at_change = anim_pos;

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      time_at_change = std::min(time,duration);



      //      collect = ev.move_api.get_matrix(mn, anim_pos_at_change, ev.mainloop_api.get_delta_time());

      start_anim2 = false;

    }



    

    next->handle_event(eve);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e, mn);

    move->frame(env);





    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::M mat,m2,mat2;

    if (anim_ongoing) {

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      //mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos += env.delta_time;

      if (anim_pos > duration-env.delta_time) {

	//std::cout << "anim_ongoing=false" << std::endl;

	anim_ongoing = false;

	collect = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());



	if (0)

	{

	  start_anim_chain = true;

	  //std::cout << "start_anim2" << std::endl;

	  anim_ongoing = false;

	  anim_ongoing2 = true; 

	  start_time2 = ev.mainloop_api.get_time();  

	  anim_pos_at_change = anim_pos;

	  float time = (ev.mainloop_api.get_time()-start_time)/100.0;

	  time_at_change = std::min(time,duration);

	}



	//anim_ongoing2 = true;

	//start_time2 = ev.mainloop_api.get_time();  

	//anim_pos_at_change = anim_pos;

      }

    } else if (anim_ongoing2) {

      float time = (ev.mainloop_api.get_time()-start_time2)/100.0;

      mat = ev.move_api.get_matrix(mn, time_at_change-time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      //mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos -= env.delta_time;

      if (time_at_change - time - ev.mainloop_api.get_delta_time() < 0.0) {

	//std::cout << "anim_ongoing2=false" << std::endl;

	anim_ongoing2 = false;

	collect = ev.matrix_api.identity();

      }

    } else {

      m2 = add_matrix2(e, env.env);

      mat2 = ev.matrix_api.mult(collect,m2);

    }

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    Matrix old_in_MV = env.in_MV;

    env.in_MV = find_matrix(e, mat2);



    Matrix old_env = env.env;

    env.env = find_matrix(e,mat2); /* * env.env*/;

    next->execute(env);

    ev.shader_api.unuse(s3);

    env.env = old_env;

    env.in_MV = old_in_MV;

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  float start_time2;

  MainLoopItem *next;

  GameApi::MN mn;

  int key;

  bool anim_ongoing;

  bool anim_ongoing2;

  float anim_pos;

  float duration;

  GameApi::M collect;

  bool key_pressed;

  float anim_pos_at_change;

  float time_at_change;

  bool key_canceled;

  bool start_anim_chain;

};

EXPORT GameApi::ML GameApi::MovementNode::temp_key_activate_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int key, float duration)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new TempKeyActivateML(e, ev, item, move, key, duration));

}

class TempKeyActivateML : public MainLoopItem

{

public:

  TempKeyActivateML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN nm, int key, float duration) : e(e), ev(ev), next(next), mn(nm),key(key), duration(duration)

  { 

    start_time = 0.0; //ev.mainloop_api.get_time();

    start_time2 = 0.0;

    anim_pos = 0.0;

    collect = ev.matrix_api.identity();

    anim_ongoing = false;

    anim_ongoing2 = false;

    key_pressed = false;

    key_canceled=false;

    start_anim_chain = false;

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &eve)

  {

    Movement *move = find_move(e, mn);

    move->event(eve);



    bool start_anim = false;

    bool start_anim2 = false;

    int ch = eve.ch;

#ifdef EMSCRIPTEN

    if (ch>=4 && ch<=29) { ch = ch - 4; ch=ch+'a'; }

    if (ch==39) ch='0';

    if (ch>=30 && ch<=38) { ch = ch-30; ch=ch+'1'; }

#endif

    if (eve.type==0x300 && ch == key && !anim_ongoing && !anim_ongoing2 && !key_pressed) { start_anim = true; } else if (eve.type==0x300 && ch==key && !key_pressed)

      {

	key_canceled=true;

      }

    if (eve.type==0x300 && ch == key) { key_pressed = true; }

    if (eve.type==0x301 && ch == key && !anim_ongoing2 && !key_canceled) { key_pressed = false;  start_anim2 = true; } 

    if (eve.type==0x301 && ch==key) { key_canceled=false;

      //if (!anim_ongoing && !anim_ongoing2 && anim_pos>0.0) {

      //	anim_pos = duration;

      //	start_anim2 = true;

      //}

    }



    if (start_anim) {

      start_anim_chain = false;

      //std::cout << "start_anim" << std::endl;

      anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

      start_anim = false;

    }

    if (start_anim2 && !start_anim_chain) {

      start_anim_chain = true;

      //std::cout << "start_anim2" << std::endl;

      anim_ongoing = false;

      anim_ongoing2 = true; 

      start_time2 = ev.mainloop_api.get_time();  

      anim_pos_at_change = anim_pos;

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      time_at_change = std::min(time,duration);



      //      collect = ev.move_api.get_matrix(mn, anim_pos_at_change, ev.mainloop_api.get_delta_time());

      start_anim2 = false;

    }



    

    next->handle_event(eve);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e, mn);

    move->frame(env);





    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::M mat,m2,mat2;

    if (anim_ongoing) {

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      //mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos += env.delta_time;

      if (anim_pos > duration-env.delta_time) {

	//std::cout << "anim_ongoing=false" << std::endl;

	anim_ongoing = false;

	collect = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());



	if (0)

	{

	  start_anim_chain = true;

	  //std::cout << "start_anim2" << std::endl;

	  anim_ongoing = false;

	  anim_ongoing2 = true; 

	  start_time2 = ev.mainloop_api.get_time();  

	  anim_pos_at_change = anim_pos;

	  float time = (ev.mainloop_api.get_time()-start_time)/100.0;

	  time_at_change = std::min(time,duration);

	}



	//anim_ongoing2 = true;

	//start_time2 = ev.mainloop_api.get_time();  

	//anim_pos_at_change = anim_pos;

      }

    } else if (anim_ongoing2) {

      float time = (ev.mainloop_api.get_time()-start_time2)/100.0;

      mat = ev.move_api.get_matrix(mn, time_at_change-time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      //mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos -= env.delta_time;

      if (time_at_change - time - ev.mainloop_api.get_delta_time() < 0.0) {

	//std::cout << "anim_ongoing2=false" << std::endl;

	anim_ongoing2 = false;

	collect = ev.matrix_api.identity();

      }

    } else {

      m2 = add_matrix2(e, env.env);

      mat2 = ev.matrix_api.mult(collect,m2);

    }

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    Matrix old_in_MV = env.in_MV;

    env.in_MV = find_matrix(e, mat2);



    Matrix old_env = env.env;

    env.env = find_matrix(e,mat2); /* * env.env*/;

    next->execute(env);

    ev.shader_api.unuse(s3);

    env.env = old_env;

    env.in_MV = old_in_MV;

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  float start_time2;

  MainLoopItem *next;

  GameApi::MN mn;

  int key;

  bool anim_ongoing;

  bool anim_ongoing2;

  float anim_pos;

  float duration;

  GameApi::M collect;

  bool key_pressed;

  float anim_pos_at_change;

  float time_at_change;

  bool key_canceled;

  bool start_anim_chain;

};

EXPORT GameApi::ML GameApi::MovementNode::temp_key_activate_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int key, float duration)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new TempKeyActivateML(e, ev, item, move, key, duration));

}

class RotateMovement : public Movement

{

public:

public:

  RotateMovement(Movement *next, float start_time, float end_time,

		 float p_x, float p_y, float p_z,

		float v_x, float v_y, float v_z, float angle)

    : next(next), start_time(start_time), end_time(end_time),

      p_x(p_x), p_y(p_y), p_z(p_z),

      v_x(v_x), v_y(v_y), v_z(v_z), angle(angle) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix m) { }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { return next->get_whole_matrix(time, delta_time); }

    if (time>=end_time) { return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), angle)*next->get_whole_matrix(time, delta_time); }

    float d = time - start_time;

    d/=(end_time-start_time); // [0..1]

    return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), d*angle)*next->get_whole_matrix(time, delta_time);

  }

private:

  Movement *next;

  float start_time, end_time;

  float p_x,p_y,p_z;

  float v_x,v_y,v_z;

  float angle;

};

EXPORT GameApi::MN GameApi::MovementNode::rotate(MN next, float start_time, float end_time,

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new RotateMovement(nxt, start_time, end_time,

					p_x,p_y,p_z,v_x, v_y, v_z, angle));

}

class RotateMovement : public Movement

{

public:

public:

  RotateMovement(Movement *next, float start_time, float end_time,

		 float p_x, float p_y, float p_z,

		float v_x, float v_y, float v_z, float angle)

    : next(next), start_time(start_time), end_time(end_time),

      p_x(p_x), p_y(p_y), p_z(p_z),

      v_x(v_x), v_y(v_y), v_z(v_z), angle(angle) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix m) { }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { return next->get_whole_matrix(time, delta_time); }

    if (time>=end_time) { return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), angle)*next->get_whole_matrix(time, delta_time); }

    float d = time - start_time;

    d/=(end_time-start_time); // [0..1]

    return Matrix::RotateAroundAxisPoint(Point(p_x,p_y,p_z),Vector(v_x,v_y,v_z), d*angle)*next->get_whole_matrix(time, delta_time);

  }

private:

  Movement *next;

  float start_time, end_time;

  float p_x,p_y,p_z;

  float v_x,v_y,v_z;

  float angle;

};

EXPORT GameApi::MN GameApi::MovementNode::rotate(MN next, float start_time, float end_time, float p_x, float p_y, float p_z, float v_x, float v_y, float v_z, float angle)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new RotateMovement(nxt, start_time, end_time,

					p_x,p_y,p_z,v_x, v_y, v_z, angle));

}

class TempKeyActivateML : public MainLoopItem

{

public:

  TempKeyActivateML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN nm, int key, float duration) : e(e), ev(ev), next(next), mn(nm),key(key), duration(duration)

  { 

    start_time = 0.0; //ev.mainloop_api.get_time();

    start_time2 = 0.0;

    anim_pos = 0.0;

    collect = ev.matrix_api.identity();

    anim_ongoing = false;

    anim_ongoing2 = false;

    key_pressed = false;

    key_canceled=false;

    start_anim_chain = false;

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &eve)

  {

    Movement *move = find_move(e, mn);

    move->event(eve);



    bool start_anim = false;

    bool start_anim2 = false;

    int ch = eve.ch;

#ifdef EMSCRIPTEN

    if (ch>=4 && ch<=29) { ch = ch - 4; ch=ch+'a'; }

    if (ch==39) ch='0';

    if (ch>=30 && ch<=38) { ch = ch-30; ch=ch+'1'; }

#endif

    if (eve.type==0x300 && ch == key && !anim_ongoing && !anim_ongoing2 && !key_pressed) { start_anim = true; } else if (eve.type==0x300 && ch==key && !key_pressed)

      {

	key_canceled=true;

      }

    if (eve.type==0x300 && ch == key) { key_pressed = true; }

    if (eve.type==0x301 && ch == key && !anim_ongoing2 && !key_canceled) { key_pressed = false;  start_anim2 = true; } 

    if (eve.type==0x301 && ch==key) { key_canceled=false;

      //if (!anim_ongoing && !anim_ongoing2 && anim_pos>0.0) {

      //	anim_pos = duration;

      //	start_anim2 = true;

      //}

    }



    if (start_anim) {

      start_anim_chain = false;

      //std::cout << "start_anim" << std::endl;

      anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

      start_anim = false;

    }

    if (start_anim2 && !start_anim_chain) {

      start_anim_chain = true;

      //std::cout << "start_anim2" << std::endl;

      anim_ongoing = false;

      anim_ongoing2 = true; 

      start_time2 = ev.mainloop_api.get_time();  

      anim_pos_at_change = anim_pos;

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      time_at_change = std::min(time,duration);



      //      collect = ev.move_api.get_matrix(mn, anim_pos_at_change, ev.mainloop_api.get_delta_time());

      start_anim2 = false;

    }



    

    next->handle_event(eve);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e, mn);

    move->frame(env);





    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::M mat,m2,mat2;

    if (anim_ongoing) {

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      //mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos += env.delta_time;

      if (anim_pos > duration-env.delta_time) {

	//std::cout << "anim_ongoing=false" << std::endl;

	anim_ongoing = false;

	collect = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());



	if (0)

	{

	  start_anim_chain = true;

	  //std::cout << "start_anim2" << std::endl;

	  anim_ongoing = false;

	  anim_ongoing2 = true; 

	  start_time2 = ev.mainloop_api.get_time();  

	  anim_pos_at_change = anim_pos;

	  float time = (ev.mainloop_api.get_time()-start_time)/100.0;

	  time_at_change = std::min(time,duration);

	}



	//anim_ongoing2 = true;

	//start_time2 = ev.mainloop_api.get_time();  

	//anim_pos_at_change = anim_pos;

      }

    } else if (anim_ongoing2) {

      float time = (ev.mainloop_api.get_time()-start_time2)/100.0;

      mat = ev.move_api.get_matrix(mn, time_at_change-time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      //mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos -= env.delta_time;

      if (time_at_change - time - ev.mainloop_api.get_delta_time() < 0.0) {

	//std::cout << "anim_ongoing2=false" << std::endl;

	anim_ongoing2 = false;

	collect = ev.matrix_api.identity();

      }

    } else {

      m2 = add_matrix2(e, env.env);

      mat2 = ev.matrix_api.mult(collect,m2);

    }

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    Matrix old_in_MV = env.in_MV;

    env.in_MV = find_matrix(e, mat2);



    Matrix old_env = env.env;

    env.env = find_matrix(e,mat2); /* * env.env*/;

    next->execute(env);

    ev.shader_api.unuse(s3);

    env.env = old_env;

    env.in_MV = old_in_MV;

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  float start_time2;

  MainLoopItem *next;

  GameApi::MN mn;

  int key;

  bool anim_ongoing;

  bool anim_ongoing2;

  float anim_pos;

  float duration;

  GameApi::M collect;

  bool key_pressed;

  float anim_pos_at_change;

  float time_at_change;

  bool key_canceled;

  bool start_anim_chain;

};

EXPORT GameApi::ML GameApi::MovementNode::temp_key_activate_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int key, float duration)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new TempKeyActivateML(e, ev, item, move, key, duration));

}

class TempKeyActivateML : public MainLoopItem

{

public:

  TempKeyActivateML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN nm, int key, float duration) : e(e), ev(ev), next(next), mn(nm),key(key), duration(duration)

  { 

    start_time = 0.0; //ev.mainloop_api.get_time();

    start_time2 = 0.0;

    anim_pos = 0.0;

    collect = ev.matrix_api.identity();

    anim_ongoing = false;

    anim_ongoing2 = false;

    key_pressed = false;

    key_canceled=false;

    start_anim_chain = false;

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &eve)

  {

    Movement *move = find_move(e, mn);

    move->event(eve);



    bool start_anim = false;

    bool start_anim2 = false;

    int ch = eve.ch;

#ifdef EMSCRIPTEN

    if (ch>=4 && ch<=29) { ch = ch - 4; ch=ch+'a'; }

    if (ch==39) ch='0';

    if (ch>=30 && ch<=38) { ch = ch-30; ch=ch+'1'; }

#endif

    if (eve.type==0x300 && ch == key && !anim_ongoing && !anim_ongoing2 && !key_pressed) { start_anim = true; } else if (eve.type==0x300 && ch==key && !key_pressed)

      {

	key_canceled=true;

      }

    if (eve.type==0x300 && ch == key) { key_pressed = true; }

    if (eve.type==0x301 && ch == key && !anim_ongoing2 && !key_canceled) { key_pressed = false;  start_anim2 = true; } 

    if (eve.type==0x301 && ch==key) { key_canceled=false;

      //if (!anim_ongoing && !anim_ongoing2 && anim_pos>0.0) {

      //	anim_pos = duration;

      //	start_anim2 = true;

      //}

    }



    if (start_anim) {

      start_anim_chain = false;

      //std::cout << "start_anim" << std::endl;

      anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

      start_anim = false;

    }

    if (start_anim2 && !start_anim_chain) {

      start_anim_chain = true;

      //std::cout << "start_anim2" << std::endl;

      anim_ongoing = false;

      anim_ongoing2 = true; 

      start_time2 = ev.mainloop_api.get_time();  

      anim_pos_at_change = anim_pos;

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      time_at_change = std::min(time,duration);



      //      collect = ev.move_api.get_matrix(mn, anim_pos_at_change, ev.mainloop_api.get_delta_time());

      start_anim2 = false;

    }



    

    next->handle_event(eve);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e, mn);

    move->frame(env);





    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::M mat,m2,mat2;

    if (anim_ongoing) {

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      //mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos += env.delta_time;

      if (anim_pos > duration-env.delta_time) {

	//std::cout << "anim_ongoing=false" << std::endl;

	anim_ongoing = false;

	collect = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());



	if (0)

	{

	  start_anim_chain = true;

	  //std::cout << "start_anim2" << std::endl;

	  anim_ongoing = false;

	  anim_ongoing2 = true; 

	  start_time2 = ev.mainloop_api.get_time();  

	  anim_pos_at_change = anim_pos;

	  float time = (ev.mainloop_api.get_time()-start_time)/100.0;

	  time_at_change = std::min(time,duration);

	}



	//anim_ongoing2 = true;

	//start_time2 = ev.mainloop_api.get_time();  

	//anim_pos_at_change = anim_pos;

      }

    } else if (anim_ongoing2) {

      float time = (ev.mainloop_api.get_time()-start_time2)/100.0;

      mat = ev.move_api.get_matrix(mn, time_at_change-time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      //mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos -= env.delta_time;

      if (time_at_change - time - ev.mainloop_api.get_delta_time() < 0.0) {

	//std::cout << "anim_ongoing2=false" << std::endl;

	anim_ongoing2 = false;

	collect = ev.matrix_api.identity();

      }

    } else {

      m2 = add_matrix2(e, env.env);

      mat2 = ev.matrix_api.mult(collect,m2);

    }

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    Matrix old_in_MV = env.in_MV;

    env.in_MV = find_matrix(e, mat2);



    Matrix old_env = env.env;

    env.env = find_matrix(e,mat2); /* * env.env*/;

    next->execute(env);

    ev.shader_api.unuse(s3);

    env.env = old_env;

    env.in_MV = old_in_MV;

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  float start_time2;

  MainLoopItem *next;

  GameApi::MN mn;

  int key;

  bool anim_ongoing;

  bool anim_ongoing2;

  float anim_pos;

  float duration;

  GameApi::M collect;

  bool key_pressed;

  float anim_pos_at_change;

  float time_at_change;

  bool key_canceled;

  bool start_anim_chain;

};

EXPORT GameApi::ML GameApi::MovementNode::temp_key_activate_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int key, float duration)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new TempKeyActivateML(e, ev, item, move, key, duration));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class KeyActivateML : public MainLoopItem

{

public:

  KeyActivateML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int key, float duration) : e(e), ev(ev), next(next), mn(mn),key(key), duration(duration)

  { 

    start_time = 0.0; //ev.mainloop_api.get_time();

    anim_pos = 0.0;

    collect = ev.matrix_api.identity();

    anim_ongoing = false;

    key_pressed = false;

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &eve)

  {

    Movement *move = find_move(e, mn);

    move->event(eve);



    int ch = eve.ch;

#ifdef EMSCRIPTEN

    if (ch>=4 && ch<=29) { ch = ch - 4; ch=ch+'a'; }

    if (ch==39) ch='0';

    if (ch>=30 && ch<=38) { ch = ch-30; ch=ch+'1'; }

#endif

    bool start_anim = false;

    if (eve.type==0x300 && ch == key) { key_pressed = true; }

    if (eve.type==0x300 && ch == key && !anim_ongoing) { start_anim = true; }

    if (eve.type==0x301 && ch == key) { key_pressed = false; }



    if (start_anim) {

      anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

    }



    next->handle_event(eve);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e, mn);

    move->frame(env);





    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::M mat,m2,mat2;

    if (anim_ongoing) {

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos += env.delta_time;

      if (anim_pos > duration-env.delta_time) {

	anim_ongoing = false;

	collect = ev.matrix_api.mult(collect, ev.move_api.get_matrix(mn, duration, env.delta_time));

	

	if (key_pressed) { // repeat animation if key is being pressed down when anim stops

	  anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

	}



      }



    } else {

      m2 = add_matrix2(e, env.env);

      mat2 = ev.matrix_api.mult(collect,m2);

    }

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    Matrix old_in_MV = env.in_MV;

    env.in_MV = find_matrix(e, mat2);



    Matrix old_env = env.env;

    env.env = find_matrix(e,mat2); /* * env.env*/;

    next->execute(env);

    ev.shader_api.unuse(s3);

    env.env = old_env;

    env.in_MV = old_in_MV;

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int key;

  bool anim_ongoing;

  float anim_pos;

  float duration;

  GameApi::M collect;

  bool key_pressed;

};

EXPORT GameApi::ML GameApi::MovementNode::key_activate_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int key, float duration)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new KeyActivateML(e,ev,item, move, key, duration));

}

class KeyActivateML : public MainLoopItem

{

public:

  KeyActivateML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int key, float duration) : e(e), ev(ev), next(next), mn(mn),key(key), duration(duration)

  { 

    start_time = 0.0; //ev.mainloop_api.get_time();

    anim_pos = 0.0;

    collect = ev.matrix_api.identity();

    anim_ongoing = false;

    key_pressed = false;

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &eve)

  {

    Movement *move = find_move(e, mn);

    move->event(eve);



    int ch = eve.ch;

#ifdef EMSCRIPTEN

    if (ch>=4 && ch<=29) { ch = ch - 4; ch=ch+'a'; }

    if (ch==39) ch='0';

    if (ch>=30 && ch<=38) { ch = ch-30; ch=ch+'1'; }

#endif

    bool start_anim = false;

    if (eve.type==0x300 && ch == key) { key_pressed = true; }

    if (eve.type==0x300 && ch == key && !anim_ongoing) { start_anim = true; }

    if (eve.type==0x301 && ch == key) { key_pressed = false; }



    if (start_anim) {

      anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

    }



    next->handle_event(eve);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e, mn);

    move->frame(env);





    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::M mat,m2,mat2;

    if (anim_ongoing) {

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos += env.delta_time;

      if (anim_pos > duration-env.delta_time) {

	anim_ongoing = false;

	collect = ev.matrix_api.mult(collect, ev.move_api.get_matrix(mn, duration, env.delta_time));

	

	if (key_pressed) { // repeat animation if key is being pressed down when anim stops

	  anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

	}



      }



    } else {

      m2 = add_matrix2(e, env.env);

      mat2 = ev.matrix_api.mult(collect,m2);

    }

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    Matrix old_in_MV = env.in_MV;

    env.in_MV = find_matrix(e, mat2);



    Matrix old_env = env.env;

    env.env = find_matrix(e,mat2); /* * env.env*/;

    next->execute(env);

    ev.shader_api.unuse(s3);

    env.env = old_env;

    env.in_MV = old_in_MV;

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int key;

  bool anim_ongoing;

  float anim_pos;

  float duration;

  GameApi::M collect;

  bool key_pressed;

};

EXPORT GameApi::ML GameApi::MovementNode::key_activate_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int key, float duration)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new KeyActivateML(e,ev,item, move, key, duration));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class KeyActivateML : public MainLoopItem

{

public:

  KeyActivateML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int key, float duration) : e(e), ev(ev), next(next), mn(mn),key(key), duration(duration)

  { 

    start_time = 0.0; //ev.mainloop_api.get_time();

    anim_pos = 0.0;

    collect = ev.matrix_api.identity();

    anim_ongoing = false;

    key_pressed = false;

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &eve)

  {

    Movement *move = find_move(e, mn);

    move->event(eve);



    int ch = eve.ch;

#ifdef EMSCRIPTEN

    if (ch>=4 && ch<=29) { ch = ch - 4; ch=ch+'a'; }

    if (ch==39) ch='0';

    if (ch>=30 && ch<=38) { ch = ch-30; ch=ch+'1'; }

#endif

    bool start_anim = false;

    if (eve.type==0x300 && ch == key) { key_pressed = true; }

    if (eve.type==0x300 && ch == key && !anim_ongoing) { start_anim = true; }

    if (eve.type==0x301 && ch == key) { key_pressed = false; }



    if (start_anim) {

      anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

    }



    next->handle_event(eve);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e, mn);

    move->frame(env);





    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::M mat,m2,mat2;

    if (anim_ongoing) {

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos += env.delta_time;

      if (anim_pos > duration-env.delta_time) {

	anim_ongoing = false;

	collect = ev.matrix_api.mult(collect, ev.move_api.get_matrix(mn, duration, env.delta_time));

	

	if (key_pressed) { // repeat animation if key is being pressed down when anim stops

	  anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

	}



      }



    } else {

      m2 = add_matrix2(e, env.env);

      mat2 = ev.matrix_api.mult(collect,m2);

    }

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    Matrix old_in_MV = env.in_MV;

    env.in_MV = find_matrix(e, mat2);



    Matrix old_env = env.env;

    env.env = find_matrix(e,mat2); /* * env.env*/;

    next->execute(env);

    ev.shader_api.unuse(s3);

    env.env = old_env;

    env.in_MV = old_in_MV;

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int key;

  bool anim_ongoing;

  float anim_pos;

  float duration;

  GameApi::M collect;

  bool key_pressed;

};

EXPORT GameApi::ML GameApi::MovementNode::key_activate_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int key, float duration)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new KeyActivateML(e,ev,item, move, key, duration));

}

class KeyActivateML : public MainLoopItem

{

public:

  KeyActivateML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int key, float duration) : e(e), ev(ev), next(next), mn(mn),key(key), duration(duration)

  { 

    start_time = 0.0; //ev.mainloop_api.get_time();

    anim_pos = 0.0;

    collect = ev.matrix_api.identity();

    anim_ongoing = false;

    key_pressed = false;

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &eve)

  {

    Movement *move = find_move(e, mn);

    move->event(eve);



    int ch = eve.ch;

#ifdef EMSCRIPTEN

    if (ch>=4 && ch<=29) { ch = ch - 4; ch=ch+'a'; }

    if (ch==39) ch='0';

    if (ch>=30 && ch<=38) { ch = ch-30; ch=ch+'1'; }

#endif

    bool start_anim = false;

    if (eve.type==0x300 && ch == key) { key_pressed = true; }

    if (eve.type==0x300 && ch == key && !anim_ongoing) { start_anim = true; }

    if (eve.type==0x301 && ch == key) { key_pressed = false; }



    if (start_anim) {

      anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

    }



    next->handle_event(eve);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e, mn);

    move->frame(env);





    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::M mat,m2,mat2;

    if (anim_ongoing) {

      float time = (ev.mainloop_api.get_time()-start_time)/100.0;

      mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

      m2 = add_matrix2(e, env.env);

      mat2 = mat;

      mat2 = ev.matrix_api.mult(mat2, collect);

      mat2 = ev.matrix_api.mult(mat2,m2);



      anim_pos += env.delta_time;

      if (anim_pos > duration-env.delta_time) {

	anim_ongoing = false;

	collect = ev.matrix_api.mult(collect, ev.move_api.get_matrix(mn, duration, env.delta_time));

	

	if (key_pressed) { // repeat animation if key is being pressed down when anim stops

	  anim_ongoing = true; start_time = ev.mainloop_api.get_time(); anim_pos = 0.0; 

	}



      }



    } else {

      m2 = add_matrix2(e, env.env);

      mat2 = ev.matrix_api.mult(collect,m2);

    }

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    Matrix old_in_MV = env.in_MV;

    env.in_MV = find_matrix(e, mat2);



    Matrix old_env = env.env;

    env.env = find_matrix(e,mat2); /* * env.env*/;

    next->execute(env);

    ev.shader_api.unuse(s3);

    env.env = old_env;

    env.in_MV = old_in_MV;

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int key;

  bool anim_ongoing;

  float anim_pos;

  float duration;

  GameApi::M collect;

  bool key_pressed;

};

EXPORT GameApi::ML GameApi::MovementNode::key_activate_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int key, float duration)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new KeyActivateML(e,ev,item, move, key, duration));

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class PTArray : public PointsApiPoints

{

public:

  PTArray(std::vector<Point> vec) : vec(vec) {}

  void Prepare() { }

  void HandleEvent(MainLoopEvent &event) { }

  bool Update(MainLoopEnv &e) { return false; }

  int NumPoints() const { return vec.size(); }

  Point Pos(int i) const { return vec[i]; }

  unsigned int Color(int i) const { return 0xffffffff; }

private:

  std::vector<Point> vec;

};

GameApi::PTS GameApi::PointsApi::pt_array(EveryApi &ev, std::vector<PT> vec)

{

  int s = vec.size();

  std::vector<Point> vec2;

  for(int i=0;i<s;i++) {

    vec2.push_back(*find_point(e,vec[i]));

  }

  return add_points_api_points(e, new PTArray(vec2));

}

class PTArray : public PointsApiPoints

{

public:

  PTArray(std::vector<Point> vec) : vec(vec) {}

  void Prepare() { }

  void HandleEvent(MainLoopEvent &event) { }

  bool Update(MainLoopEnv &e) { return false; }

  int NumPoints() const { return vec.size(); }

  Point Pos(int i) const { return vec[i]; }

  unsigned int Color(int i) const { return 0xffffffff; }

private:

  std::vector<Point> vec;

};

GameApi::PTS GameApi::PointsApi::pt_array(EveryApi &ev, std::vector<PT> vec)

{

  int s = vec.size();

  std::vector<Point> vec2;

  for(int i=0;i<s;i++) {

    vec2.push_back(*find_point(e,vec[i]));

  }

  return add_points_api_points(e, new PTArray(vec2));

}

class LocalMove : public MainLoopItem

{

public:

  LocalMove(GameApi::Env &env, GameApi::EveryApi &ev, MainLoopItem *inner, PointsApiPoints *o) : env(env), ev(ev), inner(inner), o(o) { }

  void Prepare() { inner->Prepare(); }

  virtual void execute(MainLoopEnv &e)

  {

    o->Update(e);

    int s = o->NumPoints();

    for(int i=0;i<s;i++)

      {

	Point p = o->Pos(i);

	GameApi::M m = ev.matrix_api.trans(p.x,p.y,p.z);

	GameApi::M m2 = add_matrix2(env, e.in_MV);

	MainLoopEnv ee = e;



	GameApi::SH s1;

	s1.id = e.sh_texture;

	GameApi::SH s11;

	s11.id = e.sh_texture_2d;

	GameApi::SH s2;

	s2.id = e.sh_array_texture;

	GameApi::SH s3;

	s3.id = e.sh_color;

	

	GameApi::M mat2 = ev.matrix_api.mult(m,m2);

	//GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

	ev.shader_api.use(s1);

	ev.shader_api.set_var(s1, "in_MV", mat2);

	//ev.shader_api.set_var(s1, "in_iMV", mat2i);

	ev.shader_api.use(s11);

	ev.shader_api.set_var(s11, "in_MV", mat2);

	//ev.shader_api.set_var(s11, "in_iMV", mat2i);

	ev.shader_api.use(s2);

	ev.shader_api.set_var(s2, "in_MV", mat2);

	//ev.shader_api.set_var(s2, "in_iMV", mat2i);

	ev.shader_api.use(s3);

	ev.shader_api.set_var(s3, "in_MV", mat2);

	//ev.shader_api.set_var(s3, "in_iMV", mat2i);

	

	

	ee.in_MV = find_matrix(env, m) * e.in_MV;

	ee.env = find_matrix(env, m) * e.in_MV;

	inner->execute(ee);

	ev.shader_api.unuse(s3);

      }	  

  }

  virtual void handle_event(MainLoopEvent &e)

  {

    inner->handle_event(e);

  }

  virtual int shader_id() { return -1; }



private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  MainLoopItem *inner;

  PointsApiPoints *o;

};

GameApi::ML GameApi::MovementNode::local_move(EveryApi &ev, ML inner_ml, PTS center_points)

{

  MainLoopItem *item = find_main_loop(e, inner_ml);

  PointsApiPoints *o = find_pointsapi_points(e, center_points);

  return add_main_loop(e, new LocalMove(e, ev, item, o));

}

class LocalMove : public MainLoopItem

{

public:

  LocalMove(GameApi::Env &env, GameApi::EveryApi &ev, MainLoopItem *inner, PointsApiPoints *o) : env(env), ev(ev), inner(inner), o(o) { }

  void Prepare() { inner->Prepare(); }

  virtual void execute(MainLoopEnv &e)

  {

    o->Update(e);

    int s = o->NumPoints();

    for(int i=0;i<s;i++)

      {

	Point p = o->Pos(i);

	GameApi::M m = ev.matrix_api.trans(p.x,p.y,p.z);

	GameApi::M m2 = add_matrix2(env, e.in_MV);

	MainLoopEnv ee = e;



	GameApi::SH s1;

	s1.id = e.sh_texture;

	GameApi::SH s11;

	s11.id = e.sh_texture_2d;

	GameApi::SH s2;

	s2.id = e.sh_array_texture;

	GameApi::SH s3;

	s3.id = e.sh_color;

	

	GameApi::M mat2 = ev.matrix_api.mult(m,m2);

	//GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

	ev.shader_api.use(s1);

	ev.shader_api.set_var(s1, "in_MV", mat2);

	//ev.shader_api.set_var(s1, "in_iMV", mat2i);

	ev.shader_api.use(s11);

	ev.shader_api.set_var(s11, "in_MV", mat2);

	//ev.shader_api.set_var(s11, "in_iMV", mat2i);

	ev.shader_api.use(s2);

	ev.shader_api.set_var(s2, "in_MV", mat2);

	//ev.shader_api.set_var(s2, "in_iMV", mat2i);

	ev.shader_api.use(s3);

	ev.shader_api.set_var(s3, "in_MV", mat2);

	//ev.shader_api.set_var(s3, "in_iMV", mat2i);

	

	

	ee.in_MV = find_matrix(env, m) * e.in_MV;

	ee.env = find_matrix(env, m) * e.in_MV;

	inner->execute(ee);

	ev.shader_api.unuse(s3);

      }	  

  }

  virtual void handle_event(MainLoopEvent &e)

  {

    inner->handle_event(e);

  }

  virtual int shader_id() { return -1; }



private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  MainLoopItem *inner;

  PointsApiPoints *o;

};

GameApi::ML GameApi::MovementNode::local_move(EveryApi &ev, ML inner_ml, PTS center_points)

{

  MainLoopItem *item = find_main_loop(e, inner_ml);

  PointsApiPoints *o = find_pointsapi_points(e, center_points);

  return add_main_loop(e, new LocalMove(e, ev, item, o));

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

EXPORT GameApi::PT GameApi::PointApi::point(float x, float y, float z)

{

  return add_point(e, x,y,z);

}

class PTArray : public PointsApiPoints

{

public:

  PTArray(std::vector<Point> vec) : vec(vec) {}

  void Prepare() { }

  void HandleEvent(MainLoopEvent &event) { }

  bool Update(MainLoopEnv &e) { return false; }

  int NumPoints() const { return vec.size(); }

  Point Pos(int i) const { return vec[i]; }

  unsigned int Color(int i) const { return 0xffffffff; }

private:

  std::vector<Point> vec;

};

GameApi::PTS GameApi::PointsApi::pt_array(EveryApi &ev, std::vector<PT> vec)

{

  int s = vec.size();

  std::vector<Point> vec2;

  for(int i=0;i<s;i++) {

    vec2.push_back(*find_point(e,vec[i]));

  }

  return add_points_api_points(e, new PTArray(vec2));

}

class PTArray : public PointsApiPoints

{

public:

  PTArray(std::vector<Point> vec) : vec(vec) {}

  void Prepare() { }

  void HandleEvent(MainLoopEvent &event) { }

  bool Update(MainLoopEnv &e) { return false; }

  int NumPoints() const { return vec.size(); }

  Point Pos(int i) const { return vec[i]; }

  unsigned int Color(int i) const { return 0xffffffff; }

private:

  std::vector<Point> vec;

};

GameApi::PTS GameApi::PointsApi::pt_array(EveryApi &ev, std::vector<PT> vec)

{

  int s = vec.size();

  std::vector<Point> vec2;

  for(int i=0;i<s;i++) {

    vec2.push_back(*find_point(e,vec[i]));

  }

  return add_points_api_points(e, new PTArray(vec2));

}

class LocalMove : public MainLoopItem

{

public:

  LocalMove(GameApi::Env &env, GameApi::EveryApi &ev, MainLoopItem *inner, PointsApiPoints *o) : env(env), ev(ev), inner(inner), o(o) { }

  void Prepare() { inner->Prepare(); }

  virtual void execute(MainLoopEnv &e)

  {

    o->Update(e);

    int s = o->NumPoints();

    for(int i=0;i<s;i++)

      {

	Point p = o->Pos(i);

	GameApi::M m = ev.matrix_api.trans(p.x,p.y,p.z);

	GameApi::M m2 = add_matrix2(env, e.in_MV);

	MainLoopEnv ee = e;



	GameApi::SH s1;

	s1.id = e.sh_texture;

	GameApi::SH s11;

	s11.id = e.sh_texture_2d;

	GameApi::SH s2;

	s2.id = e.sh_array_texture;

	GameApi::SH s3;

	s3.id = e.sh_color;

	

	GameApi::M mat2 = ev.matrix_api.mult(m,m2);

	//GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

	ev.shader_api.use(s1);

	ev.shader_api.set_var(s1, "in_MV", mat2);

	//ev.shader_api.set_var(s1, "in_iMV", mat2i);

	ev.shader_api.use(s11);

	ev.shader_api.set_var(s11, "in_MV", mat2);

	//ev.shader_api.set_var(s11, "in_iMV", mat2i);

	ev.shader_api.use(s2);

	ev.shader_api.set_var(s2, "in_MV", mat2);

	//ev.shader_api.set_var(s2, "in_iMV", mat2i);

	ev.shader_api.use(s3);

	ev.shader_api.set_var(s3, "in_MV", mat2);

	//ev.shader_api.set_var(s3, "in_iMV", mat2i);

	

	

	ee.in_MV = find_matrix(env, m) * e.in_MV;

	ee.env = find_matrix(env, m) * e.in_MV;

	inner->execute(ee);

	ev.shader_api.unuse(s3);

      }	  

  }

  virtual void handle_event(MainLoopEvent &e)

  {

    inner->handle_event(e);

  }

  virtual int shader_id() { return -1; }



private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  MainLoopItem *inner;

  PointsApiPoints *o;

};

GameApi::ML GameApi::MovementNode::local_move(EveryApi &ev, ML inner_ml, PTS center_points)

{

  MainLoopItem *item = find_main_loop(e, inner_ml);

  PointsApiPoints *o = find_pointsapi_points(e, center_points);

  return add_main_loop(e, new LocalMove(e, ev, item, o));

}

class LocalMove : public MainLoopItem

{

public:

  LocalMove(GameApi::Env &env, GameApi::EveryApi &ev, MainLoopItem *inner, PointsApiPoints *o) : env(env), ev(ev), inner(inner), o(o) { }

  void Prepare() { inner->Prepare(); }

  virtual void execute(MainLoopEnv &e)

  {

    o->Update(e);

    int s = o->NumPoints();

    for(int i=0;i<s;i++)

      {

	Point p = o->Pos(i);

	GameApi::M m = ev.matrix_api.trans(p.x,p.y,p.z);

	GameApi::M m2 = add_matrix2(env, e.in_MV);

	MainLoopEnv ee = e;



	GameApi::SH s1;

	s1.id = e.sh_texture;

	GameApi::SH s11;

	s11.id = e.sh_texture_2d;

	GameApi::SH s2;

	s2.id = e.sh_array_texture;

	GameApi::SH s3;

	s3.id = e.sh_color;

	

	GameApi::M mat2 = ev.matrix_api.mult(m,m2);

	//GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

	ev.shader_api.use(s1);

	ev.shader_api.set_var(s1, "in_MV", mat2);

	//ev.shader_api.set_var(s1, "in_iMV", mat2i);

	ev.shader_api.use(s11);

	ev.shader_api.set_var(s11, "in_MV", mat2);

	//ev.shader_api.set_var(s11, "in_iMV", mat2i);

	ev.shader_api.use(s2);

	ev.shader_api.set_var(s2, "in_MV", mat2);

	//ev.shader_api.set_var(s2, "in_iMV", mat2i);

	ev.shader_api.use(s3);

	ev.shader_api.set_var(s3, "in_MV", mat2);

	//ev.shader_api.set_var(s3, "in_iMV", mat2i);

	

	

	ee.in_MV = find_matrix(env, m) * e.in_MV;

	ee.env = find_matrix(env, m) * e.in_MV;

	inner->execute(ee);

	ev.shader_api.unuse(s3);

      }	  

  }

  virtual void handle_event(MainLoopEvent &e)

  {

    inner->handle_event(e);

  }

  virtual int shader_id() { return -1; }



private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  MainLoopItem *inner;

  PointsApiPoints *o;

};

GameApi::ML GameApi::MovementNode::local_move(EveryApi &ev, ML inner_ml, PTS center_points)

{

  MainLoopItem *item = find_main_loop(e, inner_ml);

  PointsApiPoints *o = find_pointsapi_points(e, center_points);

  return add_main_loop(e, new LocalMove(e, ev, item, o));

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class MatrixMovement : public Movement

{

public:

  MatrixMovement(Movement *next, Matrix m) : next(next), m(m) { }

  virtual void event(MainLoopEvent &e) { next->event(e); }

  virtual void frame(MainLoopEnv &e) { next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { next->draw_event(e); }



  void set_matrix(Matrix mm) { m = mm; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    return next->get_whole_matrix(time, delta_time)*m;

  }

private:

  Movement *next;

  Matrix m;

};

EXPORT GameApi::MN GameApi::MovementNode::trans2(MN next, float dx, float dy, float dz)

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new MatrixMovement(nxt, Matrix::Translate(dx,dy,dz)));  

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class TranslateMovement : public Movement

{

public:

  TranslateMovement(Movement *next, float start_time, float end_time,

		    float dx, float dy, float dz)

    : next(next), start_time(start_time), end_time(end_time),

      dx(dx), dy(dy), dz(dz) { }

  virtual void event(MainLoopEvent &e) { if (next) next->event(e); }

  virtual void frame(MainLoopEnv &e) { if (next) next->frame(e); }

  virtual void draw_frame(DrawLoopEnv &e) { if (next) next->draw_frame(e); }

  virtual void draw_event(FrameLoopEvent &e) { if (next) next->draw_event(e); }



  void set_matrix(Matrix m) { }

  void set_pos(float ddx, float ddy, float ddz) { dx=ddx; dy=ddy; dz=ddz; }

  Matrix get_whole_matrix(float time, float delta_time) const

  {

    if (time<start_time) { Matrix m=Matrix::Identity(); return next?next->get_whole_matrix(time, delta_time):m; }

    if (time>=end_time) { Matrix m=Matrix::Identity(); return Matrix::Translate(dx,dy,dz)*(next?next->get_whole_matrix(time,delta_time):m); }

    float d = time - start_time;

    //if (fabs(end_time-start_time)>0.01)

      d/=(end_time-start_time);

    return Matrix::Translate(dx*d,dy*d,dz*d)*(next?next->get_whole_matrix(time, delta_time):Matrix::Identity());

  }

private:

  Movement *next;

  float start_time, end_time;

  float dx,dy,dz;

};

EXPORT GameApi::MN GameApi::MovementNode::translate(MN next, 

{

  Movement *nxt = find_move(e, next);

  return add_move(e, new TranslateMovement(nxt,start_time, end_time,

					   dx,dy,dz));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class MoveML : public MainLoopItem

{

public:

  MoveML(GameApi::Env &e, GameApi::EveryApi &ev, MainLoopItem *next, GameApi::MN mn, int clone_count, float time_delta) : e(e), ev(ev), next(next), mn(mn), clone_count(clone_count), time_delta(time_delta) 

  {

    firsttime = true;

    firsttime2 = false;

    start_time = 0.0; //ev.mainloop_api.get_time();

  }

  void reset_time() {

    start_time = ev.mainloop_api.get_time();

  }

  int shader_id() { return next->shader_id(); }

  void handle_event(MainLoopEvent &env)

  {

    next->handle_event(env);

    Movement *move = find_move(e,mn);

    move->event(env);

  }

  void Prepare() { next->Prepare(); }

  void execute(MainLoopEnv &env)

  {

    Movement *move = find_move(e,mn);

    move->frame(env);



    if (firsttime) {

      firsttime2 = true;

    }

    if (!firsttime && firsttime2)

      {

	reset_time();

	firsttime2 = false;

      }

    firsttime = false;

    for(int i=0;i<clone_count;i++)

      {

    GameApi::SH s1;

    s1.id = env.sh_texture;

    GameApi::SH s11;

    s11.id = env.sh_texture_2d;

    GameApi::SH s2;

    s2.id = env.sh_array_texture;

    GameApi::SH s3;

    s3.id = env.sh_color;

    GameApi::SH s4;

    s4.id = next->shader_id();

		    

    float time = (env.time*1000.0-start_time)/100.0+i*time_delta;

    GameApi::M mat = ev.move_api.get_matrix(mn, time, ev.mainloop_api.get_delta_time());

    //Matrix mat_i = find_matrix(e, mat);

    //std::cout << mat_i << std::endl;

    GameApi::M m2 = add_matrix2(e, env.env);

    //std::cout << env.env << std::endl;

    GameApi::M mat2 = ev.matrix_api.mult(mat,m2);

#ifdef HAS_MATRIX_INVERSE

    GameApi::M mat2i = ev.matrix_api.transpose(ev.matrix_api.inverse(mat2));

#endif

    ev.shader_api.use(s1);

    ev.shader_api.set_var(s1, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s1, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s11);

    ev.shader_api.set_var(s11, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s11, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s2);

    ev.shader_api.set_var(s2, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s2, "in_iMV", mat2i);

#endif

    ev.shader_api.use(s3);

    ev.shader_api.set_var(s3, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s3, "in_iMV", mat2i);

#endif

    if (s4.id != -1)

      {

    ev.shader_api.use(s4);

    ev.shader_api.set_var(s4, "in_MV", mat2);

#ifdef HAS_MATRIX_INVERSE

    ev.shader_api.set_var(s4, "in_iMV", mat2i);

#endif

      }





    //Matrix old_in_MV = env.in_MV;

    MainLoopEnv ee = env;

    ee.in_MV = find_matrix(e, mat2);



    //Matrix old_env = env.env;

    //float old_time = env.time;

    ee.env = find_matrix(e,mat2); /* * env.env*/;

    ee.time = env.time + i*time_delta/10.0;

    next->execute(ee);

    ev.shader_api.unuse(s3);

    //env.env = old_env;

    //env.time = old_time;

    //env.in_MV = old_in_MV;

      }

  }

private:

  GameApi::Env &e;

  GameApi::EveryApi &ev;

  float start_time;

  MainLoopItem *next;

  GameApi::MN mn;

  int clone_count;

  float time_delta;

  bool firsttime;

  bool firsttime2;

};

EXPORT GameApi::ML GameApi::MovementNode::move_ml(EveryApi &ev, GameApi::ML ml, GameApi::MN move, int clone_count, float time_delta)

{

  MainLoopItem *item = find_main_loop(e, ml);

  return add_main_loop(e, new MoveML(e,ev,item, move, clone_count, time_delta));

}

class ArrayMainLoop : public MainLoopItem

{

public:

  ArrayMainLoop(GameApi::Env &env, GameApi::EveryApi &ev, std::vector<MainLoopItem*> vec) : env(env), ev(ev), vec(vec) { }

  void Prepare() {

    int s = vec.size();

    for(int i=0;i<s;i++) vec[i]->Prepare();

  }

  void execute(MainLoopEnv &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	MainLoopEnv ee = e;



	// here's a block needed to distribute in_MV to different cases.

	int id = vec[i]->shader_id();

	if (id!=-1) {

	  GameApi::SH sh;

	  sh.id = id;

	  GameApi::M m = add_matrix2( env, e.in_MV);

	  ev.shader_api.use(sh);

	  ev.shader_api.set_var(sh, "in_MV", m);

	}

	vec[i]->execute(ee);

      }

  }

  void handle_event(MainLoopEvent &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	vec[i]->handle_event(e);

      }

  }

#if 0

  int shader_id() { 

    int s = vec.size();

    for(int i=s-1;i>=0;i--)

      {

	if (vec[i]->shader_id()!=-1) return vec[i]->shader_id();

      }

    return -1; 

  }

#endif

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  std::vector<MainLoopItem*> vec;

};

EXPORT GameApi::ML GameApi::MainLoopApi::array_ml(std::vector<ML> vec)

{

  std::vector<MainLoopItem*> vec2;

  int s = vec.size();

  for(int i=0;i<s;i++)

    {

      //std::cout << "array_ml id: " << vec[i].id << std::endl;

      vec2.push_back(find_main_loop(e,vec[i]));

    }

  return add_main_loop(e, new ArrayMainLoop(vec2));

}

class ArrayMainLoop : public MainLoopItem

{

public:

  ArrayMainLoop(GameApi::Env &env, GameApi::EveryApi &ev, std::vector<MainLoopItem*> vec) : env(env), ev(ev), vec(vec) { }

  void Prepare() {

    int s = vec.size();

    for(int i=0;i<s;i++) vec[i]->Prepare();

  }

  void execute(MainLoopEnv &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	MainLoopEnv ee = e;



	// here's a block needed to distribute in_MV to different cases.

	int id = vec[i]->shader_id();

	if (id!=-1) {

	  GameApi::SH sh;

	  sh.id = id;

	  GameApi::M m = add_matrix2( env, e.in_MV);

	  ev.shader_api.use(sh);

	  ev.shader_api.set_var(sh, "in_MV", m);

	}

	vec[i]->execute(ee);

      }

  }

  void handle_event(MainLoopEvent &e)

  {

    int s = vec.size();

    for(int i=0;i<s;i++)

      {

	vec[i]->handle_event(e);

      }

  }

#if 0

  int shader_id() { 

    int s = vec.size();

    for(int i=s-1;i>=0;i--)

      {

	if (vec[i]->shader_id()!=-1) return vec[i]->shader_id();

      }

    return -1; 

  }

#endif

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  std::vector<MainLoopItem*> vec;

};

EXPORT GameApi::ML GameApi::MainLoopApi::array_ml(GameApi::EveryApi &ev, std::vector<ML> vec)

{

  std::vector<MainLoopItem*> vec2;

  int s = vec.size();

  for(int i=0;i<s;i++)

    {

      //std::cout << "array_ml id: " << vec[i].id << std::endl;

      vec2.push_back(find_main_loop(e,vec[i]));

    }

  return add_main_loop(e, new ArrayMainLoop(e,ev,vec2));

}

class RenderP : public MainLoopItem

{

public:

  RenderP(GameApi::Env &env, GameApi::EveryApi &ev, GameApi::PolygonApi &api, GameApi::P p) : env(env), ev(ev), api(api), p(p)

  {

    shader.id = -1;

    firsttime = true;

  }

  int shader_id() { return shader.id; }

  void handle_event(MainLoopEvent &e)

  {

  }

  void Prepare() {}

  void execute(MainLoopEnv &e)

  { 

    if (firsttime)

      {

	va = ev.polygon_api.create_vertex_array(p,false);

      }



    GameApi::SH sh;

    if (ev.polygon_api.is_texture(va))

      {

	sh.id = e.sh_texture;

	if (ev.polygon_api.is_array_texture(va))

	  {

	    sh.id = e.sh_array_texture;

	  }

      }

    else

      {

	sh.id = e.sh_color;

      }



    GameApi::US u_v;

    GameApi::US u_f;

    u_v.id = 0;

    u_f.id = 0;

    if (e.us_vertex_shader!=-1)

      u_v.id = e.us_vertex_shader;

    if (e.us_fragment_shader!=-1)

      u_f.id = e.us_fragment_shader;

    if (firsttime)

      {

	if (u_v.id == 0)

	  u_v = ev.uber_api.v_empty();

	if (u_f.id == 0)

	  u_f = ev.uber_api.f_empty(false);

      }



#if 1

    if (ev.polygon_api.is_texture(va))

      {

	sh.id = e.sh_texture;

	if (firsttime)

	  {

	    if (e.us_vertex_shader==-1)

	      u_v = ev.uber_api.v_texture(u_v);

	    if (e.us_fragment_shader==-1)

	      u_f = ev.uber_api.f_texture(u_f);

	  }

	if (ev.polygon_api.is_array_texture(va))

	  {

	    sh.id = e.sh_array_texture;

	      if (firsttime)

	      {

		if (e.us_vertex_shader==-1)

		  u_v = ev.uber_api.v_texture_arr(u_v);

		if (e.us_fragment_shader==-1)

		  u_f = ev.uber_api.f_texture_arr(u_f);

	      }

	  }

      }

    else

      {

	sh.id = e.sh_color;

	if (firsttime)

	  {

	    if (e.us_vertex_shader==-1)

	      {

		u_v = ev.uber_api.v_colour(u_v);

		u_v = ev.uber_api.v_light(u_v);

	      }

	    if (e.us_fragment_shader==-1)

	      {

		u_f = ev.uber_api.f_colour(u_f);

		u_f = ev.uber_api.f_light(u_f);

	      }

	  }

      }

#endif



    if (firsttime && shader.id==-1)

      {

	GameApi::US vertex;

	GameApi::US fragment;

	vertex.id = u_v.id; //e.us_vertex_shader;

	fragment.id = u_f.id; //e.us_fragment_shader;

	if (e.sfo_id==-1)

	  {

	    shader = ev.shader_api.get_normal_shader("comb", "comb", "", vertex, fragment,e.v_shader_functions, e.f_shader_functions);

	  }

	else

	  {

	    GameApi::SFO sfo;

	    sfo.id = e.sfo_id;

	    shader = ev.shader_api.get_normal_shader("comb", "comb", "", vertex, fragment,e.v_shader_functions, e.f_shader_functions, false, sfo);

	  }

	ev.mainloop_api.init_3d(shader);

	ev.mainloop_api.alpha(true); 



      }



    if (shader.id!=-1)

      {

#if 1

    //ev.shader_api.use(sh);

	GameApi::M m = add_matrix2( env, e.in_MV); //ev.shader_api.get_matrix_var(sh, "in_MV");

	GameApi::M m1 = add_matrix2(env, e.in_T); //ev.shader_api.get_matrix_var(sh, "in_T");

	GameApi::M m2 = add_matrix2(env, e.in_N); //ev.shader_api.get_matrix_var(sh, "in_N");

	GameApi::M m3 = add_matrix2(env, e.in_P);

	ev.shader_api.use(shader);

	ev.shader_api.set_var(shader, "in_MV", m);

	ev.shader_api.set_var(shader, "in_iMV", ev.matrix_api.transpose(ev.matrix_api.inverse(m)));

	ev.shader_api.set_var(shader, "in_T", m1);

	ev.shader_api.set_var(shader, "in_P", m3);

	ev.shader_api.set_var(shader, "in_N", m2);

	//ev.shader_api.set_var(shader, "time", e.time);



	sh = shader;

#endif

	}

    if (firsttime) { firsttime = false; }

    ev.shader_api.use(sh);

    ev.shader_api.set_var(sh, "in_POS", e.in_POS);

    api.render_vertex_array(va);

    ev.shader_api.unuse(sh);

  }

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  GameApi::PolygonApi &api;

  bool firsttime;

  GameApi::VA va;

  GameApi::P p;

  GameApi::SH shader;

};

EXPORT GameApi::ML GameApi::PolygonApi::render_vertex_array_ml2(EveryApi &ev, P p)

{

    GameApi::PTS pts = ev.points_api.single_pts();

    GameApi::ML ml = ev.materials_api.render_instanced_ml(ev,p,pts);

    return ml;

    // return add_main_loop(e, new RenderP(e, ev, *this, p));

}

class RenderP : public MainLoopItem

{

public:

  RenderP(GameApi::Env &env, GameApi::EveryApi &ev, GameApi::PolygonApi &api, GameApi::P p) : env(env), ev(ev), api(api), p(p)

  {

    shader.id = -1;

    firsttime = true;

  }

  int shader_id() { return shader.id; }

  void handle_event(MainLoopEvent &e)

  {

  }

  void Prepare() {}

  void execute(MainLoopEnv &e)

  { 

    if (firsttime)

      {

	va = ev.polygon_api.create_vertex_array(p,false);

      }



    GameApi::SH sh;

    if (ev.polygon_api.is_texture(va))

      {

	sh.id = e.sh_texture;

	if (ev.polygon_api.is_array_texture(va))

	  {

	    sh.id = e.sh_array_texture;

	  }

      }

    else

      {

	sh.id = e.sh_color;

      }



    GameApi::US u_v;

    GameApi::US u_f;

    u_v.id = 0;

    u_f.id = 0;

    if (e.us_vertex_shader!=-1)

      u_v.id = e.us_vertex_shader;

    if (e.us_fragment_shader!=-1)

      u_f.id = e.us_fragment_shader;

    if (firsttime)

      {

	if (u_v.id == 0)

	  u_v = ev.uber_api.v_empty();

	if (u_f.id == 0)

	  u_f = ev.uber_api.f_empty(false);

      }



#if 1

    if (ev.polygon_api.is_texture(va))

      {

	sh.id = e.sh_texture;

	if (firsttime)

	  {

	    if (e.us_vertex_shader==-1)

	      u_v = ev.uber_api.v_texture(u_v);

	    if (e.us_fragment_shader==-1)

	      u_f = ev.uber_api.f_texture(u_f);

	  }

	if (ev.polygon_api.is_array_texture(va))

	  {

	    sh.id = e.sh_array_texture;

	      if (firsttime)

	      {

		if (e.us_vertex_shader==-1)

		  u_v = ev.uber_api.v_texture_arr(u_v);

		if (e.us_fragment_shader==-1)

		  u_f = ev.uber_api.f_texture_arr(u_f);

	      }

	  }

      }

    else

      {

	sh.id = e.sh_color;

	if (firsttime)

	  {

	    if (e.us_vertex_shader==-1)

	      {

		u_v = ev.uber_api.v_colour(u_v);

		u_v = ev.uber_api.v_light(u_v);

	      }

	    if (e.us_fragment_shader==-1)

	      {

		u_f = ev.uber_api.f_colour(u_f);

		u_f = ev.uber_api.f_light(u_f);

	      }

	  }

      }

#endif



    if (firsttime && shader.id==-1)

      {

	GameApi::US vertex;

	GameApi::US fragment;

	vertex.id = u_v.id; //e.us_vertex_shader;

	fragment.id = u_f.id; //e.us_fragment_shader;

	if (e.sfo_id==-1)

	  {

	    shader = ev.shader_api.get_normal_shader("comb", "comb", "", vertex, fragment,e.v_shader_functions, e.f_shader_functions);

	  }

	else

	  {

	    GameApi::SFO sfo;

	    sfo.id = e.sfo_id;

	    shader = ev.shader_api.get_normal_shader("comb", "comb", "", vertex, fragment,e.v_shader_functions, e.f_shader_functions, false, sfo);

	  }

	ev.mainloop_api.init_3d(shader);

	ev.mainloop_api.alpha(true); 



      }



    if (shader.id!=-1)

      {

#if 1

    //ev.shader_api.use(sh);

	GameApi::M m = add_matrix2( env, e.in_MV); //ev.shader_api.get_matrix_var(sh, "in_MV");

	GameApi::M m1 = add_matrix2(env, e.in_T); //ev.shader_api.get_matrix_var(sh, "in_T");

	GameApi::M m2 = add_matrix2(env, e.in_N); //ev.shader_api.get_matrix_var(sh, "in_N");

	GameApi::M m3 = add_matrix2(env, e.in_P);

	ev.shader_api.use(shader);

	ev.shader_api.set_var(shader, "in_MV", m);

	ev.shader_api.set_var(shader, "in_iMV", ev.matrix_api.transpose(ev.matrix_api.inverse(m)));

	ev.shader_api.set_var(shader, "in_T", m1);

	ev.shader_api.set_var(shader, "in_P", m3);

	ev.shader_api.set_var(shader, "in_N", m2);

	//ev.shader_api.set_var(shader, "time", e.time);



	sh = shader;

#endif

	}

    if (firsttime) { firsttime = false; }

    ev.shader_api.use(sh);

    ev.shader_api.set_var(sh, "in_POS", e.in_POS);

    api.render_vertex_array(va);

    ev.shader_api.unuse(sh);

  }

private:

  GameApi::Env &env;

  GameApi::EveryApi &ev;

  GameApi::PolygonApi &api;

  bool firsttime;

  GameApi::VA va;

  GameApi::P p;

  GameApi::SH shader;

};

EXPORT GameApi::ML GameApi::PolygonApi::render_vertex_array_ml2(EveryApi &ev, P p)

{

#ifdef HAS_INSTANCING

    GameApi::PTS pts = ev.points_api.single_pts();

    GameApi::ML ml = ev.materials_api.render_instanced_ml(ev,p,pts);

    return ml;

#else

     return add_main_loop(e, new RenderP(e, ev, *this, p));

#endif

}

GameApi::ML GameApi::MainLoopApi::restart_screen(EveryApi &ev, ML ml, std::string fontname)

{

  BM I1=ev.bitmap_api.newbitmap(500,30,00000000);

  FI I2=ev.font_api.load_font(fontname,30,30);

  BM I3=ev.font_api.draw_text_string(I2,"Press",5,30);

  BM I4=ev.bitmap_api.blitbitmap(I1,I3,0,0);

  FI I5=ev.font_api.load_font(fontname,30,30);

  BM I6=ev.font_api.draw_text_string(I5,"R",5,30);

  BM I7=ev.bitmap_api.blitbitmap(I4,I6,160,0);

  FI I8=ev.font_api.load_font(fontname,30,30);

  BM I9=ev.font_api.draw_text_string(I8,"to",5,30);

  BM I10=ev.bitmap_api.blitbitmap(I7,I9,210,0);

  FI I11=ev.font_api.load_font(fontname,30,30);

  BM I12=ev.font_api.draw_text_string(I11,"Restart",5,30);

  BM I13=ev.bitmap_api.blitbitmap(I10,I12,285,0);

  ML I14=ev.sprite_api.vertex_array_render(ev,I13);

  MN I15=ev.move_api.empty();

  MN I16=ev.move_api.trans2(I15,150,300,0);

  ML I17=ev.move_api.move_ml(ev,I14,I16,1,10.0);

  ML I18=ev.sprite_api.turn_to_2d(ev,I17,0.0,0.0,800.0,600.0);

  ML I19=ev.mainloop_api.array_ml(std::vector<ML>{I18,ml});

  return I19;

}

GameApi::ML GameApi::MainLoopApi::restart_screen(EveryApi &ev, ML ml, std::string fontname)

{

  BM I1=ev.bitmap_api.newbitmap(500,30,00000000);

  FI I2=ev.font_api.load_font(fontname,30,30);

  BM I3=ev.font_api.draw_text_string(I2,"Press",5,30);

  BM I4=ev.bitmap_api.blitbitmap(I1,I3,0,0);

  FI I5=ev.font_api.load_font(fontname,30,30);

  BM I6=ev.font_api.draw_text_string(I5,"R",5,30);

  BM I7=ev.bitmap_api.blitbitmap(I4,I6,160,0);

  FI I8=ev.font_api.load_font(fontname,30,30);

  BM I9=ev.font_api.draw_text_string(I8,"to",5,30);

  BM I10=ev.bitmap_api.blitbitmap(I7,I9,210,0);

  FI I11=ev.font_api.load_font(fontname,30,30);

  BM I12=ev.font_api.draw_text_string(I11,"Restart",5,30);

  BM I13=ev.bitmap_api.blitbitmap(I10,I12,285,0);

  ML I14=ev.sprite_api.vertex_array_render(ev,I13);

  MN I15=ev.move_api.empty();

  MN I16=ev.move_api.trans2(I15,150,300,0);

  ML I17=ev.move_api.move_ml(ev,I14,I16,1,10.0);

  ML I18=ev.sprite_api.turn_to_2d(ev,I17,0.0,0.0,800.0,600.0);

  ML I19=ev.mainloop_api.array_ml(ev,std::vector<ML>{I18,ml});

  return I19;

}

class MainLoopSplitter_win32_and_emscripten : public Splitter

{

public:

  MainLoopSplitter_win32_and_emscripten(GameApi::ML code, bool logo, bool fpscounter, float start_time, float duration, int screen_width, int screen_height) : code(code), logo(logo), fpscounter(fpscounter), timeout(duration), start_time(start_time), screen_width(screen_width), screen_height(screen_height)

  {

    firsttime = true;

  }

  virtual void set_env(GameApi::Env *ei)

  {

    e = ei;

  }

  virtual void set_everyapi(GameApi::EveryApi *evi)

  {

    ev = evi;

  }

  virtual void Init()

  {

    score = 0;

    hidden_score = 0;



    Envi_2 &env = envi;

    env.logo_shown = logo;

    env.fpscounter = fpscounter;

    env.timeout = start_time+timeout;

    env.start_time = start_time;

    env.screen_width = screen_width;

    env.screen_height = screen_height;

    env.ev = ev;

    

    GameApi::SH sh = env.ev->shader_api.colour_shader();

    GameApi::SH sh2 = env.ev->shader_api.texture_shader();

    GameApi::SH sh3 = env.ev->shader_api.texture_array_shader();

    

    // rest of the initializations

    env.ev->mainloop_api.init_3d(sh);

    env.ev->mainloop_api.init_3d(sh2);

    env.ev->mainloop_api.init_3d(sh3);

    env.ev->shader_api.use(sh);

    

    GameApi::ML ml = mainloop(*env.ev);

    if (async_pending_count > 0) { env.logo_shown = true; }

    

    env.mainloop = ml;

    

    env.color_sh = sh;

    env.texture_sh = sh2;

    env.arr_texture_sh = sh3;

    

    env.ev->mainloop_api.reset_time();

    if (env.logo_shown) {

      if (gameapi_seamless_url == "") {

	env.ev->mainloop_api.display_logo(*env.ev);

      } else {

	env.ev->mainloop_api.display_seamless(*env.ev);

      }

    } else {

	env.ev->mainloop_api.advance_time(env.start_time/10.0*1000.0);

    }

     env.ev->mainloop_api.alpha(true);

     g_low->ogl->glEnable(Low_GL_DEPTH_TEST);

     GameApi::MainLoopApi::Event e;

     while((e = env.ev->mainloop_api.get_event()).last==true)

       {

	 /* this eats all events from queue */

       }

     g_hide_container.clear();



  }

  virtual int Iter()

  {

    Envi_2 *env = (Envi_2*)&envi;





    //std::cout << "async: " << async_pending_count << std::endl;

    if ((async_pending_count > 0 && !async_is_done)||no_draw_count>0) { env->logo_shown = true; }

    if (async_pending_count != async_pending_count_previous)

      {

	//std::cout << "ASync pending count=" << async_pending_count << std::endl;

	async_pending_count_previous = async_pending_count;

      }

    if (env->logo_shown)

      {

	bool b = false;

	if (gameapi_seamless_url=="") {

	  //std::cout << "Logo iter" << std::endl;

	  b = env->ev->mainloop_api.logo_iter();

	  //std::cout << "End of Logo iter" << std::endl;

	} else {

	  b = env->ev->mainloop_api.seamless_iter();

	}

	if (b && async_pending_count==0 && no_draw_count==0) { env->logo_shown = false;

	  env->ev->mainloop_api.reset_time();

	  env->ev->mainloop_api.advance_time(env->start_time/10.0*1000.0);

	}

	//if (g_shows_hundred) { env->logo_shown=false; }

	if (async_pending_count==0 && no_draw_count>0) { /* pass through */}

	else

	  return -1;

      }

    async_is_done = true;



    if (firsttime) {

      MainLoopItem *item = find_main_loop(env->ev->get_env(),code);

      //std::cout << "Splitter/Prepare:" << std::endl;

      item->Prepare();

      //std::cout << "Splitter/End of Prepare:" << std::endl;

      firsttime = false;

    }



    

    if (no_draw_count==0)

      env->ev->mainloop_api.clear_3d(0xff000000);

    

    // handle esc event

    GameApi::MainLoopApi::Event e;

    while((e = env->ev->mainloop_api.get_event()).last==true)

      {

	//std::cout << e.ch << " " << e.type << std::endl;

#ifndef EMSCRIPTEN

	if (e.ch==27 && e.type==0x300) { /*std::cout << "Esc pressed2!" << std::endl;*/ env->exit = true; return 0; }

#endif

	

	//GameApi::InteractionApi::quake_movement_event(*env->ev,e, env->pos_x, env->pos_y, env->rot_y,

	//					      env->data, env->speed_x, env->speed_y,

	//			   1.0, 1.0*3.14159*2.0/360.0);

	//std::cout << "Splitter/Event:" << std::endl;

	env->ev->mainloop_api.event_ml(env->mainloop, e);

	//std::cout << "Splitter/End of Event:" << std::endl;

	

      }

    //GameApi::InteractionApi::quake_movement_frame(*env->ev, env->pos_x, env->pos_y, env->rot_y,

    //						  env->data, env->speed_x, env->speed_y,

    //						  1.0, 1.0*3.14159*2.0/360.0);

    

    GameApi::M mat = env->ev->matrix_api.identity();

    if (screen_width<600) {

      mat = env->ev->matrix_api.scale(-1.0,-1.0,1.0);

    }

    env->ev->shader_api.use(env->color_sh);

    env->ev->shader_api.set_var(env->color_sh, "in_MV", mat);

    //env->ev->shader_api.set_var(env->color_sh, "in_iMV", env->ev->matrix_api.transpose(env->ev->matrix_api.inverse(mat)));

    env->ev->shader_api.use(env->texture_sh);

    env->ev->shader_api.set_var(env->texture_sh, "in_MV", mat);

    //env->ev->shader_api.set_var(env->texture_sh, "in_iMV", env->ev->matrix_api.transpose(env->ev->matrix_api.inverse(mat)));

    

    env->ev->shader_api.use(env->arr_texture_sh);

    env->ev->shader_api.set_var(env->arr_texture_sh, "in_MV", mat);

    //env->ev->shader_api.set_var(env->arr_texture_sh, "in_iMV", env->ev->matrix_api.transpose(env->ev->matrix_api.inverse(mat)));

    env->ev->shader_api.use(env->color_sh);

    

    GameApi::M in_MV = mat; //env->ev->mainloop_api.in_MV(*env->ev, true);

    GameApi::M in_T = env->ev->mainloop_api.in_T(*env->ev, true);

    GameApi::M in_N = env->ev->mainloop_api.in_N(*env->ev, true);

    

    //std::cout << "Splitter/execute_ml" << std::endl;

    env->ev->mainloop_api.execute_ml(env->mainloop, env->color_sh, env->texture_sh, env->texture_sh, env->arr_texture_sh, in_MV, in_T, in_N, env->screen_width, env->screen_height);

    //std::cout << "Splitter/end of execute_ml" << std::endl;



    if (env->fpscounter)

      env->ev->mainloop_api.fpscounter();

    if (env->ev->mainloop_api.get_time()/1000.0*10.0 > env->timeout)

      {

	//env->exit = true;

	std::cout << "Timeout2, exiting.." << std::endl;

      }

    

    // swapbuffers

    env->ev->mainloop_api.swapbuffers();

    //xsg_low->ogl->glGetError();

    return -1;

  }

  virtual void Destroy()

  {

	float scale_x = 1.0;

	float scale_y = 1.0;

	if (g_event_screen_y!=-1) {

	  scale_x = float(g_event_screen_x)/float(screen_width);

	  scale_y = float(g_event_screen_y)/float(screen_height);

	}

	g_low->ogl->glViewport(0,0,screen_width*scale_x, screen_height*scale_y);

    // this is needed for win32 build in editor

      g_low->ogl->glDisable(Low_GL_DEPTH_TEST);

  }

  virtual Splitter* NextState(int code)

  {

    return 0;

  }

  GameApi::ML mainloop(GameApi::EveryApi &ev)

  {

    return code;

  }



private:

  GameApi::ML code;

  bool logo;

  bool fpscounter;

  float timeout;

  float start_time;

  int screen_width;

  int screen_height;

  Envi_2 envi;

  bool firsttime;

};

EXPORT GameApi::RUN GameApi::BlockerApi::game_window2(GameApi::EveryApi &ev, ML ml, bool logo, bool fpscounter, float start_time, float duration)

{

  Splitter *spl = new MainLoopSplitter_win32_and_emscripten(ml,logo, fpscounter, start_time, duration, ev.mainloop_api.get_screen_sx(), ev.mainloop_api.get_screen_sy());

  return add_splitter(e, spl);

}

class MainLoopSplitter_win32_and_emscripten : public Splitter

{

public:

  MainLoopSplitter_win32_and_emscripten(GameApi::ML code, bool logo, bool fpscounter, float start_time, float duration, int screen_width, int screen_height) : code(code), logo(logo), fpscounter(fpscounter), timeout(duration), start_time(start_time), screen_width(screen_width), screen_height(screen_height)

  {

    firsttime = true;

  }

  virtual void set_env(GameApi::Env *ei)

  {

    e = ei;

  }

  virtual void set_everyapi(GameApi::EveryApi *evi)

  {

    ev = evi;

  }

  virtual void Init()

  {

    score = 0;

    hidden_score = 0;



    Envi_2 &env = envi;

    env.logo_shown = logo;

    env.fpscounter = fpscounter;

    env.timeout = start_time+timeout;

    env.start_time = start_time;

    env.screen_width = screen_width;

    env.screen_height = screen_height;

    env.ev = ev;

    

    GameApi::SH sh = env.ev->shader_api.colour_shader();

    GameApi::SH sh2 = env.ev->shader_api.texture_shader();

    GameApi::SH sh3 = env.ev->shader_api.texture_array_shader();

    

    // rest of the initializations

    env.ev->mainloop_api.init_3d(sh);

    env.ev->mainloop_api.init_3d(sh2);

    env.ev->mainloop_api.init_3d(sh3);

    env.ev->shader_api.use(sh);

    

    GameApi::ML ml = mainloop(*env.ev);

    if (async_pending_count > 0) { env.logo_shown = true; }

    

    env.mainloop = ml;

    

    env.color_sh = sh;

    env.texture_sh = sh2;

    env.arr_texture_sh = sh3;

    

    env.ev->mainloop_api.reset_time();

    if (env.logo_shown) {

      if (gameapi_seamless_url == "") {

	env.ev->mainloop_api.display_logo(*env.ev);

      } else {

	env.ev->mainloop_api.display_seamless(*env.ev);

      }

    } else {

	env.ev->mainloop_api.advance_time(env.start_time/10.0*1000.0);

    }

     env.ev->mainloop_api.alpha(true);

     g_low->ogl->glEnable(Low_GL_DEPTH_TEST);

     GameApi::MainLoopApi::Event e;

     while((e = env.ev->mainloop_api.get_event()).last==true)

       {

	 /* this eats all events from queue */

       }

     g_hide_container.clear();



  }

  virtual int Iter()

  {

    Envi_2 *env = (Envi_2*)&envi;





    //std::cout << "async: " << async_pending_count << std::endl;

    if ((async_pending_count > 0 && !async_is_done)||no_draw_count>0) { env->logo_shown = true; }

    if (async_pending_count != async_pending_count_previous)

      {

	//std::cout << "ASync pending count=" << async_pending_count << std::endl;

	async_pending_count_previous = async_pending_count;

      }

    if (env->logo_shown)

      {

	bool b = false;

	if (gameapi_seamless_url=="") {

	  //std::cout << "Logo iter" << std::endl;

	  b = env->ev->mainloop_api.logo_iter();

	  //std::cout << "End of Logo iter" << std::endl;

	} else {

	  b = env->ev->mainloop_api.seamless_iter();

	}

	if (b && async_pending_count==0 && no_draw_count==0) { env->logo_shown = false;

	  env->ev->mainloop_api.reset_time();

	  env->ev->mainloop_api.advance_time(env->start_time/10.0*1000.0);

	}

	//if (g_shows_hundred) { env->logo_shown=false; }

	if (async_pending_count==0 && no_draw_count>0) { /* pass through */}

	else

	  return -1;

      }

    async_is_done = true;



    if (firsttime) {

      MainLoopItem *item = find_main_loop(env->ev->get_env(),code);

      //std::cout << "Splitter/Prepare:" << std::endl;

      item->Prepare();

      //std::cout << "Splitter/End of Prepare:" << std::endl;

      firsttime = false;

    }



    

    if (no_draw_count==0)

      env->ev->mainloop_api.clear_3d(0xff000000);

    

    // handle esc event

    GameApi::MainLoopApi::Event e;

    while((e = env->ev->mainloop_api.get_event()).last==true)

      {

	//std::cout << e.ch << " " << e.type << std::endl;

#ifndef EMSCRIPTEN

	if (e.ch==27 && e.type==0x300) { /*std::cout << "Esc pressed2!" << std::endl;*/ env->exit = true; return 0; }

#endif

	

	//GameApi::InteractionApi::quake_movement_event(*env->ev,e, env->pos_x, env->pos_y, env->rot_y,

	//					      env->data, env->speed_x, env->speed_y,

	//			   1.0, 1.0*3.14159*2.0/360.0);

	//std::cout << "Splitter/Event:" << std::endl;

	env->ev->mainloop_api.event_ml(env->mainloop, e);

	//std::cout << "Splitter/End of Event:" << std::endl;

	

      }

    //GameApi::InteractionApi::quake_movement_frame(*env->ev, env->pos_x, env->pos_y, env->rot_y,

    //						  env->data, env->speed_x, env->speed_y,

    //						  1.0, 1.0*3.14159*2.0/360.0);

    

    GameApi::M mat = env->ev->matrix_api.identity();

    if (screen_width<600) {

      mat = env->ev->matrix_api.scale(-1.0,-1.0,1.0);

    }

    env->ev->shader_api.use(env->color_sh);

    env->ev->shader_api.set_var(env->color_sh, "in_MV", mat);

    //env->ev->shader_api.set_var(env->color_sh, "in_iMV", env->ev->matrix_api.transpose(env->ev->matrix_api.inverse(mat)));

    env->ev->shader_api.use(env->texture_sh);

    env->ev->shader_api.set_var(env->texture_sh, "in_MV", mat);

    //env->ev->shader_api.set_var(env->texture_sh, "in_iMV", env->ev->matrix_api.transpose(env->ev->matrix_api.inverse(mat)));

    

    env->ev->shader_api.use(env->arr_texture_sh);

    env->ev->shader_api.set_var(env->arr_texture_sh, "in_MV", mat);

    //env->ev->shader_api.set_var(env->arr_texture_sh, "in_iMV", env->ev->matrix_api.transpose(env->ev->matrix_api.inverse(mat)));

    env->ev->shader_api.use(env->color_sh);

    

    GameApi::M in_MV = mat; //env->ev->mainloop_api.in_MV(*env->ev, true);

    GameApi::M in_T = env->ev->mainloop_api.in_T(*env->ev, true);

    GameApi::M in_N = env->ev->mainloop_api.in_N(*env->ev, true);

    

    //std::cout << "Splitter/execute_ml" << std::endl;

    env->ev->mainloop_api.execute_ml(env->mainloop, env->color_sh, env->texture_sh, env->texture_sh, env->arr_texture_sh, in_MV, in_T, in_N, env->screen_width, env->screen_height);

    //std::cout << "Splitter/end of execute_ml" << std::endl;



    if (env->fpscounter)

      env->ev->mainloop_api.fpscounter();

    if (env->ev->mainloop_api.get_time()/1000.0*10.0 > env->timeout)

      {

	//env->exit = true;

	std::cout << "Timeout2, exiting.." << std::endl;

      }

    

    // swapbuffers

    env->ev->mainloop_api.swapbuffers();

    //xsg_low->ogl->glGetError();

    return -1;

  }

  virtual void Destroy()

  {

	float scale_x = 1.0;

	float scale_y = 1.0;

	if (g_event_screen_y!=-1) {

	  scale_x = float(g_event_screen_x)/float(screen_width);

	  scale_y = float(g_event_screen_y)/float(screen_height);

	}

	g_low->ogl->glViewport(0,0,screen_width*scale_x, screen_height*scale_y);

    // this is needed for win32 build in editor

      g_low->ogl->glDisable(Low_GL_DEPTH_TEST);

  }

  virtual Splitter* NextState(int code)

  {

    return 0;

  }

  GameApi::ML mainloop(GameApi::EveryApi &ev)

  {

    return code;

  }



private:

  GameApi::ML code;

  bool logo;

  bool fpscounter;

  float timeout;

  float start_time;

  int screen_width;

  int screen_height;

  Envi_2 envi;

  bool firsttime;

};

EXPORT GameApi::RUN GameApi::BlockerApi::game_window2(GameApi::EveryApi &ev, ML ml, bool logo, bool fpscounter, float start_time, float duration)

{

  float screen_x = ev.mainloop_api.get_screen_sx();

  float screen_y = ev.mainloop_api.get_screen_sy();



  ml = ev.mainloop_api.display_background(ev,ml);

  Splitter *spl = new MainLoopSplitter_win32_and_emscripten(ml,logo, fpscounter, start_time, duration, screen_x, screen_y);

  return add_splitter(e, spl);

}

int main()
{
P I1=ev.polygon_api.quad_z(0,300,-100,0,0);
BM I2=ev.bitmap_api.newbitmap(170,60,ff0000ff);
FI I3=ev.font_api.load_font(http://meshpage.org/assets/Chunkfive.otf,40,40);
BM I4=ev.font_api.draw_text_string(I3,start,5,30);
BM I5=ev.bitmap_api.border(I4,10,10,10,10);
BM I6=ev.bitmap_api.blitbitmap(I2,I5,0,0);
BM I7=ev.bitmap_api.flip_y(I6);
MT I8=ev.materials_api.texture(ev,I7,1.0);
ML I9=ev.materials_api.bind(I1,I8);
PT I10=ev.point_api.point(0.0,0.0,0.0);
P I11=ev.polygon_api.sphere(I10,20,5,5);
PT I12=ev.point_api.point(0.0,0.0,0.0);
PT I13=ev.point_api.point(0,-300,0);
P I14=ev.polygon_api.cone(30,I12,I13,10,10);
P I15=ev.polygon_api.or_elem(I11,I14);
PT I16=ev.point_api.point(0.0,0.0,0.0);
P I17=ev.polygon_api.sphere(I16,20,5,5);
PT I18=ev.point_api.point(0.0,0.0,0.0);
PT I19=ev.point_api.point(0,-300,0);
P I20=ev.polygon_api.cone(30,I18,I19,10,10);
P I21=ev.polygon_api.or_elem(I17,I20);
P I22=ev.polygon_api.translate(I21,300,0,0);
P I23=ev.polygon_api.or_elem(I15,I22);
P I24=ev.polygon_api.recalculate_normals(I23);
P I25=ev.polygon_api.smooth_normals2(I24);
MT I26=ev.materials_api.gltf_material3(ev,0.5,0.8,1.0,1.0,1.0,1.0,1.0,1.0,1.0,-1.0);
ML I27=ev.materials_api.bind(I25,I26);
ML I28=ev.mainloop_api.array_ml(ev,std::vector<ML>{I9,I27});
MN I29=ev.move_api.mn_empty();
MN I30=ev.move_api.trans2(I29,800,-150,0);
MN I31=ev.move_api.translate(I30,0,100,-2000,0,0);
ML I32=ev.move_api.move_ml(ev,I28,I31,1,10.0);
P I33=ev.polygon_api.quad_z(0,200,0,300,0);
PT I34=ev.point_api.point(0.0,0.0,0.0);
PT I35=ev.point_api.point(60000,0,0);
C I36=ev.curve_api.line(I34,I35);
PTS I37=ev.curve_api.sample(I36,300);
BM I38=ev.bitmap_api.newbitmap(200,300,00000000);
PT I39=ev.point_api.point(0.0,0.0,0.0);
PT I40=ev.point_api.point(0,300,0);
BM I41=ev.bitmap_api.gradient(I39,I40,ffff8822,ff221108,200,300);
BB I42=ev.bool_bitmap_api.bb_empty(200,300);
BB I43=ev.bool_bitmap_api.bb_empty(200,100);
BB I44=ev.bool_bitmap_api.bb_empty(100,100);
BB I45=ev.bool_bitmap_api.tri(I44,0,100,100,30,100,100);
BB I46=ev.bool_bitmap_api.sprite(I43,I45,0,0,1,1);
BB I47=ev.bool_bitmap_api.bb_empty(100,100);
BB I48=ev.bool_bitmap_api.tri(I47,0,100,100,30,100,100);
BM I49=ev.bool_bitmap_api.to_bitmap(I48,255,255,255,255,0,0,0,0);
BM I50=ev.bitmap_api.flip_x(I49);
BB I51=ev.bool_bitmap_api.from_bitmaps_color(I50,255,255,255);
BB I52=ev.bool_bitmap_api.sprite(I46,I51,100,0,1,1);
BM I53=ev.bool_bitmap_api.to_bitmap(I52,255,255,255,255,0,0,0,0);
BM I54=ev.bitmap_api.repeat_bitmap(I53,1,1);
BB I55=ev.bool_bitmap_api.from_bitmaps_color(I54,255,255,255);
BB I56=ev.bool_bitmap_api.sprite(I42,I55,0.0,0.0,1.0,1.0);
BB I57=ev.bool_bitmap_api.bb_empty(200,100);
BB I58=ev.bool_bitmap_api.not_bitmap(I57);
BB I59=ev.bool_bitmap_api.sprite(I56,I58,0,100,1,1);
BB I60=ev.bool_bitmap_api.part_circle(100,50,50,50,-3.14159,0,0,50);
BB I61=ev.bool_bitmap_api.not_bitmap(I60);
BM I62=ev.bool_bitmap_api.to_bitmap(I61,255,255,255,255,0,0,0,0);
BM I63=ev.bitmap_api.repeat_bitmap(I62,2,1);
BB I64=ev.bool_bitmap_api.from_bitmaps_color(I63,255,255,255);
BB I65=ev.bool_bitmap_api.sprite(I59,I64,0,200,1,1);
BM I66=ev.bitmap_api.blitbitmap_bb(I38,I41,0,0,I65);
BM I67=ev.bitmap_api.flip_y(I66);
MT I68=ev.materials_api.texture(ev,I67,1.0);
ML I69=ev.materials_api.bind_inst(I33,I37,I68);
MN I70=ev.move_api.mn_empty();
MN I71=ev.move_api.trans2(I70,-1200,0,0);
MN I72=ev.move_api.translate(I71,0,4000,-37000,0,0);
ML I73=ev.move_api.move_ml(ev,I69,I72,1,10.0);
P I74=ev.polygon_api.quad_z(0,200,0,300,0);
PT I75=ev.point_api.point(0.0,0.0,0.0);
PT I76=ev.point_api.point(60000,0,0);
C I77=ev.curve_api.line(I75,I76);
PTS I78=ev.curve_api.sample(I77,300);
BM I79=ev.bitmap_api.newbitmap(200,300,00000000);
PT I80=ev.point_api.point(0.0,0.0,0.0);
PT I81=ev.point_api.point(0,300,0);
BM I82=ev.bitmap_api.gradient(I80,I81,ffff8822,ff221108,200,300);
BB I83=ev.bool_bitmap_api.bb_empty(200,300);
BB I84=ev.bool_bitmap_api.bb_empty(200,100);
BB I85=ev.bool_bitmap_api.bb_empty(100,100);
BB I86=ev.bool_bitmap_api.tri(I85,0,100,100,30,100,100);
BB I87=ev.bool_bitmap_api.sprite(I84,I86,0,0,1,1);
BB I88=ev.bool_bitmap_api.bb_empty(100,100);
BB I89=ev.bool_bitmap_api.tri(I88,0,100,100,30,100,100);
BM I90=ev.bool_bitmap_api.to_bitmap(I89,255,255,255,255,0,0,0,0);
BM I91=ev.bitmap_api.flip_x(I90);
BB I92=ev.bool_bitmap_api.from_bitmaps_color(I91,255,255,255);
BB I93=ev.bool_bitmap_api.sprite(I87,I92,100,0,1,1);
BM I94=ev.bool_bitmap_api.to_bitmap(I93,255,255,255,255,0,0,0,0);
BM I95=ev.bitmap_api.repeat_bitmap(I94,1,1);
BB I96=ev.bool_bitmap_api.from_bitmaps_color(I95,255,255,255);
BB I97=ev.bool_bitmap_api.sprite(I83,I96,0.0,0.0,1.0,1.0);
BB I98=ev.bool_bitmap_api.bb_empty(200,100);
BB I99=ev.bool_bitmap_api.not_bitmap(I98);
BB I100=ev.bool_bitmap_api.sprite(I97,I99,0,100,1,1);
BB I101=ev.bool_bitmap_api.part_circle(100,50,50,50,-3.14159,0,0,50);
BB I102=ev.bool_bitmap_api.not_bitmap(I101);
BM I103=ev.bool_bitmap_api.to_bitmap(I102,255,255,255,255,0,0,0,0);
BM I104=ev.bitmap_api.repeat_bitmap(I103,2,1);
BB I105=ev.bool_bitmap_api.from_bitmaps_color(I104,255,255,255);
BB I106=ev.bool_bitmap_api.sprite(I100,I105,0,200,1,1);
BM I107=ev.bitmap_api.blitbitmap_bb(I79,I82,0,0,I106);
BM I108=ev.bitmap_api.flip_y(I107);
MT I109=ev.materials_api.texture(ev,I108,1.0);
ML I110=ev.materials_api.bind_inst(I74,I78,I109);
MN I111=ev.move_api.mn_empty();
MN I112=ev.move_api.trans2(I111,-1200,-200,0);
MN I113=ev.move_api.translate(I112,0,4000,-57000,0,0);
ML I114=ev.move_api.move_ml(ev,I110,I113,1,10.0);
ML I115=ev.mainloop_api.depthfunc(I114,2);
ML I116=ev.mainloop_api.blendfunc(I115,2,3);
ML I117=ev.mainloop_api.array_ml(ev,std::vector<ML>{I73,I116});
BB I118=ev.bool_bitmap_api.bb_empty(800,300);
BB I119=ev.bool_bitmap_api.circle(I118,500,50,450);
BM I120=ev.bool_bitmap_api.to_bitmap(I119,255,255,20,20,0,0,0,0);
BB I121=ev.bool_bitmap_api.bb_empty(800,300);
BB I122=ev.bool_bitmap_api.circle(I121,500,50,300);
BM I123=ev.bool_bitmap_api.to_bitmap(I122,255,255,50,50,0,0,0,0);
BM I124=ev.bitmap_api.blitbitmap(I120,I123,0,0);
BB I125=ev.bool_bitmap_api.bb_empty(800,300);
BB I126=ev.bool_bitmap_api.circle(I125,500,50,140);
BM I127=ev.bool_bitmap_api.to_bitmap(I126,255,255,100,100,0,0,0,0);
BM I128=ev.bitmap_api.blitbitmap(I124,I127,0,0);
BB I129=ev.bool_bitmap_api.bb_empty(800,300);
BB I130=ev.bool_bitmap_api.circle(I129,500,50,100);
BM I131=ev.bool_bitmap_api.to_bitmap(I130,255,255,180,180,0,0,0,0);
BM I132=ev.bitmap_api.blitbitmap(I128,I131,0,0);
BB I133=ev.bool_bitmap_api.bb_empty(800,300);
BB I134=ev.bool_bitmap_api.circle(I133,500,50,80);
BM I135=ev.bool_bitmap_api.to_bitmap(I134,255,255,200,200,0,0,0,0);
BM I136=ev.bitmap_api.blitbitmap(I132,I135,0,0);
BB I137=ev.bool_bitmap_api.bb_empty(800,300);
BB I138=ev.bool_bitmap_api.circle(I137,500,50,50);
BM I139=ev.bool_bitmap_api.to_bitmap(I138,255,255,255,255,0,0,0,0);
BM I140=ev.bitmap_api.blitbitmap(I136,I139,0,0);
BM I141=ev.bitmap_api.flip_y(I140);
ML I142=ev.polygon_api.sprite_render(ev,I141,-700,700,-320,160,0);
MN I143=ev.move_api.mn_empty();
MN I888=ev.move_api.scale2(I143,1200/800,900/600,1);
MN I144=ev.move_api.trans2(I888,0,320,0);
ML I145=ev.move_api.move_ml(ev,I142,I144,1,10.0);
ML I146=ev.sprite_api.turn_to_2d(ev,I145,0,0,800,600);
PT I147=ev.point_api.point(0,-50,0);
PT I148=ev.point_api.point(0,200,0);
P I149=ev.polygon_api.cone(20,I147,I148,50,70);
PT I150=ev.point_api.point(0,-50,0);
PT I151=ev.point_api.point(0,-300,0);
P I152=ev.polygon_api.cone(20,I150,I151,30,70);
P I153=ev.polygon_api.cube(-100,100,-200,-100,90,100);
P I154=ev.polygon_api.cube(-300,300,0,130,90,100);
P I155=ev.polygon_api.cube(-10,10,-200,-130,100,150);
PT I156=ev.point_api.point(0,-150,90);
PT I157=ev.point_api.point(0,-150,0);
P I158=ev.polygon_api.cone(20,I156,I157,30,30);
PT I159=ev.point_api.point(0,65,90);
PT I160=ev.point_api.point(0,65,0);
P I161=ev.polygon_api.cone(20,I159,I160,65,65);
P I162=ev.polygon_api.or_elem(I158,I161);
P I163=ev.polygon_api.disc(ev,30,0,-300,0,0,1,0,30);
P I164=ev.polygon_api.disc(ev,30,0,200,0,0,1,0,50);
P I165=ev.polygon_api.or_array2(std::vector<P>{I149,I152,I153,I154,I155,I162,I163,I164});
P I166=ev.polygon_api.recalculate_normals(I165);
P I167=ev.polygon_api.smooth_normals2(I166);
MT I168=ev.materials_api.m_def(ev);
MT I169=ev.materials_api.phong(ev,I168,0.0,0.0,1,ff884422,ff666666,150);
MT I170=ev.materials_api.web(ev,I169,-1.03,2,ff000000);
MT I171=ev.materials_api.web(ev,I170,1.03,2,ff000000);
ML I172=ev.materials_api.bind(I167,I171);
PT I173=ev.point_api.point(0.0,0.0,0.0);
P I174=ev.polygon_api.sphere(I173,20,5,5);
PTS I175=ev.points_api.bullet(44,0,150,0,0,200,0,2000,15,200);
MT I176=ev.materials_api.m_def(ev);
MT I177=ev.materials_api.phong(ev,I176,0.0,0.0,1,ff886688,ff666666,5);
ML I178=ev.materials_api.bind_inst(I174,I175,I177);
ML I179=ev.mainloop_api.array_ml(ev,std::vector<ML>{I172,I178});
P I180=ev.polygon_api.cube(-150,150,200,220,-10,10);
MT I181=ev.materials_api.m_def(ev);
MT I182=ev.materials_api.phong(ev,I181,0.0,0.0,1,ff884422,ff666666,150);
MT I183=ev.materials_api.web(ev,I182,-1.03,2,ff000000);
MT I184=ev.materials_api.web(ev,I183,1.03,2,ff000000);
ML I185=ev.materials_api.bind(I180,I184);
MN I186=ev.move_api.mn_empty();
MN I187=ev.move_api.rotate(I186,0,10000,0,0,0,0,1,0,8000);
ML I188=ev.move_api.move_ml(ev,I185,I187,1,10.0);
ML I189=ev.mainloop_api.array_ml(ev,std::vector<ML>{I179,I188});
MN I190=ev.move_api.mn_empty();
MN I191=ev.move_api.scale2(I190,0.5,0.5,0.5);
MN I192=ev.move_api.rotatez(I191,-1.59);
MN I193=ev.move_api.rotatex(I192,-1.59);
ML I194=ev.move_api.move_ml(ev,I189,I193,1,10.0);
MN I195=ev.move_api.mn_empty();
MN I196=ev.move_api.rotate(I195,0,20,0,0,0,0,0,1,1.59);
ML I197=ev.move_api.temp_key_activate_ml(ev,I194,I196,119,20);
MN I198=ev.move_api.mn_empty();
MN I199=ev.move_api.rotate(I198,0,20,0,0,0,0,0,1,-1.59);
ML I200=ev.move_api.temp_key_activate_ml(ev,I197,I199,115,20);
MN I201=ev.move_api.mn_empty();
MN I202=ev.move_api.translate(I201,0,5,0,60,0);
ML I203=ev.move_api.key_activate_ml(ev,I200,I202,119,5);
MN I204=ev.move_api.mn_empty();
MN I205=ev.move_api.translate(I204,0,5,0,-60,0);
ML I206=ev.move_api.key_activate_ml(ev,I203,I205,115,5);
MN I207=ev.move_api.mn_empty();
MN I208=ev.move_api.trans2(I207,-200,0,100);
ML I209=ev.move_api.move_ml(ev,I206,I208,1,10.0);
HML I400=ev.mainloop_api.html_url(http://meshpage.org/assets/flag_ml.mp);
ML I210=ev.mainloop_api.load_ML_script2(ev,I400,#1,b,c,d,e);
MN I211=ev.move_api.mn_empty();
MN I212=ev.move_api.trans2(I211,3800,-150,0);
MN I213=ev.move_api.translate(I212,0,300,-6000,0,0);
ML I214=ev.move_api.move_ml(ev,I210,I213,1,10.0);
ML I215=ev.mainloop_api.load_ML_script2(ev,I400,#2,b,c,d,e);
MN I216=ev.move_api.mn_empty();
MN I217=ev.move_api.trans2(I216,5800,-150,0);
MN I218=ev.move_api.translate(I217,0,600,-12000,0,0);
ML I219=ev.move_api.move_ml(ev,I215,I218,1,10.0);
ML I220=ev.mainloop_api.load_ML_script2(ev,I400,#3,b,c,d,e);
MN I221=ev.move_api.mn_empty();
MN I222=ev.move_api.trans2(I221,7800,-150,0);
MN I223=ev.move_api.translate(I222,0,900,-18000,0,0);
ML I224=ev.move_api.move_ml(ev,I220,I223,1,10.0);
HML I401=ev.mainloop_api.html_url(http://meshpage.org/assets/birds_ml.mp);
ML I225=ev.mainloop_api.load_ML_script2(ev,I401,a,b,c,d,e);
PT I226=ev.point_api.point(0,0,0);
PT I227=ev.point_api.point(3200,0,0);
PT I228=ev.point_api.point(6400,0,0);
PTS I229=ev.points_api.pt_array(ev,std::vector<PT>{I226,I227,I228});
ML I230=ev.move_api.local_move(ev,I225,I229);
MN I231=ev.move_api.mn_empty();
MN I232=ev.move_api.trans2(I231,4200,0,0);
MN I233=ev.move_api.translate(I232,0,900,-18000,0,0);
ML I234=ev.move_api.move_ml(ev,I230,I233,1,10.0);
ML I235=ev.mainloop_api.load_ML_script2(ev,I401,a,b,c,d,e);
PT I236=ev.point_api.point(0,0,0);
PT I237=ev.point_api.point(3200,0,0);
PT I238=ev.point_api.point(6400,0,0);
PTS I239=ev.points_api.pt_array(ev,std::vector<PT>{I236,I237,I238});
ML I240=ev.move_api.local_move(ev,I235,I239);
MN I241=ev.move_api.mn_empty();
MN I242=ev.move_api.trans2(I241,6200,-400,0);
MN I243=ev.move_api.translate(I242,0,900,-18000,0,0);
ML I244=ev.move_api.move_ml(ev,I240,I243,1,10.0);
ML I245=ev.mainloop_api.array_ml(ev,std::vector<ML>{I32,I117,I146,I209,I214,I219,I224,I234,I244});
P I246=ev.polygon_api.p_empty();
ML I247=ev.polygon_api.render_vertex_array_ml2(ev,I246);
ML I248=ev.mainloop_api.restart_screen(ev,I247,http://meshpage.org/assets/Chunkfive.otf);
ML I249=ev.mainloop_api.matrix_range_check(ev,I245,I248,http://meshpage.org/assets/test_data.txt);
ML I250=ev.mainloop_api.restart_game(ev,I249,114);
RUN I251=ev.blocker_api.game_window2(ev,I250,false,false,0.0,100000.0);

}