    ESENTHEL ENGINE SDK      00 - Start.txt

    /******************************************************************************/
    #include "stdafx.h"   // include precompiled header
    #include "resource.h" // include resources (icon)
    /******************************************************************************/
    void InitPre() // init before engine inits
    {
       // here you will have to setup initial engine settings
       // like application name, its options, screen resolution...

       App.name("Start");            // application name
       App.icon=(Char*)IDI_ICON1;    // setup icon
       App.flag=APP_NO_FX;           // set APP_NO_FX option to tell engine to load only basic drawing methods (no 3d and special effects)
       PakAdd("../data/engine.pak"); // load engine data
    }
    /******************************************************************************/
    Bool Init() // init after engine inits
    {
       // here when engine will be ready you can load your game data
       // return false when error occured

       return true;
    }
    /******************************************************************************/
    void Shut() // shut at exit
    {
       // this is called when the engine is about to exit
    }
    /******************************************************************************/
    Bool Main() // main updating
    {
       // here you have to process each frame update

       if(Kb.bp(KB_ESC))return false; // exit if escape on the keyboard pressed
       return true;                   // continue
    }
    /******************************************************************************/
    void Draw() // main drawing
    {
       // here you have to tell engine what to draw on the screen

       D.clear(TURQ);                                                                       // clear screen to turquoise color
       D.text (0, 0.1,"This is the First Tutorial");                                        // draw text at (0, 0.1) position
       D.text (0,-0.1,"Replace the CPP with some other file to view a different Tutorial"); // draw text at (0,-0.1) position
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      01 - Drawing.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       Here are presented the most basic drawing functions

    /******************************************************************************/
    void InitPre()
    {
       App.name("Drawing");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE); // clear to white

       // draw texts
       {
          D.text(0,0,"Default text settings"); // default text draw

          TextDS tds; // text draw settings, contains information about font size, aligning, color, ..

          tds.color=BLACK; // set black color
          tds.scale*=1.4f; // change scale
          D.text(tds,0,-0.2,"Bigger");

          tds.scale/=1.4f;    // reset scale
          tds.align.set(1,0); // change aligning
          D.text(tds,0,-0.4,"Right Aligned");

          tds.color=GREEN;     // change color to green
          tds.align.set(-1,0); // change aligning
          D.text(tds,0,-0.6,"Colored Left Aligned");

          tds.align.set(0,0);              // reset aligning
          tds.color=ColorHue(Tm.time()/3); // assign color to Color Hue according to current time
          D.text(tds,0,-0.8,"Multi colored");
       }

       // draw shapes
       {
          D.rect  (BLUE  , 0.5,0.5, 0.6,0.6);  // draw blue rectangle at given coordinates
          D.circle(RED   , 0.1, -0.5,0.5);     // draw red circle with 0.1 radius at (-0.5,0.5) position
          D.dot   (BLACK , 0,0.5);             // draw black dot at (0,0.5) position
          D.line  (GREEN , -0.4,0.5, 0.4,0.6); // draw green line
          D.tri   (YELLOW,Vec2(-0.5,-0.4),Vec2(-0.4,-0.2),Vec2(-0.4,-0.4)); // draw yellow triangle from given points
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      02 - Input.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Vec2 point; // point position
    Char c;     // character pressed
    /******************************************************************************/
    void InitPre()
    {
       App.name("Input");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK; // here change the default text color
       Text_ds.shadow=0;     // here disable shadows
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       if(Kb.c())c=Kb.c(); // if character pressed remember it to draw it later

       if(Kb.b(KB_LEFT ))point.x-=Tm.d()/2; // move point left  when 'left  arrow' is on according to time delta
       if(Kb.b(KB_RIGHT))point.x+=Tm.d()/2; // move point right when 'right arrow' is on according to time delta
       if(Kb.b(KB_DOWN ))point.y-=Tm.d()/2; // move point down  when 'down  arrow' is on according to time delta
       if(Kb.b(KB_UP   ))point.y+=Tm.d()/2; // move point up    when 'up    arrow' is on according to time delta

       if(Kb.bp(KB_Z))point.x-=0.1; // when 'z' is pushed        , move point left
       if(Kb.br(KB_X))point.x+=0.1; // when 'x' is released      , move point right
       if(Kb.bd(KB_C))point.y+=0.1; // when 'c' is double clicked, move point up

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       D.dot(RED  ,Ms.pos); // draw red   dot at mouse cursor position
       D.dot(GREEN,point ); // draw green dot at 'point' position

       if(Ms.b(0))D.dot(BLACK, -0.1,0.4, 0.1); // when 0th mouse button on, draw big black dot
       if(Ms.b(1))D.dot(BLACK,  0.1,0.4, 0.1); // when 1st mouse button on, draw big black dot

       D.text(0,0.9, S+"character : "+c ); // draw stored character
       D.text(0,0.7, S+"mouse : "+Ms.pos); // draw mouse  position
       D.text(0,0.6, S+"point : "+point ); // draw point  position
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      03 - Image.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Gfx gfx; // image
    /******************************************************************************/
    void InitPre()
    {
       App.name("Image");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       gfx="../data/gfx/particle/star.gfx"; // load image from file
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(BLACK);

       // draw image
       gfx.draw(-0.5,0.5, 1,1); // draw at (-0.5,0.5) position with (1,1) size
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      04 - Cache.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    void InitPre()
    {
       App.name("Cache");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(BLACK);

       Gfxs("../data/gfx/particle/star.gfx")->draw(-0.5,0.5, 1,1); // get image from cache and draw at (-0.5,0.5) position with (1,1) size

       // for safer use, you can first check if resource exists using 'get' method
       if(Gfx *gfx=Gfxs.get("non existing image.gfx")) // try to get non existing image, NULL will be returned since image doesn't exist
          gfx->draw(-0.5,0.5, 1,1); // this won't happen

       // see what will happen if you wan't to use "non existing image.gfx" when space pressed
       if(Kb.b(KB_SPACE))
       {
          Gfxs("non existing image.gfx")->draw(-0.5,0.5, 1,1); // when space pushed an error will be shown and application will exit immediately
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      05 - Gui.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Window window; // gui window
    Text   text  ; // gui text
    Button button; // gui button
    /******************************************************************************/
    void InitPre()
    {
       App.name("GUI");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.mode(800,600);
    }
    /******************************************************************************/
    Bool Init()
    {
       Gui   +=window.create(Rect(-0.5,-0.4,0.5,0.3)       ,"Window Title"); // create window and add it to Gui
       window+=text  .create(Vec2(0.5,-0.2f)               ,"text"        ); // create text   and add it to 'window', coordinates are relative to parent (it's top left point)
       window+=button.create(Rect(0.35f,-0.47f,0.65f,-0.4f),"OK"          ); // create button and add it to 'window', coordinates are relative to parent (it's top left point)
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Gui.update(); // update GUI

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(WHITE);
       Gui.draw (); // draw GUI
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      06 - 3D.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    void InitPre()
    {
       App.name("3D");
       App.flag=APP_NO_FX|APP_MS_EXCLUSIVE; // setup mouse exclusive mode to hide cursor
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=5; // set initial camera distance to 5 meters
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       CamHandle(0.1,10,CAMH_ROT|CAMH_ZOOM); // simple camera handle allowing minimum 0.1(10cm) and maximum 10meters zoom, and allowing rotation and zooming

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

                  Box (1                 ).draw(BLACK); // draw black box with 1 meter radius
       if(Ms.b(0))Ball(1    , Vec(-3,0,0)).draw(BLACK); // when 0th mouse button pushed draw black ball with 1   meter radius and (-3,0,0) position
       if(Ms.b(1))Tube(0.3,2, Vec( 3,0,0)).draw(BLACK); // when 1st mouse button pushed draw black tube with 0.1 meter radius, 2 meters height and (3,0,0) position
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      07 - Mesh.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mshb mshb; // mesh base (contains vertexes, edges, triangles, quads)
    /******************************************************************************/
    void InitPre()
    {
       App.name("Mesh");
       App.flag=APP_MS_EXCLUSIVE; // mouse exclusive mode to hide cursor, and APP_NO_FX removed since we'll be using vertex lit Mshb rendering
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=4;
       mshb.create(Torus(1,0.3),VTX_NRM); // create Mshb from torus, and automatically create vertex normals in order to lit the mshb properly
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ROT|CAMH_ZOOM);
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(TURQ);
       LightDir(Vec(0,0,1)).set(); // set directional light in (0,0,1) direction before rendering to achieve lighting (NOTE: only directional light is supported in simple rendering mode)

       if(Ms.b(0)) // when left mouse button on
       {
          Torus(1,0.3).draw(WHITE,true); // draw flat colored torus through Torus shape
       }else
       {
          mshb.draw(NULL); // draw through Mshb with default material (it will be shaded properly because it has vertex normals)
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Geometry\Camera.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    void InitPre()
    {
       App.name("Camera");
       App.flag=APP_NO_FX|APP_MS_EXCLUSIVE;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=5;
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       // settings
       Cam.yaw  -=Ms.d.x;                         // modify yaw      according to mouse delta x
       Cam.pitch+=Ms.d.y;                         // modify pitch    according to mouse delta y
       Cam.roll +=(Kb.b(KB_Z)-Kb.b(KB_X))*Tm.d(); // modify roll     according to Z and X keyboard buttons
       Cam.dist -=Ms.wheel*0.2;                   // modify distance according to mouse wheel
       Clamp(Cam.dist,0.1,10);                    // clamp  distance to minimum and maximum values

       if(Kb.b(KB_LEFT ))Cam.at-=Cam.matrix.x*Tm.d();
       if(Kb.b(KB_RIGHT))Cam.at+=Cam.matrix.x*Tm.d();
       if(Kb.b(KB_UP   ))Cam.at+=Cam.matrix.y*Tm.d();
       if(Kb.b(KB_DOWN ))Cam.at-=Cam.matrix.y*Tm.d();

       // camera
       Cam.setSpherical    (Cam.at,Cam.yaw,Cam.pitch,Cam.roll,Cam.dist); // set spherical camera with 'look at' position, angles and distance
       Cam.updateVelocities(                                          ); // after camera settings are up, we need to update camera velocities in order to achieve correct motion blur when enabled
       Cam.set             (                                          ); // set as active camera

       // camera effects
       if(Kb.bp(KB_SPACE))QuakeFx.addShort(); // add short quake camera effect when space pressed
                          QuakeFx.update  (); // update          camera effects
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       // draw 4x4 boxes
       REPD(x,4)
       REPD(z,4)Box(0.3,Vec(x,0,z)).draw(BLACK);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Geometry\Matrix.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       Matrix is a set of values which can be used to determine object's:
       -position
       -orientation (rotation)
       -scale

       Matrix is built from 4 vectors:
       -position
       -x direction (right  )
       -y direction (up     )
       -z direction (forward)

       The default Matrix is called MatrixIdentity, it has its vectors set as following:
       position(0,0,0) - located at world center, zero position
       x       (1,0,0) - points right
       y       (0,1,0) - points up
       z       (0,0,1) - points forward

    /******************************************************************************/
    void InitPre()
    {
       App.name("Matrix");
       App.flag=APP_NO_FX|APP_MS_EXCLUSIVE;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=5;
       Text_ds.color =BLACK;
       Text_ds.shadow=0;
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ROT|CAMH_ZOOM);
       return true;
    }
    /******************************************************************************/
    void Draw(Matrix &matrix) // this function handles optional 'matrix' drawing
    {
       if(Kb.b(KB_SPACE)) // draw matrix when space is pressed
       {
          SetMatrix(); // reset drawing matrix

          matrix.pos.draw(GREY,0.02f);                    // draw matrix position with grey color
          D.line(RED  , matrix.pos, matrix.pos+matrix.x); // draw matrix 'x' (right  ) vector with red   color
          D.line(GREEN, matrix.pos, matrix.pos+matrix.y); // draw matrix 'y' (up     ) vector with green color
          D.line(BLUE , matrix.pos, matrix.pos+matrix.z); // draw matrix 'z' (forward) vector with blue  color
       }
    }
    void Draw()
    {
       D.clear(WHITE);

       // box
       {
          SetMatrix(MatrixIdentity); // set default matrix identity
          Box(1).draw(BLACK);        // draw box at current matrix

          Draw(MatrixIdentity); // draw matrix
       }

       // ball
       {
          Matrix m;                           // matrix (matrix is a position + orientation)
          m.setPos(Vec(-3,0,0));              // init matrix with initial position
          SetMatrix(m);                       // set as active matrix
          Ball(1).draw(BLACK,false,VecI2(8)); // draw ball at current matrix

          Draw(m); // draw matrix
       }

       // tube
       {
          Matrix m;
          m.setRotateX(Tm.time());         // init matrix with initial x-rotation according to angle from time
          m.move(Vec(3,0,0));              // move matrix to the right
          SetMatrix(m);                    // set as active matrix
          Tube(0.2,2).draw(BLACK,false,6); // draw tube

          Draw(m); // draw matrix
       }

       D.text(0,0.9,"Press Space to draw Matrixes");
    }
    /******************************************************************************

       NOTE : if matrix method         starts with 'set' it means it resets matrix and then applies transformation
              if matrix method doesn't start  with 'set' it means it                   just applies transformation

       instead of writing:
          Matrix m;
          m.setRotateX(Tm.time());
          m.move(Vec(3,0,0));
          SetMatrix(m);

       you can write:
          SetMatrix(Matrix().setRotateX(Tm.time()).move(Vec(3,0,0)));

    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Graphics\2D Effects.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Gfx logo    , // logo image
        fade    ; // fading texture
    Flt fx_value; // effect value
    Int fx_index; // effect index
    /******************************************************************************/
    void InitPre()
    {
       App.name("2D Effects");
       App.flag=APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");
       D.mode(800,600);
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       // import esenthel engine logo
       logo.Import("../data/logo.png",-1,GFX_2D);

       // create fading texture
       fade.create2D(128,128, GFX_L8, 1);
       if(fade.lock())
       {
          REPD(x,fade.x())
          REPD(y,fade.y())fade.pixel(x,y,Random(256));
          fade.unlock();
       }
       fade.blur(5,false); // apply gaussian blur with 5 pixel range and no clamping

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       // change effect on key pressed, and reset effect value
       if(Kb.bp(KB_1)){fx_index=1; fx_value=0;}
       if(Kb.bp(KB_2)){fx_index=2; fx_value=0;}
       if(Kb.bp(KB_3)){fx_index=3; fx_value=0;}
       if(Kb.bp(KB_4)){fx_index=4; fx_value=0;}
       if(Kb.bp(KB_5)){fx_index=5; fx_value=0;}
       if(Kb.bp(KB_6)){fx_index=6; fx_value=0;}

       // increase effect value
       fx_value+=Tm.d();

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       if(Kb.b(KB_SPACE))fade.drawFs();else // if space pressed draw fading texture to full screen
       switch(fx_index)
       {
          case 0:
          {
             D.text(0,0,"Press 1,2,3,4,5,6 keys to view different effects");
          }break;

          case 1: // Draw Ripple Effect through Gfx::draw()
          {
             // set ripple effect values
             RippleFx ripple;
             ripple.alpha_add  = fx_value;
             ripple.alpha_scale=-1;

             // draw image with ripple effect
             logo.draw(ripple, -1,1,2,2);
          }break;

          case 2: // Draw Ripple Effect through helper screen
          {
             // draw to helper screen
             D.fxBegin(true);     // start drawing to helper screen
             logo.draw(-1,1,2,2); // image draw
             D.fxEnd();           // restore default screen drawing

             // set ripple effect values
             RippleFx ripple;
             ripple.alpha_add  = fx_value;
             ripple.alpha_scale=-1;

             // draw helper screen with ripple effect
             ripple.draw();
          }break;

          case 3: // Draw Fade Effect
          {
             // draw to helper screen
             D.fxBegin(true);     // start drawing to helper screen
             logo.draw(-1,1,2,2); // image draw
             D.fxEnd();           // restore default screen drawing

             // fade in helper screen with 'fade' fading texture
             FadeFx(fx_value/2,&fade);
          }break;

          case 4: // Titles Effect
          {
             // draw to helper screen
             D.fxBegin(true);                                                  // start drawing to helper screen
             REP(30)D.text(0,D.h()+(Frac(Tm.time())-i)*0.08,"Text Text Text"); // draw text
             D.fxEnd();                                                        // restore default screen drawing

             // set effect values
             TitlesFx titles;

             // draw helper screen with titles effect
             titles.draw();
          }break;

          case 5: // Wave Effect
          {
             logo.drawFs();           // draw logo on full screen
             WaveFx(Tm.time()/2,0.8); // apply wave effect onto the full screen
          }break;

          case 6: // Radial Blur Effect
          {
             logo.drawFs();                    // draw logo on full screen
             RadialBlurFx(Frac(fx_value)*0.3); // apply radial blur effect onto the full screen
          }break;
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Graphics\Color Transformations.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    enum COL_TRANS_MODE // color transformation modes
    {
       CT_RGB,
       CT_RBG,
       CT_GRB,
       CT_GBR,
       CT_BRG,
       CT_BGR,
       CT_MONO,
       CT_HUE,
       CT_HUE2,
       CT_CUSTOM,
       CT_CUSTOM2,
    };
    CChar8 *CTText[]= // color transformation description
    {
       "RGB",
       "RBG",
       "GRB",
       "GBR",
       "BRG",
       "BGR",
       "MONO",
       "HUE",
       "HUE+",
       "CUSTOM",
       "CUSTOM2",
    };
    Gfx    gfx   ; // Esenthel image
    Tabs   tabs  ; // transformation tabs
    Slider slider; // transformation power/alpha
    /******************************************************************************/
    void InitPre()
    {
       App.name("Color Transformations");
       PakAdd("../data/engine.pak");
       D.mode(800,600);
    }
    /******************************************************************************/
    Bool Init()
    {
       gfx.Import("../data/logo.png",-1,GFX_2D,1);
       Gui+=tabs  .create(Rect_U (0,D.h(),D.w()*2,0.06),0,CTText,ELMS(CTText));
       Gui+=slider.create(Rect_LU(-D.w(),D.h()-0.1,0.4,0.1)).set(1);
            slider.color=WHITE;
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       return true;
    }
    /******************************************************************************/
    void ApplyColorTransformation(Int mode)
    {
       ColorMatrix cm;             // color transformation matrix
       Flt         alpha=slider(); // color transformation power

       switch(mode)
       {
          case CT_RGB : cm.setRGB   (           ).draw(alpha); break;
          case CT_RBG : cm.setRBG   (           ).draw(alpha); break;
          case CT_GRB : cm.setGRB   (           ).draw(alpha); break;
          case CT_GBR : cm.setGBR   (           ).draw(alpha); break;
          case CT_BRG : cm.setBRG   (           ).draw(alpha); break;
          case CT_BGR : cm.setBGR   (           ).draw(alpha); break;
          case CT_MONO: cm.setMono  (           ).draw(alpha); break;
          case CT_HUE : cm.setHue   (Tm.time()/4).draw(alpha); break;
          case CT_HUE2: ColorTransHB(Tm.time()/4,1    ,alpha); break; // use 'ColTransHB' to get correct Hue-Brightness transformation

          case CT_CUSTOM:
          {
             // set custom matrix

             //         dest.r, dest.g, dest.b
             cm.x  .set(1     , 1     , 1     ); // src.r
             cm.y  .set(0     , 0     , 0     ); // src.g
             cm.z  .set(0     , 0     , 0     ); // src.b

             //         add.r , add.g , add.b
             cm.pos.set(0     , 0.2   , 0     ); // 1

             cm.draw(alpha);
          }break;

          case CT_CUSTOM2:
          {
             // set custom matrix #2

             //         dest.r, dest.g, dest.b
             cm.x  .set(0.5   , 0.5   , 0.5   ); // src.r
             cm.y  .set(0.5   , 0.5   , 0.5   ); // src.g
             cm.z  .set(0.3   , 0.3   , 1.0   ); // src.b

             //         add.r , add.g , add.b
             cm.pos.set(0     , 0     , 0     ); // 1

             cm.draw(alpha);
          }break;
       }
    }
    void Draw()
    {
       D.clear();

       // draw
       gfx.drawFs();
       D.rectShadedX(BLACK,RED  , -D.w()/2,-0.7, D.w()/2, -0.75);
       D.rectShadedX(BLACK,GREEN, -D.w()/2,-0.8, D.w()/2, -0.85);
       D.rectShadedX(BLACK,BLUE , -D.w()/2,-0.9, D.w()/2, -0.95);

       // transform colors
       ApplyColorTransformation(tabs());

       // draw gui after transformation
       Gui.draw();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Graphics\Colors HSB.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    void InitPre()
    {
       App.name("Colors HSB");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.mode(800,600);
    }
    /******************************************************************************/
    Bool Init()
    {
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       REPD(x,1024)
       {
          Flt  s0= x   /1024.0f        , // calculate step0 (fraction)
               s1=(x+1)/1024.0f        , // calculate step1 (fraction)
               x0=-1+s0*2              , // calculate x0 position
               x1=-1+s1*2              ; // calculate x1 position
          UInt c0=ColorHue(s0         ), // calculate color0 from hue value
               c1=ColorHSB(s0,1,1     ), // calculate color1 from hue saturation brightness value
               c2=ColorHue(c1,Ms.pos.x); // calculate color2 from color1 modified by hue from mouse x position

          // draw rectangles with different colors
          D.rect(c0,x0, 0.1,x1, 0.2);
          D.rect(c1,x0,-0.1,x1, 0.0);
          D.rect(c2,x0,-0.3,x1,-0.2);
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Graphics\Dynamic Image.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Gfx gfx; // image
    /******************************************************************************/
    void InitPre()
    {
       App.name("Dynamic Image");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       gfx.create2D(256,256, GFX_A8R8G8B8, 1); // create 256X256 image, A8R8G8B8 type, 1 mipmap

       if(gfx.lock()) // in order to edit the texture we must first lock it
       {
          FREPD(y,gfx.y()) // iterate through all y's
          FREPD(x,gfx.x()) // iterate through all x's
          {
             gfx.color(x,y, ARGB(255,x,y,0)); // set image (x,y) pixel color to ARGB color
          }
          gfx.unlock(); // unlock
       }
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       gfx.draw(-0.5,0.5, 1,1); // draw at (-0.5,0.5) position with (1,1) size
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Graphics\Font Make Unicode.txt

    [Error] - File could not be written...

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Graphics\Font Make.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       Creating Font is split into few parts:
          1. Call 'FontMake' to generate an image on your hard disk, the image will contain all desired characters
          2. Optionally you can modify the file on your disk, to customize the font graphics
          3. Use 'Font::create' method to create a font from the image

       Once you have created a Font, you can just save it using 'Font::save',
          and then in the game load it via 'Font::load' or by using Font cache - 'Fonts'

       Loading already created font ('Font::load' or 'Fonts') is much faster than creating a font ('Font::create')

    /******************************************************************************/
    Font   *font  ; // new font
    Button  button;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Font Make");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    void CreateFont()
    {
       Char *characters=L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()[]<>{}`~_-+=;:,.?/|\\'\""; // these are all the basic characters you may want to include in your font
       // please note that you don't have to worry about accidentally including the same character multiple times, because the engine will only generate 1 copy of a single character
       // for example you can freely set 'characters' to "0123ABC01" and the engine will generate only "0123ABC"

       FontMake("Times New Roman",characters,64,0,"LocalData/Times New Roman.png"); // create a image of desired characters created from the font "Times New Roman" located in your "Windows/Fonts" folder, and save it to disk (64 pixel size, 0 weight)

       // here you may optionally perform some modifications to the image, for example edit the image in external programs

       // after the image is ready, create the final font from it
       Font font;
       if(font.create("LocalData/Times New Roman.png",characters)) // create font from the image and use exactly the same character set 'characters' which were used in the 'FontMake' function
          font.save  ("LocalData/Times New Roman.font"          ); // save it, to load it later in your application
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       CreateFont(); // create the new font and save it to disk

       font=Fonts("LocalData/Times New Roman.font"); // load the font

       // now let's change Gui's default font for buttons
       Gui.tds_button.font=font;                            // assign the new font
       Gui+=button.create(Rect_C(0,-0.3,0.4,0.1),"Button"); // create a sample button to view the changes

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(WHITE);
       Gui.draw ();

       TextDS tds;       // text draw settings
       tds.font  =font ; // set font parameter to the newly created font
       tds.color =BLACK; // set black color
       tds.shadow=    0; // set no shadow

       D.text(    0,0.2,"This is the default font!"); // draw some text with the default       font
       D.text(tds,0,0  ,"This is the new font!"    ); // draw some text with the newly created font, please note the first parameter 'tds' is used to specify the new settings
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Graphics\Import Image.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Gfx gfx; // image
    /******************************************************************************/
    void InitPre()
    {
       App.name("Importing Images");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       gfx.Import("../data/logo.png",-1,GFX_2D); // import PNG format as a texture
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       gfx.draw(-1,0.5, 2,1); // draw at (-1,0.5) position with (2,1) size
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Graphics\VI - Vertex Index Buffer.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    void InitPre()
    {
       App.name("VI - Vertex Index Buffer");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       // to draw big number of shapes more efficiently please use VertexIndexBuffer (VI)

       Char8 *mode;

       if(Kb.b(KB_SPACE)) // when space on, draw in classic mode
       {
          REP(10000)D.line (GREEN, 0,0, Cos(i*PI2/10000),Sin(i*PI2/10000)); // draw 10000 lines      in classic mode
          REP(10000)D.rectL(ColorHue(i/10000.),Rect_C(0,0,i/20000.));       // draw 10000 rectangles in classic mode

          mode="Classic";
       }else // draw in buffered mode
       {
          // draw lines
          {
                       VI.color(GREEN); // set green color
             REP(10000)VI.line (0,0, Cos(i*PI2/10000),Sin(i*PI2/10000)); // draw 10000 lines in buffered mode
                       VI.end  ();      // finish drawing
          }
          //draw rectangles
          {
             REP(10000)VI.rectL(ColorHue(i/10000.),Rect_C(0,0,i/20000.)); // draw 10000 lines in buffered mode
                       VI.end  (); // finish drawing
          }
          mode="Buffered";
       }

       D.text(0,0.9,S+mode+" drawing" );
       D.text(0,0.8,S+"Fps: "+Tm.fps());
    }
    /******************************************************************************
    NOTE:
    Each type of drawing must be ended with it's own "end" method

       // forbidden
       {
          REP(10)VI.line(..);
          REP(10)VI.rect(..);
                 VI.end ();
       }

       // good
       {
          REP(10)VI.line(..);
                 VI.end ();

          REP(10)VI.rect(..)
                 VI.end ();
       }

    if one drawing method has color parameter and the other doesn't, it means they're different, and separate "end" is needed here as well

       // forbidden
       {
          REP(10)VI.line(RED, x0,y0,x1,y1);
          REP(10)VI.line(     x0,y0,x1,y1);
                 VI.end ();
       }

       // good
       {
          REP(10)VI.line(RED, x0,y0,x1,y1);
                 VI.end ();

                 VI.color(RED);
          REP(10)VI.line (x0,y0,x1,y1);
                 VI.end  ();
       }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\01 - Bars.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Window   window  ; // gui window
    SlideBar slidebar; // gui slidebar
    Progress progress; // gui progressbar
    Slider   slider  ; // gui slider
    /******************************************************************************/
    void InitPre()
    {
       App.name("Bars");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.mode(800,600);
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       Gui   +=window  .create(Rect(-0.5,-0.4,0.5,0.4),"Window with bars");
       window+=slidebar.create(Rect(0.1,-0.2,0.9,-0.12)); // create slidebar
       window+=progress.create(Rect(0.1,-0.4,0.9,-0.32)); // create progressbar
       window+=slider  .create(Rect(0.1,-0.6,0.9,-0.52)); // create slider

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();

       progress.set(slidebar()); // set progress bar according to slidebar value

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(WHITE);
       Gui.draw();
       D.text(0,-0.7,S+"SlideBar "   +slidebar()); // draw slidebar    value
       D.text(0,-0.8,S+"ProgressBar "+progress()); // draw progressbar value
       D.text(0,-0.9,S+"Slider "     +slider  ()); // draw slider      value
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\02 - Buttons.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Int    value   ; // simple integer value
    Button button_a, // gui button
           button_b, // gui button
           button_c; // gui button
    /******************************************************************************/
    void InitPre()
    {
       App.name("Buttons");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.mode(800,600);
    }
    /******************************************************************************/
    void Func(Ptr) // custom function which will be called when button pushed
    {
       value++;
    }
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       Gui+=button_a.create(Rect_C(-0.5,0, 0.45,0.08),"Button Func"  ,Func); // create button which will call 'Func' function when pushed
       Gui+=button_b.create(Rect_C( 0.0,0, 0.45,0.08),"Button Manual"     ); // create button without any functions, we will handle it manually
       Gui+=button_c.create(Rect_C( 0.5,0, 0.45,0.08),"Button Stay"       ); button_c.mode=BUTTON_STAY; // create button and set a special mode

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();

       if(button_b())value++; // manually check if button pushed

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(WHITE);
       Gui.draw ();

       D.text(0,0.6,S+"value = "     +value     ); // draw 'value' on screen
       D.text(0,0.5,S+"button_c() = "+button_c()); // draw state of 'button_c'

       // please note that you can also use automatically called functions with BUTTON_STAY mode
       // and you can manually check for state change of such button this way:
       if(button_c.changed())value++;
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\03 - Tabs.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Window window; // gui window
    Tabs   tabs  ; // gui tabs
    Text   text  ; // gui text
    Button button; // gui button
    Image  image ; // gui image
    /******************************************************************************/
    void InitPre()
    {
       App.name("Tabs");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.mode(800,600);
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       CChar8 *tab[]=
       {
          "First",
          "Second",
          "Third",
       };

       Gui   +=window.create(Rect   (-0.5,-0.4,0.5,0.4),"Window with tabs");
       window+=tabs  .create(Rect_LU(0,0,window.crect.w(),0.08),0,tab,ELMS(tab)); // create tabs

       // add some elements to tabs
       {
          tabs.add(0,text  .create(Vec2  (window.crect.w()/2,-window.crect.h()/2        ),"Text"                     )); // create and add text   to 0th tab
          tabs.add(1,button.create(Rect_C(window.crect.w()/2,-window.crect.h()/2,0.4,0.1),"Button"                   )); // create and add button to 1st tab
          tabs.add(2,image .create(Rect_C(window.crect.w()/2,-window.crect.h()/2,0.5,0.5),Gfxs("LocalData/image.gfx"))); // create and add image  to 2nd tab
       }

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(WHITE);
       Gui.draw ();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\04 - Window Menu.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Window window; // gui window
    Menu   menu  ; // gui menu
    /******************************************************************************/
    void InitPre()
    {
       App.name("Window Menu");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.mode(800,600);
    }
    /******************************************************************************/
    // here are defined functions which are going to be used by menu commands when activated
    void MenuFileNew (){}
    void MenuFileOpen(){}
    void MenuFileSave(){}
    void MenuFileExit(){StateExit.set();}
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       Gui+=window.create(Rect(-0.5,-0.4,0.5,0.4),"Window with menu");
       {
          using namespace MenuDefs; // use this namespace to simplify menu creation
          // from now on (in current scope) N is a menu node
          N n; // let's start with main node
          {
             N &f=(n+="File"); // add "File" element to main node, and store it's reference in 'f'
             f.New().create("New" ,MenuFileNew ,KbSc('n',KBSC_CTRL)); // add "New"  command to 'f', giving it's procedure and keyboard shortcut (ctrl+n)
             f.New().create("Open",MenuFileOpen,KbSc('o',KBSC_CTRL)); // add "Open" command to 'f', giving it's procedure and keyboard shortcut (ctrl+o)
             f.New().create("Save",MenuFileSave,KbSc('s',KBSC_CTRL)); // add "Save" command to 'f', giving it's procedure and keyboard shortcut (ctrl+s)
             f++; // add empty line
             f.New().create("Exit",MenuFileExit,KbSc('x',KBSC_CTRL)); // add "Exit" command to 'f', giving it's procedure and keyboard shortcut (ctrl+x)
          }
          {
             N &e=(n+="Edit");
             e.New().create("Option",CMENU_TOGGLABLE); // giving CMENU_TOGGLE flag means that we can toggle this element
             {
                N &c=(e+="Children");
                c+=            "child 1";
                c.New().create("child 2").desc("This is child 2"); // this element has a description which will be shown when mouse cursor stops on the element
                c.New().create("child 3",CMENU_TOGGLABLE).setOn(); // this element can be toggled and is checked by default
             }
          }
          window+=menu.create(n); // create menu from nodes and add it to window
       }
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(WHITE);
       Gui.draw ();
       D  .text (0,-0.7,S+"'Option' is "+menu("edit/option")); // draw state of "option" located in "edit" using operator() method

       // Another way of checking if a command has been selected is to use 'pushed' method, like this:
       if(menu.pushed("edit/children/child 1"))
       {
          // if we're here then "edit/children/child 1" has been selected
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\05 - List.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    struct Struct // custom structure
    {
       Flt  f;
       Int  i;
       Byte b;
    }data[10]= // sample data array
    {
       {1.0, 15, 4},
       {2.0, 25, 3},
       {3.0, 35, 2},
       {4.0, 45, 1},
    };
    ListGroup list_group[]= // gui list group (stores information about structure format)
    {
       ListGroup(MEMBER(Struct,f),0.3,L"Float"  ), // group describing 'f' member in 'Struct' structure, width of group=0.3, name="Float"
       ListGroup(MEMBER(Struct,i),0.3,L"Integer"), // group describing 'i' member in 'Struct' structure, width of group=0.3, name="Integer"
       ListGroup(MEMBER(Struct,b),0.2,L"Byte"   ), // group describing 'b' member in 'Struct' structure, width of group=0.2, name="Byte"
    };
    /******************************************************************************/
    Window       window; // gui window
    Region       region; // gui region
    List<Struct> list  ; // gui list
    /******************************************************************************/
    void InitPre()
    {
       App.name("List");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.mode(800,600);
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       Gui   +=window.create(Rect(-0.5,-0.4,0.5,0.4),"Window with list");
       window+=region.create(Rect(0.05,-0.6,0.95,-0.1));                            // create region
       region+=list  .create(list_group,ELMS(list_group)).setData(data,ELMS(data)); // create list with 'list_group' groups and 'data' data

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(WHITE);
       Gui.draw ();
       if(Struct *cur=list())D.text(0,-0.7,S+"current element's Integer value "+cur->i);
                             D.text(0,-0.8,S+"current element (on the list) "  +list.cur);
                             D.text(0,-0.9,S+"original element (in data) "     +list.orderToElm(list.cur));
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\06 - ComboBox.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    ComboBox combobox_a, // combobox
             combobox_b; // combobox

    struct ComboBoxElm // combobox element structure
    {
       VecI2 vec;
    }veci2[]=
    {
       {VecI2(0, 0)},
       {VecI2(0,10)},
       {VecI2(0,20)},
       {VecI2(1, 0)},
       {VecI2(1,10)},
       {VecI2(1,20)},
    };

    CChar* ComboBoxElmFunc(ComboBoxElm &elm) // function which transforms ComboBoxElm into a string
    {
       static Str str;
       return str=S+elm.vec.x+" x "+elm.vec.y;
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("ComboBox");
       App.flag=APP_FULL_TOGGLE|APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       // combobox A (from text-only elements)
       {
          static CChar8 *elm[]= // combobox elements (must be non-local)
          {
             "First",
             "Second",
             "Third",
          };
          Gui+=combobox_a.create(Rect_C(-0.5,0, 0.4,0.08),elm,ELMS(elm)); // create combobox with simple elements (text-only)
       }

       // combobox B (from custom structure)
       {
          ListGroup lg[]= // list groups
          {
             ListGroup(ComboBoxElmFunc,0.3,L"Function"), // list group which uses custom function for data interpretation
          };
          Gui+=combobox_b.create(Rect_C(0.5,0, 0.4,0.08)); // create combobox

          // assign custom elements
          combobox_b.setGroups(lg   ,ELMS(lg   ),true)  // set list groups
                    .setData  (veci2,ELMS(veci2)     ); // set list data
       }

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       D.text (-0.5, 0.1,S+"combobox_a element: "+combobox_a()); // draw selected element
       D.text ( 0.5, 0.1,S+"combobox_b element: "+combobox_b()); // draw selected element
       Gui.draw();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\07 - Game Menu.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    struct MenuNew // new-game menu
    {
       Window window;
       Text   text;
       Button close;

       static void Close(Ptr){Mn.window.fadeOut();}

       void create()
       {
          Gui   +=window.create(Rect_C(0,0,0.9,0.5)).barVisible(false).hide();
          window+=text  .create(Vec2  (window.crect.w()/2,-0.15),"New Game");
          window+=close .create(Rect_C(window.crect.w()/2,-window.crect.h()/2-0.1,0.4,0.08),"Close",Close);
       }
    }Mn;
    /******************************************************************************/
    struct MenuLoad // load-game menu
    {
       Window window;
       Text   text;
       Button close;

       static void Close(Ptr){Ml.window.fadeOut();}

       void create()
       {
          Gui   +=window.create(Rect_C(0,0,0.9,0.5)).barVisible(false).hide();
          window+=text  .create(Vec2  (window.crect.w()/2,-0.15),"Load Game");
          window+=close .create(Rect_C(window.crect.w()/2,-window.crect.h()/2-0.1,0.4,0.08),"Close",Close);
       }
    }Ml;
    /******************************************************************************/
    struct MenuOptions // options menu
    {
       Window window;
       Text   text;
       Button close;

       static void Close(Ptr){Mo.window.fadeOut();}

       void create()
       {
          Gui   +=window.create(Rect_C(0,0,0.9,0.5)).barVisible(false).hide();
          window+=text  .create(Vec2  (window.crect.w()/2,-0.15),"Options");
          window+=close .create(Rect_C(window.crect.w()/2,-window.crect.h()/2-0.1,0.4,0.08),"Close",Close);
       }
    }Mo;
    /******************************************************************************/
    struct MenuMain // main menu
    {
       Window window;
       Button b_new,b_load,b_options,b_exit;

       static void New    (Ptr){Mn.window.fadeIn();}
       static void Load   (Ptr){Ml.window.fadeIn();}
       static void Options(Ptr){Mo.window.fadeIn();}
       static void Exit   (Ptr){StateExit.set();}

       void create()
       {
          Gui   +=window   .create(Rect_C(0,-0.1,0.6,0.6)).barVisible(false);
          window+=b_new    .create(Rect_C(window.crect.w()/2,-0.15,0.4,0.08),"New"    ,New);
          window+=b_load   .create(Rect_C(window.crect.w()/2,-0.25,0.4,0.08),"Load"   ,Load);
          window+=b_options.create(Rect_C(window.crect.w()/2,-0.35,0.4,0.08),"Options",Options);
          window+=b_exit   .create(Rect_C(window.crect.w()/2,-0.45,0.4,0.08),"Exit"   ,Exit);
          window.flag&=~WIN_MOVABLE; // disable moving of this window
          window.level=-1          ; // set lower level so this window will be always below the other created in this tutorial
       }
    }Mm;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Game Menu");
       App.flag=APP_FULL_TOGGLE; // we'll be using GUI effects (window fading) so make sure APP_NO_FX isn't selected
       PakAdd("../data/engine.pak");
       D.mode(800,600).sync(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       // in games disable highlighting elements with keyboard focus
       Gui.kb_lit=0;

       // change default gui text colors
       Gui.tds_text.color=WHITE;
       Gui.tds_text.shadow=255;

       // change Default Gui Window Style
       Gui.style_window.gfx_back    =Gfxs("../data/Gui/Style/0/back.gfx");
       Gui.style_window.gfx_border  =Gfxs("../data/Gui/Style/0/border.gfx");
       Gui.style_window.border_color=WHITE;
       Gui.style_window.back_color  =BLUE;
       Gui.style_window.border_width=0.03;

       Mn.create();
       Ml.create();
       Mo.create();
       Mm.create();
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear();
       Gui.draw ();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\08 - Loading Gui Objects.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       Instead of creating all Gui Objects manually in the code,
       you can create them in the Gui Editor tool, and then just load them.

    /******************************************************************************/
    GuiObjs   gui_objs;
    TextLine *name;
    Button   *next;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Loading Gui Objects");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");
       D.mode(800,600).sync(true);
    }
    /******************************************************************************/
    void ButtonFunction(Ptr) // custom function called when button pressed
    {
       if(name)name->clear(); // if we have accessed the 'name' TextLine then simply clear it
    }
    /******************************************************************************/
    Bool Init()
    {
       Gui.kb_lit=0;

       // load prepared Gui Objects in Gui Editor
       if(gui_objs.load("gui/obj/player name.gobj"))
       {
          // if loaded succesfully 'gui_objs' now contains all the buttons, windows and other objects, stored in containers
          // first we'll add all of them to the Gui (more specifically to the active desktop) :
          Gui+=gui_objs;

          // now all objects are placed onto the desktop

          // the next step is to access the objects, accessing is done by requesting objects by name
          // each objects name has to be manually set in the Gui Editor
          name=gui_objs.getTextLine("name"); // get the 'player name' TextLine, which has its name set to "name" (it has been set in the Gui Editor)
          next=gui_objs.getButton  ("next"); // get the 'next'        Button  , which has its name set to "next" (it has been set in the Gui Editor)

          next->func=ButtonFunction; // once we have the button we can manually assign a function for it, which will be called when the button is pressed

          return true;
       }
       return false;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear();
       Gui.draw ();

       if(name)D.text(0,0.9,S+(*name)()); // draw accessed TextLine value
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\09 - Extending Gui Objects.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       Because the main methods of Gui Objects are virtual, you can extend them.

    /******************************************************************************/
    struct Button2 : Button // Create a new class extending the default Gui Button
    {
       virtual void     test  (GuiPC &gpc); // extend testing if object is under mouse cursor
       virtual Button2& update(GuiPC &gpc); // extend updating   object
       virtual void     draw  (GuiPC &gpc); // extend drawing    object
    };

    void Button2::test(GuiPC &gpc) // extend testing
    {
       __super::test(gpc); // call default method
    }

    Button2& Button2::update(GuiPC &gpc) // extend updating
    {
       __super::update(gpc); // call default method
       return T;             // return self
    }

    void Button2::draw(GuiPC &gpc) // extend drawing
    {
       D.clip(gpc.clip); // clip display drawing to given clipping rectangle, this is needed for example when object is inside a window, and is partially hidden because the parent's rectangle doesn't fully cover this object

       UInt color=(visuallyPushed() ? BLACK : ColorLerp(RED_DARK,RED,lit())); // set different color depending if the button is pushed and highlighted
       D.rect(color, rect+gpc.offset); // draw a background rectangle, moved by 'gpc.offset' (parents offset)

       D.text(rect.center()+gpc.offset, text); // draw button's text, at center of rectangle and again moved by 'gpc.offset'
    }
    /******************************************************************************/
    Button2 button; // create a sample button
    /******************************************************************************/
    void InitPre()
    {
       App.name("Extending Gui Objects");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");
       D.mode(800,600).sync(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       Gui+=button.create(Rect_C(0,0,0.5,0.1),"New Button"); // add the button to the active desktop
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(WHITE);
       Gui.draw ();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\10 - Extending and Loading Gui Objects.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    // Define extended version of default 'Button'
    /******************************************************************************/
    struct Button2 : Button
    {
       virtual void     test  (GuiPC &gpc);
       virtual Button2& update(GuiPC &gpc);
       virtual void     draw  (GuiPC &gpc);
    };
    void Button2::test(GuiPC &gpc)
    {
       __super::test(gpc);
    }
    Button2& Button2::update(GuiPC &gpc)
    {
       __super::update(gpc);
       return T;
    }
    void Button2::draw(GuiPC &gpc)
    {
       D.clip(gpc.clip);

       UInt color=(visuallyPushed() ? BLACK : ColorLerp(RED_DARK,RED,lit()));
       D.rect(color, rect+gpc.offset);

       D.text(rect.center()+gpc.offset, text);
    }
    /******************************************************************************/
    GuiObjs gui_objs;
    Button2 button;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Extending and Loading Gui Objects");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");
       D.mode(800,600).sync(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       Gui.kb_lit=0;

       // replace default 'Button' class with extended 'Button2'
       gui_objs.replaceButton<Button2>();

       // load the gui objects
       if(gui_objs.load("gui/obj/player name.gobj"))
       {
          Gui+=gui_objs;
          return true;
       }
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(BLACK);
       Gui.draw ();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\11 - Multiple Viewports.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       In this tutorial we'll present multiple viewports with different cameras,
       We'll use 'GViewport::user' to set camera's index

    /******************************************************************************/
    GViewport viewport[2];
    Camera    camera  [2];
    /******************************************************************************/
    void Render(GViewport &viewport) // rendering function wich will be called when drawing the Gui Viewport element
    {
       Int camera_index=Mid(viewport.userd,0,ELMS(camera)-1); // get camera index and clamp it for safety, in case the user data is invalid

       // activate camera
       camera[camera_index].set();

       // simple rendering
       D.clear(BLACK);
       Box(1,Vec(0,0,0)).draw(WHITE);
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Multiple Viewports");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");
       D.mode(800,600).sync(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       // initialize cameras
       camera[0].setSpherical(Vec(0,0,0),0,0,0,3);
       camera[1].setSpherical(Vec(0,0,0),0,0,0,3);

       Gui+=viewport[0].create(Rect_C(-0.5,0,0.9,0.9),Render,(Ptr)0); // create a viewport with 'user=0' to mark camera[0] usage
       Gui+=viewport[1].create(Rect_C( 0.5,0,0.9,0.9),Render,(Ptr)1); // create a viewport with 'user=1' to mark camera[1] usage

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();

       // now we'll modify camera angles and distance
       // first we'll detect which camera to update
       {
          Camera *cam=NULL; // start with none

          // 'Gui.viewport' specifies current Gui Viewport under mouse cursor
          if(Gui.viewport==&viewport[0])cam=&camera[0];else
          if(Gui.viewport==&viewport[1])cam=&camera[1];

          if(cam) // if found a camera
          {
             // modify camera values by mouse movement
             if(Ms.b(0)) // only when mouse button pressed
             {
                cam->yaw  -=Ms.d.x;
                cam->pitch+=Ms.d.y;
             }

             // modify camera distance by mouse wheel
             if(Ms.wheel<0)cam->dist*=1.2;
             if(Ms.wheel>0)cam->dist/=1.2;

             cam->setSpherical(); // apply changes by calling 'setSpherical' which sets camera matrix from current values
          }
       }

       // update all camera velocities, this is needed when using Motion Blur effect
       REPA(camera)camera[i].updateVelocities();

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(WHITE);
       Gui.draw (     );
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Gui\12 - Window IO.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    WindowIO wio_mesh; // window handling input/ouput
    Mesh     mesh    ; // mesh which will be used for saving,loadng and drawing
    /******************************************************************************/
    void InitPre()
    {
       App.name("Window IO");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");
       D.mode(800,600).sync(true);
    }
    /******************************************************************************/
    void Load(CChar *name) // this function will be called when WindowIO will load a file
    {
       mesh.load(name);
    }
    void Save(CChar *name) // this function will be called when WindowIO will save a file
    {
       // here you can save your file, however in this tutorial we're not going to do this
       // mesh.save(name);
    }
    /******************************************************************************/
    Bool Init()
    {
       wio_mesh.create("mesh",CNULL,IOPath(),Load,Save); // create a WindowIO, giving accepted file extension, paths, and IO functions
       wio_mesh.path_mode=WIN_IOP_PART; // set displaying path mode on the window title bar

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();

       wio_mesh.update(); // WindowIO needs to be manually updated

       // activate saving/loading on keypress
       if(Kb.bp(KB_F2))wio_mesh.save();
       if(Kb.bp(KB_F3))wio_mesh.load();

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D   .clear(GREY);
       Cam .setSpherical(Vec(0),Tm.time(),0,0,mesh.box.size().length()*1.2).updateVelocities().set();
       LightDir(Cam.matrix.z).set();
       mesh.draw(MatrixIdentity);
       D   .text(0,0.9,"Press F2/F3 to save/load");
       Gui .draw();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Calculator.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    TextLine textline; // Gui TextLine
    /******************************************************************************/
    void InitPre()
    {
       App.name("Calculator");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       Gui+=textline.create(Rect(-0.5,0,0.5,0.1)); // add textline to gui desktop
       textline.kbSet();                           // set keyboard focus

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(WHITE);
       Gui.draw ();
       D.text(0,-0.4,S+CalcR(textline())); // draw calculated value from 'textline' as Real
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Config.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    void InitPre()
    {
       App.name("Config");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");

       // here you can set initial settings
       // they will be used in case "config.txt" file is not found or incomplete
       // ..

       if(ConfigLoad()) // here settings are loaded from "config.txt"
       {
          // if settings were loaded properly, you can optionally override them here
          // ..
       }
    }
    /******************************************************************************/
    Bool Init()
    {
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
       ConfigSave(); // here settings are saved to "config.txt"
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Cpu.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Str s;
    /******************************************************************************/
    void InitPre()
    {
       App.name("CPU");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       // check which features are supported
       if(Cpu.flag()&CPU_MMX   )s.space()+="MMX";
       if(Cpu.flag()&CPU_3DNOW )s.space()+="3dNow";
       if(Cpu.flag()&CPU_3DNOW2)s.space()+="3dNow+";
       if(Cpu.flag()&CPU_SSE   )s.space()+="SSE";
       if(Cpu.flag()&CPU_SSE2  )s.space()+="SSE2";
       if(Cpu.flag()&CPU_SSE3  )s.space()+="SSE3";

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       D.text (0,0.3,S+"Number of cores: "   +Cpu.cores());
       D.text (0,0.1,S+"Supported features: "+s);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Drag & Drop.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Memb<Char[MAX_PATH]> names;
    /******************************************************************************/
    void Drop()
    {
       names.clear(); // remove all existing elements in container

       for(;CChar *name=DropName();) // iterate through all files dropped
       {
          // here you can perform operations on dropped file, by accessing it's 'name'
          // in this tutorial we will just store the name in a memory container

          Set(names.New(),name); // copy 'name' to 'names' container
       }
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Drag & Drop");
       App.flag=APP_NO_FX;
       App.drop=Drop; // enable Drag & Drop by specifying function called when a file will be dropped on window
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       D.text (0,0.9,"Drag & Drop some files to this window");

       FREPA(names)D.text(0,0.7-i*0.1,names[i]); // draw all file names
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\File.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       Files are universal and can be used to:
          -read/write from stdio files (typical files on you Hard Drive)
          -read files from Pak         (an archive of multiple files)
       They handle encrypting/decrypting with given Secure key

    /******************************************************************************/
    struct Data
    {
       Char text[256];
    };
    /******************************************************************************/
    void InitPre()
    {
       App.name("File");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       Data data;
       Set(data.text,"Sample text");

       // for testing we'll start with with writing to a file in memory
       {
          File f; // file object

          f.writeMem(          ); // start writing to memory (file will automatically handle the memory allocations)
          f.putByte (       128); // put Byte       '128' to file
          f.putDwrd (0x12345678); // put U32 '0x12345678' to file
          f<<data;                // put 'data'           to file (it's raw memory)
       }

       // now let's write all that to a real file on Hard Disk
       {
          File f;

          f.write  ("LocalData/file.dat"); // start writing to file
          f.putByte(       128);
          f.putDwrd(0x12345678);
          f<<data;
       }

       // when the file is created we can now read it
       {
          File f;

                 f.read   ("LocalData/file.dat"); // start reading file
          Byte b=f.getByte(); // read Byt (returns 128)
          UInt d=f.getDwrd(); // read U32 (returns 0x12345678)
                 f>>data    ; // read 'data' (data.text should be "Sample text")
       }
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\FileFind.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Memb<Char[MAX_PATH]> names;
    /******************************************************************************/
    void InitPre()
    {
       App.name("FileFind");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    void AddName(CChar *name) // add 'name' to names list
    {
       Set(names.New(),name); // create new element in names and set it's name
    }

    void ManualFind(Str path) // manually iterate through directories and files
    {
       for(FileFind ff(path); ff();)switch(ff.type) // start looking for files in path, continue while active, and check for encountered type
       {
          case FSTD_DIR : ManualFind(ff.pathName()); break; // if directory encountered start looking inside it
          case FSTD_FILE: AddName   (ff.pathName()); break; // if file      encountered add it to the list
       }
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       if(Kb.bp(KB_SPACE))
       {
          names.clear();          // clear elements
          FAll("source",AddName); // use FAll which operates on all files inside given path (AddName will be called multiple times with each file name as a parameter)
       }

       if(Kb.bp(KB_ENTER))
       {
          names.clear();        // clear elements
          ManualFind("source"); // manually iterate through all directories and files
       }

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       D.text (0,0.9,"Press Space to use FAll, or press Enter for FileFind");

       FREPA(names)D.text(0,0.8-i*0.1,names[i]); // draw all file names
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\FileText.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       FileText is meant for operations performed on a text file

    /******************************************************************************/
    struct Data // custom Data structure to test text file saving/loading
    {
       Flt  volume;
       Int  graphics_mode;
       Char player_name[64];

       Bool saveTxt(Str name); // save data to   text file
       Bool loadTxt(Str name); // load data from text file
    };
    /******************************************************************************/
    Bool Data::saveTxt(Str name)
    {
       FileText f; // FileText object

       if(f.write(name)) // if file opened successfully
       {
          f.put    ("Volume       = ",volume       );
          f.put    ("GraphicsMode = ",graphics_mode); // please note "GraphicsMode" is used instead of "Graphics Mode" (names are required to don't have spaces)
          f.putName("PlayerName   = ",player_name  ); // FileText::putName will automatically put the value in quotes
          return true; // return success
       }
       return false; // return failure
    }

    Bool Data::loadTxt(Str name)
    {
       // set default values to members in case file not found or file incomplete
       volume=1;
       graphics_mode=5;
       player_name[0]=0;

       FileText f;

       if(f.read(name)) // if file opened successfully
       {
          for(;f.level();) // process file within its level
          {
             if(f.cur("Volume"      ))volume       =Sat(f.getReal()     );else // if encountered "Volume"       then read a floating point value, saturate it and store into 'value'
             if(f.cur("GraphicsMode"))graphics_mode=Mid(f.getInt (),0,10);else // if encountered "GraphicsMode" then read a integer        value, clamp    it and store into 'graphics_mode'
             if(f.cur("PlayerName"  ))Set(player_name,  f.getName()     );     // if encountered "PlayerName"   then read a string using 'FileText::getName' method     into 'player_name'
          }
          return true; // return success
       }
       return false; // return failure
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("FileText");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       // set sample data values
       Data data;
           data.volume       =0.5;
           data.graphics_mode=2;
       Set(data.player_name,"He-Man");

       data.saveTxt("LocalData/file.txt"); // save data to   text file
       data.loadTxt("LocalData/file.txt"); // load data from text file

       OSLaunch("LocalData/file.txt"); // open the text file in default Windows viewer to check what actually has been saved

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\IO Path.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       To work easily with relative path's 'IOPath' is used
       when IOPath is set it is treated as additional path for your files/resources

       For Example you have all your data stored in 'd:/game/data', like:
       'd:/game/data/gfx/..'
       'd:/game/data/anim/..'
       'd:/game/data/obj/..'

       and you'd like to access them more simply:
       "gfx/.."
       "anim/.."
       "obj/.."

       To do so, all you have to do is set IOPath to "d:/game/data"

    /******************************************************************************/
    Gfx *gfx;
    /******************************************************************************/
    void InitPre()
    {
       App.name("IO Path");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       // in this sample we'll load "image.gfx" which is located in "LocalData" folder where the tutorials are ("LocalData/image.gfx")
       IOPath("LocalData");   // setup additional IO Search Path
       gfx=Gfxs("image.gfx"); // load image, IOPath will be used automatically

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       gfx->draw(-0.5,0.5, 1,1);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Memory.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    struct Data // custom data structure
    {
       Byte bytes[100];
       Int  integer;
       Flt  value;
    };
    /******************************************************************************/
    // memory containers
    Memb<Data> memb; // block based
    Meml<Data> meml; // list  based
    /******************************************************************************/
    void InitPre()
    {
       App.name("Memory");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       // adding elements
       {
          // Memb
          {
             Data &data=memb.New();
             data.integer=5;
          }
          // Meml
          {
             Data &data=meml.New();
             data.integer=5;
          }
       }

       // iterating through all elements
       {
          // Memb
          for(Int i=0; i<memb.elms(); i++)
          {
             Data &d=memb[i];
          }
          // Memb through better macro
          FREPA(memb)
          {
             Data &d=memb[i];
          }

          // Meml
          for(MemlNode *i=meml.first; i; i=i->next)
          {
             Data &d=meml[i];
          }
          // Meml through macro
          MFREP(meml) // please note that here 'i' is not an 'Int' but a 'MemlNode*'
          {
             Data &d=meml[i];
          }
       }

       // removing elements
       {
          // Memb
          {
             memb.remove(0,true); // remove 0th element, second parameter determines keeping order (read more in the header)
          }
          // Meml
          {
             meml.remove(meml.first);
          }
       }

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Mouse Cursor.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    void InitPre()
    {
       App.name("Mouse Cursor");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       if(Kb.bp(KB_1))Ms.cursor(Gfxs("../data/gfx/cursor/0.gfx")); // if '1' pressed change cursor to '0.gfx'
       if(Kb.bp(KB_2))Ms.cursor(Gfxs("../data/gfx/cursor/1.gfx")); // if '2' pressed change cursor to '1.gfx'

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       D.text (0,0,"Press '1' or '2' to change mouse cursor");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Number.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       Number is a number able to store very big values with big precision (Int or Real)

    /******************************************************************************/
    Number n0,n1,n2,n3,n4;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Number");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       // assign 1.0
       n0=1.0;
       // do some big operations
       n0*=100000; n0.sqrt(); n0+=123.456;
       n0*=100000; n0.sqrt(); n0+=123.456;
       n0*=100000; n0.sqrt(); n0+=123.456;
       // revert operations
       n0-=123.456; n0.sqr(); n0/=100000;
       n0-=123.456; n0.sqr(); n0/=100000;
       n0-=123.456; n0.sqr(); n0/=100000;
       // n0 should be back to 1.0

       // calculate sqrt(sqrt(sqrt(1000000000000000000000000000000.)))
       n1=Str("1000000000000000000000000000000.");
       n1.sqrt();
       n1.sqrt();
       n1.sqrt();

       // NOTE: Number can be internally an Int or Real (check Number::real)
       // any operation between Int and Int results also in Int (any other in Real)
       // when calculating Number(10)/3 you'll get 3 instead of 3.333..
       // to convert Number to be Int or Real use toInt() and toReal() methods
       {
          n2=Number(10  )/3; // Int /Int = Int  (3)
          n3=Number(10.0)/3; // Real/Int = Real (3.333..)

          n4=10;       // Int
          n4.toReal(); // convert to Real
          n4/=3;       // Real/Int = Real (3.333..)
       }
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       D.text (0,0.6, S+"n0 = "+n0.asReal());
       D.text (0,0.4, S+"n1 = "+n1.asReal());
       D.text (0,0.2, S+"n2 = "+n2.asReal());
       D.text (0,0.1, S+"n3 = "+n3.asReal());
       D.text (0,0.0, S+"n4 = "+n4.asReal());
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Pak Create.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Byte b1,b2; // bytes
    /******************************************************************************/
    void InitPre()
    {
       App.name("Pak Create");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       // create Pak from one file/directory
       {
          PakCreate("LocalData"); // create Pak from "LocalData" folder, if no 'pak_name' is specified it will be automatically set (in this case it'll be "LocalData.pak")
       }

       // create Pak from list of files
       {
          Memb<Char[MAX_PATH]> list;
          Set(list.New(),"LocalData" ); // add "LocalData"  directory to the list
          Set(list.New(),"stdafx.h"  ); // add "stdafx.h"   file      to the list
          Set(list.New(),"stdafx.cpp"); // add "stdafx.cpp" file      to the list
          PakCreate(list);              // create Pak from list, 'pak_name' will be automatically set to "Tutorials.pak"
       }

       // create Pak from files in memory
       {
          Memb<File> file; // array of file's which we'll create and write to them

          using namespace PakDefs; // use this namespace to simplify Pak creation
          // from now on in current scope:
          // N is a file node Node<PakNode>

          N n; // lets start with main node
          {
             File &f=file.New();             // add new file to array
             f.writeMem();                   // start writing to memory
             f.putByte(123);                 // write a Byte to that file
             n.New().set("File 1.dat",f);    // add this file to file nodes
          }
          {
             N &d=(n+="Directory");          // add new directory
             {
                File &f=file.New();          // add new file to array
                f.writeMem();                // start writing to memory
                f.putByte(234);              // write a Byte to that file
                d.New().set("File 2.dat",f); // add this file to directory
             }
          }
          PakCreate(n,"Pak from memory.pak"); // create Pak from nodes
       }

       // load custom Pak
       {
          PakAdd("Pak from memory.pak");

          // from now on any data stored in loaded Pak can be accessed through IO methods
          {
             File f1("File 1.dat");           // open the file
             b1=f1.getByte();                 // read Byte from that file

             File f2("Directory/File 2.dat"); // open the file
             b2=f2.getByte();                 // read Byte from that file
          }
       }
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       D.text (0,0,S+b1+"  "+b2); // display bytes
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Pak.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       Pak is a storage file type, it contains multiple files inside.
       Once you load a Pak you can access all the files inside it.

    /******************************************************************************/
    Gfx *gfx;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Pak's");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       // 'sample.pak' used in this tutorial has only one folder 'folder' and one file 'image.gfx' located in 'folder' like this:
       // "folder/image.gfx"

       // load custom Pak
       PakAdd("../data/sample.pak");

       // from now on any data stored in loaded Pak can be accessed through IO methods
       {
          // you can open files stored in that Pak:
          {
             File f;
             f.read   ("folder/image.gfx"); // start reading file
             f.getByte(                  ); // get Byte from that file
          }
          // you can access resources through cache
          {
             gfx=Gfxs("folder/image.gfx");
          }
       }

       // Pak's can be easily made using "Converter.exe" located in "Tools" folder
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       gfx->draw(-0.5,0.5, 1,1);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Pathfind.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    PathFind    pf       ; // path finder
    Memb<VecI2> path     ; // path
    VecI2       start,end; // start and end position of wanted path
    /******************************************************************************/
    void InitPre()
    {
       App.name("Pathfind");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.sync(true);
    }
    Bool Init()
    {
       Gfx map;
       if( map.ImportTry("../data/gfx/map/map.png",-1,GFX_SOFT))
       {
          pf.create(map.x(),map.y());
          REPD(y,pf.y())
          REPD(x,pf.x())
          {
             UInt color=map.color(x,y); // get pixel color of loaded map
             pf.pixelFlag(x,y,(color!=BLACK) ? PFP_WALKABLE : 0); // set non black color for walkable pixels
          }
       }
       return true;
    }
    void Shut()
    {
    }
    /******************************************************************************/
    VecI2 ScreenToPix(Vec2 &screen)
    {
       Int size=Max(pf.x(),pf.y())*4/3;
       return VecI2(Round((screen.x+D.h()*3/4)*size/2),
                    Round((screen.y+D.h()*3/4)*size/2));
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       // set starting position on LMB
       if(Ms.b(0))
       {
          start=ScreenToPix(Ms.pos);
          pf.find(start,path);
       }

       // set ending position on RMB
       if(Ms.b(1))
       {
          end=ScreenToPix(Ms.pos);
          pf.setTarget(end.x,end.y).find(start,path);
       }

       return true;
    }
    /******************************************************************************/
    void DrawPixel(Int x,Int y,UInt color)
    {
       Int size=Max(pf.x(),pf.y())*4/3;
       VI.dot(color, Vec2(x,y)*2/size-D.h()*3/4, 1.0f/size);
    }
    void Draw()
    {
       D.clear(GREY);

       REPD(y,pf.y())
       REPD(x,pf.x())DrawPixel(x,y,FlagTest(pf.pixelFlag(x,y),PFP_WALKABLE) ? WHITE : BLACK); // draw map
       REPA(path    )DrawPixel(path[i].x,path[i].y,YELLOW);                                   // draw path              with yellow color
                     DrawPixel(start  .x,start  .y,GREEN );                                   // draw starting position with green  color
                     DrawPixel(end    .x,end    .y,RED   );                                   // draw ending   position with red    color
       VI.end();

       D.text(0,0.9,"Press LMB and RMB to set Start and End position");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Random.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    void InitPre()
    {
       App.name("Random");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.sync(true); // enable screen synchronization
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;
       Cam    .dist  =2;
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC  ))return false;
       if(Kb.b (KB_SPACE))CamHandle(0.1,10,CAMH_ZOOM|CAMH_ROT);
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       if(Kb.b(KB_SPACE)) // when space on draw random points in 3D
       {
          // here we're rendering 10 000 dots, such big number is more efficient to draw through VertexIndexBuffer (for more information about it check its tutorial in "advanced\graphics")
                    VI.color(ColorAlpha(TURQ,0.1));   // set color
          REP(10000)VI.dot  (Random(Capsule(0.5,2))); // draw dot at random position in capsule
                    VI.end  ();                       // finish buffered drawing
       }else
       {
          D.text(0,0.7,S+Random(4)+"  "+Random(10,15)+"  "+RandomF()+"  "+RandomF(10,15));
          REP(1000)D.dot(BLUE,Random(Circle(0.5           ))); // draw 1000 random points inside circle
          REP(1000)D.dot(RED ,Random(Rect  (0.5,-0.5,1,0.5))); // draw 1000 random points inside rectangle
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Sort.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Flt floats[8];

    struct CustomData
    {
       Byte bytes[100];
       Flt  real;
       Int  integer;
    }data[8];

    Memb<CustomData> memb;
    /******************************************************************************

       Custom comparing functions must be of "Int name(TYPE &a,TYPE &b)" format
       they receive references to 2 custom data elements
       they must return:
       -1 if 'a' should be before 'b'
       +1 if 'a' should be after  'b'
        0 if 'a' is the same as   'b'

    /******************************************************************************/
    Int CompareCustomData(CustomData &a,CustomData &b)
    {
       if(a.real<b.real)return -1;
       if(a.real>b.real)return +1;
                        return  0;
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Sorting");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       REPA(floats)floats[i]     =RandomF(10); // fill 'floats'    with random values (0..10)
       REPA(data  )data  [i].real=RandomF(10); // fill 'data.real' with random values (0..10)
       REP (8     )memb  (i).real=RandomF(10); // fill 'memb.real' with random values (0..10)

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       if(Kb.bp(KB_SPACE)) // sort when space pressed
       {
          Sort(floats,ELMS(floats)                  ); // sort 'floats'
          Sort(data  ,ELMS(data  ),CompareCustomData); // sort custom data by giving pointer to data, number of elements and custom comparing function
          Sort(memb               ,CompareCustomData); // sort custom data by giving memory block                        and custom comparing function
       }

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       D.text (0,0.7,"Press Space to sort");

       Str s="floats:  "; FREPA(floats){s+=floats[i]     ; s+="  ";} D.text(0, 0.2,s); // draw 'floats'    in one string
           s="data:  "  ; FREPA(data  ){s+=data  [i].real; s+="  ";} D.text(0, 0.0,s); // draw 'data.real' in one string
           s="memb:  "  ; FREPA(memb  ){s+=memb  [i].real; s+="  ";} D.text(0,-0.2,s); // draw 'memb.real' in one string
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\States.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       States are used for different 'Application States'
       for example there can be 'intro state', 'menu state', 'game state'

    /******************************************************************************/
    extern State StateMenu,StateIntro,StateGame; // forward declare used states in this tutorial
    /******************************************************************************/
    void InitPre()
    {
       App.name("States");
       PakAdd("../data/engine.pak");
    }
    Bool Init()
    {
       StateIntro.set(); // set StateIntro as the active state, this means that from now on, only StateIntro's update and drawing methods will be called instead of 'Main' and 'Draw'
       return true;
    }
    void Shut()
    {
    }
    Bool Main(){return true;}
    void Draw(){}
    /******************************************************************************/
    // INTRO
    /******************************************************************************/
    Bool   InitIntro(){return true;}
    void   ShutIntro(){}
    Bool UpdateIntro()
    {
       if(StateActive->time()>3 || Kb.bp(KB_ESC)) // if active state (which here is StateIntro) is running for more than 3 seconds or escape pressed
          StateMenu.set(1.0);                     // then switch to 'StateMenu' state with 1.0 second smooth fading
       return true;
    }
    void DrawIntro()
    {
       D.clear(BLACK);
       D.text (0,0,"Intro");
    }
    State StateIntro(UpdateIntro,DrawIntro,InitIntro,ShutIntro);
    /******************************************************************************/
    // MENU
    /******************************************************************************/
    Bool   InitMenu(){return true;}
    void   ShutMenu(){}
    Bool UpdateMenu()
    {
       if(Kb.bp(KB_ESC))return false;         // when escape pressed exit application
       if(Kb.bp(KB_ENTER))StateGame.set(0.5); // when enter  pressed set 'StateGame' with 0.5 second smooth fading
       return true;
    }
    void DrawMenu()
    {
       D.clear(GREY);
       D.text (0, 0  ,"Menu");
       D.text (0,-0.3,"Press Enter to start the game");
       D.text (0,-0.5,"Press Escape to exit");
    }
    State StateMenu(UpdateMenu,DrawMenu,InitMenu,ShutMenu);
    /******************************************************************************/
    // GAME
    /******************************************************************************/
    Bool   InitGame(){return true;}
    void   ShutGame(){}
    Bool UpdateGame()
    {
       if(Kb.bp(KB_ESC))StateMenu.set(1.0); // when escape pressed set 'StateMenu' with 1.0 second smooth fading
       return true;
    }
    void DrawGame()
    {
       D.clear(TURQ);
       D.text (0,0,"Game");
    }
    State StateGame(UpdateGame,DrawGame,InitGame,ShutGame);
    /******************************************************************************

       Typically methods will be called in this order:

       Init()

           InitIntro()
             UpdateIntro()
               DrawIntro()
                   ..
             UpdateIntro()
               DrawIntro()
           ShutIntro()

           InitMenu ()
             UpdateMenu()
               DrawMenu()
                   ..
             UpdateMenu()
               DrawMenu()
           ShutMenu()

           InitGame()
             UpdateGame()
               DrawGame()
                   ..
             UpdateGame()
               DrawGame()
           ShutGame()

           InitMenu()
             UpdateMenu()
               DrawMenu()
                   ..
             UpdateMenu()
               DrawMenu()
           ShutMenu()

       Shut()

    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Threads 2.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Flt time;
    /******************************************************************************/
    void Calculate(Real x)
    {
       // perform lot's of numerical calculations
       REP(1000)
       REP(1000)
       {
          x =Cos(Sin(x*x+Sqrt(x)));
          x+=Pow(10+x,10+x*5);
          x =Cbrt(Tan(x));
       }
    }
    /******************************************************************************/
    void SingleThreadCalculate()
    {
       Calculate(1);
       Calculate(2);
    }
    /******************************************************************************/
    Bool ThreadProcA(Thread &thread)
    {
       Calculate(1); // perform calculations
       return false; // stop the thread after calculations
    }
    Bool ThreadProcB(Thread &thread)
    {
       Calculate(2); // perform calculations
       return false; // stop the thread after calculations
    }
    void MultiThreadCalculate()
    {
       // create the threads
       Thread thread_a(ThreadProcA),
              thread_b(ThreadProcB);

       // wait for the threads to finish processing
       thread_a.wait();
       thread_b.wait();

       // delete threads
       thread_a.del();
       thread_b.del();
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Threads");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       if(Kb.bp(KB_1))
       {
          time=Tm.curTime();       // get current time
          SingleThreadCalculate(); // perform calculations on one thread
          time=Tm.curTime()-time;  // get difference between remembered and current time
       }

       if(Kb.bp(KB_2))
       {
          time=Tm.curTime();      // get current time
          MultiThreadCalculate(); // perform calculations on multiple threads
          time=Tm.curTime()-time; // get difference between remembered and current time
       }
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       D.text(0,0.9,S+"Press 1 for single threaded calculations");
       D.text(0,0.8,S+"Press 2 for multi threaded calculations");

       D.text(0,0,S+"Time spent for calculations : "+time);

       REP(3)
       {
          Flt  a=Tm.time()*2+i*PI2/3;
          Tri2 t;
          t.p[0].set(0,0);
          t.p[1].set(Cos(a      ),Sin(a      ));
          t.p[2].set(Cos(a+PI2/9),Sin(a+PI2/9));
          (t*0.2-Vec2(0,0.5)).draw(GREY);
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Threads.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       Threads are programs (functions) which run simultaneously

    /******************************************************************************/
    // global integers
    Int x,
        y[2];

    // threads
    Thread thread_x,
           thread_y0,
           thread_y1;
    /******************************************************************************

       Thread functions must be of "Bool name(Thread &thread)" format
       they return true when wan't to continue thread processing, and false when wan't to stop them
       as input parameter thread functions receive reference to the Thread which calls them

    /******************************************************************************/
    Bool ThreadProc(Thread &thread_caller)
    {
       x++;         // simple increase x value
       return true; // continue processing
    }

    Bool ThreadProcWithUserData(Thread &thread_caller)
    {
       y[thread_caller.userd]++; // make use of thread_caller 'userd' user data, and increase wanted 'y' (it will be y[0] or y[1])
       return true;              // continue processing
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Threads");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       // create threads
       thread_x .create(ThreadProc            , 0,0,100        ); // thread_x  will use 'ThreadProc'             as it's procedure, and it will be called once in 100 miliseconds
       thread_y0.create(ThreadProcWithUserData, 0,0,100, Ptr(0)); // thread_y0 will use 'ThreadProcWithUserData' as it's procedure,     it will be called once in 100 miliseconds, and it will use '0' as it's user data
       thread_y1.create(ThreadProcWithUserData, 0,0,100, Ptr(1)); // thread_y1 will use 'ThreadProcWithUserData' as it's procedure,     it will be called once in 100 miliseconds, and it will use '1' as it's user data
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
       // delete threads
       thread_x .del();
       thread_y0.del();
       thread_y1.del();
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       // draw values
       D.text(0,0.2,S+"x: "   +x   );
       D.text(0,0.1,S+"y[0]: "+y[0]);
       D.text(0,0.0,S+"y[1]: "+y[1]);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Video Playback.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Theora video;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Video Playback");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       if(!video.create("../data/video/test.ogv"))return Exit("Can't create video"); // create video from Theora File
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       video.update(Tm.curTime()); // update video to current application time

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D    .clear();
       video.draw (); // draw video
       D    .text (0,0.9,S+video.time()); // draw time position of video
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Misc\Zip.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Char text[]={L"This is a simple text which will be compressed using ZLIB compression. 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
    Byte *  compressed, // buffer where   compressed data will be stored
         *decompressed; // buffer where decompressed data will be stored

    I32  src_size=SIZE(text),
         compressed_buf_size,
         compressed_size,
       decompressed_size;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Zip compression");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       // compression
       {
          // for compression we'll need buffer which will hould enough data
          // how much is enough is calculated through 'ZipSize' function and giving source size
          compressed_buf_size=ZipSize(src_size);

          // create raw memory buffer able to store 'compressed_buf_size' bytes
          Alloc(compressed,compressed_buf_size);

          // compress data
          // before compressing we must set destination buffer size('compressed_size') to maximum memory available
          compressed_size=compressed_buf_size;
          ZipCompress(compressed,compressed_size,text,src_size); // now 'compressed' contains compressed data, and 'compressed_size' is the actual size of compressed data
       }

       // decompression
       {
          // for decompression we'll need buffer which will hold decompressed data (we know that decompressed size is the size of the source)
          Alloc(decompressed,src_size);

          // decompress data
          // before decompression we must set destination buffer size('decompressed_size') to maximum memory available
          decompressed_size=src_size;
          ZipDecompress(decompressed,decompressed_size,compressed,compressed_size); // now 'decompressed' contains decompressed data, and 'decompressed_size' is the actual size of decompressed data
       }
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
       // free buffers
       Free(  compressed);
       Free(decompressed);
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       D.text(0,0.2,S+"Source size: "+src_size);
       D.text(0,0.1,S+"Compressed size: "+compressed_size);
       D.text(0,0.0,S+"Buffer size used for compression: "+compressed_buf_size);

       D.text(0,-0.2,"Source text:"      ); D.text(Sin(Tm.time())*2.5,-0.3,               text);
       D.text(0,-0.5,"Decompressed text:"); D.text(Sin(Tm.time())*2.5,-0.6,(Char*)decompressed);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Net\Download.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Gfx      gfx;
    Download download;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Downloading file");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       download.create("http://www.esenthel.com/download/logo.gfx"); // create downloader

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
       download.del(); // delete downloader
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       if(download.state()==DWNL_DONE) // if all data downloaded successfully
       {
          // data can be accessed freely through Download::buf,size methods
          // for example download.buf()[0] is the first Byte of data
          // we'll use the downloaded data to load an image from it

          if(!gfx.is()) // check if we haven't already created it
          {
             File f(download.data(),download.size()); // create a file from memory data
             gfx.load(f);                             // load a gfx from the file
          }
       }
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       if(gfx.is())     // when image is downloaded and created
          gfx.drawFs(); // draw it

       switch(download.state())
       {
          case DWNL_NONE    : D.text(0,   0,  "Nothing");break;
          case DWNL_WAIT    : D.text(0,   0,  "Awaiting for connection..");break;
          case DWNL_DOWNLOAD: D.text(0,   0,S+"Downloading.. "+download.done()+'/'+download.size());break;
          case DWNL_DONE    : D.text(0,-0.9,  "Done");break;
          case DWNL_ERROR   : D.text(0,   0,  "Error encountered");break;
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Net\Ftp.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    void InitPre()
    {
       App.name("FTP");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.sync(true);
    }
    Bool Init()
    {
       Ftp ftp; // create and Ftp object

       // login to the FTP
       if(ftp.login("ftp.host.com","user","password")) // in order to connect to an FTP server you will need to change these parameters to your custom
       {
          // sample upload
          ftp.upload(File("c:/test.file"),"/test.file"); // upload "c:/test.file" to the FTP "/test.file"

          // sample download
          File file; file.writeMem();      // open the file for writing to memory
          ftp.download("/test.file",file); // download "/test.file" from the FTP to 'file'

          // sample list files
          Memb<FtpFile> files;      // container for the files
          ftp.listFiles("/",files); // list all files in the root "/" ftp to the 'files' container

          // logout
          ftp.logout();
       }

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       return true;
    }
    void Draw()
    {
       D.clear(WHITE);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Net\Socket.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       This tutorial presents the most basic socket usage.
       It needs to be launched few times, so multiple windows of it will appear on the desktop.

       Each of the program instances (windows) will create it's own 'player' and a socket (internet connection).

       At the start of the program, it tries to contact other instances (windows) by sending empty data to specific ports.
       When each of the program instances (windows) receive data from other instances, they store their address in a memory container, as a list of "external players"

       In the update each instance sends its own player position to all other instances, so they'll know the most recent player position.
       This way each instance receives data from other instances about their player positions.

    /******************************************************************************/
    #define BASE_PORT 10000
    /******************************************************************************/
    struct Player // player, contains only a position
    {
       Vec2 pos; // position

       void draw(UInt color) // draw
       {
          Circle(0.1,pos).draw(color,true);
       }
       Player() // constructor
       {
          pos.zero();
       }
    };
    struct Peer // peers (external players from other program instances)
    {
       SockAddr addr  ; // their socket address
       Player   player; // their player data
    };
    /******************************************************************************/
    Player     player; // this program instance player
    Socket     sock  ; // this program instance socket
    Memb<Peer> peer  ; // container of external peers
    /******************************************************************************/
    void InitPre()
    {
       App.name("Socket");
       App.flag=APP_NO_FX|APP_WORK_IN_BACKGROUND; // specify work in background flag to work also when not focused
       PakAdd("../data/engine.pak");
       D.mode(400,300).sync(true);
    }
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;
       Text_ds.scale*=2;

       // create this instance socket (internet connection)
       {
          // try to initialize socket on one of the ports starting from BASE_PORT
          // some ports will not be accessible because other program instances may have already reserved them
          FREP(50)if(sock.createPeer(BASE_PORT+i))break; // 50 attempts, stops on first usable port

          sock.block(false); // set non-blocking mode, this will disable waiting when receiving data through socket
       }

       // make contact with other sockets created by other program instances
       {
          SockAddr addr;        // socket address
          addr.ip("127.0.0.1"); // set    address ip to 'localhost', which is your computer
          FREP(50)              // now check 50 ports where possibly other instances of the tutorial have created a socket
          {
             addr.port(BASE_PORT+i);      // set port of the address
             if(addr.port()!=sock.port()) // if it's on a different port than our socket (which means that it's not us)
                sock.send(addr,NULL,0);   // send empty data just to contact the other socket to let it know that we exist
          }
       }

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
       sock.del();
       peer.del();
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       // update this instance player position
       if(App.active() && Ms.b(0)) // when application is active (focused) and left mouse button pushed
       {
          player.pos+=Ms.d; // move player position
       }

       // send this instance player position to all external players
       REPA(peer)
       {
          sock.send(peer[i].addr,&player.pos,SIZE(player.pos));
       }

       // receive positions from other players
       for(SockAddr addr;;)
       {
          Vec2 pos;
          Int  rcv=sock.receive(addr,&pos,SIZE(pos)); // check if the socket receives any data
          if(  rcv<0)break;                           // if no data then break

          // here we've received some data from an external program instance
          {
             // first we'll check for its address, and store it on the "external player" list
             Peer *p=NULL;
             REPA(peer)if(peer[i].addr==addr){p=&peer[i]; break;} // check if it's already stored on the list
             if(!p)                                               // if not found in add it
             {
                p=&peer.New();
                p->addr=addr;
             }

             // now we've got the sender stored on the list, so we can check for any data that the external player is sending to us
             if(rcv==SIZE(pos))p->player.pos=pos; // if number of received data bytes is equal to Vec2 size then it's a new position of the external player
          }
       }

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       // draw players
                         player.draw(ColorI(        sock.port())); // draw this instance player  with color depending on its   socket port number
       REPA(peer)peer[i].player.draw(ColorI(peer[i].addr.port())); // draw external      players with color depending on their socket port number

       // draw instructions
       D.text(0,0.88,"Launch this tutorial multiple times");
       D.text(0,0.74,"Press LMB and move the Mouse");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Sound\Music.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    // music themes, each for storing tracks
    MusicTheme *mt_battle , // this is battle theme used for playing when battles
               *mt_explore, // exploring theme
               *mt_calm   ; // calm theme
    /******************************************************************************/
    void InitPre()
    {
       App.name("Music");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       if(mt_battle=MusicThemeNew()) // create 'mt_battle' theme
       {
          *mt_battle+="../data/music/battle0.ogg"; // add "battle0.ogg" track to 'mt_battle' theme
          *mt_battle+="../data/music/battle1.ogg"; // add "battle1.ogg" track to 'mt_battle' theme
       }
       if(mt_explore=MusicThemeNew()) // create 'mt_explore' theme
       {
          *mt_explore+="../data/music/explore.ogg"; // add "explore.ogg" track to 'mt_explore' theme
       }
       if(mt_calm=MusicThemeNew()) // create 'mt_calm' theme
       {
          *mt_calm+="../data/music/calm.ogg"; // add "calm.ogg" track to 'mt_calm' theme
       }
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       if(Kb.c('1'))Music.play(mt_battle );
       if(Kb.c('2'))Music.play(mt_explore);
       if(Kb.c('3'))Music.play(mt_calm   );
       if(Kb.c('4'))Music.play(NULL      );
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       if(Music.theme) // if any theme playing
       {
          D.text(0,0.2,S+"song: "+Music.name());
          D.text(0,0.0,S+"time " +Music.time()+" / "+Music.length()+" length");
       }else
       {
          D.text(0,0,"No theme playing");
       }
       D.text(0,-0.2,"Press 1-battle, 2-explore, 3-calm, 4-none");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Sound\Sound 3D.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Sound sound;      // sound
    Vec   pos(0,0,3); // sound position
    /******************************************************************************/
    void InitPre()
    {
       App.name("Sound 3D");
       App.flag=APP_NO_FX|APP_MS_EXCLUSIVE;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       sound.play("../data/sound/water.ogg",pos,1,true); // play looped 3D sound, volume=1, position='pos'
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|CAMH_ROT);

       // update all 3D sound positions
       {
          sound.pos(pos); // since 'pos' is the same in each frame, the sound position doesn't need to be updated, but let's do it anyway
       }

       // update listener parameters
       {
          Listener.pos   (Cam.matrix.pos           )  // set listener position    (from camera)
                  .orn   (Cam.matrix.z,Cam.matrix.y)  // set listener orientation (from camera)
                  .update(                         ); // updates all 3D parameters, only after this call all changes take effect
       }
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       Ball(1,pos).draw(BLACK); // draw ball at sound position
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Sound\Sound.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Sound sound; // water sound
    /******************************************************************************/
    void InitPre()
    {
       App.name("Sound");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC  ))return false;
       if(Kb.bp(KB_SPACE))SoundPlay("../data/sound/metal.ogg"); // play sound on space

       if(Kb.bp(KB_ENTER)) // toggle water on enter
       {
          if(sound.playing()) // if already playing
          {
             sound.del(); // delete sound
          }else
          {
             sound.play("../data/sound/water.ogg",true); // play with loop option enabled
          }
       }

       // change volumes on mouse wheel
       {
          if(Ms.wheel>0)sound.volume(sound.volume()+0.1);else
          if(Ms.wheel<0)sound.volume(sound.volume()-0.1);
       }

       // change speed on LMB/RMB
       {
          if(Ms.b(0))sound.speed(sound.speed()-Tm.d()*0.4);
          if(Ms.b(1))sound.speed(sound.speed()+Tm.d()*0.4);
       }
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       D.text (0, 0.2,  "Press space to play 'metal'");
       D.text (0, 0.0,S+"Press enter to stop/play looped 'water' (playing: "     +sound.playing()+')');
       D.text (0,-0.2,S+"Use mouse wheel to change water sound volume (current: "+sound.volume ()+')');
       D.text (0,-0.4,S+  "Press LMB/RMB to change water sound speed (current: " +sound.speed  ()+')');
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\1 - Geometry, Graphics, Gui, Misc, Net, Sound\Sound\Volume Groups.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    MusicTheme *mt_battle  , // music themes
               *mt_explore ;
    Sound       sound      ; // sound
    Slider      vol_fx     , // volume bars
                vol_music  ,
                vol_ambient;
    Text       tvol_fx     , // volume text
               tvol_music  ,
               tvol_ambient;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Volume groups");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Gui.tds_text.scale*=1.5f; // make all Text objects bigger

       if(mt_battle=MusicThemeNew()) // create mt_battle theme
       {
          *mt_battle+="../data/music/battle0.ogg"; // add "battle0.ogg" track to 'mt_battle' theme
          *mt_battle+="../data/music/battle1.ogg"; // add "battle0.ogg" track to 'mt_battle' theme
       }
       if(mt_explore=MusicThemeNew()) // create mt_explore theme
       {
          *mt_explore+="../data/music/explore.ogg"; // add "explore.ogg" track to 'mt_explore' theme
       }

       Music  .play(mt_battle ); // play theme as music
       Ambient.play(mt_explore); // play theme as ambient
       sound  .play("../data/sound/water.ogg",true); // play looped sound

       Gui+=vol_fx     .create(Rect(-0.1,0.30,0.3,0.40),SoundVolume.fx     ()); Gui+=tvol_fx     .create(Vec2(-0.3,0.35),"Fx"     );
       Gui+=vol_music  .create(Rect(-0.1,0.15,0.3,0.25),SoundVolume.music  ()); Gui+=tvol_music  .create(Vec2(-0.3,0.20),"Music"  );
       Gui+=vol_ambient.create(Rect(-0.1,0.00,0.3,0.10),SoundVolume.ambient()); Gui+=tvol_ambient.create(Vec2(-0.3,0.05),"Ambient");
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();

       // set new volumes
       SoundVolume.fx     (vol_fx     ());
       SoundVolume.music  (vol_music  ());
       SoundVolume.ambient(vol_ambient());
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D  .clear(WHITE);
       Gui.draw ();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Animation\01 - Animation.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    CSkeleton cskel;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Animation");
       App.flag=APP_MS_EXCLUSIVE;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       Cam.dist=2;
       Cam.yaw =PI;

       cskel.create("../data/obj/chr/skeleton/0.skel",1.7); // create controlled skeleton from skel file, with 1.7 meter height
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ROT|CAMH_ZOOM);

       // set animations
       {
          cskel.clear();     // clear controlled skeleton animation
          if(Kb.b(KB_SPACE)) // when space pressed
          {
             cskel.animate(L"../data/anim/walk.anim",Tm.time()); // animate with "walk" animation and current time position
          }
          cskel.updateMatrix(MatrixIdentity); // update controlled skeleton animation matrixes
          cskel.updateVelocities(          ); // update controlled skeleton bone velocities (this is needed for Motion Blur effect)
       }

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);

       // render
       {
          LightDir(Vec(0,0,-1)).set(); // set light

          Meshs("../data/obj/chr/skeleton/0.mesh")->draw(cskel); // get mesh from cache and render it with controlled skeleton matrixes

          if(Kb.ctrl) // when control pressed
          {
             SetMatrix();     // restore default matrix
             cskel.draw(RED); // draw controlled skeleton
          }
       }

       D.text(0,0.8,"Hold space to animate");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Animation\02 - Skeleton Points.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       Skeleton points are special points attached to skeletons

       They can be used to render items in correct places

       Skeleton points can be accessed after animating skeleton through CSkeleton::getPoint method,
       which returns reference to OrientP structure which is an orientation and position

    /******************************************************************************/
    CSkeleton cskel;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Skeleton Points");
       App.flag=APP_MS_EXCLUSIVE;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=2;
       Cam.yaw =PI;

       cskel.create("../data/obj/chr/skeleton/0.skel",1.7);
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ROT|CAMH_ZOOM);

       // set animations
       cskel.clear().animate(L"../data/anim/walk.anim",Tm.time()).updateMatrix(MatrixIdentity).updateVelocities();

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       LightDir(Vec(0,0,-1)).set();

       // draw mesh
       Meshs("../data/obj/chr/skeleton/0.mesh")->draw(cskel);

       // draw skeleton point
       SetMatrix();
       cskel.getPoint("HandR").draw(RED);
       cskel.getPoint("HandL").draw(RED);
       cskel.getPoint("Head" ).draw(RED);

       // draw item in right hand
       {
          OrientP &hand_r=cskel.getPoint("HandR");
          Matrix   m;
          m.setPosDir(hand_r.pos,hand_r.perp,hand_r.dir)               // set position and directions according to skeleton point
           .scaleOrn(0.7);                                             // scale down the matrix orientation a little, making the item smaller
          Meshs("../data/obj/item/weapon/blunt/club/0.mesh")->draw(m); // render item with matrix
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Animation\03 - Blending.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    CSkeleton cskel;
    Flt       blend; // blending value (0..1)
    Bool      walk ; // if want to walk
    /******************************************************************************/
    void InitPre()
    {
       App.name("Animation Blending");
       App.flag=APP_MS_EXCLUSIVE;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.color =BLACK;
       Text_ds.shadow=0;

       Cam.dist=2;
       Cam.yaw =PI;

       cskel.create("../data/obj/chr/skeleton/0.skel",1.7); // create controlled skeleton from skel file, with 1.7 meter height
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ROT|CAMH_ZOOM);
       if(Kb.bp(KB_SPACE))walk^=1; // change 'walk' when space pressed

       // adjust blend value
       if(walk)
       {
          blend+=Tm.d()*2;
          if(blend>1)blend=1;
       }else
       {
          blend-=Tm.d()*2;
          if(blend<0)blend=0;
       }

       // set animations
       {
          cskel.clear  (); // clear controlled skeleton animation
          cskel.animate(L"../data/anim/walk.anim",Tm.time(),   blend); // animate with "walk" animation, current time position and '  blend' blending weight
          cskel.animate(L"../data/anim/run.anim" ,Tm.time(), 1-blend); // animate with "walk" animation, current time position and '1-blend' blending weight
          cskel.updateMatrix(MatrixIdentity).updateVelocities();      // update controlled skeleton animation and velocities
       }

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       LightDir(Vec(0,0,-1)).set();

       // render
       {
          Meshs("../data/obj/chr/skeleton/0.mesh")->draw(cskel); // get mesh from cache and render it with controlled skeleton

          if(Kb.ctrl) // when control pressed
          {
             SetMatrix();     // restore default matrix
             cskel.draw(RED); // draw controlled skeleton
          }
       }

       D.text(0,0.8,S+"Press space to toggle blending (Walk: "+walk+", Blend: "+blend+')');
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Animation\04 - Manual Editing.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    CSkeleton cskel;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Animation Manual Editing");
       App.flag=APP_MS_EXCLUSIVE;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=2;
       Cam.yaw =PI;

       cskel.create("../data/obj/chr/skeleton/0.skel",1.7);
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ROT|CAMH_ZOOM);

       // set animations
       {
          cskel.clear().animate(L"../data/anim/walk.anim",Tm.time()); // set default walking animation

          Orient &head=cskel.getBone("head").orn;         // get head bone orientation
          head*=Matrix3().setRotateZ(Sin(Tm.time()*1.5)); // rotate head orientation according to time

          cskel.updateMatrix(MatrixIdentity) // update all matrixes
               .updateVelocities();          // update all bone velocities
       }

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(WHITE);
       LightDir(Vec(0,0,-1)).set();

       // draw
       Meshs("../data/obj/chr/skeleton/0.mesh")->draw(cskel);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\01 - Physics.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       This tutorial is using PhysX, to run it, you must:
          -have PhysX SystemSoftware installed from http://developer.nvidia.com/object/physx_downloads.html
          -have "NxCooking.dll" in your application folder

    /******************************************************************************/
    Actor ground,
          box   ,
          ball  ;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Physics");
       App.flag=APP_MS_EXCLUSIVE|APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.sync(true);
    }
    Bool Init()
    {
       Cam.dist=4;

       // create physics
       Physics.create();

       // create actors
       ground.create(Box (15,1,15,Vec(0  ,-2, 0)), 0); // create ground actor from Box and density=0 (which means it's a static actor - will not move)
       box   .create(Box (0.3    ,Vec(0.1, 1, 0)));
       ball  .create(Ball(0.3    ,Vec(  0, 0, 0)));

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|CAMH_ROT);

       // physics update
       {
          Physics.sim(); // start frame simulation

          // physics simulation takes some time, so you can do some calculations here
          // important : you may not modify actors between Physics.sim() and Physics.get()

          Physics.get(); // get results of frame simulation
       }

       Flt s=3;

       // add forces to ball
       if(Kb.b(KB_UP   ))ball.addForce(Vec(0,0, 1)*s);
       if(Kb.b(KB_DOWN ))ball.addForce(Vec(0,0,-1)*s);
       if(Kb.b(KB_LEFT ))ball.addForce(Vec(-1,0,0)*s);
       if(Kb.b(KB_RIGHT))ball.addForce(Vec( 1,0,0)*s);

       // add forces to ball according to camera
       if(Kb.b(KB_W))ball.addForce( !PointOnPlane(Cam.matrix.z,Vec(0,1,0))*s);
       if(Kb.b(KB_S))ball.addForce(-!PointOnPlane(Cam.matrix.z,Vec(0,1,0))*s);
       if(Kb.b(KB_A))ball.addForce(-!PointOnPlane(Cam.matrix.x,Vec(0,1,0))*s);
       if(Kb.b(KB_D))ball.addForce( !PointOnPlane(Cam.matrix.x,Vec(0,1,0))*s);

       // add velocity to ball
       if(Kb.bp(KB_SPACE))ball.addVel(Vec(0,3,0));
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D      .clear();
       Physics.draw (); // draw physical actors
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\02 - Multi shaped actor.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Actor ground,
          ball  ,
          actor ;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Multi shaped actors");
       App.flag=APP_MS_EXCLUSIVE|APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.sync(true);
    }
    Bool Init()
    {
       Cam.dist=4;

       Physics.create();
       ground .create(Box (15,1,15,Vec(0,-2,0)), 0);
       ball   .create(Ball(0.3,Vec(0,1.3,0)));

       ActorCD acd;                        // multi-shaped actor creation description
       acd.add(Box (0.2                )); // add box  to 'acd'
       acd.add(Ball(0.2,Vec(-0.3,0.2,0))); // add ball to 'acd'
       acd.add(Ball(0.2,Vec( 0.3,0.2,0))); // add ball to 'acd'
       actor.create(acd,Vec(0,0.3,0));     // create actor from 'acd'

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|CAMH_ROT);

       Physics.sim().get();

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D      .clear();
       Physics.draw ();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\03 - Joints.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Actor ground,
          ball  ,
          box   ;
    Joint joint     ; // joint, used to connect two actors together, or attach one to a fixed point in the world
    Vec   joint_pos , // joint position (used only for drawing)
          joint_axis; // joint axis     (used only for drawing)
    /******************************************************************************/
    void InitPre()
    {
       App.name("Joints");
       App.flag=APP_MS_EXCLUSIVE|APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.sync(true);
    }
    Bool Init()
    {
       Cam.dist =4;
       Cam.pitch=-0.2;

       Physics.create();
       ground .create(Box_U(15,1,15,Vec(0,0,0)), 0);
       ball   .create(Ball (0.3,Vec(-1,0.3,0))).vel(Vec(5,0,0)); // create a ball on ground and set its initial velocity to right

       Box_D b(0.1,2,2,Vec(2,0,0));
       box.create(b).ignore(ground); // create a box from 'b' and ignore collisions with 'ground' actor

       joint_pos=b.cornerLDF(); // set joint position to box left-down-front corner
       joint_axis.set(0,1,0);   // set joint axis     to up
       joint.createHinge(box,NULL, joint_pos, joint_axis); // create a hinge joint in order to attach 'box' actor at 'joint_pos' world position and 'joint_axis' axis

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       Physics.sim().get();

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D      .clear();
       Physics.draw ();

       joint_pos.draw(RED);                              // draw joint position
       D.line(GREEN, joint_pos, joint_pos+joint_axis*3); // draw a line from joint position and it's axis
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\04 - Joints 2.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Actor ground,
          box   ;
    Joint joint ;
    Vec   joint_pos,
          joint_dir;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Joints");
       App.flag=APP_MS_EXCLUSIVE|APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.sync(true);
    }
    Bool Init()
    {
       Cam.dist=4;

       Physics.create();
       ground .create(Box(15,1,15,Vec(0,-2,0)), 0);

       Box_D b(2,2,0.2);
       box.create(b); // create a box from 'b'

       joint_pos=b.cornerLDF(); // set joint position  to box left-down-front corner
       joint_dir.set(1,0,0);    // set joint direction to right
       joint.createSliding(box, NULL, joint_pos, joint_dir, 0, 1.5); // create a sliding joint in order to attach 'box' actor at 'joint_pos' world position, 'joint_dir' direction and 0 .. 1.5 moving limits

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       Physics.sim().get();

       if(Kb.b(KB_LEFT ))box.addVel(Vec(-Tm.d(),0,0)); // add left    velocity
       if(Kb.b(KB_RIGHT))box.addVel(Vec( Tm.d(),0,0)); // add right   velocity
       if(Kb.b(KB_UP   ))box.addVel(Vec(0,0, Tm.d())); // add forward velocity which will not affect the actor
       if(Kb.b(KB_DOWN ))box.addVel(Vec(0,0,-Tm.d())); // add bacward velocity which will not affect the actor

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D      .clear();
       Physics.draw ();

       joint_pos.draw(RED);                             // draw joint position
       D.line(GREEN, joint_pos, joint_pos+joint_dir*3); // draw a line from joint position and it's direction

       D.text(0,0.9,S+"Press Left / Right to change velocity");
       D.text(0,0.8,S+"Press Up / Down to change velocity, the object won't move because of the joint");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\05 - Controllers.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Actor      ground   ,
               actor[10];
    Controller ctrl     ; // controller - it's meant to be used as a 'character actor'
    /******************************************************************************/
    void InitPre()
    {
       App.name("Character Controllers");
       App.flag=APP_MS_EXCLUSIVE|APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.sync(true);
    }
    Bool Init()
    {
       Cam    .dist=4;
       Physics.create();
       ground .create(Box(15,1,15,Vec(0,-2,0)), 0);

       // create random actors
       REPA(actor)switch(Random(3))
       {
          case 0: actor[i].create(Box    (RandomF(0.1,0.5),                 Random(Box(10,1,10)))); break;
          case 1: actor[i].create(Ball   (RandomF(0.1,0.5),                 Random(Box(10,1,10)))); break;
          case 2: actor[i].create(Capsule(RandomF(0.1,0.2),RandomF(0.5,1.0),Random(Box(10,1,10)))); break;
       }

       // create controller
       ctrl.create(Capsule(0.4,1.7));
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // move camera on right mouse button

       Physics.sim().get();

       // update controller (move on WSAD keys, crouch on Shift key, jump on Space key)
       Flt s=3;
       Vec vel(0,0,0);
       if(Kb.b(KB_W))vel+=!PointOnPlane(Cam.matrix.z,Vec(0,1,0))*s;
       if(Kb.b(KB_S))vel-=!PointOnPlane(Cam.matrix.z,Vec(0,1,0))*s;
       if(Kb.b(KB_A))vel-=!PointOnPlane(Cam.matrix.x,Vec(0,1,0))*s;
       if(Kb.b(KB_D))vel+=!PointOnPlane(Cam.matrix.x,Vec(0,1,0))*s;
       ctrl.update(vel, Kb.shift, Kb.bp(KB_SPACE) ? 3.5 : 0);

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D      .clear();
       Physics.draw ();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\06 - Testing.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Actor ground,ball;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Testing");
       App.flag=APP_MS_EXCLUSIVE|APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.sync(true);
    }
    Bool Init()
    {
       Cam.dist=4;
       Physics.create();

       ground.create(Box (15,1,15,Vec(0,-2,0)), 0);
       ball  .create(Ball(1,Vec(0,3,0)));

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // move camera on right mouse button

       Physics.sim().get();

       if(Kb.bp(KB_SPACE))ball.addVel(Vec(0,5,0)); // add velocity to the ball when space pressed

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D      .clear();
       Physics.draw ();

       // test if custom ray hits some actor
       {
          Vec     start( 4,0,0), // starting position of ray
                  end  (-4,0,0); // ending   position of ray
          PhysHit phys_hit     ; // phys-hit object for receiving hit parameters if any

          if(Physics.ray(start,end-start,&phys_hit)) // if ray hit something
          {
             D.line(RED  , start, phys_hit.plane.p);                                 // draw a red   line from staring position to hit position
             D.line(GREEN, phys_hit.plane.p, phys_hit.plane.p+phys_hit.plane.n*0.3); // draw a green line presenting the hit normal vector
             D.dot (RED  , phys_hit.plane.p);                                        // draw the contact point
          }else
          {
             D.line(BLUE, start, end); // draw a blue line from starting position to end position
          }
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\07 - Detecting objects under cursor.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    enum ACTOR_GROUPS // actor groups (for example in the game you can specify following groups: door, item, character, ..)
    {
       GROUP_BACKGROUND, // background
       GROUP_OBJ       , // objects
    };
    /******************************************************************************/
    Actor ground,
          obj[10];
    /******************************************************************************/
    void InitPre()
    {
       App.name("Detecting objects under cursor");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.sync(true);
    }
    Bool Init()
    {
       Cam.setSpherical(Vec(0,0,-2), 0,-0.7,0, 6).set(); // set camera position and activate it

       Physics.create();

       ground.create(Box(15,1,15,Vec(0,-2,0)), 0).group(GROUP_BACKGROUND); // create ground and set its group to background

       // create random actors
       REPA(obj)
       {
          switch(Random(3))
          {
             case 0: obj[i].create(Box    (RandomF(0.1,0.5),                 Random(Box(10,1,10)))); break;
             case 1: obj[i].create(Ball   (RandomF(0.1,0.5),                 Random(Box(10,1,10)))); break;
             case 2: obj[i].create(Capsule(RandomF(0.1,0.2),RandomF(0.5,1.0),Random(Box(10,1,10)))); break;
          }

          obj[i].group(GROUP_OBJ).userd(i); // set actor's group to 'object' group and set its user data, in this tutorial it'll be index of the object in the array
       }

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Physics.sim().get();

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D      .clear();
       Physics.draw ();

       // we'll now test if mouse points on some actor
       // to do that we'll perform a standard ray testing
       // with initial ray 'start' point located near the camera, and 'end' point located as far as viewport range reaches
       {
          // to obtain 'start' and 'end' point we'll use a special function called 'ScreenToPosDir' which transforms a screen position (Vec2) to world space position and direction
          Vec screen_pos,
              screen_dir;
          ScreenToPosDir(Ms.pos, screen_pos, screen_dir); // obtain 'screen_pos' and 'screen_dir' from Mouse cursor position

          // now having world space position and direction we can calculate ray 'start' and 'end' positions
          Vec start=screen_pos,
              end  =screen_pos + screen_dir*Viewport.range;

          // having ray positions we can perform a ray test
          PhysHit phys_hit;
          if(Physics.ray(start,end-start,&phys_hit)) // if ray hit something
          {
             D.text(0,0.9,  "Ray has hit an actor!");
             D.text(0,0.8,S+"Actor's group: "            +phys_hit.group);
             D.text(0,0.7,S+"Actor's user data (index): "+phys_hit.userd);
          }else
          {
             D.text(0,0.9,"Ray hasn't hit anything");
          }
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\08 - Grabbing.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Actor ground, // ground
          obj   ; // object
    Grab  grab  ; // grabber
    /******************************************************************************/
    void InitPre()
    {
       App.name("Grabbing objects");
       App.flag=APP_NO_FX;
       PakAdd("../data/engine.pak");
       D.sync(true);
    }
    Bool Init()
    {
       Cam.setSpherical(Vec(0,0,-2), 0,-0.7,0, 6).set(); // set camera position and activate it

       Physics.create();

       ground.create(Box(15,1,15,Vec(0,-2,0)), 0); // create ground
       obj   .create(Box(0.3                )   ); // create object

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Physics.sim().get();

       if(Kb.ctrl) // if want to grab
       {
          if(!grab.is()) // if not yet grabbing
          {
             grab.create(obj,Vec(0,0.3,0),10); // start grabbing 'obj' actor at (0,0.3,0) local position with a power of 10
          }
          if(grab.is()) // if grabbing something
          {
             // drag the object to left/right/forward/backwards
             Vec dir(0);
             if(Kb.b(KB_LEFT ))dir.x--;
             if(Kb.b(KB_RIGHT))dir.x++;
             if(Kb.b(KB_DOWN ))dir.y--;
             if(Kb.b(KB_UP   ))dir.y++;
             grab.pos(grab.pos()+dir*Tm.d()*2);
          }
       }else
       {
          if(grab.is())grab.del();
       }

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D      .clear();
       Physics.draw ();

       if(!grab.is())D.text(0,0.9,"Hold Control to grab the object");
       else          D.text(0,0.9,"Use the arrow keys to drag around the object");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\09 - Physical meshes.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Controller  ctrl ; // character controller
    MeshGroup   mshg ; //          mesh group (used for rendering)
    PhysGroup   phsg ; // physical mesh group (used for collisions)
    Memb<Actor> actor; // container of actors that will be created out of 'phsg'
    /******************************************************************************/
    void InitPre()
    {
       App.name("Physical meshes");
       App.flag=APP_MS_EXCLUSIVE;
       IOPath("../data");
       PakAdd("engine.pak");
       D.full(true).sync(true);
    }
    Bool Init()
    {
       Cam.dist=6;
       Physics.create();

       ctrl.create(Capsule(0.4,1.7,Vec(0,1,0))); // create character controller

       mshg.load  ("obj/terrain/0.mshg"); // load terrain MeshGroup
       phsg.create(mshg);                 // create physical body group (PhysGroup) from 'mshg'
       FREPA(phsg)                        // for all physical bodies (Phys) inside 'phsg'
       {
          Actor &a=actor.New();   // create new  Actor in container
          a.create(phsg.phys(i)); // create that Actor from i-th Phys in 'phsg'
       }
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // move camera on right mouse button

       Physics.sim().get();

       // update controller (move on WSAD keys, crouch on Shift key, jump on Space key)
       Flt s=3;
       Vec vel(0,0,0);
       if(Kb.b(KB_W))vel+=!PointOnPlane(Cam.matrix.z,Vec(0,1,0))*s;
       if(Kb.b(KB_S))vel-=!PointOnPlane(Cam.matrix.z,Vec(0,1,0))*s;
       if(Kb.b(KB_A))vel-=!PointOnPlane(Cam.matrix.x,Vec(0,1,0))*s;
       if(Kb.b(KB_D))vel+=!PointOnPlane(Cam.matrix.x,Vec(0,1,0))*s;
       ctrl.update(vel, Kb.shift, Kb.bp(KB_SPACE) ? 3.5 : 0);

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear();
       LightDir(Cam.matrix.z).set();

       mshg   .draw(MatrixIdentity); // draw mesh
       Physics.draw(              ); // draw physics
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\10 - Ragdoll.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Actor     ground , // ground actor
              box[3] ; // stairs
    CSkeleton cskel  ; // controlled skeleton
    Ragdoll   ragdoll; // ragdoll
    /******************************************************************************/
    void SetPose()
    {
       cskel.clear().updateMatrix(Matrix().setRotateX(0.45).move(Vec(0,3,0))).updateVelocities(); // set skeleton animation to default pose and custom matrix

       ragdoll.fromSkel(cskel); // setup ragdoll from skeleton animation
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Ragdoll");
       App.flag=APP_MS_EXCLUSIVE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true);
       Cam.dist =5;
       Cam.pitch=-0.3;
       Cam.yaw  =PI;
    }
    Bool Init()
    {
       Physics.create();

       ground.create(Box_U(15,1,15,Vec(0,-1,0)),0);
       REPA(box)box[i].create(Box(1,Vec(0,i*0.5-0.5,i*-0.5-0.3)),0);

       cskel  .create("obj/chr/skeleton/0.skel",1.8); // create skeleton
       ragdoll.create(cskel);                         // create ragdoll from skeleton

       SetPose();

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // move camera on right mouse button

       Physics.sim().get();

       ragdoll.toSkel(cskel); // set skeleton from ragdoll

       if(Kb.bp(KB_SPACE))SetPose();

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear();
       LightDir(Cam.matrix.z).set();

       Meshs("obj/chr/skeleton/0.mesh")->draw(cskel);

       Physics.draw();

       D.text(0,0.9,"Press Space to reset simulation");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\11 - Vehicle.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Flt   angle   ; // car wheel angle
    Actor car     , // car    actor
          ground  ; // ground actor
    Wheel wheel[4]; // wheels
    /******************************************************************************/
    void InitPre()
    {
       App.name("Vehicle");
       App.flag=APP_FULL_TOGGLE|APP_NO_FX;
       PakAdd("../data/engine.pak");

       D.mode(800,600).sync(true);
       ViewportFull.range=200;
    }
    Bool Init()
    {
       Cam.dist=10;
       Physics.create();
       ground .create(Box_U(100,1,100),0);
       ground .pos   (ground.pos()-Vec(0,3,0));

       // create car
       car.create    (Box(2,1,4));                    // create actor
       car.massCenter(car.massCenter()-Vec(0,1.0,0)); // lower mass center

       // create car wheels
       Wheel::Param wp; // wheel parameters
       wheel[0].create(car,Vec( 1,-0.5, 1.5),wp);
       wheel[1].create(car,Vec(-1,-0.5, 1.5),wp);
       wheel[2].create(car,Vec( 1,-0.5,-1.5),wp);
       wheel[3].create(car,Vec(-1,-0.5,-1.5),wp);

       return true;
    }
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1f,200,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       Physics.sim().get();

       if(Kb.bp(KB_ENTER))car.pos(Vec(0,3,0)); // reset car position on ENTER key

       // adjust car controls
       {
          angle=LerpTime(angle,(Kb.b(KB_D)-Kb.b(KB_A))*PI_4,0.01); // adjust wheel angle

          Flt accel=(Kb.b(KB_W)-Kb.b(KB_S))*1600, // acceleration
              brake= Kb.b(KB_SPACE)        *3200; // brakes

          wheel[0].angle(angle);              // set angle
          wheel[1].angle(angle);              // set angle
          wheel[2].accel(accel).brake(brake); // set acceleration and brakes
          wheel[3].accel(accel).brake(brake); // set acceleration and brakes
       }

       // update wheels
       REPAO(wheel).update();

       return true;
    }
    void Draw()
    {
       D      .clear();
       Physics.draw ();

       (car.massCenter()*car.matrix()).draw(RED); // draw mass center
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Physics\12 - Cloth.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Actor ground,
          box   ,
          ball  ;
    Cloth cloth ; // Physical Cloth
    /******************************************************************************/
    void InitPre()
    {
       App.name("Physical Clothes");
       App.flag=APP_MS_EXCLUSIVE;
       PakAdd("../data/engine.pak");
       D.mode(1024,768).sync(true);
    }
    Bool Init()
    {
       Cam.dist =4;
       Cam.pitch=-PI_4;

       Physics.create();

       ground.create(Box (15,1,15,Vec( 0,-2,0)), 0);
       box   .create(Box (0.3    ,Vec(-1, 0,0)));
       ball  .create(Ball(0.3    ,Vec( 1, 0,0)));

       // create cloth
       Cloth::Param param; // parameters for cloth creation
       Mshb         mshb ; // clothes are created from meshes, so create a mesh for it
       mshb .createPlane(32,32,VTX_TX0)                                            // create mesh as 32x32 vertex plane with texture coordinates set
            .transform(Matrix().setRotateX(PI_2).move(Vec(-0.5,1,-0.5)).scale(3)); // transform mesh by matrix
       cloth.create(mshb,Materials("../data/mtrl/ground/0.mtrl"),param);           // create cloth from mesh

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));
       Physics.sim().get();
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       LightDir(Cam.matrix.z).set();
       D      .clear();
       Physics.draw ();
       cloth  .draw (); // draw cloth
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\01 - Rendering.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh mesh;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Rendering");
       App.flag=APP_MS_EXCLUSIVE;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=2;

       mesh.create(1).base(0).create(Ball(1),VTX_TX0|VTX_NRM|VTX_TNG);                // create Mesh with 1 Mshb, and create this Mshb from Ball with automatic texture coordinates, normals and tangents
       mesh.setMaterial(Materials("../data/mtrl/brick/0.mtrl")).setRender().setBox(); // set mesh material, rendering version and bounding box

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(1.5,10,CAMH_ZOOM|CAMH_ROT);
       return true;
    }
    /******************************************************************************/
    void Render() // Rendering Method
    {
       switch(Renderer()) // Rendering Method will be called multiple times with different Rendering Modes
       {
          // first there is "solid rendering" mode where you need to render all solid meshes
          case RM_SOLID:
             mesh.draw(MatrixIdentity);
          break;

          // then there is "light rendering" mode where you need to render all the lights
          case RM_LIGHT:
             LightDir(Vec(0,0,1)).add();
          break;
       }
    }
    void Draw()
    {
       // instead of typical "D.clear(WHITE);" we'll now use advanced rendering :
       Renderer(Render); // render with 'Render' method

       D.text(0,0.9,S+"Fps: "+Tm.fps()); // show number of fps
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\02 - Sky.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh mesh; // sample mesh
    Gfx  gfx ; // sky box texture
    /******************************************************************************/
    void InitPre()
    {
       App.name("Rendering Sky");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.mode(800,600);
       ViewportFull.range=20; // set initial viewport range to 20 meters to see sky fog when zoomed out
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=6;

       // create mesh
       mesh.create(1).base(0).create(Ball(1),VTX_TX0|VTX_NRM|VTX_TNG);
       mesh.setMaterial(Materials("../data/mtrl/brick/0.mtrl")).setRender().setBox();

       // import skybox
       gfx.Import("../data/gfx/sky/skybox.jpg",GFX_A8R8G8B8,GFX_CUBE);

       // set default sky
       Sky.set();

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(2.5,18,CAMH_ZOOM|CAMH_ROT);

       if(Kb.bp(KB_1))Sky.clear(                                       ); // disable sky
       if(Kb.bp(KB_2))Sky.set  (Vec(0.35,0.45,0.64),Vec(0.30,0.38,0.54)); // set sky from colors
       if(Kb.bp(KB_3))Sky.set  (gfx                                    ); // set sky from skybox

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             REPD(x,3)
             REPD(z,3)mesh.draw(Matrix(1,Vec(x-1,0,z-1)*3));
          break;

          case RM_LIGHT:
             LightDir(!Vec(1,-1,1)).add();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,"Press 1,2,3 for different skies");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\03 - Fog.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Material *brick,
             *glass;
    Mesh      mbox ,
              mball;
    Vec       pos[64];

    Window   window;
    Slider   fog_frac,
             fog_exp ;
    Text    tfog_frac,
            tfog_exp ;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Fog");
       App.flag=APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.full(true).bloom(0.8,0.6,0.3,true);
       ViewportFull.range=25;

       // hide mouse
       Ms.hide();
    }
    /******************************************************************************/
    Bool Init()
    {
       brick=Materials("../data/mtrl/brick/0.mtrl");
       glass=Materials("../data/mtrl/glass/0.mtrl");

       mbox .create(1).base(0).create( Box( 10),VTX_TX0|VTX_NRM|VTX_TNG).reverse(); // create mesh box, reverse it because it's meant to be viewed from inside
       mball.create(1).base(0).create(Ball(0.5),VTX_TX0|VTX_NRM|VTX_TNG)          ; // create mesh ball

       // set mesh materials, rendering versions and bounding boxes
       mbox .setMaterial(brick).setRender().setBox();
       mball.setMaterial(glass).setRender().setBox();

       // set random positions inside box
       REPA(pos)pos[i]=Random(mbox.box);

       // set camera
       Cam.at   = mbox.box.cornerLDF()/2;
       Cam.dist = 10;
       Cam.pitch=-PI_4;
       Cam.yaw  = PI_4;

       // set Sky and initial fog parameters
       Sky.set    (Vec(0.3),Vec(0.3))
          .fogFrac(0);

       // add gui fog controls
       Gui   +=window   .create(Rect_C(0,-0.75,0.9,0.34),"Fog Parameters").hide();
       window+=tfog_frac.create(Vec2(0.2,-0.08),"Fraction"); window+=fog_frac.create(Rect_C(0.2+window.crect.w()/2,-0.08,0.25,0.05),Sky.fogFrac()).desc("Fraction of the Viewport Range where the Fog starts");
       window+=tfog_exp .create(Vec2(0.2,-0.16),"Exponent"); window+=fog_exp .create(Rect_C(0.2+window.crect.w()/2,-0.16,0.25,0.05),Sky.fogExp ()).desc("Fog Density");

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       CamHandle(0.01,100,Ms.hidden() ? CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT) : 0); // when mouse hidden operate the camera

       if(Kb.bp(KB_TAB))
       {
          Ms    .toggle               (); // toggle mouse  visibility when tab pressed
          window.visibleToggleActivate(); // toggle window visibility when tab pressed
       }

       // set fog parameters
       Sky.fogFrac(    fog_frac()    )
          .fogExp (Pow(fog_exp (),16));

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mbox.draw(MatrixIdentity);
             REPA(pos)
             {
                glass->color.v3=ColorVec(ColorHue(Flt(i)/ELMS(pos)));
                glass->validate();
                mball.draw(Matrix(pos[i]));
             }
          break;

          case RM_LIGHT:
             LightPoint(40,Vec(0,0,0)).add();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       Gui.draw();
       if(Ms.hidden())D.text(0,0.9,S+"Press Tab to toggle parameters");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\04 - Suns.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    MeshGroup terrain;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Suns");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.3).hpRt(true).hwDepthBuffer(true);

       Cam.pitch=0.5f;
    }
    Bool Init()
    {
       terrain.load("obj/terrain/0.mshg"); // terrain
       Sky.set();                          // sky

       // sun
       {
          Sun &sun=Suns.New();               // create a new sun in 'Suns' container
          sun.set(*Gfxs("gfx/sky/sun.gfx")); // set image
          sun.pos=!Vec(1,1,1);               // set custom position
       }

       // moon
       {
          Sun &moon=Suns.New();                // create a new sun in 'Suns' container
          moon.set(*Gfxs("gfx/sky/moon.gfx")); // set image
          moon.pos =!Vec(-1,1,1);              // set custom position
          moon.size*=0.6;                      // decrease default size
          moon.blend=false;                    // disable blending, and thus set adding mode
          moon.gfx_color=0x00404040;           // set gfx color
          moon.light_color=0;                  // disable light casting
          moon.rays.mode=SUN_RAYS_OFF;         // disable sun rays for the moon
       }

       return true;
    }
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01,500,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             terrain.draw(MatrixIdentity);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\05 - Bumpmapping.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh mbox ,
         mball;
    /******************************************************************************

       In this tutorial we'll dynamically show different Bump Mapping modes
       Changing Bump Mapping modes in runtime requires reseting shader effects of manually created Meshes
       To achieve this we need to create a function which will reset effects of those meshes:

    /******************************************************************************/
    void SetEffect()
    {
       mbox .setEffect();
       mball.setEffect();
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Rendering Bumpmapping");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.set_effect=SetEffect          ; // set 'SetEffect' function to be used when needed
       D.full(true).bumpMode(BUMP_FLAT); // start with flat bump mapping
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=3;

       Material *material=Materials("../data/mtrl/brick/0.mtrl");

       mbox .create(1).base(0).create( Box(4),VTX_TX0|VTX_NRM|VTX_TNG).reverse(); // create mesh box, reverse it because it's meant to be viewed from inside
       mball.create(1).base(0).create(Ball(1),VTX_TX0|VTX_NRM|VTX_TNG)          ; // create mesh ball

       // set mesh materials, rendering versions and bounding boxes
       mbox .setMaterial(material).setRender().setBox();
       mball.setMaterial(material).setRender().setBox();

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // move camera on right mouse button

       // change bump mapping when keys pressed
       if(Kb.bp(KB_1))D.bumpMode(BUMP_FLAT    );
       if(Kb.bp(KB_2))D.bumpMode(BUMP_NORMAL  );
       if(Kb.bp(KB_3))D.bumpMode(BUMP_PARALLAX);
       if(Kb.bp(KB_4))D.bumpMode(BUMP_RELIEF  );

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mbox .draw(MatrixIdentity);
             mball.draw(MatrixIdentity);
          break;

          case RM_LIGHT:
             LightPoint(25,Vec(0,3,0)).add();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,S+"Fps "+Tm.fps());
       D.text(0,0.8,"Press 1,2,3,4 keys for different Bumpmapping modes");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\06 - Viewport.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh mbox ,
         mball;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Viewport");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.full(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=3;

       Material *material=Materials("../data/mtrl/brick/0.mtrl");

       mbox .create(1).base(0).create( Box(4),VTX_TX0|VTX_NRM|VTX_TNG).reverse(); // create mesh box, reverse it because it's meant to be viewed from inside
       mball.create(1).base(0).create(Ball(1),VTX_TX0|VTX_NRM|VTX_TNG)          ; // create mesh ball

       // set mesh materials, rendering versions and bounding boxes
       mbox .setMaterial(material).setRender().setBox();
       mball.setMaterial(material).setRender().setBox();

       return true;
    }
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // move camera on right mouse button
       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mbox .draw(MatrixIdentity);
             mball.draw(MatrixIdentity);
          break;

          case RM_LIGHT:
             LightPoint(25,Vec(0,3,0)).add();
          break;
       }
    }
    void Draw()
    {
       // render to active viewport
       Renderer(Render);

       // render to another viewport
       {
          // set new viewport
          Rect rect(-D.w(),-D.h(),0,0); // setup viewport rectangle to left bottom quarter
               rect.extend(-0.05);      // extend with negative value, to make it smaller
          Viewport.set(rect);           // set viewport with given rectangle

          // render everything once again
          Renderer(Render);

          // restore default viewport by activating ViewportFull
          ViewportFull.set();
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\07 - Motion Blur.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    struct Object
    {
       Matrix matrix; // matrix
       Vec       vel, // linear  velocity
             ang_vel; // angular velocity
    }object[12];
    /******************************************************************************/
    Mesh mbox ,
         mball;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Rendering Motion Blur");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.full(true).mtnMode(MTN_HIGH); // enable motion blur
       D.mtnVelScale(0.20);            // increase motion blurring
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=3;

       Material *material=Materials("../data/mtrl/brick/0.mtrl");

       mbox .create(1).base(0).create( Box(  4),VTX_TX0|VTX_NRM|VTX_TNG).reverse(); // create mesh box, reverse it because it's meant to be viewed from inside
       mball.create(1).base(0).create(Ball(0.2),VTX_TX0|VTX_NRM|VTX_TNG)          ; // create mesh ball

       // set mesh materials, rendering versions and bounding boxes
       mbox .setMaterial(material).setRender().setBox();
       mball.setMaterial(material).setRender().setBox();

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       CamHandle(0.1,10,CAMH_ZOOM|(Ms.b(1) ? CAMH_MOVE : CAMH_ROT)); // move camera on right mouse button

       // change motion blur mode when keys pressed
       if(Kb.bp(KB_1))D.mtnMode(MTN_NONE);
       if(Kb.bp(KB_2))D.mtnMode(MTN_LOW );
       if(Kb.bp(KB_3))D.mtnMode(MTN_HIGH);

       // update ball object matrixes and calculate velocity changes automatically
       Flt speed=4;
       REPA(object)
       {
          // calculate new matrix
          Vec2   v; SinCos(v.y,v.x, i*PI2/ELMS(object) + Tm.time()*speed); // calculate sine and cosine of angle
          Matrix new_matrix(Vec(v.x,0,v.y));                               // create 'new_matrix' with initial position

          // calculate velocity changes according to old and new matrix
          GetVel(object[i].vel,object[i].ang_vel, object[i].matrix,new_matrix);

          // store new matrix
          object[i].matrix=new_matrix;
       }

       return true;
    }
    /******************************************************************************/
    void Render() // rendering method
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mbox.draw(MatrixIdentity,Vec(0,0,0));                                     // box is rendered with identity matrix and (0,0,0) velocity
             REPA(object)mball.draw(object[i].matrix,object[i].vel,object[i].ang_vel); // draw ball objects with their matrix and velocities
          break;

          case RM_LIGHT:
             LightPoint(25,Vec(0,3,0)).add();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,S+"Fps "+Tm.fps()); // show number of fps
       D.text(0,0.8,"Press 1,2,3 keys for different Motion Blur modes");
       switch(D.mtnMode())
       {
          case MTN_NONE: D.text(0,0.7,"No Motion Blur"  ); break;
          case MTN_LOW : D.text(0,0.7,"Camera only"     ); break;
          case MTN_HIGH: D.text(0,0.7,"Camera + Objects"); break;
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\08 - Materials.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Material material_brick,
             material_fur,
             material_glow,
             material_rfl;
    Mesh     mesh;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Rendering Materials");
       App.flag=APP_MS_EXCLUSIVE;
       PakAdd("../data/engine.pak");

       D.full(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=4;

       material_brick.reset();                                    // setup defaults
       material_brick.diffuse=Gfxs("../data/mtrl/brick/0.gfx"  ); // set diffuse texture
       material_brick.normal =Gfxs("../data/mtrl/brick/0.n.gfx"); // set normal  texture
       material_brick.detail =Gfxs("../data/mtrl/brick/det.gfx"); // set detail  texture

       material_fur.reset();             // setup defaults
       material_fur.technique=MTECH_FUR; // set fur technique
       material_fur.det_power =1;        // in  fur technique 'det_power' is used for fur length
       material_fur.det_scale/=2;        // in  fur technique 'det_scale' is used for fur scale

       material_glow.reset();  // setup defaults
       material_glow.glow=0.5; // set glow amount

       material_rfl.reset();                                       // setup defaults
       material_rfl.diffuse   =Gfxs("../data/mtrl/glass/0.gfx"  ); // set diffuse texture to white
       material_rfl.normal    =Gfxs("../data/mtrl/glass/0.n.gfx"); // set normal  texture
       material_rfl.reflection=Gfxs("../data/mtrl/glass/rfl.gfx"); // set reflection texture
       material_rfl.color.set(1,0.66,0.33,0); // set color
       material_rfl.specular=0.5 ;            // set specular
       material_rfl.bump    =0.09;            // set bump value
       material_rfl.rough   =0.05;            // set roughness
       material_rfl.reflect =0.8 ;            // set reflection

       mesh.create(1).base(0).create(Ball(1),VTX_TX0|VTX_NRM|VTX_TNG); // create Mesh with 1 Mshb, and create this Mshb from Ball and automatic texture coordinates, normals and tangents
       mesh.setRender().setBox();                                      // set mesh rendering version and bounding box

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(1.5,10,CAMH_ZOOM|CAMH_ROT);

       if(Ms.b(0)) // on left mouse button change colors of materials
       {
          material_glow .color.x=0.5;
          material_brick.color.y=0.5;
          material_fur  .color.z=0.5;
       }else
       {
          // restore default rgb color values
          material_glow .color.v3=1;
          material_brick.color.v3=1;
          material_fur  .color.v3=1;
       }
       // validate changes
       material_glow .validate();
       material_brick.validate();
       material_fur  .validate();

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_FUR  : // here since fur technique is being used we must process also 'RM_FUR' mode, in it we can simply render everything which is in 'RM_SOLID' mode
          case RM_SOLID:
             mesh.setMaterial(&material_glow ).draw(Matrix(Vec(-1, 1,0)));
             mesh.setMaterial(&material_brick).draw(Matrix(Vec( 1, 1,0)));
             mesh.setMaterial(&material_fur  ).draw(Matrix(Vec( 1,-1,0)));
             mesh.setMaterial(&material_rfl  ).draw(Matrix(Vec(-1,-1,0)));
          break;

          case RM_LIGHT: LightDir(Vec(0,0,1)).add(); break;
       }
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\09 - Shadows.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh mbox , // mesh box
         mball; // mesh ball
    /******************************************************************************/
    void InitPre()
    {
       App.name("Rendering Shadows");
       App.flag=APP_MS_EXCLUSIVE;
       PakAdd("../data/engine.pak");
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=3;

       Material *material=Materials("../data/mtrl/brick/0.mtrl");

       mbox .create(1).base(0).create( Box(3),VTX_TX0|VTX_NRM|VTX_TNG).reverse(); // create mesh box, reverse it because it's meant to be viewed from inside
       mball.create(1).base(0).create(Ball(1),VTX_TX0|VTX_NRM|VTX_TNG)          ; // create mesh ball

       // set mesh materials, rendering versions and bounding boxes
       mbox .setMaterial(material).setRender().setBox();
       mball.setMaterial(material).setRender().setBox();

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(1.5,10,CAMH_ZOOM|CAMH_ROT);
       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mbox .draw(MatrixIdentity);
             mball.draw(MatrixIdentity);
          break;

          case RM_LIGHT:
             LightPoint(10,Vec(Cos(Tm.time()),Sin(Tm.time()),-1.5)).add();
          break;

          // since we want to render shadows we have to process additional rendering mode 'RM_SHD_MAP' (render shadows through shadow maps)
          // here we will render all meshes which cast shadows
          case RM_SHD_MAP:
             mball.draw(MatrixIdentity);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);

       D.text(0,0.9,S+"Fps "+Tm.fps()); // show number of fps
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\10 - Volumetric Lights.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh mbox, // mesh box
         mmb ; // mesh middle barrier
    /******************************************************************************/
    void InitPre()
    {
       App.name("Volumetric Lights");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE; // mouse exclusive, display can be toggled with Alt+Enter
       PakAdd("../data/engine.pak");

       D.mode(1024,700).volLight(true); // enable volumetric lighting
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=8;

       Material *material=Materials("../data/mtrl/brick/0.mtrl");

       mbox.create(1).base(0).create(Box(3)    ,VTX_TX0|VTX_NRM|VTX_TNG).reverse();
       mmb .create(1).base(0).create(Box(6,1,6),VTX_TX0|VTX_NRM|VTX_TNG);
       // make hole inside 'mmb' by subtracting from it a temporary box (3D geometry subtraction will be used)
       {
          Mshb temp;
          temp.create(Box(1),VTX_TX0|VTX_NRM|VTX_TNG); // create temporary box
          mmb .base(0).csg(temp,SEL_SUB);              // subtract 'temp' from 'mmb'

          mmb.setNormals().setTangents().setBinormals(); // re-create normals tangents and binormals
       }

       mbox.setMaterial(material).setRender().setBox();
       mmb .setMaterial(material).setRender().setBox();

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(2,10,CAMH_ZOOM|CAMH_ROT);
       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mbox.draw(MatrixIdentity);
             mmb .draw(MatrixIdentity);
          break;

          case RM_LIGHT:
             LightPoint(5,Vec(Cos(Tm.time()),1,Sin(Tm.time())),Vec(1), 0.1).add(); // render light with volumetric amount set to 0.1
          break;

          case RM_SHD_MAP:
             mbox.draw(MatrixIdentity); // volumetric lighting depends on shadow map, so we need to render 'mbox' too
             mmb .draw(MatrixIdentity);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\11 - Ambient Occlusion.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       In this tutorial is presented how to achieve high ambient lighting value with satisfactionary looks

    /******************************************************************************/
    struct AmbientControls
    {
       Window    win;
       Text     tmode,tsoft,tjitter,thalf_res,tpower,tcontrast,trange,tscale,tbias;
       ComboBox  mode, soft;
       CheckBox  jitter,half_res;
       Slider    power,contrast,range,scale,bias;

       void create()
       {
          static CChar8 *modes[]=
          {
             "off",
             "low",
             "high #1",
             "high #2",
             "high #3",
             "high #4",
          };
          static CChar8 *softing[]=
          {
             "0",
             "1",
             "2",
          };
          Flt y=0,h=0.062;
          Gui+= win     .create(Rect_RD(D.w(),-D.h(),0.9,0.67),"Ambient Parameters").hide(); y-=h;
          win+=tmode    .create(Vec2   (0.2,y),"Mode"           ); win+=mode    .create(Rect_C(0.2+win.crect.w()/2,y,0.25,0.05),modes  ,ELMS(modes  )).set(D.ambMode()); y-=h;
          win+=tsoft    .create(Vec2   (0.2,y),"Soft"           ); win+=soft    .create(Rect_C(0.2+win.crect.w()/2,y,0.25,0.05),softing,ELMS(softing)).set(D.ambSoft()); y-=h;
          win+=tjitter  .create(Vec2   (0.2,y),"Jitter"         ); win+=jitter  .create(Rect_C(0.2+win.crect.w()/2,y,0.05,0.05),D.ambJitter  ()    ); y-=h;
          win+=thalf_res.create(Vec2   (0.2,y),"Half Resolution"); win+=half_res.create(Rect_C(0.2+win.crect.w()/2,y,0.05,0.05),D.ambHalfRes ()    ); y-=h;
          win+=tpower   .create(Vec2   (0.2,y),"Power"          ); win+=power   .create(Rect_C(0.2+win.crect.w()/2,y,0.25,0.05),D.ambPower   ()    ); y-=h;
          win+=tcontrast.create(Vec2   (0.2,y),"Contrast"       ); win+=contrast.create(Rect_C(0.2+win.crect.w()/2,y,0.25,0.05),D.ambContrast()/4  ); y-=h;
          win+=trange   .create(Vec2   (0.2,y),"Range"          ); win+=range   .create(Rect_C(0.2+win.crect.w()/2,y,0.25,0.05),D.ambRange   ()/0.4); y-=h;
          win+=tscale   .create(Vec2   (0.2,y),"3D Scale"       ); win+=scale   .create(Rect_C(0.2+win.crect.w()/2,y,0.25,0.05),D.ambScale   ()/4  ); y-=h;
          win+=tbias    .create(Vec2   (0.2,y),"Bias"           ); win+=bias    .create(Rect_C(0.2+win.crect.w()/2,y,0.25,0.05),D.ambBias    ()    ); y-=h;
       }
    }AC;
    /******************************************************************************/
    Mesh   mbackground,
           mball,
           mbox ;
    Matrix matrix_ball[25],
           matrix_box [25];
    /******************************************************************************/
    void InitPre()
    {
       App.name("Ambient Occlusion");
       App.flag=APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.full(true).ambMode(AMB_HIGH3).ambSoft(1).ambJitter(1).ambHalfRes(1).ambPower(0.8); // set initial ambient occlusion parameters

       Ms.hide(); // hide mouse
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=5;

       Material *brick=Materials("../data/mtrl/brick/0.mtrl"),
                *glass=Materials("../data/mtrl/glass/0.mtrl");

       mbackground.create(1).base(0).create( Box(3  ),VTX_TX0|VTX_NRM|VTX_TNG).reverse(); // create background box
       mbox       .create(1).base(0).create( Box(0.5),VTX_TX0|VTX_NRM|VTX_TNG);           // create box
       mball      .create(1).base(0).create(Ball(0.5),VTX_TX0|VTX_NRM|VTX_TNG);           // create ball

       mbackground.setMaterial(brick).setRender().setBox();
       mbox       .setMaterial(glass).setRender().setBox();
       mball      .setMaterial(glass).setRender().setBox();

       // setup random matrixes
       REPA(matrix_ball)matrix_ball[i].setRotateXY(RandomF(PI2),RandomF(PI2)).move(Random(mbackground.box));
       REPA(matrix_box )matrix_box [i].setRotateXY(RandomF(PI2),RandomF(PI2)).move(Random(mbackground.box));

       AC.create();

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       CamHandle(0.01,100,Ms.hidden() ? CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT) : 0); // when mouse hidden operate the camera

       if(Kb.bp(KB_TAB))
       {
             Ms .toggle               (); // toggle mouse  visibility when tab pressed
          AC.win.visibleToggleActivate(); // toggle window visibility when tab pressed
       }

       // set Ambient Occlusion parameters
       D.ambMode    (AC.mode    ())
        .ambSoft    (AC.soft    ())
        .ambJitter  (AC.jitter  ())
        .ambHalfRes (AC.half_res())
        .ambPower   (AC.power   ())
        .ambContrast(AC.contrast()*4)
        .ambRange   (AC.range   ()*0.4)
        .ambScale   (AC.scale   ()*4)
        .ambBias    (AC.bias    ());

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mbackground.draw(MatrixIdentity);
             REPA(matrix_ball)mball.draw(matrix_ball[i]);
             REPA(matrix_box )mbox .draw(matrix_box [i]);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       Gui.draw();
       if(Ms.hidden())D.text(0,0.9,S+"Press Tab to toggle parameters");
       else           D.text(0,0.9,S+"Fps: "+Tm.fps());
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\12 - Early Z.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       EarlyZ is a technique of rejecting pixels which aren't visible
       Another way of doing this optimization is to sort objects manually before rendering, so they will be rendered in front-to-back order.
       -   Advantage of EarlyZ is that it's simpler to use and it's pixel-precise, instead of object-precise as in manual object sorting
       -Disadvantage is that it requires additional pass of rendering, but fortunately it consists only of vertex transformations and z-buffer setting

    /******************************************************************************/
    Mesh mbox ,
         mball;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Early Z");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.full(true).bumpMode(BUMP_RELIEF); // setup relief bump mapping to enable pixel-heavy processing
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=3;

       Material *material=Materials("../data/mtrl/brick/0.mtrl");

       mbox .create(1).base(0).create( Box(5),VTX_TX0|VTX_NRM|VTX_TNG).reverse();
       mball.create(1).base(0).create(Ball(1),VTX_TX0|VTX_NRM|VTX_TNG);

       mbox .setMaterial(material).setRender().setBox();
       mball.setMaterial(material).setRender().setBox();

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));
       return true;
    }
    /******************************************************************************/
    void Render()
    {
       // to use EarlyZ just render in 'RM_EARLY_Z' mode all big objects which occlude others
       switch(Renderer())
       {
          case RM_EARLY_Z:       // in this tutorial we'll simply render the same things as in 'RM_SOLID' mode
             if(!Kb.b(KB_SPACE)) // disable EarlyZ when space pressed
             {
                       mbox .draw(MatrixIdentity);
                FREP(5)mball.draw(Matrix(2,Vec(0,0,5-i))); // draw in back-to-front order to present EarlyZ speedup
             }
          break;

          case RM_SOLID:
                    mbox .draw(MatrixIdentity);
             FREP(5)mball.draw(Matrix(2,Vec(0,0,5-i))); // draw in back-to-front order to present EarlyZ speedup
          break;

          case RM_LIGHT:
             LightPoint(25,Vec(0,3,-1)).add();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,S+"Fps: "+Tm.fps());
       D.text(0,0.8,  "Hold Space to disable EarlyZ");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\13 - Bloom.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Material *brick,
             *glass;
    Mesh      mbox ,
              mball;
    Vec       pos[32];

    Window   window;
    Text    tbloom_org,
            tbloom_scale,
            tbloom_cut,
            tbloom_overbright;
    Slider   bloom_org,
             bloom_scale,
             bloom_cut;
    CheckBox bloom_overbright;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Bloom configuration");
       App.flag=APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.full(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=3;

       brick=Materials("../data/mtrl/brick/0.mtrl");
       glass=Materials("../data/mtrl/glass/0.mtrl");

       mbox .create(1).base(0).create( Box(  4),VTX_TX0|VTX_NRM|VTX_TNG).reverse(); // create mesh box, reverse it because it's meant to be viewed from inside
       mball.create(1).base(0).create(Ball(0.5),VTX_TX0|VTX_NRM|VTX_TNG)          ; // create mesh ball

       // set mesh materials, rendering versions and bounding boxes
       mbox .setMaterial(brick).setRender().setBox();
       mball.setMaterial(glass).setRender().setBox();

       // set random positions inside box
       REPA(pos)pos[i]=Random(mbox.box);

       // add gui bloom controls
       Gui   +=window.create(Rect_C(0,-0.7,0.6,0.5),"Bloom Parameters");
       window+=tbloom_org       .create(Vec2(0.13,-0.08),"Origin"     ); window+=bloom_org       .create(Rect_C(0.1+window.crect.w()/2,-0.08,0.25,0.05),D.bloomOriginal  ());
       window+=tbloom_scale     .create(Vec2(0.13,-0.16),"Scale"      ); window+=bloom_scale     .create(Rect_C(0.1+window.crect.w()/2,-0.16,0.25,0.05),D.bloomScale     ());
       window+=tbloom_cut       .create(Vec2(0.13,-0.24),"Cutoff"     ); window+=bloom_cut       .create(Rect_C(0.1+window.crect.w()/2,-0.24,0.25,0.05),D.bloomCut       ());
       window+=tbloom_overbright.create(Vec2(0.13,-0.32),"OverBright" ); window+=bloom_overbright.create(Rect_C(0.1+window.crect.w()/2,-0.32,0.05,0.05),D.bloomOverbright());

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();

       Cam.setSpherical(Vec(0,0,0),Tm.time()/16,-0.3,0,3).updateVelocities().set(); // set autorotating camera

       D.bloom(bloom_org(),bloom_scale(),bloom_cut(),bloom_overbright()); // set bloom parameters

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mbox.draw(MatrixIdentity);
             REPA(pos)
             {
                glass->color.v3=ColorVec(ColorHue(Flt(i)/ELMS(pos)));
                mball.draw(Matrix(pos[i]));
             }
          break;

          case RM_LIGHT:
             LightPoint(25,Vec(0,3,0)).add();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       Gui.draw();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\14 - Depth of Field.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Material *brick,
             *glass;
    Mesh      mbox ,
              mball;
    Vec       pos[32];

    Window   window;
    CheckBox dof_hi;
    ComboBox dof_blurs;
    Slider   dof_power,
             dof_range;
    Text    tdof_hi,
            tdof_blurs,
            tdof_power,
            tdof_range;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Depth of Field");
       App.flag=APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.full(true).dof(DOF_HIGH,1, 1,0,5); // set initial depth of field parameters

       // hide mouse
       Ms.hide();
    }
    /******************************************************************************/
    Bool Init()
    {
       brick=Materials("../data/mtrl/brick/0.mtrl");
       glass=Materials("../data/mtrl/glass/0.mtrl");

       mbox .create(1).base(0).create( Box(  4),VTX_TX0|VTX_NRM|VTX_TNG).reverse(); // create mesh box, reverse it because it's meant to be viewed from inside
       mball.create(1).base(0).create(Ball(0.5),VTX_TX0|VTX_NRM|VTX_TNG)          ; // create mesh ball

       // set mesh materials, rendering versions and bounding boxes
       mbox .setMaterial(brick).setRender().setBox();
       mball.setMaterial(glass).setRender().setBox();

       // set random positions inside box
       REPA(pos)pos[i]=Random(mbox.box);

       // set camera
       Cam.at   = mbox.box.cornerLDF()/2;
       Cam.dist = 10;
       Cam.pitch=-PI_4;
       Cam.yaw  = PI_4;

       // add gui Dof controls
       static CChar8 *blurs[]=
       {
          "1",
          "2",
          "3",
       };
       Gui   +=window    .create(Rect_C(0,-0.7,0.9,0.50),"Depth of Field Parameters").hide();
       window+=tdof_hi   .create(Vec2(0.2,-0.08),"High Quality"); window+=dof_hi   .create(Rect_C(0.2+window.crect.w()/2,-0.08,0.05,0.05),D.dofMode ()==DOF_HIGH).desc("Prevents foreground objects leaking into background");
       window+=tdof_blurs.create(Vec2(0.2,-0.16),"Blurs"       ); window+=dof_blurs.create(Rect_C(0.2+window.crect.w()/2,-0.16,0.25,0.05),blurs,ELMS(blurs)).set(D.dofBlurs()-1);
       window+=tdof_power.create(Vec2(0.2,-0.24),"Power"       ); window+=dof_power.create(Rect_C(0.2+window.crect.w()/2,-0.24,0.25,0.05),D.dofPower());
       window+=tdof_range.create(Vec2(0.2,-0.32),"Range"       ); window+=dof_range.create(Rect_C(0.2+window.crect.w()/2,-0.32,0.25,0.05),D.dofRange()/10);

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();
       CamHandle(0.01,100,Ms.hidden() ? CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT) : 0); // when mouse hidden operate the camera

       if(Kb.bp(KB_TAB))
       {
          Ms    .toggle               (); // toggle mouse  visibility when tab pressed
          window.visibleToggleActivate(); // toggle window visibility when tab pressed
       }

       // set depth of field parameters
       D.dof(dof_hi () ? DOF_HIGH : DOF_ON, dof_blurs()+1, dof_power(), Cam.dist, dof_range()*10);

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mbox.draw(MatrixIdentity);
             REPA(pos)
             {
                glass->color.v3=ColorVec(ColorHue(Flt(i)/ELMS(pos)));
                glass->validate(); // changing parameters realtime requires calling 'validate'
                mball.draw(Matrix(pos[i]));
             }
          break;

          case RM_LIGHT:
             LightPoint(25,Vec(0,3,0)).add();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       Gui.draw();
       if(Ms.hidden())D.text(0,0.9,S+"Press Tab to toggle parameters");
       else           D.text(0,0.9,S+"Fps "+Tm.fps());
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\15 - Particles.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh      mbox;
    Particles part[4]; // particles
    /******************************************************************************/
    void InitPre()
    {
       App.name("Particles");
       App.flag=APP_FULL_TOGGLE|APP_MS_EXCLUSIVE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true);
       Cam.dist=2;
    }
    /******************************************************************************/
    Bool Init()
    {
       // create mesh box
       mbox.create(1).base(0).create(Box(4),VTX_TX0|VTX_NRM|VTX_TNG).reverse();
       mbox.setMaterial(Materials("mtrl/brick/0.mtrl")).setRender().setBox();

       // create particles
       {
          // we'll start with a fire-like particle
          Gfx  *gfx  =Gfxs("gfx/particle/fire.gfx"); // image
          UInt  col  =ARGB(0,40,0,0);                // color
          Int   num  =30;                            // number
          Flt   r    =0.1,                           // radius
                life =1.0,                           // average life
                vel  =0.2;                           // random velocity
          Vec   accel(0,1,0);                        // acceleration
          Shape shape(Ball(0.05));                   // particles initial shape

          part[0].create(*gfx,col,num,r,life,vel,accel,shape); // create particles
          part[0].set   (Vec(-0.5,0,0)                      ); // move to the left
          part[0].reset (                                   ); // reset every single particle for random position and other parameters

          // let's set part[1] with different settings, to make it magic-like
          {
             gfx =Gfxs("gfx/particle/fire.gfx");
             col =ARGB(0,0,0,40);
             num =100;
             r   =0.05;
             life=1.0;
             vel =0;
             accel.zero();
             shape=Capsule(0.1,0.4);

             part[1].create(*gfx,col,num,r,life,vel,accel,shape); // create particles
             part[1].reset (                                   ); // reset every single particle
             part[1].func=PARTICLE_SIN;                           // change particles power function to sinus based
          }

          // and now part[2], fountain-like
          {
             gfx =Gfxs("gfx/particle/drop.gfx");
             col =ARGB(150,20,120,200); // part[2] will be rendered in a different way (alpha blended) so make sure to set up alpha value in the color
             num =500;
             r   =0.02;
             life=1.0;
             vel =1.0;
             accel.set(0,-2,0);
             shape=Vec(0,0,0);

             part[2].create(*gfx,col,num,r,life,vel,accel,shape); // create particles
             part[2].set   (Vec(0.5,0,0)                       ); // move to the right
             part[2].vel.set(2,2,0);                              // set initial vector velocity
             part[2].damping=0.98;                                // enable damping
             part[2].reset(                                    ); // reset every single particle
          }

          // part[3], smoke-like
          {
             gfx =Gfxs("gfx/particle/fire.gfx");
             col =ARGB(100,0,0,0); // part[3] will be rendered in a different way (alpha blended) so make sure to set up alpha value in the color
             num =40;
             r   =0.15;
             life=1.5;
             vel =0.2;
             accel.zero();
             shape=Vec(0,0,0);

             part[3].create(*gfx,col,num,r,life,vel,accel,shape); // create particles
             part[3].set   (Vec(-1,0,0)                        ); // move to the left
             part[3].reset (                                   ); // reset every single particle
          }
       }
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       // modify part[3] position
       Vec2 pos; SinCos(pos.y,pos.x,Tm.time()+PI);
       part[3].set(Vec(pos.x,0,pos.y));

       // update particles
       REPA(part)part[i].update();

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mbox.draw(MatrixIdentity);
          break;

          case RM_LIGHT:
             LightPoint(30,Vec(0,3,0)).add();
          break;

          // particles are rendered in RM_PALETTE or RM_BLEND modes
          // the first  one (RM_PALETTE) is for objects rendered using color palette, and take their colors from 'Renderer.color_palette' texture (you can assign this texure to your custom version with command "Renderer.color_palette=Gfxs(..)")
          // the second one (RM_BLEND  ) is for objects rendered with standard alpha blending
          // let's render part[0] and part[1] as pallette based, and part[2] and part[3] with standard alpha blending

          case RM_PALETTE: // palette based
             part[0].draw();
             part[1].draw();
          break;

          case RM_BLEND: // alpha blending
             part[2].draw();
             part[3].draw();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\16 - Blood.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include <EsenthelEngine/EsenthelEngine.h>
    /******************************************************************************/
    Mesh   *chr   ; // character mesh
    Gfx    *main  , // main   blood texture
           *single; // single blood texture
    BloodFx blood ; // blood particle effect
    /******************************************************************************/
    void InitPre()
    {
       App.name("Blood Effect");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak",NULL);

       Cam.dist=3;
       D.full(1).hpRt(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       Sky.set();

       chr=Meshs("obj/chr/human/0.mesh");

       main  =Gfxs("gfx/particle/blood/0.gfx");
       single=Gfxs("gfx/particle/blood/1.gfx");

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1f,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       // enable blood effect
       if(Kb.bp(KB_SPACE)) // on space
          blood.create(main,single,0xFF800000,60,Vec(0,1,0),Vec(1.6,0,0),1); // create blood effect

       // update blood effect
       blood.update();

       return true;
    }
    /******************************************************************************/
    Void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
          case RM_SHD_MAP:
             chr->draw(Matrix(2).rotateY(PI)); // draw character mesh
          break;

          case RM_LIGHT:
             LightPoint(5,Vec(0,1,-1)).add();
          break;

          case RM_BLEND:
             blood.draw(); // draw Blood Effect in Alpha Blending mode
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,"Press Space to enable Blood Effect");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\17 - Explosion.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include <EsenthelEngine/EsenthelEngine.h>
    /******************************************************************************/
    Mesh       *chr      , // character mesh
                box      ; // box       mesh
    Gfx        *main     , // main   explosion texture
               *single   ; // single explosion texture
    ExplosionFx explosion; // explosion particle effect
    /******************************************************************************/
    void InitPre()
    {
       App.name("Blood Effect");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak",NULL);

       Cam.dist=3;
       D.full(1).bumpMode(BUMP_PARALLAX).mtnMode(MTN_HIGH); // Explosion Effect makes use of Motion Blur
    }
    /******************************************************************************/
    Bool Init()
    {
       box.create(1).base(0).create(Box(2),VTX_TX0|VTX_NRM|VTX_TNG).reverse();
       box.setMaterial(Materials("mtrl/brick/0.mtrl")).setRender().setBox();

       chr=Meshs("obj/chr/human/0.mesh");

       main  =Gfxs("gfx/particle/explosion/0.gfx");
       single=Gfxs("gfx/particle/explosion/1.gfx");

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       // enable explosion effect
       if(Kb.bp(KB_SPACE)) // on space
       {
          explosion.create(main,single,0x00600000,32,Vec(0,0,0),1); // create explosion effect
          QuakeFx.addMedium();                                      // add medium earth quake
       }

       // update Explosion Effect
       explosion.update();

       // update Quake Effect
       QuakeFx.update();

       CamHandle(0.1f,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       return true;
    }
    /******************************************************************************/
    Void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID  :
          case RM_SHD_MAP:
             box .draw(MatrixIdentity);
             chr->draw(Matrix(2).rotateY(PI));
          break;

          case RM_LIGHT:
             LightPoint(5,Vec(0,1,-1)).add();
          break;

          case RM_PALETTE:
             explosion.draw(); // draw Explosion Effect in Color Palette mode
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,"Press Space to enable Explosion Effect");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\18 - Holographic Images.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh mbox,mball;
    Gfx  gfx;
    Flt  density_factor=0.05;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Holographic Images");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");
       D.full(true).ambPower(0.1);
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=3;

       // create standard meshes and materials
       Material *material=Materials("mtrl/brick/0.mtrl");

       mbox .create(1).base(0).create( Box(5),VTX_TX0|VTX_NRM|VTX_TNG).reverse(       ); mbox .setMaterial(material).setRender().setBox();
       mball.create(1).base(0).create(Ball(1),VTX_TX0|VTX_NRM|VTX_TNG).weldVal(VTX_POS); mball.setMaterial(material).setRender().setBox();

       // create holographic image
       Int size=64;
       gfx.create(size,size,size,GFX_A8R8G8B8,GFX_3D,1); // size x size x size dimensions, A8R8G8B8 type, 3D mode, 1 mip map
       if(gfx.lock()) // start manual pixel editing
       {
          REPD(z,gfx.z())
          REPD(y,gfx.y())
          REPD(x,gfx.x())
          {
             Flt fx=Flt(x)/(gfx.x()-1), // x pixel fraction value 0..1
                 fy=Flt(y)/(gfx.y()-1), // y pixel fraction value 0..1
                 fz=Flt(z)/(gfx.z()-1); // z pixel fraction value 0..1

             Flt px=fx*2-1, // x pixel position value -1..1
                 py=fy*2-1, // y pixel position value -1..1
                 pz=fz*2-1; // z pixel position value -1..1

             Vec4 color=0;

             if(x<=1 || x>=gfx.x()-2
             || y<=1 || y>=gfx.y()-2
             || z<=1 || z>=gfx.z()-2) // if current pixel is on border
             {
                color.set(0,1,0, RandomF(0.5,1)); // green color with random alpha
             }
             else // if current pixel is inside
             {
                // blue sphere
                Flt length=Vec(px,py,pz).length();
                Flt sphere=(1-Sat(Abs(length-0.5)*8));//*RandomF();

                // red fade
                Flt red_fade=0.5*fx*fx*RandomF();

                // color value from blue sphere and red fade
                if(Flt sum=sphere+red_fade) // total alpha value
                   color.set(1*red_fade/sum, 0.5*sphere/sum, 1*sphere/sum, sum);
             }

             gfx.color3DF(x,y,z,color); // store the pixel color
          }
          gfx.unlock(); // end pixel editing
       }

       REP(3)gfx.sharpen(1,1,true,true); // sharpen the image 3 times

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,1000,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       if(Kb.b(KB_Q))density_factor/=1+Tm.d();
       if(Kb.b(KB_W))density_factor*=1+Tm.d();

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID  :
          case RM_SHD_MAP:
             mbox .draw(MatrixIdentity);
             mball.draw(Matrix(Vec(0,-3,0)));
          break;

          case RM_LIGHT:
             LightPoint(20,Vec(0,3,3)).add();
          break;

          case RM_BLEND: // holographic images need to be drawn in RM_BLEND mode
             gfx.draw3D(WHITE,0, Matrix(Vec(1,1,1),Vec(0)), density_factor, 1, 4,64);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,S+"Fps: "+Tm.fps());
       D.text(0,0.8,S+"Density Factor: "+density_factor+" (Q/W to change)");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\19 - Layered Clouds.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    MeshGroup terrain;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Layered Clouds");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.3);
    }
    Bool Init()
    {
       terrain.load       ("obj/terrain/0.mshg");          // terrain
       Sky    .set        ();                              // sky
       Suns   .New().set  ( *Gfxs("gfx/sky/sun.gfx"));     // sun
       Clouds .layered.set(3,Gfxs("Clouds/Layers/0.gfx")); // clouds
       return true;
    }
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01,500,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       if(Kb.bp(KB_F10))Renderer.screenShots("screenshot/","bmp");
       if(Kb.bp(KB_F11))D.toggle();

       if(!Kb.b(KB_SPACE))Clouds.layered.update(); // if space not pressed then update clouds position

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             terrain.draw(MatrixIdentity);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,S+"Fps "+Tm.fps());
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\20 - Volumetric Clouds.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    struct DisplayOptions
    {
       Window   window;
       CheckBox vol, hp_rt, hdr;
       Text    tvol,thp_rt,thdr;

       void create()
       {
          Gui   +=window.create(Rect_R(D.w(),0.5,0.8,0.35),"Display Options");
          window+=vol   .create(Rect (0.05,-0.10,0.10,-0.05)); window+=tvol  .create(Vec2(0.45,-0.075),"Volumetric Lighting");
          window+=hp_rt .create(Rect (0.05,-0.18,0.10,-0.13)); window+=thp_rt.create(Vec2(0.45,-0.155),"High Precision RenderTargets");
          window+=hdr   .create(Rect (0.05,-0.26,0.10,-0.21)); window+=thdr  .create(Vec2(0.45,-0.235),"High Dynamic Range");
       }
       void update()
       {
          D.volLight(vol  ());
          D.hpRt    (hp_rt());
          D.hdr     (hdr  ());
       }
    }Opt;
    /******************************************************************************/
    struct CloudImages
    {
       Window window;
       Button generate,save,load;
       Gfx    cloud,detail;

       static void Generate(Ptr)
       {
          if(!Ci.detail.is()) // if detail image hasn't yet been created
          {
             CreateVolumetricDetail(Ci.detail,128,16,128); // create volumetric detail image, this image is used in cloud image creation, and it also can be used in the drawing process for additional quality
             Ci.detail.blur(1,false); // blur it
          }

          CreateVolumetricCloud(Ci.cloud,&Ci.detail, 256,32,256, 3, false, 80);
          Ci.cloud.lumFromAlphaAndLight(DIRF_RIGHT|DIRF_DOWN|DIRF_FORWARD,1.0);
          Tm      .skipUpdate(); // generating clouds is slow, so don't update timer in this frame
       }
       static void Save(Ptr){Ci.cloud.save("LocalData/cloud.gfx"); Ci.detail.save("LocalData/detail.gfx");}
       static void Load(Ptr){Ci.cloud.load("LocalData/cloud.gfx"); Ci.detail.load("LocalData/detail.gfx");}

       void create()
       {
          Gui   +=window  .create(Rect_LD(-D.w(),-D.h(),0.5,0.3),"Cloud Images");
          window+=generate.create(Rect_C (window.rect.w()  /2,-0.08,0.35,0.06),"Generate",Generate);
          window+=save    .create(Rect_C (window.rect.w()*1/3,-0.18,0.15,0.06),"Save"    ,Save    );
          window+=load    .create(Rect_C (window.rect.w()*2/3,-0.18,0.15,0.06),"Load"    ,Load    );

          Clouds.volumetric.set(&cloud,NULL);
       }
    }Ci;
    /******************************************************************************/
    struct CloudParams
    {
       Window    window;
       Slider    dns, shd, col0, col1,  scale, curve, height;
       Text     tdns,tshd,tcol0,tcol1, tscale,tcurve,theight;
       CheckBox  detail, hi_res;
       Text     tdetail,thi_res;
       Button    save  , load  ;

       static void Save(Ptr){   Clouds.volumetric.save("LocalData/volumetric_clouds");                 }
       static void Load(Ptr){if(Clouds.volumetric.load("LocalData/volumetric_clouds"))Cp.cloudsToGui();}

       void create()
       {
          Gui+=window.create(Rect_RD(D.w(),-D.h(),0.6,0.77),"Cloud Parameters");

          window+=tdns .create(Vec2(0.15,-0.05),"Density"); window+=dns .create(Rect_LU(0.3,-0.03,0.25,0.05), 3.0/6);
          window+=tshd .create(Vec2(0.15,-0.10),"Shadow" ); window+=shd .create(Rect_LU(0.3,-0.08,0.25,0.05), 0.5  );
          window+=tcol0.create(Vec2(0.15,-0.15),"Color0" ); window+=col0.create(Rect_LU(0.3,-0.13,0.25,0.05), 0.38 );
          window+=tcol1.create(Vec2(0.15,-0.20),"Color1" ); window+=col1.create(Rect_LU(0.3,-0.18,0.25,0.05), 0.7  );

          window+=tscale .create(Vec2(0.15,-0.30),"Scale" ); window+=scale .create(Rect_LU(0.3,-0.28,0.25,0.05), 0.5);
          window+=tcurve .create(Vec2(0.15,-0.35),"Curve" ); window+=curve .create(Rect_LU(0.3,-0.33,0.25,0.05), 0.5);
          window+=theight.create(Vec2(0.15,-0.40),"Height"); window+=height.create(Rect_LU(0.3,-0.38,0.25,0.05), 0.5);

          window+=tdetail.create(Vec2(0.20,-0.50),"Detail"         ); window+=detail.create(Rect(0.40,-0.53,0.45,-0.48));
          window+=thi_res.create(Vec2(0.20,-0.57),"High Resolution"); window+=hi_res.create(Rect(0.40,-0.60,0.45,-0.55));

          window+=save.create(Rect_C(0.17,-0.67,0.18,0.06),"Save",Save);
          window+=load.create(Rect_C(0.43,-0.67,0.18,0.06),"Load",Load);
       }
       void cloudsToGui()
       {
          dns .set(Clouds.volumetric.density/6);
          shd .set(Clouds.volumetric.shadow);
          col0.set(Clouds.volumetric.dark_color  .avg());
          col1.set(Clouds.volumetric.bright_color.avg());

          scale .set(LerpR(0.125f,0.375f,Clouds.volumetric.scale ));
          curve .set(LerpR(0.000f,0.060f,Clouds.volumetric.curve ));
          height.set(LerpR(0.000f,1.540f,Clouds.volumetric.height));

          detail.set(Clouds.volumetric.detail!=NULL);
          hi_res.set(Clouds.volumetric.hi_res      );
       }
       void guiToClouds()
       {
          Clouds.volumetric.density=Lerp(0,6,dns());
          Clouds.volumetric.shadow =Lerp(0,1,shd());
          Clouds.volumetric.dark_color  .set(col0());
          Clouds.volumetric.bright_color.set(col1());

          Clouds.volumetric.scale =Lerp(0.125f,0.375f,scale ());
          Clouds.volumetric.curve =Lerp(0.000f,0.060f,curve ());
          Clouds.volumetric.height=Lerp(0.000f,1.540f,height());

          Clouds.volumetric.detail=(detail() ? &Ci.detail : NULL);
          Clouds.volumetric.hi_res=hi_res();
       }
    }Cp;
    /******************************************************************************/
    MeshGroup terrain;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Volumetric Clouds");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.3).hdrExposure(0.7);
    }
    Bool Init()
    {
       terrain.load("obj/terrain/0.mshg");
       Sky .set();
       Suns.New().set(*Gfxs("gfx/sky/sun.gfx"));

       // gui
       Opt.create();
       Ci .create();
       Cp .create();
       return true;
    }
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01,500,Ms.hidden() ? CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT) : 0); // when mouse hidden operate the camera

       if(Kb.bp(KB_TAB))
       {
          Ms .              toggle(); // toggle mouse visibility when tab pressed
          Opt.window.visibleToggle();
          Ci .window.visibleToggle();
          Cp .window.visibleToggle();
       }

       Gui.update();
       Opt.update();
       Cp .guiToClouds();

       if(Kb.bp(KB_F10))Renderer.screenShots("screenshot/","bmp");
       if(Kb.bp(KB_F11))D       .toggle();

       if(!Kb.b(KB_SPACE))Clouds.volumetric.update(Vec2(4,4)); // if space not pressed then update clouds position by given velocity

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             terrain.draw(MatrixIdentity);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       Gui.draw();
       D.text(0,0.9,S+"Fps "+Tm.fps());
       D.text(0,0.8,Ms.hidden() ? "Press Tab to toggle parameters" : "Press Tab to operate the camera");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\21 - Object Clouds.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    MeshGroup terrain ;
    Gfx       image[3]; // cloud images

    struct Cloud
    {
       Gfx    *gfx;
       Matrix  matrix;

       Cloud()
       {
          gfx=NULL;
       }

       void draw(UInt color,UInt color_add)
       {
          if(gfx)gfx->draw3D(color,color_add, matrix, 0.5, 0.5);
       }
    };
    Memb<Cloud> clouds; // container of clouds
    /******************************************************************************/
    void InitPre()
    {
       App.name("Object Clouds");
       App.flag=APP_FULL_TOGGLE|APP_MS_EXCLUSIVE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.3).hpRt(true);

       Cam.dist =1;
       Cam.yaw  =2.8;
       Cam.pitch=0.3;
       Cam.at.set(0,0,0);

       ViewportFull.range=200;
    }
    Bool Init()
    {
       terrain.load("obj/terrain/0.mshg");
       Sky.set();
       {
          Sun &sun=Suns.New();
          sun.set(*Gfxs("gfx/sky/sun.gfx"));
          sun.rays.mode=SUN_RAYS_HIGH;
       }

       // create cloud images
       Gfx detail; CreateVolumetricDetail(detail, 32,16,32); detail.blur(1,false);
       REPA(image)
       {
          CreateVolumetricCloud(image[i],&detail, 64,32,64, 3, true, 80);
          image[i].mulAdd(Vec4(1,1,1,4),Vec4(0,0,0,0)); // scale alpha value
          image[i].lumFromAlphaAndLight(DIRF_RIGHT|DIRF_DOWN|DIRF_FORWARD,0.5);
       }

       Flt average_size=4;

       // holographic images may not intersect with each other, so set positions based on a regular grid modified by slight rotations and offsets
       for(Int x=-2; x<=2; x++)
       for(Int z=-2; z<=2; z++)
       {
          Cloud &cloud=clouds.New();

          // set random image
          cloud.gfx=&image[Random(ELMS(image))];

          // set cloud matrix
          cloud.matrix.setScale(average_size*RandomF(0.8,1.2))
                      .scale   (Vec(1,0.5,1))
                      .rotateXY(RandomF(-0.1,0.1),RandomF(-0.4,0.4))
                      .move    ((Vec(x,0,z)+Random.vec(-0.25,0.25))*average_size*2)
                      .move    (Vec(0,10,0));
       }

       return true;
    }
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01,500,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       return true;
    }
    /******************************************************************************/
    Int Compare(Cloud &c0,Cloud &c1)
    {
       return CompareTransparencyOrder(c0.matrix.pos,c1.matrix.pos);
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             terrain.draw(MatrixIdentity);
          break;

          case RM_CLOUD: // clouds in order to affect the sun rays must be drawn in RM_CLOUD mode
          {
             Flt  color_dark  =0.38,
                  color_bright=0.78;
             UInt color       =           ColorBrightness(color_bright-color_dark)   ,
                  color_add   =ColorAlpha(ColorBrightness(             color_dark),0);

             // clouds are transparent so they need to be sorted before rendering
             clouds.sort(Compare);

             // draw the clouds
             REPAO(clouds).draw(color,color_add);
          }break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,S+"Fps "+Tm.fps());
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\22 - Water.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    MeshGroup terrain;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Water");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.3).hpRt(true).hwDepthBuffer(true);

       Cam.at.set(0,2,0);
       Cam.pitch=-0.5;
       Cam.dist =30;
       Cam.yaw  =2.8;
    }
    Bool Init()
    {
       terrain.load("obj/terrain/0.mshg");          // terrain
       terrain.scale(Vec(1,10,1)).move(Vec(0,5,0)); // scale and move terrain vertically
       Sky .set();                                  // sky
       Suns.New().set(*Gfxs("gfx/sky/sun.gfx"));    // sun

       Water.set(*Gfxs("gfx/water/0.gfx"),*Gfxs("gfx/water/0.n.gfx"),Gfxs("gfx/fx/reflection.gfx")); // set water from textures

       return true;
    }
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01,500,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       // here you can optionally set different water surface plane
       if(Kb.b(KB_UP  ))Water.plane(Water.plane() + Vec(0,1,0)*Tm.d()); // move water surface plane upwards
       if(Kb.b(KB_DOWN))Water.plane(Water.plane() - Vec(0,1,0)*Tm.d()); // move water surface plane downwards

       // update water waves movement
       Water.update(Vec2(0.2,0.2));

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          // When rendering water, an additional rendering mode has to be used
          // RM_SOLID_M is "rendering solid in mirrors / water surfaces" mode
          // for the most simplicity you can render the same things as in RM_SOLID mode

          case RM_SOLID  :
          case RM_SOLID_M:
             terrain.draw(MatrixIdentity);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,S+"Fps "+Tm.fps());
       D.text(0,0.8,"Press up/down keys to change water level");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\23 - Markers.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    MeshGroup terrain;
    Marker    marker[2]; // 2 markers
    /******************************************************************************/
    void InitPre()
    {
       App.name("Markers");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.3);

       Cam.pitch=-0.5;
       Cam.dist =10;
    }
    Bool Init()
    {
       terrain.load("obj/terrain/0.mshg");
       Sky .set();
       Suns.New().set(*Gfxs("gfx/sky/sun.gfx"));

       // setup markers
       REPA(marker)
       {
          Marker &m=marker[i];
          m.glow =0;
          m.color=(i ? YELLOW : RED);
          m.gfx  =Gfxs("gfx/particle/star.gfx");
          m.size =2;
          m.range_opaque=0.2;
          m.range_fade  =0.3;
          m.local_matrix.setPosDir(Vec(0,0,0), Vec(0,1,0)); // setup matrix to (0,0,0) position, facing up (0,1,0)

          // set matrix position at terrain surface
          PosPointMeshY(Vec2(i ? 1 : -1, 0),terrain,&m.local_matrix.pos);
       }
       return true;
    }
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01,500,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       // rotate markers matrix in their Z axis according to time delta
       REPA(marker)marker[i].local_matrix.orn.rotateZVec(Tm.d());

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             terrain.draw(MatrixIdentity);
          break;

          // markers can be rendered in RM_OVERLAY, RM_BLEND and RM_PALETTE modes, in this tutorial we'll use RM_BLEND
          case RM_BLEND:
             REPA(marker)marker[i].draw(MatrixIdentity);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\24 - Mesh Outline.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Material *brick,
             *glass;
    Mesh      mbox ,
              mball;
    Vec       pos[32];
    /******************************************************************************/
    void InitPre()
    {
       App.name("Depth of Field");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");
       D.full(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       brick=Materials("mtrl/brick/0.mtrl");
       glass=Materials("mtrl/glass/0.mtrl");

       mbox .create(1).base(0).create( Box(  4),VTX_TX0|VTX_NRM|VTX_TNG).reverse(); // create mesh box, reverse it because it's meant to be viewed from inside
       mball.create(1).base(0).create(Ball(0.5),VTX_TX0|VTX_NRM|VTX_TNG)          ; // create mesh ball

       // set mesh materials, rendering versions and bounding boxes
       mbox .setMaterial(brick).setRender().setBox();
       mball.setMaterial(glass).setRender().setBox();

       // set random positions inside box
       REPA(pos)pos[i]=Random(mbox.box);

       // set camera
       Cam.dist=5;

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_LIGHT:
             LightPoint(25,Vec(0,3,0)).add();
          break;

          case RM_SOLID:
             mbox.draw(MatrixIdentity);
             REPA(pos)
             {
                glass->color.v3=ColorVec(ColorHue(Flt(i)/ELMS(pos)));
                glass->validate();
                mball.draw(Matrix(pos[i]));
             }
          break;

          // when we wan't to use Mesh Outlining we need to process additional rendering mode 'RM_OUTLINE'
          case RM_OUTLINE:
             if(Kb.b(KB_SPACE)) // outline only when space pressed
             {
                Renderer.outlineUse(); // outlining mode is optional, and when used the engine needs to be notified about it
                Flt alpha=Frac(Tm.time()*2,2);
                if( alpha>1)alpha=2-alpha;
                REPA(pos) // for all balls
                {
                   UInt hue=ColorHue  (Flt(i)/ELMS(pos)),
                        col=ColorAlpha(hue,alpha);
                   SetHighlight(col);          // before drawing the mesh, set highlight color
                   mball.draw(Matrix(pos[i])); // now    draw    the mesh
                }
             }
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,"Press Space to outline the balls");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\25 - Laser and Electricity.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh mbox     ;
    Vec  point[32]; // laser can be drawn out of an array of points, this is such an array which will be filled with circle coordinates

    // instead of drawing one laser, we will render few of them, each with it's own vertical position
    struct Laser
    {
       Flt position_y,
           velocity_y;
    }laser[]=
    {
       {0, 0.4},
       {0, 0.6},
       {0, 0.8},
       {0,-0.4},
       {0,-0.6},
       {0,-0.8},
    };

    ElectricityFx electricity; // electricity effect
    /******************************************************************************/
    void InitPre()
    {
       App.name("Laser");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.full(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=3;

       // create standard meshes and materials
       Material *material=Materials("../data/mtrl/brick/0.mtrl");

       mbox.create(1).base(0).create(Box(4),VTX_TX0|VTX_NRM|VTX_TNG).reverse();
       mbox.setMaterial(material).setRender().setBox();

       // setup point array for laser
       REPA(point)
       {
          Flt angle=Lerp(PI_4, -PI-PI_4, i/Flt(ELMS(point)-1)); // linearly interpolate angle from 'i' (0..point elements)
          point[i].set(Cos(angle),0,Sin(angle));                // set point positions on a circle
       }

       // setup electricity effect control points
       electricity.original.New().set(-1,0,-1);
       electricity.original.New().set( 0,0, 1);
       electricity.original.New().set( 1,0,-1);

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,10,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // move camera on right mouse button

       // update laser positions
       REPA(laser)
       {
          Laser &l=laser[i];

           // update lasers position
           l.position_y+=l.velocity_y*Tm.d();

          // if position is too high or to low then change the sign of velocity, so the laser will start moving in a different direction
          if(l.position_y>1 || l.position_y<-1)CHS(l.velocity_y);
       }

       // update electricity
       electricity.update();

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mbox.draw(MatrixIdentity);
          break;

          case RM_LIGHT:
             LightPoint(25,Vec(0,3,0)).add();
          break;
       }

       // draw laser and electricity in RM_LIGHT and RM_SOLID modes
       switch(Renderer())
       {
          case RM_LIGHT:
          case RM_SOLID:
          {
             // draw laser
             REPA(laser)
             {
                SetMatrix(Matrix(Vec(0,laser[i].position_y,0)));                                     // setup matrix for the laser
                DrawLaser(ARGB(128,128,0,0), ARGB(128,128,0,0), 1, 0.005, false, point,ELMS(point)); // here alpha determines glow amount
             }

             // draw electricity
             SetMatrix(Matrix(Vec(0,-1.5,1)));
             electricity.draw();
          }break;
       }
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\26 - Cel Shading.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Material glass;
    Mesh     mball;
    Vec      pos[32];
    /******************************************************************************/
    void InitPre()
    {
       App.name("Cel Shading");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");
       D.full(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       // set cel shading
       D.bumpMode  (BUMP_FLAT      ); // cel-shading works best with flat bump mapping
       D.hpRt      (true           ); // cel-shading works best with high precision render targets
       D.edgeDetect(EDGE_DETECT_FAT); // set edge detection
       Renderer.cel_shade_palette=Gfxs("gfx/fx/cel light palette.gfx"); // set light palette which modifies global lighting

       // set sky, material and mesh
       Sky.set();

       glass.reset();

       mball.create(1).base(0).create(Ball(0.5),VTX_TX0|VTX_NRM|VTX_TNG);
       mball.setMaterial(glass).setRender().setBox();

       REPA(pos)pos[i]=Random(Box(8,4,8,Vec(0,2,0)));

       Cam.dist=10;

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_LIGHT:
          {
             LightDir(!Vec(1,-1,1)).add();
          }break;

          case RM_SOLID:
          {
             Mshgs("obj/terrain/0.mshg")->draw(MatrixIdentity);

             REPA(pos)
             {
                glass.color.v3=ColorVec(ColorHue(Flt(i)/ELMS(pos)));
                glass.validate();
                mball.draw(Matrix(pos[i]));
             }
          }break;
       }
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\2 - Animation, Physics, Rendering\Rendering\27 - Multi-Threaded Rendering.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include <EsenthelEngine/EsenthelEngine.h>
    /******************************************************************************

       In order to take advantage of multiple cores on your CPU, multi-threaded rendering is used.

       It works by rendering graphics on one thread, and processing data on the other.

       To avoid multi-threaded issues you need to store your game data in two versions:
          -backuped data (which contains only data required for rendering, like position and mesh)
          -normal   data (which contains all the data of your object, including position, mesh and other custom parameters)

       Multi-threaded rendering will look like this:

       +-------------------------+-----------------------+
       |        Thread 1         |        Thread 2       |
       +-------------------------+-----------------------+
       |    Backup your data     |                       |
       +-------------------------+-----------------------+
       | Process the data update |  Render 3D graphics   |
       +-------------------------+-----------------------+
       |   Wait until rendered   |                       |
       +-------------------------+-----------------------+
       |     Draw 2D graphics    |                       |
       +-------------------------+-----------------------+

       While Rendering 3D graphics on other thread:
          - you must not modify 'Viewport' viewport or activate another viewport
          - you must not modify 'Cam'      camera   or activate another camera
          - you must not call methods changing rendering matrixes/velocities (SetMatrix, SetVel, SetAngVel, CSkeleton::setMatrix)

       Note:
          Performance gains may vary depending on:
             -your system (mainly GPU & CPU - number of cores and general performance)
             -amount of calculations in update
             -amount of objects rendered

    /******************************************************************************/
    struct ObjectBackup // game object backup - contains only data required for rendering
    {
       Vec   pos;
       Mesh *mesh;

       void draw() // rendering method
       {
          mesh->draw(Matrix(pos)); // render 'mesh' at 'pos' position
       }
    };
    struct Object // game object
    {
       Flt   parameters[256];
       Vec   pos;
       Mesh *mesh;

       // note that this structure doesn't contain any rendering method, as we'll be rendering only through ObjectBackup::draw

       void backup(ObjectBackup &dst) // backup data method
       {
          // backup all data needed for rendering here
          dst.pos =pos;
          dst.mesh=mesh;
       }

       Object(){Zero(T);}
    };
    /******************************************************************************/
    Bool multi_threaded; // if multi-threaded mode

    Mesh mbox , // mesh box
         mball; // mesh sphere

    Memb<Object      > mobj       ; // Object's       memory block
    Memb<ObjectBackup> mobj_backup; // ObjectBackup's memory block
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_EARLY_Z:
          case RM_SHD_MAP:
          case RM_SOLID  :
             mbox.draw(MatrixIdentity);
             REPA(mobj_backup)mobj_backup[i].draw(); // render backuped data
          break;

          case RM_LIGHT:
             LightPoint(1,Vec(0,0.8,0)).add();
          break;
       }
    }
    void Render3D()
    {
       Renderer(Render);
    }
    void Draw2D()
    {
       D.text(0,0.9,multi_threaded ? "Multi-threaded rendering" : "Single-threaded rendering");
       D.text(0,0.8,S+"CPU Cores "+Cpu.cores());
       D.text(0,0.7,S+"Fps "      +Tm .fps  ());
       D.text(0,0.6,  "Press 1,2 to change rendering mode");
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Multi-Threaded Rendering");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak",NULL);

       D.full(true).bumpMode(BUMP_PARALLAX).shdSoft(2);
    }
    /******************************************************************************/
    Bool Init()
    {
       // create materials
       Material *brick=Materials("../data/mtrl/brick/0.mtrl");

       // create meshes
       mbox .create(1).base(0).create(Box (1   ),VTX_TX0|VTX_NRM|VTX_TNG).reverse(); // create mesh box
       mball.create(1).base(0).create(Ball(0.08),VTX_TX0|VTX_NRM|VTX_TNG)          ; // create mesh sphere

       // set mesh materials, rendering versions and bounding boxes
       mbox .setMaterial(brick).setRender().setBox();
       mball.setMaterial(brick).setRender().setBox();

       // create some objects
       REP(256)
       {
          Object &obj=mobj.New();    // create new object in container
          obj.pos =Random(mbox.box); // set it's random position
          obj.mesh=&mball;           // set it's mesh
       }

       if(Cpu.cores()>1) // if we have more than one core
       {
          StateMain.threadedSet(Render3D); // set StateMain (our current state) to have multi-threaded rendering
          multi_threaded=true;
       }

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01f,10,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       // toggle multi-threaded rendering when keys pressed
       if(Kb.bp(KB_1)){StateActive->threadedSet(NULL    ); multi_threaded=false;} // disable multi-threaded rendering when '1' pressed
       if(Kb.bp(KB_2)){StateActive->threadedSet(Render3D); multi_threaded=true ;} //  enable multi-threaded rendering when '2' pressed

       // 4 steps of multi-threaded processing
       {
          // 1st - Backup data
          mobj.backup(mobj_backup); // backup all object's to object_bkp's

          // 2nd - Start multi-threaded rendering
          StateActive->threadedStart(); // after this call, Render3D will be working on the second thread

          // 3rd - Process data update here
          REPA(mobj)
          {
             Object &obj=mobj[i];
             // do some heavy floating point operations
             REPA(obj.parameters)obj.parameters[i]+=Sqrt(Sin(i*PI)*Pow(i,i*2.0)*16);
          }

          // 4th - Stop multi-threaded rendering (if it hasn't finished yet, it will wait for it)
          if(StateActive->threadedStop())
          {
             // if we're here then multi-threaded rendering is enabled, so we need to call 2D drawing manually
             Draw2D();
          }
       }

       return true;
    }
    /******************************************************************************/
    void Draw() // if multi-threaded rendering is enabled, classic 'Draw' will not be called
    {
       Render3D();
         Draw2D();

       D.text(0,-0.9,"Rendering through 'Draw'");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\3 - Mesh\Mesh\Grass 2.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    MeshGroup  terrain        ; // terrain mesh
    Grass      grass          ; // grass   renderer
    Grass::Elm grass_elm[4096]; // single grass element
    /******************************************************************************/
    void InitPre()
    {
       App.name("Grass");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).ambPower(0.3).shdMapSize(1024);
       ViewportFull.range=50;
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=6;
       Cam.at.set(0,2,0);
       Sky .set();
       Suns.New().set(*Gfxs("gfx/sky/sun.gfx"));

       // load terrain mesh
       terrain.load("obj/terrain/0.mshg");

       // create grass renderer
       grass.create();

       // set random grass matrixes
       terrain.setFaceNormals(); // make sure terrain has face normals, since we'll need those later
       REPA(grass_elm)
       {
          Grass::Elm &elm   =grass_elm[i];
          Matrix     &matrix=elm.matrix;
                             elm.param.set(0,0,0,255); // set parameters

          matrix.setScale(Vec(0.18,0.3,0.18)).rotateY(RandomF(PI2)); // set scaled matrix and rotate it

          Vec start=Random(terrain.box); // set random position at top of the terrain mesh box
              start.y=terrain.box.max.y;

          I32 hit_face,hit_mshb,hit_mesh;
          if(SweepPointMesh(start,-Vec(0,terrain.box.h(),0),terrain,NULL,NULL,&matrix.pos,&hit_face,&hit_mshb,&hit_mesh)) // cast a ray down-wards and store contact info
          {
             Mshb &mshb=terrain.mesh(hit_mesh).base(hit_mshb);                                             // this is the Mshb that we've hit
             Vec  &nrm =((hit_face&SIGN_BIT) ? mshb.quad.nrm[hit_face^SIGN_BIT] : mshb.tri.nrm[hit_face]); // this is the face normal that we've hit
             matrix.orn*=Matrix3().setUp(nrm);                                                             // transform our grass matrix according to surface normal
             matrix.pos.y-=0.05;                                                                           // move it down a little
          }
       }

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // move camera on right mouse button
       UpdateGrassAndLeafs(); // update grass bending
       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SHD_MAP:
          case RM_SOLID  :
             terrain.draw(MatrixIdentity);          // render terrain
             grass.draw(grass_elm,ELMS(grass_elm)); // render grass
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\3 - Mesh\Mesh\Grass.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    MeshGroup terrain ; // terrain mesh
    Mesh      grass   ; // grass   mesh
    Vec       pos[600]; // grass   positions
    /******************************************************************************/
    void InitPre()
    {
       App.name("Grass");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.3).shdMapSize(1024).shdSoft(1);
       ViewportFull.range=30;
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist =6;
       Cam.pitch=-1;
       Sky .set();
       Suns.New().set(*Gfxs("gfx/sky/sun.gfx"));

       // load terrain mesh
       terrain.load("obj/terrain/0.mshg");

       // create grass mesh
       grass.create(1).base(0).createGrass(48);
       grass.setMaterial(Materials("mtrl/grass/blade.mtrl")).setRender().setBox();

       // set random positions on terrain surface
       REPA(pos)PosPointMeshY(Random(terrain.box).xz()*0.4,terrain,&pos[i]);

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // move camera on right mouse button
       UpdateGrassAndLeafs(); // update grass bending
       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SHD_MAP:
          case RM_SOLID  :
             REPA(pos)grass  .draw(Matrix(0.25,pos[i]));
                      terrain.draw(MatrixIdentity);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\3 - Mesh\Mesh\Separate parts rendering 1.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh   mesh;
    Matrix matrix;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Separate parts rendering");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.mode(800,600);
       Cam.dist=3;
    }
    /******************************************************************************/
    Bool Init()
    {
       mesh.create(3); // create mesh with room for 3 parts

       // setup #0
       {
          MeshPart &part=mesh.part(0);
          part.base.create(Ball(0.7),VTX_TX0|VTX_NRM|VTX_TNG); // create Mshb
          part.setMaterial(Materials("mtrl/brick/0.mtrl"));    // set material
          Set(part.name,"ball");                               // set name
       }

       // setup #1
       {
          MeshPart &part=mesh.part(1);
          part.base.create(Tube(0.3,3),VTX_TX0|VTX_NRM|VTX_TNG); // create Mshb
          part.setMaterial(Materials("mtrl/glass/0.mtrl"));      // set material
          Set(part.name,"tube");                                 // set name
       }

       // setup #2
       {
          MeshPart &part=mesh.part(2);
          part.base.create(Box(3,0.3,0.3),VTX_TX0|VTX_NRM|VTX_TNG); // create Mshb
          part.setMaterial(Materials("mtrl/grass/0.mtrl"));         // set material
          Set(part.name,"box");                                     // set name
       }

       mesh.setRender().setBox(); // setup mesh rendering version and bounding box
       matrix.setPos(Vec(0,0,1)); // setup object matrix with position (0,0,1)

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01f,10,CAMH_ZOOM|(Ms.b(1) ? CAMH_MOVE : CAMH_ROT));
       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear();
       LightDir(Cam.matrix.z).set();

       if(!Kb.b(KB_SPACE)) // if space not pressed
       {
          mesh.draw(matrix); // render all parts with one object matrix
       }else
       {
          // when space pressed render each part separately with different matrix
          {
             CChar8 *name[]=
             {
                "tube",
                "box",
             };
             mesh.showAll().hide(name,ELMS(name)).draw(matrix); // render all parts EXCEPT those listed in 'names'
          }
          {
             Matrix local_transformation;
                    local_transformation.setRotateX(Tm.time()/2);
             mesh.hideAll().show("tube").draw(local_transformation*matrix); // render ONLY those parts that are named "tube"
          }
          {
             Matrix local_transformation;
                    local_transformation.setRotateZ(Tm.time()/2);
             mesh.hideAll().show("box").draw(local_transformation*matrix); // render ONLY those parts that are named "box"
          }
          mesh.showAll(); // remember to un-hide all elements after separate parts rendering
       }

       D.text(0,0.8,"Hold space to render each part with different matrix");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\3 - Mesh\Mesh\Separate parts rendering 2 - Skeleton.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh     *mesh;
    Skeleton *skel;

    Flt  rifle_angle=0,
        turret_angle=0;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Separate parts rendering");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.mode(800,600).ambPower(0.5);
       Cam.dist=3;
    }
    /******************************************************************************/
    Bool Init()
    {
       mesh=Meshs    ("Obj/vehicle/tank/0.mesh");
       skel=Skeletons("Obj/vehicle/tank/0.skel");

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01f,10,CAMH_ZOOM|(Ms.b(1) ? CAMH_MOVE : CAMH_ROT));

        rifle_angle+=(Kb.b(KB_S)-Kb.b(KB_W))*Tm.d(); Clamp(rifle_angle,-0.5,0.1);
       turret_angle+=(Kb.b(KB_E)-Kb.b(KB_Q))*Tm.d();

       return true;
    }
    /******************************************************************************/
    void DrawTank(Matrix &world_matrix)
    {
       // access skeleton bones
       OrientP &rifle =skel->getBone("rifle" );
       OrientP &turret=skel->getBone("turret");

       // set local transformations
       Matrix  rifle_transform;  rifle_transform.setTransformAtPos(rifle .pos,Matrix3().setRotateX( rifle_angle));
       Matrix turret_transform; turret_transform.setTransformAtPos(turret.pos,Matrix3().setRotateY(turret_angle));

       // convert local transformations to global matrixes (which is equal to 'local transformation' * 'parent matrix')
       Matrix turret_matrix=turret_transform* world_matrix,
               rifle_matrix= rifle_transform*turret_matrix;

       // draw the mesh parts separately
       mesh->hideAll().show("rifle" ).draw( rifle_matrix);
       mesh->hideAll().show("turret").draw(turret_matrix);
       mesh->hideAll().show("hull"  ).draw( world_matrix);
       mesh->showAll();
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(0xFF6080FF);
       LightDir(Cam.matrix.z).set();

       DrawTank(MatrixIdentity);

       D.text(0,0.9,S+ "Rifle Angle : "+ rifle_angle+" (W/S to change)");
       D.text(0,0.8,S+"Turret Angle : "+turret_angle+" (Q/E to change)");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\3 - Mesh\Mesh\Separate parts rendering 3 - Controlled Skeleton.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       In this tutorial we'll render separate parts with matrixes automatically calculated by Controlled Skeleton

       CSkeleton will handle transforming child matrixes by parent matrixes

       All we need to do is:
          1. Create CSkeleton on the base of the object's Skeleton
          2. Animate the CSkeleton
          3. Render the parts using CSkeleton bone matrixes

       As for animating the CSkeleton we'll use CSkelBone's relative rotation - CSkelBone::rot which is an 'AxisRoll' object

       AxisRoll contains of:
          struct AxisRoll
          {
             Vec axis;
             Flt roll;
          };
          Where 'axis' direction determines the axis of rotation
                'axis' length    determines how much we'll rotate the object around 'axis' direction
                'roll' is an additional parameter, which determines the angle of rotation around original bone direction

       AxisRoll members when calling CSkeleton::clear() are reset {axis=Vec(0,0,0); roll=0;}

       After reseting the members we'll adjust their values according to our desired angles

    /******************************************************************************/
     Mesh     *mesh;
     Skeleton *skel;
    CSkeleton cskel;

    Flt  rifle_angle=0,
        turret_angle=0;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Separate parts rendering");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.mode(800,600).ambPower(0.5);
       Cam.dist=3;
    }
    /******************************************************************************/
    Bool Init()
    {
       mesh=Meshs    ("Obj/vehicle/tank/0.mesh");
       skel=Skeletons("Obj/vehicle/tank/0.skel");

       cskel.create(*skel); // create a controlled skeleton

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    void AnimateTank(Matrix &world_matrix) // animate the tank skeleton
    {
       cskel.clear(); // reset the rotation values
       cskel.getBone("rifle" ).rot.axis.x+= rifle_angle; // adjust rotation in X axis                        by  'rifle_angle'
       cskel.getBone("turret").rot.roll  +=turret_angle; // adjust rotation around bone's original direction by 'turret_angle'
       cskel.updateMatrix(world_matrix); // calculate the final matrixes
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01f,10,CAMH_ZOOM|(Ms.b(1) ? CAMH_MOVE : CAMH_ROT));

        rifle_angle+=(Kb.b(KB_S)-Kb.b(KB_W))*Tm.d(); Clamp(rifle_angle,-0.5,0.1);
       turret_angle+=(Kb.b(KB_E)-Kb.b(KB_Q))*Tm.d();

       AnimateTank(MatrixIdentity);

       return true;
    }
    /******************************************************************************/
    void DrawTank()
    {
       // draw the mesh parts separately
       // use calculated skeleton bone transformation matrixes
       mesh->hideAll().show("rifle" ).draw(cskel.getBone("rifle" ).matrix());
       mesh->hideAll().show("turret").draw(cskel.getBone("turret").matrix());
       mesh->hideAll().show("hull"  ).draw(cskel.                  matrix());
       mesh->showAll();
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear(0xFF6080FF);
       LightDir(Cam.matrix.z).set();

       DrawTank();

       D.text(0,0.9,S+ "Rifle Angle : "+ rifle_angle+" (W/S to change)");
       D.text(0,0.8,S+"Turret Angle : "+turret_angle+" (Q/E to change)");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\3 - Mesh\Mesh\Terrain.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Gfx       ground;
    MeshGroup mshg  ; // here MeshGroup is used instead of a Mesh (single mesh)
    /******************************************************************************/
    void InitPre()
    {
       App.name("Terrain");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.3).shdSoft(1);
       ViewportFull.range=40;
    }
    /******************************************************************************/
    void CreateMesh(Mesh &mesh)
    {
       // create random terrain heightmap
       Gfx gfx(128,128,1,GFX_I8,GFX_SOFT);
       REPD(y,gfx.y())
       REPD(x,gfx.x())gfx.pixel(x,y,Random(256)); // software images don't need to be locked/unlocked
       gfx.blur(5,false);                         // apply gaussian blur to the heightmap with 5 pixel range and no clamping

       // create terrain Mesh
       mesh.create(1).base(0).createPlane(128,128,VTX_TX0); // create 2D plane with 128x128 vertexes
       mesh.base(0).texScale(Vec2(16));                     // scale texture coordinates
       mesh.base(0).displaceZ(gfx);                         // displace vertexes Z position from heightmap
       mesh.transform(Matrix().setPos(Vec(-0.5,-0.6,-0.5)).rotateX(PI_2).scale(Vec(50,8,50))); // transform by matrix
       mesh.setNormals();                                   // recalculate normals
       mesh.setMaterial(Materials("mtrl/grass/0.mtrl"));    // set material
       mesh.setBox();                                       // set bounding box
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.at.y+=2; // move camera up

       Sky .set();
       Suns.New().set(*Gfxs("gfx/sky/sun.gfx"));

       // create mesh
       Mesh mesh;
       CreateMesh(mesh);

       // create terrain MeshGroup from standard Mesh
       mshg.create(mesh,VecI(5,1,5)); // create MeshGroup with 5x1x5 (5*1*5=25) splits (Mesh is splitted to 25 parts along axises)
       mshg.setRender();

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01f,10,CAMH_ZOOM|(Ms.b(1) ? CAMH_MOVE : CAMH_ROT));
       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             mshg.draw(MatrixIdentity);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       if(Kb.b(KB_SPACE))REPA(mshg)mshg.mesh(i).box.draw(); // draw mesh bounding boxes
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\3 - Mesh\Mesh\Tree.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Mesh tree; // tree mesh
    /******************************************************************************/
    void InitPre()
    {
       App.name("Tree");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.3);
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=14;
       Cam.at.set(0,8,0);

       Sky .set();
       Suns.New().set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor();
       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // move camera on right mouse button
       if(Kb.bp(KB_TAB))D.ambMode(!D.ambMode());                  // toggle ambient occlusion on tab pressed

       if(Kb.bp(KB_SPACE))
       {
          // create the tree
          Memb<Material*> leaf_materials; // container of leaf materials
          leaf_materials.New()=Materials("mtrl/leaf/0/0.mtrl");
          leaf_materials.New()=Materials("mtrl/leaf/0/1.mtrl");

          tree.createTree(Materials("mtrl/bark/0.mtrl"),leaf_materials)
              .setRender ();
       }
       UpdateGrassAndLeafs(); // call this to update wind bending
       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             tree.draw(MatrixIdentity);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,"Press Space to create a tree");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Demos\Auto Depth of Field.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Bool ray_hit    ; // if testing ray hit anything
    Vec  ray_hit_pos; // if hit, then this is the hit position

    Material *brick,
             *glass;
    Mesh      mbox ,
              mball,
              mcapsule;

    struct Object // object
    {
       Actor actor; // actor
       Mesh *mesh ; // mesh

       void draw() // draw
       {
          if(mesh)mesh->draw(actor.matrix());
       }
    };
    Memb<Object> obj; // objects
    /******************************************************************************/
    void InitPre()
    {
       App.name("Auto Depth of Field");
       App.flag=APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.full(true).sync(true);
       ViewportFull.range=32;
       Ms.hide();

       // set initial depth of field parameters
       D.dof(DOF_HIGH,1, 1,0,6);
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();

       // get materials
       brick=Materials("../data/mtrl/brick/0.mtrl");
       glass=Materials("../data/mtrl/glass/0.mtrl");

       // shapes used for mesh and actor creation
       Box     box (32,1,32);
       Ball    ball(0.5);
       Capsule capsule(0.3,2);

       // create meshes
       mbox    .create(1).base(0).create(box    ,VTX_TX0|VTX_NRM|VTX_TNG).texScale(Vec2(16));
       mball   .create(1).base(0).create(ball   ,VTX_TX0|VTX_NRM|VTX_TNG);
       mcapsule.create(1).base(0).create(capsule,VTX_TX0|VTX_NRM|VTX_TNG);

       // set mesh materials, rendering versions and bounding boxes
       mbox    .setMaterial(brick).setRender().setBox();
       mball   .setMaterial(glass).setRender().setBox();
       mcapsule.setMaterial(brick).setRender().setBox();

       // create objects
       {
          // ground
          {
             Object &o=obj.New();
             o.mesh=&mbox;
             o.actor.create(box,0).pos(Vec(0,-box.h()/2,0));
          }

          // pillars
          REPD(x,16)
          REPD(z,16)
          {
             Object &o=obj.New();
             o.mesh=&mcapsule;
             o.actor.create(capsule,0).pos(Vec(box.lerpX(x/15.0),capsule.h/2-capsule.r,box.lerpZ(z/15.0)));
          }

          // balls
          REP(100)
          {
             Object &o=obj.New();
             o.mesh=&mball;
             o.actor.create(ball).pos(Vec(box.lerpX(RandomF()),ball.r+capsule.h,box.lerpZ(RandomF())));
          }
       }

       // set initial camera
       Cam.setAngle(Vec(0,2,0),0,-0.2).set();

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Physics.sim().get();

       // update camera
       {
          if(Kb.b(KB_A    ))Cam.matrix.pos-=Cam.matrix.x*Tm.d();
          if(Kb.b(KB_D    ))Cam.matrix.pos+=Cam.matrix.x*Tm.d();
          if(Kb.b(KB_W    ))Cam.matrix.pos+=Cam.matrix.z*Tm.d();
          if(Kb.b(KB_S    ))Cam.matrix.pos-=Cam.matrix.z*Tm.d();
          if(Kb.b(KB_SPACE))Cam.matrix.pos+=Cam.matrix.y*Tm.d();
          if(Kb.b(KB_LCTRL))Cam.matrix.pos-=Cam.matrix.y*Tm.d();
          if(Ms.hidden())
          {
             Cam.yaw  -=Ms.dir_d.x;
             Cam.pitch+=Ms.dir_d.y;
          }
          Cam.setAngle(Cam.matrix.pos,Cam.yaw,Cam.pitch).updateVelocities().set();
       }

       // toggle mouse
       if(Kb.bp(KB_TAB))Ms.toggle();

       // test ray
       {
          Flt     new_z; // new Z focus
          PhysHit phys_hit;
          Vec     pos,dir;

          if(Ms.hidden())
          {
             pos=Cam.matrix.pos;
             dir=Cam.matrix.z;
          }else
          {
             ScreenToPosDir(Ms.pos,pos,dir);
          }

          if(Physics.ray(pos,dir*Viewport.range,&phys_hit)) // cast a ray from camera and check if it hits something
          {
             ray_hit    =true;
             ray_hit_pos=phys_hit.plane.p;
             new_z      =phys_hit.dist; //set new z focus to ray hit distance
          }else
          {
             ray_hit=false;
             new_z  =Viewport.range; // set new z focus to viewport range
          }

          // set new depth of field z focus
          D.dofZ(LerpTime(D.dofZ(),new_z,0.001));
       }

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID:
             REPAO(obj).draw();
          break;

          case RM_LIGHT:
             LightDir(!Vec(1,-1,1)).add();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);

       if(ray_hit)
       {
          SetMatrix();
          Ball(0.1,ray_hit_pos).draw();
       }

       D.text(0,0.9,"Press Tab to toggle mouse, WSAD+Space+Control to move camera");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Demos\Day Night Cycle.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    MeshGroup terrain; // terrain mesh
    Flt       hour   ; // current hour
    /******************************************************************************/
    void InitPre()
    {
       App.name("Nature");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.2).hpRt(true).shdSoft(1).shdMapSize(1024);
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=6;
       Cam.at.set(0,2,0);
       Sky .set();
       Suns.New().set(*Gfxs("gfx/sky/sun.gfx")).rays.mode=SUN_RAYS_HIGH;

       // load terrain mesh
       terrain.load("obj/terrain/0.mshg");

       // set initial hour
       hour=5;

       // load clouds
       Clouds.layered.set(3,Gfxs("Clouds/Layers/0.gfx"));
       REPAO(Clouds.layered.layer).velocity*=4;

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // move camera on right mouse button

       // update hour
       hour+=Tm.d()*2;

       // set sun position
       Sun &sun=Suns[0];
       SinCos(sun.pos.y,sun.pos.x,hour/24*PI2-PI_2); sun.pos.z=0;
       sun.pos*=Matrix3().setRotateY(PI-PI_4);

       // tweak the sun to rise earlier, and set later
       sun.pos.y+=0.5;
       sun.pos.normalize();

       // set sun color
       Flt power=Sat(Cbrt(sun.pos.y));
       sun.light_color=power;

       // set sky color
       Vec   night_color(0.02,0.04,0.10),
           horizon_color(0.35,0.45,0.64),
               sky_color(0.30,0.38,0.54);
       Sky.set(Lerp(night_color,horizon_color,power),sky_color*power);

       // update clouds
       Clouds.layered.update();
       REP(Clouds.layered.layers())Clouds.layered.layer[i].color=ColorBrightness(power);

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SHD_MAP:
          case RM_SOLID  :
             terrain.draw(MatrixIdentity); // render terrain
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,S+"Hour "+(Trunc(hour)%24));
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Demos\Facial Animation.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    CSkeleton cskel;
    Mesh     *mesh;

    Window   window;
    Text     text  [5];
    Slider   slider[4];
    CheckBox blink;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Facial Animation");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.2).shdMode(SHD_MAP_HW).shdSoft(1).shdMapSize(1024).hpRt(true);
       ViewportFull.range=8;
    }
    /******************************************************************************/
    Bool Init()
    {
       // camera
       Cam.dist=0.4;
       Cam.at.set(0,0.75,0);
       Cam.yaw=PI;
       Cam.setSpherical().set();

       // sun
       Sun &sun=Suns.New();
       sun.set(*Gfxs("gfx/sky/sun.gfx"));
       sun.pos        =!Vec(1,1,3);
       sun.light_color=1-D.ambColor();

       // sky
       Sky.set();

       // character
       cskel.create("obj/chr/human/0.skel",1.8);
       mesh=Meshs  ("obj/chr/human/0.mesh");

       // gui
       Gui   +=window .create(Rect_R(D.w(),0,0.49,0.50),"Expressions");
       window+=text[0].create(Vec2(0.13,-0.05),"Angry"     ); window+=slider[0].create(Rect_L(0.26,-0.05,0.2 ,0.05));
       window+=text[1].create(Vec2(0.13,-0.13),"Astonished"); window+=slider[1].create(Rect_L(0.26,-0.13,0.2 ,0.05));
       window+=text[2].create(Vec2(0.13,-0.21),"Sad"       ); window+=slider[2].create(Rect_L(0.26,-0.21,0.2 ,0.05));
       window+=text[3].create(Vec2(0.13,-0.29),"Smile"     ); window+=slider[3].create(Rect_L(0.26,-0.29,0.2 ,0.05));
       window+=text[4].create(Vec2(0.13,-0.37),"Blink"     ); window+=blink    .create(Rect_L(0.26,-0.37,0.05,0.05),true);

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Gui.update();

       // animate
       Flt time=Tm.time();
       cskel.clear  ()
            .animate(L"anim/face/angry.anim"     ,time,slider[0]())
            .animate(L"anim/face/astonished.anim",time,slider[1]())
            .animate(L"anim/face/sad.anim"       ,time,slider[2]())
            .animate(L"anim/face/smile.anim"     ,time,slider[3]());

       if(blink())
       {
          Flt blend=Frac(time,3); // blink every      3   seconds
              blend/=0.1;         // blink duration = 0.1 seconds
          if( blend>1)blend=2-blend;
          cskel.animate(L"anim/face/blink.anim",time,blend,true);
       }

       cskel.updateMatrix(MatrixIdentity)
            .updateVelocities();

       if(!Gui.window_lit && Ms.b(0))CamHandle(0.01,10,CAMH_ZOOM|CAMH_ROT);

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SOLID  :
          case RM_SHD_MAP:
             mesh->draw(cskel);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       Gui.draw();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Demos\Lights.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    Int      lights=3   ; // number of lights (1..3)
    Material material   ; // material light
    Mesh     mbox       , // mesh box
             mball      , // mesh ball
             mlight     , // mesh light
             mballs     ; // mesh ball (shadow stencil version)
    Vec      ball_pos[8], // ball  positions
            light_pos[3]; // light positions
    /******************************************************************************/
    void SetEffect()
    {
       mbox .setEffect();
       mball.setEffect();
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Lights Rendering Demo");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       PakAdd("../data/engine.pak");

       D.set_effect=SetEffect;
       D.full(true).bumpMode(BUMP_RELIEF).shdSoft(1).shdJitter(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       // create materials
       Material *brick=Materials("../data/mtrl/brick/0.mtrl");
       material.reset();
       material.glow=0.6;
       material.ambient=1;

       // create meshes
       mbox  .create(1).base(0).create( Box(1   ),VTX_TX0|VTX_NRM|VTX_TNG).reverse(       ); // create mesh box , reverse it because it's meant to be viewed from inside
       mball .create(1).base(0).create(Ball(0.15),VTX_TX0|VTX_NRM|VTX_TNG).weldVal(VTX_POS); // create mesh ball, weld it's vertex positions (stencil shadows are very sensitive to even the smallest irregularities)
       mlight.create(1).base(0).create(Ball(0.04));

       // set mesh materials, rendering versions and bounding boxes
       mbox  .setMaterial( brick   ).setRender().setBox();
       mball .setMaterial( brick   ).setRender().setBox();
       mlight.setMaterial(&material).setRender().setBox();

       // create stencil shadow version of ball mesh
       mballs.create(mball).toStencilShadow();

       // set random positions
       REPA(ball_pos)ball_pos[i]=Random(Box(0.9));

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.01f,10,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       // update light positions when space is not pressed
       if(!Kb.b(KB_SPACE))
       {
          static Flt t; t+=Tm.d()/2;
          light_pos[0].set(0,0,0.3); light_pos[0]*=Matrix3().setRotateX(t).rotateY(t/2  ).rotateZ(t/3  );
          light_pos[1].set(0,0,0.6); light_pos[1]*=Matrix3().setRotateX(t).rotateY(t/1.5).rotateZ(t/2.5);
          light_pos[2].set(0,0,0.5); light_pos[2]*=Matrix3().setRotateX(t).rotateY(t/1.3).rotateZ(t/3.2);
       }

       // change settings
       if(Kb.c('1'))lights=1;
       if(Kb.c('2'))lights=2;
       if(Kb.c('3'))lights=3;

       if(Kb.c('q'))D.shdMode(SHD_NONE);
       if(Kb.c('w'))D.shdMode(SHD_MAP    ).shdSoft(0);
       if(Kb.c('e'))D.shdMode(SHD_MAP    ).shdSoft(1);
       if(Kb.c('r'))D.shdMode(SHD_MAP_HW ).shdSoft(0);
       if(Kb.c('t'))D.shdMode(SHD_MAP_HW ).shdSoft(1);
       if(Kb.c('y'))D.shdMode(SHD_STENCIL).shdSoft(0);
       if(Kb.c('u'))D.shdMode(SHD_STENCIL).shdSoft(1);

       if(Kb.c('a'))D.bumpMode(BUMP_FLAT    );
       if(Kb.c('s'))D.bumpMode(BUMP_NORMAL  );
       if(Kb.c('d'))D.bumpMode(BUMP_PARALLAX);
       if(Kb.c('f'))D.bumpMode(BUMP_RELIEF  );

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SHD_STENCIL:
             REPA(ball_pos)mballs.draw(Matrix(ball_pos[i]));
          break;

          case RM_EARLY_Z:
          case RM_SHD_MAP:
          case RM_SOLID  :
          {
                           mbox .draw(MatrixIdentity);
             REPA(ball_pos)mball.draw(Matrix(ball_pos[i]));

             if(Renderer()!=RM_SHD_MAP) // don't render light balls in shadow mapping mode - this will disable casting shadows for them
             {
                              material.color.v3.set(1  ,1,0.5); material.validate(); mlight.draw(Matrix(light_pos[0]));
                if(lights>=2){material.color.v3.set(0.5,1,1  ); material.validate(); mlight.draw(Matrix(light_pos[1]));}
                if(lights>=3){material.color.v3.set(0.5,1,0.5); material.validate(); mlight.draw(Matrix(light_pos[2]));}
             }
          }break;

          case RM_LIGHT:
          {
             REP(lights)mlight.draw(Matrix(light_pos[i]));

             switch(lights)
             {
                case 1:
                   LightPoint(0.50,light_pos[0],Vec(1)).add();
                break;

                case 2:
                   LightPoint(0.45,light_pos[0],Vec(1,0.5,0.0)).add();
                   LightPoint(0.45,light_pos[1],Vec(0,0.5,1.0)).add();
                break;

                case 3:
                   LightPoint(0.40,light_pos[0],Vec(1  ,0.3,0.0)).add();
                   LightPoint(0.40,light_pos[1],Vec(0.0,0.3,1  )).add();
                   LightPoint(0.40,light_pos[2],Vec(0.0,0.4,0.0)).add();
                break;
             }
          }break;
       }
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Demos\Nature.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************/
    const Bool hi_quality=true; // change to false to disable hi-quality settings
    /******************************************************************************/
    MeshGroup terrain; // terrain mesh
    Mesh      tree[4]; // tree    mesh
    Grass     grass  ; // grass   renderer

    Grass::Elm grass_elm   [hi_quality ? 5000 : 3000]; // single grass element
    Matrix      tree_matrix[hi_quality ?   20 :   10]; // tree  matrixes
    /******************************************************************************/
    void InitPre()
    {
       App.name("Nature");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).ambPower(0.35).hwDepthBuffer(true).shdMode(SHD_MAP_HW);

       if(hi_quality)
       {
          D.hdr(true).hpRt(true).bumpMode(BUMP_PARALLAX).hdrExposure(0.7).bloomOverbright(true)
           .ambMode(AMB_LOW).ambRange(0.05).ambHalfRes(true)
           .shdSoft(1).shdMapSize(1024).shdJitter(true).grassShadow(true)
           .mtnMode(MTN_HIGH);

          ViewportFull.range=50;
       }else
       {
          D.bendLeafs(false);
          ViewportFull.range=35;
       }
    }
    /******************************************************************************/
    Bool Init()
    {
       Cam.dist=6;
       Cam.at.set(0,2,0);
       Sky.set();

       // set sun
       Sun &sun=Suns.New();
       sun.set(*Gfxs("gfx/sky/sun.gfx"));
       sun.light_color=1-D.ambColor();
       sun.rays.mode  =(hi_quality ? SUN_RAYS_HIGH : SUN_RAYS_LOW);

       // set water
       if(hi_quality)
       {
          Water.set  (*Gfxs("gfx/water/0.gfx"),*Gfxs("gfx/water/0.n.gfx"),Gfxs("gfx/fx/reflection.gfx"));
          Water.plane(Water.plane()-Vec(0,0.8,0));
          Water.wave_scale=0.3;
       }

       // load clouds
       Clouds.layered.set(3,Gfxs("Clouds/Layers/0.gfx"));

       // load terrain mesh
       terrain.load("obj/terrain/0.mshg");

       // create tree meshes
       Memb<Material*> leaf_materials;
       leaf_materials.New()=Materials("mtrl/leaf/0/0.mtrl");
       leaf_materials.New()=Materials("mtrl/leaf/0/1.mtrl");
       REPA(tree)tree[i].createTree(Materials("mtrl/bark/0.mtrl"),leaf_materials).scale(Vec(0.5)).setRender();

       // create grass renderer
       grass.create();

       // set tree matrixes
       REPA(tree_matrix)
       {
          tree_matrix[i].setRotateY(RandomF(PI2));                             // set matrix from random Y rotation
          PosPointMeshY(Random(terrain.box).xz(),terrain,&tree_matrix[i].pos); // set random position on surface
          tree_matrix[i].pos.y-=0.1;                                           // move it down a little
       }

       // set random grass matrixes
       terrain.setFaceNormals(); // make sure terrain has face normals, since we'll need those later
       REPA(grass_elm)
       {
          Grass::Elm &elm    =grass_elm[i];
          Matrix      &matrix=elm.matrix;
                              elm.param.set(0,0,0,Random(16,128)); // set parameters

          matrix.setScale(Vec(0.18,0.3,0.18)).rotateY(RandomF(PI2)); // set scaled matrix and rotate it

          Vec start  =Random(terrain.box); // set random position at top of the terrain mesh box
              start.y=terrain.box.max.y;

          I32 hit_face,hit_mshb,hit_mesh;
          if(SweepPointMesh(start,-Vec(0,terrain.box.h(),0),terrain,NULL,NULL,&matrix.pos,&hit_face,&hit_mshb,&hit_mesh)) // cast a ray down-wards and store contact info
          {
             Mshb &mshb=terrain.mesh(hit_mesh).base(hit_mshb);                                             // this is the Mshb that we've hit
             Vec  &nrm =((hit_face&SIGN_BIT) ? mshb.quad.nrm[hit_face^SIGN_BIT] : mshb.tri.nrm[hit_face]); // this is the face normal that we've hit
             matrix.orn  *=Matrix3().setUp(nrm);                                                           // transform our grass matrix according to surface normal
             matrix.pos.y-=0.05;                                                                           // move it down a little
          }
       }

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(0)?CAMH_MOVE_XZ:(Ms.b(1)?CAMH_MOVE:CAMH_ROT))); // move camera on left/right mouse button
       Clouds.layered.update();
       Water .        update(Vec2(0.2));
       UpdateGrassAndLeafs();

       if(Kb.bp(KB_F10))Renderer.screenShots("ScreenShot/","bmp");

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       switch(Renderer())
       {
          case RM_SHD_MAP:
          case RM_SOLID  :
          case RM_SOLID_M:
             terrain.draw(MatrixIdentity);                             // render terrain
             REPA(tree_matrix)tree[i%ELMS(tree)].draw(tree_matrix[i]); // render trees
             grass.draw(grass_elm,ELMS(grass_elm));                    // render grass
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,S+"Fps "+Tm.fps());
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\01 - Character.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       Define your custom player character class basing on already defined Game::Chr
       Game::Chr is a class which handles the most basic character methods
       including : movement, animations, physics and actions

    /******************************************************************************/
    struct Player : Game::Chr // extend character class by defining a player class based on the character
    {
       virtual Bool update(); // here we'll update the player (please note that this is a virtual method)
    };
    /******************************************************************************/
    Bool Player::update()
    {
       // here we update character input according to mouse and keyboard
       // before we set the input, we need to check if the character isn't controlled by an automatic action
       if(action)
       {
          // if it's controlled by an action we leave the input with no changes,
          // however we can optionally break that action, by pressing for example movement keys
          if(Kb.b(KB_W) || Kb.b(KB_S) || Kb.b(KB_A) || Kb.b(KB_D) || Kb.b(KB_Q) || Kb.b(KB_E))actionBreak();
       }

       if(!action) // if the character isn't controlled by an automatic action, we can set the input
       {
          // turn & move
          input.anglei.x=Kb.b(KB_Q)-Kb.b(KB_E);
          input.anglei.y=Kb.b(KB_T)-Kb.b(KB_G);
          input.diri  .x=Kb.b(KB_D)-Kb.b(KB_A);
          input.diri  .z=Kb.b(KB_W)-Kb.b(KB_S);
          input.diri  .y=Kb.b(KB_SPACE)-Kb.b(KB_LSHIFT);

          // dodge, crouch, walk, jump
          input.dodge = Kb.bd(KB_D)-Kb.bd(KB_A);
          input.crouch= Kb.b (KB_LSHIFT);
          input.walk  = Kb.b (KB_LCTRL );
          input.jump  =(Kb.bp(KB_SPACE) ? 3.5 : 0);

          // mouse turn
          Flt max=DegToRad(900)*Tm.d(),
              dx =Ms.dir_ds.x*1.7,
              dy =Ms.dir_ds.y*1.7*Ms.inv();
          angle.x-=Mid(dx,-max,max);
          angle.y+=Mid(dy,-max,max);

          // ready stance change
          ready^=Kb.bp(KB_R);
       }

       return __super::update(); // call Game::Chr::update on which Player is based on
    }
    /******************************************************************************/
    Actor  ground; // ground actor
    Player player; // player
    /******************************************************************************/
    void InitPre()
    {
       App.name("Game Character");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true);

       Cam.dist=5;
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       ground .create(Box(15,1,15,Vec(0,-2,0)),0);

       player.create(0.45, 1.8, Vec(0,0,0), *Meshs("obj/chr/human/0.mesh"), *Skeletons("obj/chr/human/0.skel"), 1.8); // create player by radius, height, position, mesh, skeleton and mesh/skeleton scale

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Physics.sim().get();

       player.update(); // update player

       Cam.setSpherical(player.ctrl.actor.pos()+Vec(0,1,0),player.angle.x,player.angle.y,0,Cam.dist*ScaleFactor(Ms.wheel*-0.2)).updateVelocities().set(); // update camera according to player angles and mouse wheel

       return true;
    }
    /******************************************************************************/
    void Draw()
    {
       D.clear();
       LightDir(Cam.matrix.z).set();

       ground.draw(); // draw ground actor
       player.draw(); // draw player
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\02 - World.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

        When writing applications with worlds, you need to additionaly include all the Headers generated by the World Editor
        these Headers are stored in the "enum/_enums.h" file in your Game Data folder
        for more information about Enums and Headers please check World Editor documentation

    /******************************************************************************/
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    Game::ObjMemx<Game::Static> Statics; // container for static    objects
    Game::ObjMemx<Game::Item  > Items;   // container for item      objects
    Game::ObjMemx<Game::Chr   > Chrs;    // container for character objects
    /******************************************************************************/
    void InitPre()
    {
       App.name("World Manager");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024);

       Cam.dist =10;
       Cam.yaw  =-PI_4;
       Cam.pitch=-0.5;
       Cam.at.set(16,0,16);
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();

       Game::World.init(); // initialize world, optionally you can change default parameters here

       // once the world is initialized, we need to tell the world 'which class handles which type'
       // this is done by assigning memory containers to certain Object Types defined in Game Enums (which were used in the World Editor)
       Game::World.setType(Statics,OBJ_STATIC)  // set 'Statics' memory container for 'OBJ_STATIC' objects
                  .setType(Items  ,OBJ_ITEM  )  // set 'Items'   memory container for 'OBJ_ITEM'   objects
                  .setType(Chrs   ,OBJ_CHR   ); // set 'Chrs'  ' memory container for 'OBJ_CHR'    objects

       // now when the engine is set up properly we can start a 'new game' with a builded world
       Game::World.New("world/sample"); // create the world by giving path to builded world

       // when the world is loaded it doesn't actually load all the terrain and objects into memory
       // it loads only information about them
       // you need to tell the world which terrain and objects you need to use at the moment
       // to do that call:
       Game::World.update(Cam.at); // which updates world to use only terrain and objects at given position, here camera position is used

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       Game::World.update(Cam.at); // update the world to given position

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw(); // draw world (this is done outside of 'switch(Renderer())' because world automatically detects active rendering mode)

       switch(Renderer())
       {
          case RM_LIGHT:
             LightDir(!Vec(1,-1,1)).add();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\03 - World with Character.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************

       In this tutorial is presented how to combine extending base classes with World Manager usage

    /******************************************************************************/
    struct Player : Game::Chr // extend character structure by defining a player class based on the character
    {
       Memx<Game::Item> item;                          // here is the characters inventory, a container of items
       virtual _Memx*   itemContainer(){return &item;} // override default method of character, to return proper item container

               void updateItems(); // update items actions
       virtual Bool update     (); // here we'll update the player
    };
    /******************************************************************************/
    Game::ObjMemx<Game::Static> Statics; // container for static objects
    Game::ObjMemx<Game::Item  > Items  ; // container for item   objects
    Game::ObjMemx<      Player> Players; // container for player objects
    /******************************************************************************/
    void Player::updateItems()
    {
       if(Kb.bp(KB_1)) // try to pickup an item
          if(Items.elms()) // if world items container has some elements
             itemPickUp(Items[0]); // pick up the first valid item

       if(Kb.bp(KB_2)) // try to drop down an item
          if(item.elms()) // if inventory has some items
             itemDropDown(item[0]); // drop down the first item

       if(!Kb.alt)grabStop();else // if don't want to grab
       {
          if(grab.is()) // if already grabbing
          {
             Vec pos;
             SinCos(pos.z,pos.x,angle.x+PI_2); // set direction according to player angle
             pos *=ctrl.radius()+0.5;          // set radius    according to player controller radius
             pos.y=ctrl.height()*0.4;          // set vertical  position
             pos +=T.pos();
             grab.pos(pos);                    // set desired grab position
          }else
          if(Items.elms()) // if isn't grabbing anything check for presence of world items
          {
             grabStart(Items[0]); // grab first present
          }
       }
    }
    /******************************************************************************/
    Bool Player::update()
    {
       if(action)
       {
          if(Kb.b(KB_W) || Kb.b(KB_S) || Kb.b(KB_A) || Kb.b(KB_D) || Kb.b(KB_Q) || Kb.b(KB_E))actionBreak();
       }

       if(!action)
       {
          // turn & move
          input.anglei.x=Kb.b(KB_Q)-Kb.b(KB_E);
          input.anglei.y=Kb.b(KB_T)-Kb.b(KB_G);
          input.diri  .x=Kb.b(KB_D)-Kb.b(KB_A);
          input.diri  .z=Kb.b(KB_W)-Kb.b(KB_S);
          input.diri  .y=Kb.b(KB_SPACE)-Kb.b(KB_LSHIFT);

          // dodge, crouch, walk, jump
          input.dodge = Kb.bd(KB_D)-Kb.bd(KB_A);
          input.crouch= Kb.b (KB_LSHIFT);
          input.walk  = Kb.b (KB_LCTRL );
          input.jump  =(Kb.bp(KB_SPACE ) ? 3.5 : 0);

          // mouse turn
          Flt max=DegToRad(900)*Tm.d(),
              dx =Ms.dir_ds.x*1.7,
              dy =Ms.dir_ds.y*1.7*Ms.inv();
          angle.x-=Mid(dx,-max,max);
          angle.y+=Mid(dy,-max,max);

          // ready stance change
          ready^=Kb.bp(KB_R);
       }

       updateItems();
       return __super::update();
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("World with Character");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024);
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.scale*=0.8;

       Physics.create();

       // create the world
       Game::World.init()
                  .setType(Statics,OBJ_STATIC)
                  .setType(Players,OBJ_CHR   ) // please note that here we'll use 'Players' memory container for 'OBJ_CHR' objects
                  .setItem(Items  ,OBJ_ITEM  ) // please note that here is called 'setItem' instead of 'setType', this is used for enabling built-in character<->item relations such as picking up and dropping items
                  .New("world/sample"        );

       Cam.setSpherical(Vec(16,0,16),-PI_4,-0.5,0,10).set(); // set initial camera

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Game::World.update(Cam.at); // update world to given position

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();

       switch(Renderer())
       {
          case RM_LIGHT:
             LightDir(!Vec(1,-1,1)).add();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
                         D.text(0,0.9,"Press WSAD keys to move, 1/2 to pick up/drop item, Alt to grab");
       if(Players.elms())D.text(0,0.8,S+"Items in inventory : "+Players[0].item.elms());
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\04 - Lights.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************

       In this tutorial is presented how to use lighting created in World Editor
       Here 2 light sources are used:
          1st is a static light defined in a constant position in the World Editor
          2nd is a light stored in a candle object, as a sub-object

    /******************************************************************************/
    struct Item : Game::Item // extend game items
    {
       Game::LightPoint light_point; // point light

       virtual void create(Game::ObjParams &obj); // extend creation
       virtual void draw  (       );              // extend drawing
       virtual void save  (File &f);              // extend saving
       virtual Bool load  (File &f);              // extend loading
    };
    /******************************************************************************/
    void Item::create(Game::ObjParams &obj)
    {
       __super::create(obj); // default create

       // add custom children
       for(Game::ObjParams *cur=&obj; cur; cur=cur->base()) // check 'obj' and all its bases
          FREPA(cur->sub_obj) // for each sub-object in 'cur'
          {
             Game::ObjParams &o=cur->sub_obj[i];

             switch(Game::World.objType(o.type())) // check the type of sub-object
             {
                case OBJ_LGT_PNT: // if its light, then create our member from its parameters
                   light_point.create(o);
                break;
             }
          }
    }
    /******************************************************************************/
    void Item::draw()
    {
       if(0) // optionally you can disable shadow casting of the item, when the item is the light source
       {
          if(Renderer()==RM_SHD_MAP && CurrentLight.src==&light_point)return; // if in shadowing mode and current light source is 'light_point' then don't draw anything
       }

       __super ::  draw(              ); // default draw
       light_point.draw(actor.matrix()); // draw light with item's matrix
    }
    /******************************************************************************/
    void Item::save(File &f)
    {
       __super::save(f); // save default data

       light_point.save(f); // save point light
    }
    Bool Item::load(File &f)
    {
       if(__super::load(f)) // load default data
       {
          light_point.load(f); // load point light
          return true;
       }
       return false;
    }
    /******************************************************************************/
    Game::ObjMemx<Item            > Items;
    Game::ObjMemx<Game::LightPoint> LightPoints; // container for point light objects
    /******************************************************************************/
    void InitPre()
    {
       App.name("Lights");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024);

       Cam.dist =10;
       Cam.yaw  =-PI_4;
       Cam.pitch=-0.5;
       Cam.at.set(16,0,16);
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();

       Game::World.init   (                       )
                  .setType(Items      ,OBJ_ITEM   )
                  .setType(LightPoints,OBJ_LGT_PNT)
                  .New    ("world/lights"         )
                  .update (Cam.at                 );

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       Game::World.update(Cam.at);

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\05 - Saving and Loading.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************

       In this tutorial is presented how to save and load World states

    /******************************************************************************/
    Game::ObjMemx<Game::Item> Items;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Lights");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3);

       Cam.dist =10;
       Cam.yaw  =-PI_4;
       Cam.pitch=-0.5;
       Cam.at.set(16,0,16);
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set();
       Sun &sun=Suns.New(); sun.set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor(); sun.pos.set(0,1,0);

       Game::World.init   (               )
                  .setType(Items,OBJ_ITEM )
                  .New    ("world/barrels")
                  .update (Cam.at         );

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       if(Kb.bp(KB_F2))Game::World.save("LocalData/save.sav"); // save game
       if(Kb.bp(KB_F3))Game::World.load("LocalData/save.sav"); // load game

       Game::World.update(Cam.at);

       // add some velocity to objects
       if(Kb.bp(KB_SPACE))REPA(Items)Items[i].actor.addVel(5*Random.dir(Vec(0,1,0),0.7));

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,"Press F2 to save and F3 to load");
       D.text(0,0.8,"Press Space to add velocity");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\06 - Pathfind.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    Game::ObjMemx<Game::Chr   > Chrs   ;
    Game::ObjMemx<Game::Static> Statics;

    Marker marker; // marker pointing character destination target
    /******************************************************************************/
    void InitPre()
    {
       App.name("Pathfind");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3);

       ViewportFull.range=50;
       Cam.dist = 10;
       Cam.yaw  =-PI_4;
       Cam.pitch=-PI_3;
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Suns   .New   ().set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor();

       Game::World.init   (                  )
                  .setType(Chrs   ,OBJ_CHR   )
                  .setType(Statics,OBJ_STATIC)
                  .New    ("world/path"      )
                  .update (Cam.at            );

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Game::World.update(Cam.at);

       // move player
       if(Ms.bp(0) && Chrs.elms()) // on LMB pressed
       {
          Vec     pos,dir ; ScreenToPosDir(Ms.pos,pos,dir); // convert screen mouse position to world position and direction
          PhysHit phys_hit;
          if(Physics.ray(pos,dir*Viewport.range,&phys_hit)) // if ray-test hit something
          {
             Chrs[0].actionMoveTo(phys_hit.plane.p); // order character to move to that location

             marker.color=YELLOW;
             marker.size=2;
             marker.range_opaque=0.1;
             marker.range_fade  =0.2;
             marker.gfx=Gfxs("gfx/particle/star.gfx");
             marker.local_matrix.setPosDir(phys_hit.plane.p,Vec(0,1,0));
          }
       }

       // rotate camera
       if(Ms.b(1))
       {
          Cam.yaw  -=Ms.dir_d.x;
          Cam.pitch+=Ms.dir_d.y;
       }
       Cam.setSpherical(Chrs[0].pos(),Cam.yaw,Cam.pitch,0,Cam.dist*ScaleFactor(Ms.wheel*-0.2)).updateVelocities().set();

       // rotate marker around its z axis
       marker.local_matrix.orn.rotateZVec(Tm.d());

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();

       switch(Renderer())
       {
          case RM_BLEND:
             if(Chrs[0].action==Game::ACTION_MOVE_TO)marker.draw(MatrixIdentity);
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);

       // show blocked places
       if(Kb.b(KB_SPACE)) // if space pressed
          if(Chrs.elms()) // if at least one character is available
       {
          Vec   pos     =Chrs[0].pos(); // get character position
          VecI2 area_pos=Game::World.worldToAreaPos(pos); // convert from world position to area coordinates
          if(const Game::Area::Path *path=Game::World.pathGet(area_pos)) // if found paths at given coordinates
          {
             D.clearZ (); // clear Z Buffer
             SetMatrix(); // reset drawing matrix

             Vec world_pos=Game::World.areaToWorldPos(area_pos).x0y();  // convert 2D Area Coordinates to 3D World Position
             Flt cell_size=(1.0f/AREA_PATH_RES)*Game::World.areaSize(); // get size of a single path cell

             VI.color(ColorAlpha(RED,0.5f)); // set drawing color to transparent RED
             REPD(y,AREA_PATH_RES)
             REPD(x,AREA_PATH_RES)if(!path->walkable(x,y)) // if current cell isn't walkable
             {
                Vec pos=world_pos+Vec(x,0,y)*cell_size; // get world position of a single path cell

                VI.quad(pos+Vec(        0,0,cell_size), // draw a quad which extends 'pos' to right and forward by 'cell_size'
                        pos+Vec(cell_size,0,cell_size),
                        pos+Vec(cell_size,0,        0),
                        pos+Vec(        0,0,        0));
             }
             VI.end();
          }
       }

       // informations
       D.text(0,0.9,"Press LMB to move player, RMB to rotate camera");
       D.text(0,0.8,"Press Space to show blocked places at character position");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\07 - Doors.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    struct Door : Game::Door // extend doors
    {
       virtual void draw(); // extend default drawing, we'll use it to enable door highlighting
    };

    struct Chr : Game::Chr // extend characters
    {
       virtual Bool update(); // extend default updating, we'll use it to detect if when moving there are some closed doors which we'll open automatically
    };
    /******************************************************************************/
    Game::ObjMemx<      Chr   > Chrs   ;
    Game::ObjMemx<      Door  > Doors  ; // container for door objects
    Game::ObjMemx<Game::Static> Statics;

    Game::Obj *Object; // game object under mouse cursor
    /******************************************************************************/
    void Door::draw() // extended door drawing
    {
       if(Object==this && Renderer()==RM_SOLID)SetHighlight(ARGB(0,30,30,30)); // if the objects is the one under cursor, enable highlight before drawing it
       __super::draw();                        // default draw
       if(Renderer()==RM_SOLID)SetHighlight(); // clear highlight to zero
    }
    /******************************************************************************/
    Bool Chr::update() // extended character updating
    {
       if(__super::update())
       {
          // we wan't to detect if a player is moving to a destination path, and if on its way there is a closed door
          if(action==Game::ACTION_MOVE_TO) // if we're in automatic action move to
          {
             // setup movement direction
             Vec dir;
             dir.y=0;
             SinCos(dir.z,dir.x,angle.x+PI_2); // 'dir' is the direction where the player is moving at the moment

             // setup a ball at characters position
             Ball ball(ctrl.radius(),pos());

             // sweep for an obstacle
             PhysHit phys_hit;
             if(Physics.sweep(ball,dir,&phys_hit,IndexToFlag(Game::GROUP_DOOR))) // test for obstacles in 1 meter range, test door actor groups only
             if(Door *door=CAST(Door,phys_hit.obj))                              // if it's actually a door
             {
                door->open(); // automatically open the door
             }
          }
          return true;
       }
       return false;
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Doors");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3);

       ViewportFull.range=50;
       Cam.dist = 10;
       Cam.yaw  =-PI_4;
       Cam.pitch=-PI_3;
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.scale*=0.8;

       Physics.create();
       Sky    .set   ();
       Suns   .New   ().set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor();

       Game::World.init   (                  )
                  .setType(Chrs   ,OBJ_CHR   )
                  .setType(Doors  ,OBJ_DOOR  )
                  .setType(Statics,OBJ_STATIC)
                  .New    ("world/door"      )
                  .update (Cam.at            );

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Game::World.update(Cam.at);

       // detect object under cursor
       Vec     pos,dir ; ScreenToPosDir(Ms.pos,pos,dir); // convert screen mouse position to world position and direction
       PhysHit phys_hit;
       if(Physics.ray(pos,dir*Viewport.range,&phys_hit)) // if ray-test hit something
       {
          Object=phys_hit.obj; // get encountered object

          if(Ms.bp(0)) // if LMB is pressed
          {
             if(Door *door=CAST(Door,Object)) // if current object is of 'Door' type
             {
                door->toggle(); // toggle door
             }
             else // if not then move to that position
             {
                if(Chrs.elms())Chrs[0].actionMoveTo(phys_hit.plane.p);
             }
          }
       }else
       {
          Object=NULL; // clear object pointer
       }

       // rotate camera
       if(Ms.b(1))
       {
          Cam.yaw  -=Ms.dir_d.x;
          Cam.pitch+=Ms.dir_d.y;
       }
       if(Chrs.elms())Cam.setSpherical(Chrs[0].pos(),Cam.yaw,Cam.pitch,0,Cam.dist*ScaleFactor(Ms.wheel*-0.2)).updateVelocities().set();

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.92,"Press LMB on the door to open or close it");
       D.text(0,0.84,"Press LMB on the ground to move the player");
       D.text(0,0.76,"Press RMB to rotate the camera");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\08 - Custom Parameters.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    // ITEM
    /******************************************************************************/
    struct Item : Game::Item // extend items
    {
       Char name[64]; // add new parameter 'name'
       I32  value   ; // add new parameter 'value'

       virtual void create(Game::ObjParams &obj); // extend default creation

       // since new parameters are declared we need to properly initialize them in constructor, and save/load them in IO methods:

       // constructor
       Item();

       // io methods
       virtual void save(File &f);
       virtual Bool load(File &f);
    };
    /******************************************************************************/
    void Item::create(Game::ObjParams &obj)
    {
       __super::create(obj); // default create

       // now setup custom parameters from 'obj'
       if(Game::Param *par=obj.findParam("name" ))Set(name ,par->asStr());
       if(Game::Param *par=obj.findParam("value"))    value=par->asInt() ;
    }
    /******************************************************************************/
    Item::Item()
    {
       name[0]=0;
       value=0;
    }
    /******************************************************************************/
    void Item::save(File &f)
    {
       __super::save(f); // default save

       f<<name<<value; // save custom parameters
    }
    Bool Item::load(File &f)
    {
       if(__super::load(f)) // if default load was successful
       {
          f>>name>>value; // load custom parameters
          return true;    // return success
       }
       return false; // return failure
    }
    /******************************************************************************/
    // MAIN
    /******************************************************************************/
    Game::ObjMemx<Item> Items;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Custom Parameters");
       App.flag=APP_FULL_TOGGLE|APP_MS_EXCLUSIVE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3);

       ViewportFull.range=50;
       Cam.at.set(16,0,16);
       Cam.dist = 10;
       Cam.pitch=-PI_3;
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.scale*=0.8;

       Physics.create();
       Sky    .set   ();
       Suns   .New   ().set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor();

       Game::World.init   (                     )
                  .setItem(Items,OBJ_ITEM       )
                  .New    ("world/custom params");

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       Game::World.update(Cam.at);

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);

       // draw item parameters
       REPA(Items)
       {
          Item  &item  =Items[i];                // get i-th Items
          Vec2   screen=PosToScreen(item.pos()); // convert world position to screen position
          D.text(screen,item.name);              // draw item's name
       }
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\09 - Extending Game Object Class.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************

       In this tutorial is presented how to extend a Game Object class.
       But unlike in previous examples, we won't base on Character/Item or other classes.
       This time we'll extend the most base class - Game::Obj.

    /******************************************************************************/
    struct NewObj : Game::Obj // extend Game Object
    {
       Vec position; // the class will contain only position

       // provide necessary methods required by Game::Obj :
          virtual void create(Game::ObjParams &obj); // extend default creation

          virtual Vec  pos(        ){return position    ;} // get position
          virtual void pos(Vec &pos){     T.position=pos;} // set position

          virtual Matrix matrix(              ){return position           ;} // get matrix
          virtual void   matrix(Matrix &matrix){     T.position=matrix.pos;} // set matrix

          virtual Bool update(){return true;} // object update
          virtual void draw  ();              // object draw

          virtual void disable(){}
          virtual void  enable(){}

       // constructor
       NewObj();

       // io methods
       virtual void save(File &f);
       virtual Bool load(File &f);
    };
    /******************************************************************************/
    NewObj::NewObj() // initialize values in constructor
    {
       position.zero();
    }
    void NewObj::create(Game::ObjParams &obj)
    {
       // now setup custom parameters from 'obj'
       position=obj.matrixFinal().pos; // obtain our 'position' member from 'obj'
    }
    /******************************************************************************/
    void NewObj::draw()
    {
       switch(Renderer())
       {
          case RM_SOLID:
          case RM_LIGHT:
          {
             SetMatrix();
             Ball(1,position).draw(ARGB(0,255,255,255)); // draw white ball at objects position
          }break;
       }
    }
    /******************************************************************************/
    void NewObj::save(File &f)
    {
       __super::save(f); // default save

       f<<position; // save custom parameters
    }
    Bool NewObj::load(File &f)
    {
       if(__super::load(f)) // if default load was successful
       {
          f>>position; // load custom parameters
          return true; // return success
       }
       return false; // return failure
    }
    /******************************************************************************/
    // MAIN
    /******************************************************************************/
    Game::ObjMemx<NewObj> NewObjs; // container for objects
    /******************************************************************************/
    void InitPre()
    {
       App.name("Game::Obj class");
       App.flag=APP_FULL_TOGGLE|APP_MS_EXCLUSIVE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3);

       ViewportFull.range=50;
       Cam.at.set(16,0,16);
       Cam.dist = 10;
       Cam.pitch=-PI_3;
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Suns   .New   ().set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor();

       Game::World.init   (                     )
                  .setType(NewObjs,OBJ_ITEM     ) // use OBJ_ITEM type because objects in the world we're using are saved with OBJ_ITEM type
                  .New    ("world/custom params");

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       Game::World.update(Cam.at);

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\10 - Dynamically Created Objects.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************

       In this tutorial is presented how to dynamically create objects

    /******************************************************************************/
    Game::ObjMemx<Game::Item> Items;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Dynamically Created Objects");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3);

       Cam.dist =16;
       Cam.yaw  =-PI_4;
       Cam.pitch=-0.5;
       Cam.at.set(16,0,16);
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Suns   .New   ().set(*Gfxs("gfx/sky/sun.gfx")).pos.set(0,1,0);

       Game::World.init   (               )
                  .setType(Items,OBJ_ITEM )
                  .New    ("world/barrels")
                  .update (Cam.at         );

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       Game::World.update(Cam.at);

       if(Kb.bp(KB_SPACE)) // on space
       {
          Game::ObjParams &obj=*Game::Objs("obj/item/misc/barrel/0.obj"); // get barrel object parameters
          Game::World.objCreate(obj,Matrix(obj.scale(),Vec(16,8,16)));    // create new object at (16,8,16) position and give objects default scaling
       }

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,"Press Space to add a Barrel");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\11 - Waypoints.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    void InitPre()
    {
       App.name("Waypoints");
       App.flag=APP_FULL_TOGGLE|APP_MS_EXCLUSIVE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).ambPower(0.3);

       ViewportFull.range=50;
       Cam.at.set(16,0,16);
       Cam.dist = 20;
       Cam.pitch=-PI_3;
    }
    /******************************************************************************/
    Bool Init()
    {
       Text_ds.scale*=0.8;

       Physics.create();
       Sky    .set   ();
       Suns   .New   ().set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor();

       Game::World.init(                 )
                  .New ("world/waypoints");

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       Game::World.update(Cam.at);

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void DrawWaypoints(Str name)
    {
       if(Game::Waypoint *waypoint=Game::World.findWaypoint(name)) // if waypoint exists
       {
                  waypoint->draw(           ); // draw waypoint
          Vec pos=waypoint->pos (Tm.time()*2); // access waypoints position at 'Tm.time()*2' length
              pos.draw(RED);                   // draw the position as red dot
       }
    }
    void Draw()
    {
       Renderer(Render);

       // draw waypoints
       // 3 waypoints are stored in World used in this tutorial, they're named as follow: "0", "1", "2"
       SetMatrix(); // first reset matrix
       REP(3)DrawWaypoints(S+i); // draw each waypoint

       D.text(0,0.9,"Notice that different Waypoints have different looping modes");
       D.text(0,0.8,"Waypoints with their looping modes are set in World Editor");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\12 - Character Animations.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    struct Player : Game::Chr
    {
       Motion attack;

       virtual void animate(); // extend skeleton animation
       virtual Bool update ();

       // io
       virtual void save(File &f);
       virtual Bool load(File &f);
    };
    /******************************************************************************/
    void Player::animate()
    {
       __super::animate(); // call default animations

       // now the skeleton is animated with default character animations (walking, running, crouching, ..)
       // so after the basic animations we can optionally replace them with custom ones, for example attacking:
       cskel.animate(attack,true); // animate skeleton with 'attack' animation motion, 'true' for replace animation mode
    }
    /******************************************************************************/
    Bool Player::update()
    {
       if(action)
       {
          if(Kb.b(KB_W) || Kb.b(KB_S) || Kb.b(KB_A) || Kb.b(KB_D) || Kb.b(KB_Q) || Kb.b(KB_E))actionBreak();
       }

       if(!action)
       {
          // turn & move
          input.anglei.x=Kb.b(KB_Q)-Kb.b(KB_E);
          input.anglei.y=Kb.b(KB_T)-Kb.b(KB_G);
          input.diri  .x=Kb.b(KB_D)-Kb.b(KB_A);
          input.diri  .z=Kb.b(KB_W)-Kb.b(KB_S);
          input.diri  .y=Kb.b(KB_SPACE)-Kb.b(KB_LSHIFT);

          // dodge, crouch, walk, jump
          input.dodge = Kb.bd(KB_D)-Kb.bd(KB_A);
          input.crouch= Kb.b (KB_LSHIFT);
          input.walk  = Kb.b (KB_LCTRL );
          input.jump  =(Kb.bp(KB_SPACE ) ? 3.5 : 0);

          // mouse turn
          Flt max=DegToRad(900)*Tm.d(),
              dx =Ms.dir_ds.x*1.7,
              dy =Ms.dir_ds.y*1.7*Ms.inv();
          angle.x-=Mid(dx,-max,max);
          angle.y+=Mid(dy,-max,max);

          // ready stance change
          ready^=Kb.bp(KB_R);
       }

       // update animation
       {
          if(Kb.bp(KB_ENTER)) // on enter pressed
             attack.set(cskel,"anim/swing/r-l.anim"); // initialize "right-hand swing to left direction" attack animation

          attack.updateAuto(3,3,1); // update attack animation motion
       }

       return __super::update();
    }
    /******************************************************************************/
    void Player::save(File &f)
    {
       __super::save(f);

       attack.save(f);
    }
    Bool Player::load(File &f)
    {
       if(__super::load(f))
       {
          return attack.load(f,cskel);
       }
       return false;
    }
    /******************************************************************************/
    Game::ObjMemx<Game::Static> Statics;
    Game::ObjMemx<Game::Item  > Items  ;
    Game::ObjMemx<      Player> Players;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Character Animations");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3);
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Suns   .New   ().set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor();

       Game::World.init()
                  .setType(Statics,OBJ_STATIC)
                  .setItem(Items  ,OBJ_ITEM  )
                  .setType(Players,OBJ_CHR   )
                  .New    ("world/sample"    );

       Cam.setSpherical(Vec(16,0,16),-PI_4,-0.5,0,10).set();

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Game::World.update(Cam.at);

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,"Press Enter to play a custom animation");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\13 - Character Default Animations.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    struct Chr : Game::Chr
    {
       Int move_to; // index of Waypoint point to move to

       virtual void create(Game::ObjParams &obj); // override default creation method to setup custom default animations after character creation

       virtual Bool update(); // override default updating to set movement commands

       Chr();
    };
    /******************************************************************************/
    Game::ObjMemx<Game::Static> Statics ;
    Game::ObjMemx<      Chr   > Chrs    ;
    Game::Waypoint             *waypoint; // pointer to waypoint stored in world
    /******************************************************************************/
    Chr::Chr()
    {
       move_to=0;
    }
    void Chr::create(Game::ObjParams &obj)
    {
       __super::create(obj); // call default creation

       // now when object has been created we can optionally override its default animations
       // for example change it's walking animation
       // to achieve this we need to change the default animation from characters skeleton animation cache 'Chr::sac'
       // on the test map used with this tutorial, there are 2 characters human and a skeleton
       // we'll replace the animation only for the skeleton character leaving human character with its default animation

       // detect if current character is a skeleton
       Bool is_skeleton=false;
       for(Game::ObjParams *cur=&obj; cur; cur=cur->base()) // iterate through all ObjParams bases
          if(CChar *name=Game::Objs(cur))  // if received the name of the object
             if(Contains(name,"skeleton")) // if the object name contains "skeleton" word
             {
                is_skeleton=true;
                break;
             }

       // replace the animation
       if(is_skeleton) // only for the skeleton
       {
          sac.walk=&cskel.getSkelAnim("anim/custom/scary walk.anim"); // this will load the animation, cache it, and set into character's animation
       }

       move_walking=true; // order the characters to always move by walking instead of running
    }
    Bool Chr::update()
    {
       if(__super::update())
       {
          if(!action) // if not performing any action
          {
             if(waypoint && waypoint->points()) // if have waypoint with some points in it
             {
                move_to=(move_to+1)%waypoint->points();     // set variable to next point index
                actionMoveTo(waypoint->point(move_to).pos); // order the character to move to the point position
             }
          }
          return true;
       }
       return false;
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Character Default Animations");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).shdMode(SHD_NONE).ambPower(0.3);
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Suns   .New   ().set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor();

       // create the world
       Game::World.init()
                  .setType(Statics,OBJ_STATIC)
                  .setType(Chrs   ,OBJ_CHR   )
                  .New    ("world/animations");

       // access the Waypoint
       waypoint=Game::World.getWaypoint("0"); // load waypoint named "0" stored in current world

       Cam.setSpherical(Vec(17,2,12),-0.4,-0.9,0,11).set(); // set initial camera

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Game::World.update(Cam.at);
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1) ? CAMH_MOVE : CAMH_ROT));

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\14 - Character Facial Animations.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    struct Player : Game::Chr
    {
       virtual void animate(); // extend skeleton animation
       virtual Bool update ();

       // optionally you can override default 'face blend' value by defining your own function
       virtual Flt animateFaceBlend();
    };
    /******************************************************************************/
    void Player::animate()
    {
       __super::animate(); // call default animations

       // facial animation
       {
          Flt blend=animateFaceBlend(); // get facial animation blending value
          // this is a factor which determines the intensity of facial animations
          // for example if the character is near the camera the blend is full (1.0) so facial animations will be performed normally
          // and if the character is far away so face isn't visible very well, blending value will be disabled (0.0)
          // disabling facial animations speeds up rendering process, so its visible only in some distance from camera

          if(blend>0)
          {
             Flt time       =Tm.time(),
                 smile_blend=1;

             cskel.animate(L"anim/face/smile.anim",time,smile_blend*blend);
          }
       }
    }
    Flt Player::animateFaceBlend()
    {
       Flt distance        =Dist(pos(),Cam.matrix.pos), // distance from camera
           full_blend_range=1  ,                        // custom range where the facial animation should be full     (1   meter)
             no_blend_range=1.5;                        // custom range where the facial animation should be disabled (1.5 meter)

       return LerpRS(no_blend_range,full_blend_range,distance); // this will returned a saturated value 0..1
    }
    /******************************************************************************/
    Bool Player::update()
    {
       if(action)
       {
          if(Kb.b(KB_W) || Kb.b(KB_S) || Kb.b(KB_A) || Kb.b(KB_D) || Kb.b(KB_Q) || Kb.b(KB_E))actionBreak();
       }

       if(!action)
       {
          // turn & move
          input.anglei.x=Kb.b(KB_Q)-Kb.b(KB_E);
          input.anglei.y=Kb.b(KB_T)-Kb.b(KB_G);
          input.diri  .x=Kb.b(KB_D)-Kb.b(KB_A);
          input.diri  .z=Kb.b(KB_W)-Kb.b(KB_S);
          input.diri  .y=Kb.b(KB_SPACE)-Kb.b(KB_LSHIFT);

          // dodge, crouch, walk, jump
          input.dodge = Kb.bd(KB_D)-Kb.bd(KB_A);
          input.crouch= Kb.b (KB_LSHIFT);
          input.walk  = Kb.b (KB_LCTRL );
          input.jump  =(Kb.bp(KB_SPACE ) ? 3.5 : 0);

          // mouse turn
          Flt max=DegToRad(900)*Tm.d(),
              dx =Ms.dir_ds.x*1.7,
              dy =Ms.dir_ds.y*1.7*Ms.inv();
          angle.x-=Mid(dx,-max,max);
          angle.y+=Mid(dy,-max,max);

          // ready stance change
          ready^=Kb.bp(KB_R);
       }

       return __super::update();
    }
    /******************************************************************************/
    Game::ObjMemx<Game::Static> Statics; // container for static objects
    Game::ObjMemx<      Player> Players; // container for player objects
    /******************************************************************************/
    void InitPre()
    {
       App.name("Character Facial Animation");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).shdSoft(1).ambPower(0.3).hpRt(true);
       ViewportFull.range=20;
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Sun &sun=Suns.New(); sun.set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor(); sun.rays.mode=SUN_RAYS_HIGH;

       // create the world
       Game::World.init()
                  .setType(Statics,OBJ_STATIC)
                  .setType(Players,OBJ_CHR   )
                  .New    ("world/sample"    );

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Game::World.update(Cam.at);

       if(Players.elms())Cam.setSpherical(Players[0].cskel.getPoint("Head").pos,Players[0].angle.x+PI,-Players[0].angle.y,0,Max(0.1f,Cam.dist*ScaleFactor(Ms.wheel*-0.2))).updateVelocities().set();

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);

       if(Players.elms())D.text(0,0.9,S+"Facial blending factor for Players[0] is: "+Players[0].animateFaceBlend());
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\15 - Character Ragdoll.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    Game::ObjMemx<Game::Static> Statics; // container for static objects
    Game::ObjMemx<Game::Chr   > Chrs   ; // container for player objects
    /******************************************************************************/
    void InitPre()
    {
       App.name("Character Ragdoll");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).shdSoft(1).ambPower(0.3);
       ViewportFull.range=30;

       Cam.at.set(16,0,16);
       Cam.yaw   =-PI_4;
       Cam.pitch =-0.5;
       Cam.dist  =4;
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Suns   .New   ().set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor();

       // create the world
       Game::World.init()
                  .setType(Statics,OBJ_STATIC)
                  .setType(Chrs   ,OBJ_CHR   )
                  .New    ("world/sample"    );

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       Game::World.update(Cam.at);

       if(Chrs.elms())
       {
          Game::Chr &chr=Chrs[0];

          if(Kb.bp(KB_1))chr.ragdollEnable (); // switch to ragdoll
          if(Kb.bp(KB_2))chr.ragdollDisable(); // switch to skeleton animation

          if(Kb.bp(KB_Q))if(chr.ragdollBlend())if(Actor *actor=chr.ragdoll.findActor("Head" ))actor->addVel(Vec(0,0,3));
          if(Kb.bp(KB_W))if(chr.ragdollBlend())if(Actor *actor=chr.ragdoll.findActor("Body" ))actor->addVel(Vec(0,0,3));
          if(Kb.bp(KB_E))if(chr.ragdollBlend())if(Actor *actor=chr.ragdoll.findActor("FootR"))actor->addVel(Vec(0,0,4));
          if(Kb.bp(KB_R))if(chr.ragdollBlend())if(Actor *actor=chr.ragdoll.findActor("HandR"))actor->addVel(Vec(0,0,4));

          Cam.setSpherical(chr.pos(),Cam.yaw-Ms.d.x,Cam.pitch+Ms.d.y,0,Max(0.1f,Cam.dist*ScaleFactor(Ms.wheel*-0.2))).updateVelocities().set();
       }

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);

       D.text(0,0.9,"Press 1,2 to switch between skeleton<->ragdoll animation");
       D.text(0,0.8,"Press q,w,e,r to simulate shot hits");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\16 - Camera Modes.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************

       Here we'll present how to properly use different camera modes

    /******************************************************************************/
    // Define viewing modes:
    enum VIEW_MODE // Viewing Mode
    {
       VIEW_FPP, // First Person
       VIEW_TPP, // Third Person
       VIEW_ISO, // Isometric
       VIEW_NUM, // number of view modes
    };
    U32 View; // current VIEW_MODE
    /******************************************************************************/
    struct Player : Game::Chr
    {
       virtual Bool update();

       virtual void draw(); // extend drawing to disable head rendering in FPP mode
    };
    /******************************************************************************/
    Game::ObjMemx<Game::Static> Statics; // container for static objects
    Game::ObjMemx<Game::Item  > Items  ; // container for item   objects
    Game::ObjMemx<      Player> Players; // container for player objects
    /******************************************************************************/
    Bool Player::update()
    {
       if(action)
       {
          if(Kb.b(KB_W) || Kb.b(KB_S) || Kb.b(KB_A) || Kb.b(KB_D) || Kb.b(KB_Q) || Kb.b(KB_E))actionBreak();
       }

       if(!action)
       {
          // turn & move
          input.anglei.x=Kb.b(KB_Q)-Kb.b(KB_E);
          input.anglei.y=Kb.b(KB_T)-Kb.b(KB_G);
          input.diri  .x=Kb.b(KB_D)-Kb.b(KB_A);
          input.diri  .z=Kb.b(KB_W)-Kb.b(KB_S);
          input.diri  .y=Kb.b(KB_SPACE)-Kb.b(KB_LSHIFT);

          // dodge, crouch, walk, jump
          input.dodge = Kb.bd(KB_D)-Kb.bd(KB_A);
          input.crouch= Kb.b (KB_LSHIFT);
          input.walk  = Kb.b (KB_LCTRL );
          input.jump  =(Kb.bp(KB_SPACE ) ? 3.5 : 0);

          // mouse turn
          if(View!=VIEW_ISO) // don't use mouse turning when in Isometric mode
          {
             Flt  max=DegToRad(900)*Tm.d(),
                  dx =Ms.dir_ds.x*1.7,
                  dy =Ms.dir_ds.y*1.7*Ms.inv();
             angle.x-=Mid(dx,-max,max);
             angle.y+=Mid(dy,-max,max);
          }

          // ready stance change
          ready^=Kb.bp(KB_R);
       }

       return __super::update();
    }

    void Player::draw()
    {
       Bool disable_head_draw=(View==VIEW_FPP && Renderer()!=RM_SHD_MAP && mesh); // disable drawing head when we're in FPP mode and we're not in shadowing mode (if this isn't included player will cast head-less shadows)

       if(disable_head_draw)mesh->hide("head"); // hide "head" mesh part in 'mesh'

       __super::draw(); // call default drawing

       if(disable_head_draw)mesh->show("head"); // un-hide "head" mesh part, so other objects which use the same mesh will have the head rendered properly
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Camera Modes");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3).hpRt(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Sun &sun=Suns.New(); sun.set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor(); sun.rays.mode=SUN_RAYS_HIGH;

       // create the world
       Game::World.init()
                  .setType(Statics,OBJ_STATIC)
                  .setType(Players,OBJ_CHR   )
                  .setItem(Items  ,OBJ_ITEM  )
                  .New("world/sample"        );

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Game::World.update(Cam.at);

       // set next camera mode when Tab pressed
       if(Kb.bp(KB_TAB))
       {
          View=(View+1)%VIEW_NUM;

          if(View==VIEW_ISO) // when set to isometric view
          {
             Cam.dist =   10; // set bigger camera distance at start
             Cam.pitch=-PI_4; // set starting camera pitch angle
          }
       }

       // setup the camera
       if(Players.elms()) // if we have at least one player
       {
          // set camera depending on current view mode
          switch(View)
          {
             case VIEW_FPP:
             {
                OrientP &head=Players[0].cskel.getPoint("head"); // obtain player "head" skeleton point (this was created in Mesh Editor)
                Cam.setPosDir(head.pos,head.dir,head.perp); // set camera from 'head' position, direction and perpendicular to direction
             }break;

             case VIEW_TPP:
             {
                Cam.dist=Max(1.0f,Cam.dist*ScaleFactor(Ms.wheel*-0.1)); // update camera distance according to mouse wheel
                Cam.setSpherical(Players[0].pos()+Vec(0,0.5,0), Players[0].angle.x, Players[0].angle.y, 0, Cam.dist); // set spherical camera looking at player position with given player angles
             }break;

             default: // VIEW_ISO
             {
                Cam.yaw  -=Ms.ds.x; // update camera yaw   angle according to mouse smooth delta x
                Cam.pitch+=Ms.ds.y; // update camera pitch angle according to mouse smooth delta y
                Clamp(Cam.pitch,-PI_2,0); // clamp to possible camera pitch angle
                Cam.dist  =Max(1.0f,Cam.dist*ScaleFactor(Ms.wheel*-0.1)); // update camera distance according to mouse wheel
                Cam.setSpherical(Players[0].pos(), Cam.yaw, Cam.pitch, 0, Cam.dist); // set spherical camera looking at player using camera angles
             }break;
          }

          // after setting camera position and angles:
          Cam.updateVelocities().set(); // update camera velocities and activate it
       }
       else // when no player on the scene
       {
          CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // default camera handling actions
       }

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);
       D.text  (0,0.9,"Press Tab to switch camera modes");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\17 - Camera Collisions.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************

       Here we'll present how to detect camera collisions

    /******************************************************************************/
    struct Player : Game::Chr
    {
       virtual Bool update();
    };
    /******************************************************************************/
    Camera desired_camera; // create a helper desired camera
    /******************************************************************************/
    Game::ObjMemx<Game::Static> Statics;
    Game::ObjMemx<Game::Item  > Items  ;
    Game::ObjMemx<      Player> Players;
    /******************************************************************************/
    Bool Player::update()
    {
       if(action)
       {
          if(Kb.b(KB_W) || Kb.b(KB_S) || Kb.b(KB_A) || Kb.b(KB_D) || Kb.b(KB_Q) || Kb.b(KB_E))actionBreak();
       }

       if(!action)
       {
          // turn & move
          input.anglei.x=Kb.b(KB_Q)-Kb.b(KB_E);
          input.anglei.y=Kb.b(KB_T)-Kb.b(KB_G);
          input.diri  .x=Kb.b(KB_D)-Kb.b(KB_A);
          input.diri  .z=Kb.b(KB_W)-Kb.b(KB_S);
          input.diri  .y=Kb.b(KB_SPACE)-Kb.b(KB_LSHIFT);

          // dodge, crouch, walk, jump
          input.dodge = Kb.bd(KB_D)-Kb.bd(KB_A);
          input.crouch= Kb.b (KB_LSHIFT);
          input.walk  = Kb.b (KB_LCTRL );
          input.jump  =(Kb.bp(KB_SPACE ) ? 3.5 : 0);

          // ready stance change
          ready^=Kb.bp(KB_R);
       }

       return __super::update();
    }
    /******************************************************************************/
    void InitPre()
    {
       App.name("Camera Collisions");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3).hpRt(true);
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Sun &sun=Suns.New(); sun.set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor(); sun.rays.mode=SUN_RAYS_HIGH;

       // create the world
       Game::World.init()
                  .setType(Statics,OBJ_STATIC)
                  .setType(Players,OBJ_CHR   )
                  .setItem(Items  ,OBJ_ITEM  )
                  .New("world/sample"        );

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       Game::World.update(Cam.at);

       // setup the camera
       if(Players.elms()) // if we have at least one player
       {
          // first setup the desired camera as in the previous tutorials
          desired_camera.yaw  -=Ms.ds.x;          // update camera yaw   angle according to mouse smooth delta x
          desired_camera.pitch+=Ms.ds.y;          // update camera pitch angle according to mouse smooth delta y
          Clamp(desired_camera.pitch,-PI_2,PI_4); // clamp to possible camera pitch angle
          desired_camera.dist=Max(1.0f,desired_camera.dist*ScaleFactor(Ms.wheel*-0.1)); // update camera distance according to mouse wheel
          desired_camera.at  =Players[0].pos();
          desired_camera.setSpherical(); // set as spherical from current values, this will set the camera's matrix (desired_camera.matrix)

          // now what we'll do is cast a small sized Ball from starting position to target camera destination
          // we'll stop the ball at first contact point, and set camera at that place

          // create a helper ball which will be used for collision detection
          Ball ball(0.1f, desired_camera.at); // we place it at starting point (where the camera is looking at)

          // now we'll move the ball in the direction where the camera should be
          Physics.move(ball, desired_camera.matrix.pos-ball.pos); // use physics move to move the ball as far as it can go without any collisions

          // now the ball.pos is located at either maximum movement distance or at nearest collision point
          // having ball's position we can now set the final camera position
          Cam.setPosDir(ball.pos, desired_camera.matrix.z, desired_camera.matrix.y); // we'll use desired_camera.matrix directions which were set in 'setSpherical' camera method

          Cam.updateVelocities().set(); // update camera velocities and activate it
       }
       else // when no player on the scene
       {
          CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT)); // default camera handling actions
       }

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,"Try to move the camera around");
       D.text(0,0.8,"and see how it gets blocked by the terrain");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\18 - Object References.txt

    /******************************************************************************/
    #include "stdafx.h"
    /******************************************************************************

       In this tutorial is presented how to properly use references to world objects using 'Reference' class.

       Let's assume a Character wants to reference an Item

       So first let's think how we would do this the easy way:

          Add a pointer to an item?

             struct Chr : Game::Chr
             {
                Item *item;
                ...

          This looks ok, but what happens if 'item' points to the Item object,
          and then during a Game Update, the Item Object is removed/deleted.

             For example another player picked up the item,
             so item's memory address has moved to a inventory container.
             Or the item has become too far from the center of action,
             that the world had to flush the item object to a temporary file on the disk.

          In that scenario 'Chr::item' still points to a memory address but at which
          there is no original Item.

       This means that additional caution needs to be taken.
       To solve this problem we'll use object's 'id' value.

       Before going any further let's sum up how objects are handled in the world:

          -When each object is created it has its 'id' set to a random value different than zero

          -When each object is deleted its 'id' is set to zero

          -Object's 'id' values are saved and loaded in SaveGame

          -After removing/deleting a world object, its memory is still accessible, but:
             -it's not used at all ('id' value is zero)
             -it's used but by another object created later ('id' value is set to new object's 'id')

       So to properly reference an object we must store a pointer to its memory and its 'id',
       in case the referenced objects memory will be used by another object later with another 'id'.

       For this - 'Reference' class is used which stores a pointer and an 'id'.

       So for example let's use a World Character and a World Item.
       The Character will hold a reference to the item as 'desired_item'.

    /******************************************************************************/
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    struct Chr : Game::Chr // extend default character
    {
       Reference<Game::Item> desired_item; // add a new parameter, which is a reference to an item (something like 'Item *desired_item;')

       // draw
       void draw2D() // this is a helper method for drawing text on the screen
       {
          if(desired_item.valid()) // check if the reference is valid
          {
             Vec pos=desired_item().pos(); // referenced objects can be accessed using operator(), but only after validation using 'valid' method as above
             D.text(0,0.8,S+"My desired item is at: ("+pos+") position");
          }
          else // if the reference has become invalid
          {
             D.text(0,0.8,"My desired item is gone"); // display a text that the reference is now invalid
          }
       }

       // handle saving and loading, following methods are needed only for saving and loading the Reference
       void save(File &f)
       {
          __super::save(f);
          desired_item.save(f); // save Reference
       }
       Bool load(File &f)
       {
          if(__super::load(f))
          {
             desired_item.load(f); // load Reference, here only the Reference 'id' is loaded, the pointer to the object is cleared because the object may not exist yet
             // searching for the actual object will be performed later (inside 'linkReferences') after all objects have been loaded
             return true;
          }
          return false;
       }
       void linkReferences() // this is called when all of the objects have been loaded
       {
          // in this method you should call 'link' on all references which the object contains
          desired_item.link(); // by calling 'link' the world manager will try to find the referenced object according to the 'id', and store its pointer into the Reference
       }
    };
    /******************************************************************************/
    Game::ObjMemx<Game::Static> Statics;
    Game::ObjMemx<Game::Item  > Items  ;
    Game::ObjMemx<      Chr   > Chrs   ;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Object References");
       App.flag=APP_MS_EXCLUSIVE|APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024);

       Cam.dist =10;
       Cam.yaw  =-PI_4;
       Cam.pitch=-0.5;
       Cam.at.set(16,0,16);
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();

       Game::World.init()
                  .setType(Statics,OBJ_STATIC)
                  .setItem(Items  ,OBJ_ITEM  )
                  .setType(Chrs   ,OBJ_CHR   )
                  .New    ("world/sample"    );

       // after loading the world, let's set the 'desired_item' for the Character
       {
          Game::World.update(Cam.at); // first world needs to be updated to a location to make sure that objects at that location are loaded

          if(Chrs.elms() && Items.elms()) // now check if the world has at least one character and one item
             Chrs[0].desired_item=Items[0]; // set the Character's reference to point to the first Item (this stores the item's memory address and its 'id')
       }

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       if(Kb.bp(KB_F2))Game::World.save("LocalData/save.sav"); // save game
       if(Kb.bp(KB_F3))Game::World.load("LocalData/save.sav"); // load game

       Game::World.update(Cam.at);

       if(Kb.bp(KB_SPACE) && Items.elms()) // when space pressed and if World Items has elements
          Items.removeValid(0); // remove 0-th item

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();

       switch(Renderer())
       {
          case RM_LIGHT:
             LightDir(!Vec(1,-1,1)).add();
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);

       D.text(0,0.9,"Press Space to remove the item");
       if(Chrs.elms())Chrs[0].draw2D(); // draw characters text
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\19 - Small Overlays.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    struct Marker2 : Marker // create a helper class which bases on Marker and uses time fading
    {
       Flt time; // time left until overlay fades out

       Marker2()
       {
          time=10; // default time is 10 seconds for an overlay to live
       }

       Bool update()
       {
                 time-=Tm.d(); // decrease time left
          return time<=0     ; // if there is no time left then return true (which means that the overlay can be deleted)
       }
       void draw(Matrix &matrix)
       {
          Marker::draw(matrix,Sat(time)); // draw the overlay with transparency of 'Saturate(time)' value
       }

       // io
       void save(File &f)
       {
          Marker::save(f);
          f<<time;
       }
       Bool load(File &f)
       {
          if(Marker::load(f))
          {
             f>>time;
             return true;
          }
          return false;
       }
    };
    /******************************************************************************/
    struct Item : Game::Item // extend items
    {
       Memb<Marker2> marker; // add marker, which is used for rendering semi transparent images on solid surfaces

       virtual Bool update(); // extend updating to include 'marker' update
       virtual void draw  (); // extend drawing  to include rendering of 'marker'

       // io
       virtual void save(File &f); // extend saving  to include members saving
       virtual Bool load(File &f); // extend loading to include members loading

       // operations
       void addBulletHole(Vec &pos,Vec &surface_normal,Vec &shot_dir); // helper method for adding a bullet hole (Marker) onto the item mesh
    };
    /******************************************************************************/
    Game::ObjMemx<Item> Items;
    /******************************************************************************/
    // ITEM
    /******************************************************************************/
    Bool Item::update()
    {
       if(__super::update())
       {
          REPA(marker)if(marker[i].update()) // update all overlays
             marker.remove(i,true); // and remove them if they faded out

          return true;
       }
       return false;
    }
    /******************************************************************************/
    void Item::draw()
    {
       __super::draw(); // call default drawing

       switch(Renderer())
       {
          case RM_OVERLAY: // overlays need to be rendered in RM_OVERLAY mode
             REPAO(marker).draw(matrixScaled()); // draw mesh_overlays with the same matrix used for default item drawing
          break;
       }
    }
    /******************************************************************************/
    void Item::save(File &f)
    {
       __super::save(f);

       marker.save(f);
    }
    Bool Item::load(File &f)
    {
       if(__super::load(f))
       {
          return marker.load(f);
       }
       return false;
    }
    /******************************************************************************/
    void Item::addBulletHole(Vec &pos,Vec &surface_normal,Vec &shot_dir)
    {
       // add a marker to the item
       marker.New().set(WHITE,0,*Gfxs("gfx/hole/bullet.gfx"),0.1f,0.05f,0.05f).matrix(matrixScaled(),Matrix().setPosDir(pos,surface_normal));

       // add impulse to the actor
       actor.addImpulse(shot_dir * 1.5f,pos);
    }
    /******************************************************************************/
    // MAIN
    /******************************************************************************/
    void InitPre()
    {
       App.name("Small Overlays");
       App.flag=APP_FULL_TOGGLE|APP_MS_EXCLUSIVE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3);

       ViewportFull.range=70;
       Cam.at.set(16,2,12);
       Cam.dist = 0.01;
       Cam.pitch=-0.2f;
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Sun &sun=Suns.New(); sun.set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor(); sun.rays.mode=SUN_RAYS_HIGH;

       Game::World.init   (                     )
                  .setItem(Items,OBJ_ITEM       )
                  .New    ("world/custom params");

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       // update the camera FPP 'WSAD' style
       if(Kb.b(KB_A     ))Cam.at-=Cam.matrix.x*Tm.d()*2;
       if(Kb.b(KB_D     ))Cam.at+=Cam.matrix.x*Tm.d()*2;
       if(Kb.b(KB_S     ))Cam.at-=Cam.matrix.z*Tm.d()*2;
       if(Kb.b(KB_W     ))Cam.at+=Cam.matrix.z*Tm.d()*2;
       if(Kb.b(KB_LSHIFT))Cam.at-=Vec(0,1,0)  *Tm.d()*2;
       if(Kb.b(KB_SPACE ))Cam.at+=Vec(0,1,0)  *Tm.d()*2;
       CamHandle(0.01,0.01,CAMH_ROT); // allow only rotation

       Game::World.update(Cam.at);

       if(Ms.bp(0)) // on LMB pressed
       {
          // calculate world position and direction vectors
          Vec     pos, dir; ScreenToPosDir(Vec2(0,0),pos,dir);
          PhysHit phys_hit; if(Physics.ray(pos,dir*Viewport.range,&phys_hit)) // if ray test hit an actor
          {
             if(phys_hit.obj) // if the actor comes from an object
             {
                if(Item *item=CAST(Item,phys_hit.obj)) // if the object is an item
                {
                   item->addBulletHole(phys_hit.plane.p, phys_hit.plane.n, dir); // call item method to add a bullet hole
                }
             }
             else // the actor doesn't have an object set, so most probably it's a terrain actor
             {
                // add a marker to the world terrain
                Game::World.terrainAddMarker(WHITE,0,*Gfxs("gfx/hole/bullet.gfx"),Matrix().setPosDir(phys_hit.plane.p, phys_hit.plane.n),0.1f,0.05f,0.05f);
             }
          }
       }

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,"Press LMB to shoot");

       // draw simple crosshair
       D.lineX(WHITE, 0, -0.08f,0.08f);
       D.lineY(WHITE, 0, -0.08f,0.08f);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\4 - Demos, Game Basics\Game Basics\20 - Big Overlays.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "../../../../../data/enum/_enums.h"
    /******************************************************************************/
    struct MeshOverlay2 : MeshOverlay // create a helper class which bases on MeshOverlay and uses time fading
    {
       Flt time; // time left until overlay fades out

       MeshOverlay2()
       {
          time=10; // default time is 10 seconds for an overlay to live
       }

       Bool update()
       {
                 time-=Tm.d(); // decrease time left
          return time<=0     ; // if there is no time left then return true (which means that the overlay can be deleted)
       }
       void draw(Matrix &matrix)
       {
          MeshOverlay::draw(matrix,Sat(time)); // draw the overlay with transparency of 'Saturate(time)' value
       }

       // io
       void save(File &f)
       {
          MeshOverlay::save(f);
          f<<time;
       }
       Bool load(File &f)
       {
          if(MeshOverlay::load(f))
          {
             f>>time;
             return true;
          }
          return false;
       }
    };
    /******************************************************************************/
    struct Item : Game::Item // extend items
    {
       I32                type        ; // ITEM_TYPE
       Memb<MeshOverlay2> mesh_overlay; // add mesh overlay, which is used for rendering semi transparent images on solid surfaces

       virtual void create(Game::ObjParams &obj); // extend creation to include accessing item type
       virtual Bool update(                    ); // extend updating to include bomb explosion, and 'mesh_overlay' update
       virtual void draw  (                    ); // extend drawing  to include rendering of 'mesh_overlay'

       // io
       virtual void save(File &f); // extend saving  to include members saving
       virtual Bool load(File &f); // extend loading to include members loading

       Item();
    };
    /******************************************************************************/
    Memb<ExplosionFx> explosion;

    Game::ObjMemx<Item> Items;
    /******************************************************************************/
    void CreateExplosion(Vec &pos) // helper function for creating an explosion at given position
    {
       // add an earthquake effect
       QuakeFx.addMedium();

       // create a new explosion effect
       explosion.New().create(Gfxs("gfx/particle/explosion/0.gfx"),Gfxs("gfx/particle/explosion/1.gfx"),0x00600000,32,pos,3);

       // set overlay parameters
       Flt  overlay_angle=RandomF(PI2),
            overlay_scale=RandomF(4,7);
       Gfx &overlay_gfx  =*Gfxs("gfx/hole/bomb.gfx");

       // add terrain overlay
       Matrix m;
       m.setPosDir     (pos,Vec(0,-1,0)); // set position and direction
       m.orn.rotateZVec(overlay_angle  ); // rotate along matrix z axis
       m.scaleOrn      (overlay_scale  ); // scale the overlay
       Game::World.terrainAddOverlay(WHITE,0,overlay_gfx,m);

       Memb<Game::Obj*> objects;
       Game::World.objQuery(objects,Ball(overlay_scale*SQRT3+1,pos),OBJ_ITEM); // get objects in explosion radius
       REPA(objects)if(Item *item=CAST(Item,objects[i])) // process world items to add overlays and apply forces to actors
       {
          // apply forces to item actors
          Actor &actor=item->actor;
          Vec    dir  =actor.pos()-pos; // get difference between actor position and explosion position
          Flt    dist =dir.normalize(); // normalize direction and store its previous length into 'dist'
                 dist*=dist;            // distance is now equal to squared distance

          if(dist)actor.addImpulse(30 * dir / dist); // final equation for impulse = (power) * (normalized direction) / (distance^2)

          // set mesh overlay for item
          if(item->mesh)
          {
             m.orn.setDir    (dir);
             m.orn.rotateZVec(overlay_angle);
             m.scaleOrn      (overlay_scale);
             if(!item->mesh_overlay.New().create(*item->mesh,overlay_gfx,m,&item->matrixScaled()))item->mesh_overlay.removeLast();
          }
       }
    }
    /******************************************************************************/
    // ITEM
    /******************************************************************************/
    Item::Item()
    {
       type=ITEM_NONE;
    }
    /******************************************************************************/
    void Item::create(Game::ObjParams &obj)
    {
       __super::create(obj);

       if(Game::Param *param=obj.findParam("type"))type=param->asEnum(); // get item type from .obj file
    }
    /******************************************************************************/
    Bool Item::update()
    {
       if(__super::update())
       {
          if(type==ITEM_MISSILE) // if this is a missile
          {
             Vec vec=actor.vel(); vec*=Tm.d()*3;
             if(actor.sweep(vec)) // if the missile actor has encountered an obstacle along the way
             {
                CreateExplosion(pos()); // create explosion at bomb's position
                return false; // return false which will delete the bomb Item
             }
          }

          REPA(mesh_overlay)if(mesh_overlay[i].update()) // update all overlays
             mesh_overlay.remove(i,true); // and remove them if they faded out

          return true;
       }
       return false;
    }
    /******************************************************************************/
    void Item::draw()
    {
       __super::draw(); // call default drawing

       switch(Renderer())
       {
          case RM_OVERLAY: // mesh overlays need to be rendered in RM_OVERLAY mode
             REPAO(mesh_overlay).draw(matrixScaled()); // draw mesh_overlays with the same matrix used for default item drawing
          break;
       }
    }
    /******************************************************************************/
    void Item::save(File &f)
    {
       __super::save(f);

       f<<type;
       mesh_overlay.save(f);
    }
    Bool Item::load(File &f)
    {
       if(__super::load(f))
       {
          f>>type;
          return mesh_overlay.load(f);
       }
       return false;
    }
    /******************************************************************************/
    // MAIN
    /******************************************************************************/
    void InitPre()
    {
       App.name("Big Overlays");
       App.flag=APP_FULL_TOGGLE|APP_MS_EXCLUSIVE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3);

       ViewportFull.range=70;
       Cam.at.set(16,0,16);
       Cam.dist = 28;
       Cam.pitch=-PI_6;
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Sun &sun=Suns.New(); sun.set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor(); sun.rays.mode=SUN_RAYS_HIGH;

       // increase default earthquake effect scale
       QuakeFx.scale*=3;

       Game::World.init   (                     )
                  .setItem(Items,OBJ_ITEM       )
                  .New    ("world/custom params");

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_MOVE:CAMH_ROT));

       Game::World.update(Cam.at);

       // update earthquake effect
       QuakeFx.update();

       // update explosions
       REPA(explosion)if(explosion[i].update())explosion.remove(i);

       if(Kb.bp(KB_SPACE)) // on space pressed
       {
          // create a 'bomb' item
          Game::ObjParams &bomb=*Game::Objs("obj/item/missile/bomb/0.obj");
          Game::World.objCreate(bomb,Matrix().setPosUp(Vec(RandomF(13,19),14,RandomF(13,19)),Vec(0,-1,0)).scaleOrn(bomb.scale()*2));
       }

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();

       switch(Renderer())
       {
          case RM_PALETTE:
             REPA(explosion)explosion[i].draw(); // draw explosions
          break;
       }
    }
    void Draw()
    {
       Renderer(Render);
       D.text(0,0.9,"Press Space to drop a Bomb");
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\5 - Projects (here all files from a single directory need to be included in project)\01 - Simple Project\Game.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "Main.h"
    /******************************************************************************/
    Bool InitGame()
    {
       return true;
    }
    void ShutGame()
    {
    }
    /******************************************************************************/
    Bool UpdateGame()
    {
       if(Kb.bp(KB_ESC))StateMenu.set(1.0);
       return true;
    }
    void DrawGame()
    {
       D.clear(TURQ);
       D.text (0,0,"Game");
    }
    /******************************************************************************/
    State StateGame(UpdateGame,DrawGame,InitGame,ShutGame);
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\5 - Projects (here all files from a single directory need to be included in project)\01 - Simple Project\Intro.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "Main.h"
    /******************************************************************************/
    Bool InitIntro()
    {
       return true;
    }
    void ShutIntro()
    {
    }
    /******************************************************************************/
    Bool UpdateIntro()
    {
       if(StateActive->time()>3 || Kb.bp(KB_ESC))
          StateMenu.set(1.0);
       return true;
    }
    void DrawIntro()
    {
       D.clear(BLACK);
       D.text (0,0,"Intro");
    }
    /******************************************************************************/
    State StateIntro(UpdateIntro,DrawIntro,InitIntro,ShutIntro);
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\5 - Projects (here all files from a single directory need to be included in project)\01 - Simple Project\Main.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "Main.h" // include the main header, which includes all other headers
    /******************************************************************************/
    void InitPre()
    {
       App.name("Simple Multi CPP Project");
       IOPath("../data");
       PakAdd("engine.pak");
    }
    Bool Init()
    {
       StateIntro.set();
       return true;
    }
    void Shut()
    {
    }
    /******************************************************************************/
    Bool Main()
    {
       return true;
    }
    void Draw()
    {
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\5 - Projects (here all files from a single directory need to be included in project)\01 - Simple Project\Menu.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "Main.h"
    /******************************************************************************/
    Bool InitMenu()
    {
       return true;
    }
    void ShutMenu()
    {
    }
    /******************************************************************************/
    Bool UpdateMenu()
    {
       if(Kb.bp(KB_ESC))return false;
       if(Kb.bp(KB_ENTER))StateGame.set(0.5);
       return true;
    }
    void DrawMenu()
    {
       D.clear(GREY);
       D.text (0, 0  ,"Menu");
       D.text (0,-0.3,"Press Enter to start the game");
       D.text (0,-0.5,"Press Escape to exit");
    }
    /******************************************************************************/
    State StateMenu(UpdateMenu,DrawMenu,InitMenu,ShutMenu);
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\5 - Projects (here all files from a single directory need to be included in project)\02 - Inventory\Inventory Gui.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "main.h"
    /******************************************************************************/
    InventoryGui InvGui;
    /******************************************************************************/
    // MANAGE
    /******************************************************************************/
    void InventoryGui::create()
    {
       // window
       Gui+=window.create(Rect_R(D.w(),0,1,1.5f),"Inventory");

       // slots
       {
          // background images
          Flt w=0.11, // default unit width
              s=0.03; // default unit spacing
          Gfx *gfx=Gfxs("gfx/inventory/slot.gfx");
          window+=slot_img[SLOT_HEAD ][0].create(Rect_U (window.crect.w()/2                 ,                               -0.05, w*2,w*2),gfx).desc("Head");
          window+=slot_img[SLOT_BODY ][0].create(Rect_U (window.crect.w()/2                 , slot_img[SLOT_HEAD][0].rect.min.y-s, w*2,w*3),gfx).desc("Body");
          window+=slot_img[SLOT_ARM_L][0].create(Rect_RU(slot_img[SLOT_BODY][0].rect.min.x-s, slot_img[SLOT_BODY][0].rect.max.y  , w*2,w*3),gfx).desc("Left Arm");
          window+=slot_img[SLOT_ARM_R][0].create(Rect_LU(slot_img[SLOT_BODY][0].rect.max.x+s, slot_img[SLOT_BODY][0].rect.max.y  , w*2,w*3),gfx).desc("Right Arm");

          // item images
          REPA(slot_img)if(i!=SLOT_TEMP)
          {
             window+=slot_img[i][1].create(slot_img[i][0].rect).desc(slot_img[i][0].desc()); slot_img[i][1].rect_color=0;
          }
       }

       // region
       {
          Rect_LU rect(0,0,window.crect.w(),window.crect.h());
                  rect.max.y=rect.min.y+0.7f;
                  rect.extend(-0.05f);
          window+=region.create(rect);
       }

       // list
       {
          ListGroup lg[]=
          {
             ListGroup(MEMBER(Item,icon ),0.2f,L"Icon" ), // 0
             ListGroup(MEMBER(Item,name ),0.5f,L"Name" ), // 1
             ListGroup(MEMBER(Item,power),0.2f,L"Power"), // 2
          };
          lg[2].precision=1; // set showing only 1 decimal precision for power float attribute
          region+=list.create(lg,ELMS(lg));

          list. cur_mode=LCM_MOUSE;
          list.draw_mode=LDM_RECTS;
       }
    }
    /******************************************************************************/
    // OPERATIONS
    /******************************************************************************/
    void InventoryGui::link(Inventory *inv)
    {
       if(T.inv!=inv)
       {
          T.inv=inv;
          if(inv)inv->inv_gui=this;

          setGui();
       }
    }
    /******************************************************************************/
    void InventoryGui::setGui()
    {
       if(inv)
       {
          // set item list
          {
             // here we have to hide the items which are assigned to slots
             // create a 'is' array which determines visibility of an element (1=visible, 0=hidden)
             Byte  *is=AllocN(Byte,inv->items.elms()); // allocate bytes for all items in container
             SetMem(is,1,inv->items.elms());           // set memory to '1' (make all items visible by default)
             REPA(inv->slot) // iterate through all slots
             {
                if(inv->slot[i].valid()) // if the slot is valid
                {
                   Int index=inv->items.validIndex(&inv->slot[i]()); // get index of a slot item in items container
                   if(InRange(index,inv->items)) // if its valid
                      is[index]=0; // set visibility for item assigned to a slot to 0, to be hidden on the list
                }
             }
             list.setData(inv->items,is); // set list data from items container and visibility list
             Free(is); // free allocated memory
          }

          // set slot images
          REP(SLOT_NUM) // for all slots
             if(i!=SLOT_TEMP) // skip temporary slot because it's not drawn using 'Image' class
          {
             Image           &img_back=     slot_img[i][0], // background image, we use it for accessing its rectangle
                             &img_item=     slot_img[i][1]; // item       image
             Reference<Item> &    item=inv->slot    [i]   ; // item at slot

             if(!item.valid())img_item.set(NULL);else // if there is no item then clear the item image slot
             {
                Gfx *icon=item().icon; // access item's icon
                img_item.set(icon);    // set slot image as the item's icon
                if(icon)               // set proper scaling
                {
                   Vec2 size(icon->x(),icon->y()); size*=PIXEL_SIZE; // set default size
                   if(size.x>img_back.rect.w())size*=img_back.rect.w()/size.x; // clamp item size to background slot width
                   if(size.y>img_back.rect.h())size*=img_back.rect.h()/size.y; // clamp item size to background slot height
                   Rect rect(img_back.rect.center()); rect.extend(size/2);
                   img_item.setRect(rect);
                }
             }
          }
       }else
       {
          list.clear();
          REP(SLOT_NUM)slot_img[i][1].set(NULL);
       }
    }
    /******************************************************************************/
    // UPDATE
    /******************************************************************************/
    void InventoryGui::update(Game::Chr &owner)
    {
       if(inv)
       {
          if(Ms.bp(0)) // if mouse button pressed
          {
             if(inv->slot[SLOT_TEMP].valid()) // if we have an item attached with mouse
             {
                if(Gui.ms==&list) // if mouse cursor is on the list
                {
                   inv->slot[SLOT_TEMP].clear(); // clear the slot reference which will result in "putting back the item into the list"
                   setGui();                     // update visuals
                }else
                if(Gui.ms==Gui.desktop || !Gui.ms) // if mouse cursor is on the desktop or nothing (this means the game world area)
                {
                   owner.itemDropDown(inv->slot[SLOT_TEMP]()); // drop the item onto the world
                }
             }
             else // we don't have an item so we want to get one
             {
                if(Gui.ms==&list) // from the list
                {
                   if(Item *item=list())
                   {
                      inv->slot[SLOT_TEMP]=item;
                      setGui();
                   }
                }
             }

             REP(SLOT_NUM)
                if(Gui.ms==&slot_img[i][0] || Gui.ms==&slot_img[i][1]) // if we want to put the item onto the i-th slot
                   if(inv->slotsCanBeSwapped(SLOT_TEMP,i))
                   {
                      Swap(inv->slot[SLOT_TEMP],inv->slot[i]); // swap temporary with i-th slot
                      setGui();                                // update visuals
                   }
          }
       }
    }
    /******************************************************************************/
    // DRAW
    /******************************************************************************/
    void InventoryGui::draw()
    {
       if(inv && inv->slot[SLOT_TEMP].valid())inv->slot[SLOT_TEMP]().drawIcon(Ms.pos);
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\5 - Projects (here all files from a single directory need to be included in project)\02 - Inventory\Inventory.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "main.h"
    /******************************************************************************/
    Inventory::~Inventory()
    {
       if(inv_gui)inv_gui->unlink();
    }
    /******************************************************************************/
    // GET
    /******************************************************************************/
    Bool Inventory::slotCanBePutTo(Int src,Int dest)
    {
       if(!InRange(src,SLOT_NUM) || !InRange(dest,SLOT_NUM))return false;

       if(slot[src].valid())switch(dest)
       {
          case SLOT_HEAD:
          case SLOT_BODY:
             if(slot[src]().type==ITEM_WEAPON)return false;
          break;
       }

       return true;
    }
    Bool Inventory::slotsCanBeSwapped(Int a,Int b)
    {
       return slotCanBePutTo(a,b) && slotCanBePutTo(b,a);
    }
    /******************************************************************************/
    // OPERATIONS
    /******************************************************************************/
    void Inventory::itemRemoved(Game::Item &item) // when an item is being removed from a character
    {
       // perform check if it is a equipped item
       REPA(slot) // for all slots
          if(slot[i]==item) // if i-th slot is set to item which is being removed
             slot[i].clear(); // clear the slot so it can no longer be referenced to the removed item
    }
    void Inventory::itemRemoved(                ){setGui();} // when item has been removed from a character
    void Inventory::itemAdded  (Game::Item &item){setGui();} // when item has been added to a character
    void Inventory::setGui     (                ){if(inv_gui)inv_gui->setGui();}
    /******************************************************************************/
    // UPDATE
    /******************************************************************************/
    void Inventory::update(Game::Chr &owner)
    {
       if(inv_gui)inv_gui->update(owner);

       // set matrixes for items in hands
       if(slot[SLOT_ARM_L].valid())
          if(OrientP *point=owner.cskel.findPoint("HandL"))
             slot[SLOT_ARM_L]().matrix(Matrix().setPosDir(point->pos,point->perp,point->dir));

       if(slot[SLOT_ARM_R].valid())
          if(OrientP *point=owner.cskel.findPoint("HandR"))
             slot[SLOT_ARM_R]().matrix(Matrix().setPosDir(point->pos,point->perp,point->dir));
    }
    /******************************************************************************/
    // DRAW
    /******************************************************************************/
    void Inventory::draw(Game::Chr &owner)
    {
       // draw items in hands
       if(slot[SLOT_ARM_L].valid())slot[SLOT_ARM_L]().draw();
       if(slot[SLOT_ARM_R].valid())slot[SLOT_ARM_R]().draw();
    }
    /******************************************************************************/
    // IO
    /******************************************************************************/
    void Inventory::save(File &f)
    {
       FREPA(slot) // for all slots
          f.putI32(items.validIndex(&slot[i]())); // store the valid index of i-th slot item in 'items' container
    }
    Bool Inventory::load(File &f)
    {
       FREPA(slot) // for all slots
       {
          Int item_index=f.getI32(); // read index of i-th slot in 'items' container

          if(InRange(item_index,items)) // if the index is in valid range
             slot[i]=items[item_index]; // set the slot to point to requested item
          else
             slot[i].clear(); // clear the item reference in i-th slot
       }
       setGui();
       return true;
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\5 - Projects (here all files from a single directory need to be included in project)\02 - Inventory\Item.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "main.h"
    /******************************************************************************/
    Item::Item()
    {
       name[0]=0;
       type=ITEM_NONE;
       power=0;
       icon=NULL;
    }
    /******************************************************************************/
    // MANAGE
    /******************************************************************************/
    void Item::create(Game::ObjParams &obj)
    {
       __super::create(obj);

       // set name
       if(Game::Param *p=obj.findParam("name"))Set(name,p->asStr());

       // set type
       if(Game::Param *p=obj.findParam("type"))type=p->asEnum();

       // set power
       if(Game::Param *p=obj.findParam("power"))power=p->asFlt();

       // get icon
       for(Game::ObjParams *op=&obj; op; op=op->base()) // iterate through all ObjParams, to find first with a valid icon
          if(CChar *op_file_name=Game::Objs(op)) // if current ObjParams is stored in a file (the file name is not NULL)
             if(icon=Gfxs.get(GetExtNot(op_file_name)+".ico.gfx")) // if there exists an icon with the same name as ObjParams but with different extension
                break; // break
    }
    /******************************************************************************/
    // DRAW
    /******************************************************************************/
    void Item::draw()
    {
       if(Lit==this && Renderer()==RM_SOLID)SetHighlight(0x303030); __super::draw();
       if(Lit==this && Renderer()==RM_SOLID)SetHighlight(0);
    }
    /******************************************************************************/
    void Item::drawIcon(Vec2 &pos)
    {
       if(icon)
       {
          icon->drawFit(pos.x,pos.y, icon->x()*PIXEL_SIZE, icon->y()*PIXEL_SIZE);
       }
    }
    /******************************************************************************/
    // IO
    /******************************************************************************/
    void Item::save(File &f)
    {
       __super::save(f);
       f<<name<<power<<type;
       f.putStr16(Gfxs(icon));
    }
    Bool Item::load(File &f)
    {
       if(__super::load(f))
       {
          f>>name>>power>>type;
          icon=Gfxs(f.getStr16());
          return true;
       }
       return false;
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\5 - Projects (here all files from a single directory need to be included in project)\02 - Inventory\Main.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "main.h"
    /******************************************************************************/
    Game::Obj            *Lit    ; // highlighted world object
    Game::ObjMemx<Item  > Items  ;
    Game::ObjMemx<Player> Players;
    /******************************************************************************/
    void InitPre()
    {
       App.name("Inventory");
       App.flag=APP_FULL_TOGGLE;
       IOPath("../data");
       PakAdd("engine.pak");

       D.full(true).sync(true).shdMapSize(1024).ambPower(0.3);

       ViewportFull.range=70;
       Cam.at.set(16,0,16);
       Cam.dist = 10;
       Cam.pitch=-PI_6;
    }
    /******************************************************************************/
    Bool Init()
    {
       Physics.create();
       Sky    .set   ();
       Sun &sun=Suns.New(); sun.set(*Gfxs("gfx/sky/sun.gfx")).light_color=1-D.ambColor(); sun.rays.mode=SUN_RAYS_HIGH;

       Game::World.init   (                )
                  .setType(Players,OBJ_CHR )
                  .setItem(Items  ,OBJ_ITEM)
                  .New    ("world/sample"  );

       InvGui.create();

       // modify default gui visuals
       Gui.style_window.blur_color=0xFF442200;
       Gui.style_window.back_color=0xFFFF4400;

       Gui.style_region.back_color=0x66000000;

       Gui.kb_lit=0;

       return true;
    }
    /******************************************************************************/
    void Shut()
    {
    }
    /******************************************************************************/
    void GetWorldObjectUnderCursor()
    {
       Lit=NULL;
       if(!Gui.ms || Gui.ms==Gui.desktop)
       {
          Vec      pos,dir; ScreenToPosDir(Ms.pos,pos,dir);
          PhysHit phys_hit; if(Physics.ray(pos,dir*Viewport.range,&phys_hit,1))Lit=phys_hit.obj;
       }
    }
    /******************************************************************************/
    Bool Main()
    {
       if(Kb.bp(KB_ESC))return false;

       if(Players.elms())Cam.at=Players[0].pos();
       CamHandle(0.1,100,CAMH_ZOOM|(Ms.b(1)?CAMH_ROT:0));

       if(Kb.bp(KB_F2))Game::World.save("LocalData/save.sav");
       if(Kb.bp(KB_F3))Game::World.load("LocalData/save.sav");

       Game::World.update(Cam.at);
       Gui.update();
       GetWorldObjectUnderCursor();

       return true;
    }
    /******************************************************************************/
    void Render()
    {
       Game::World.draw();
    }
    void Draw()
    {
       Renderer(Render);
       Gui   .draw();
       InvGui.draw();
    }
    /******************************************************************************/

    ESENTHEL ENGINE SDK      Advanced\5 - Projects (here all files from a single directory need to be included in project)\02 - Inventory\Player.txt

    /******************************************************************************/
    #include "stdafx.h"
    #include "main.h"
    /******************************************************************************/
    Player::Player()
    {
       InvGui.link(&inv); // when creating a player automatically link him with InvGui
    }
    /******************************************************************************/
    // UPDATE
    /******************************************************************************/
    Bool Player::update()
    {
       if(__super::update())
       {
          // detect if the player wants to pickup an item
          if(Lit && Ms.bp(0)) // if hase highlighted object and mouse button pressed
             if(Item *item=CAST(Item,Lit)) // if the object is an item
                itemPickUp(*item); // pick it up

          // update the inventory
          inv.update(T);

          return true;
       }
       return false;
    }
    /******************************************************************************/
    // DRAW
    /******************************************************************************/
    void Player::draw()
    {
       __super::draw( );
            inv.draw(T);
    }
    /******************************************************************************/
    // IO
    /******************************************************************************/
    void Player::save(File &f)
    {
       __super::save(f);
            inv.save(f);
    }
    Bool Player::load(File &f)
    {
       if(__super::load(f))
       {
          return inv.load(f);
       }
       return false;
    }
    /******************************************************************************/