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;
}
/******************************************************************************/