{-------------------------------}
{------- uObjectsManager -------}
{-------------------------------}
{                               }
{ version:  0.2                 }
{ date:     22.02.2011          }
{                               }
{-------- developed by: --------}
{                               }
{     Vadim Burenkov aka Vad    }
{                               }
{ mail: vadim_burenkov@mail.ru  }
{                               }
{-------------------------------}
unit uObjectsManager;

{$DEFINE STATIC}

//Directive allow you to use light engine
{$DEFINE LE_SUPPORT}

interface

uses
  DataLists,
  zglChipmunk,
  {$IFDEF LE_SUPPORT}
  LightEngine2D,
  {$ENDIF}

  {$IFNDEF STATIC}
  zglHeader
  {$ELSE}
  zgl_Textures,
  zgl_Textures_png,
  zgl_Sprite_2d,
  zgl_math_2d
  {$ENDIF}
  ;

type
 TPolyData = record
  verts: array of cpVect;
  vCount:integer;
end;

type
 TCircleData = record
  p: cpVect;
  r:integer;
end;

type
 TObjectData = record
  poly: array of TPolyData;
  pCount:integer;
  circle: array of TCircleData;
  cCount:integer;

  m,f,e:single;
  tex:shortstring;
end;

type
 PGameObject=^TGameObject;
  TGameObject = record
   cpPoly   : array of PcpShape;
   pCount:integer;
   cpCircle: array of PcpShape;
   {$IFDEF LE_SUPPORT}
   lePoly : array of PShadowShape;
   leCircle: array of PShadowShape;
   {$ENDIF}
   cCount:integer;
   body:PcpBody;
   tex:zglPTexture;
   size:single;
   next,prev:PGameObject;
end;


function obj_LoadData( p: ShortString ): TObjectData;
procedure obj_SaveData( t: TObjectData; p: ShortString );

function obj_Create( objData: TObjectData; size: single ): PGameObject;
procedure obj_Free( t: PGameObject );
procedure obj_Draw( t: PGameObject );
procedure obj_Update( t: PGameObject );
procedure obj_Each( p: dl_proc );

var
  obj_List: TDataList;
  mSpace: PcpSpace;

implementation

function obj_LoadData( p: ShortString ): TObjectData;
var
  f:file;
  n,j:integer;
  t:TObjectData;
begin
  Assignfile(f,p);
  reset(f,1);

  blockread(f,t.pCount,SizeOf(t.pCount));
  SetLength(t.Poly,t.pCount);
  for n:=0 to t.pCount-1 do
  begin
   blockread(f,t.Poly[n].vCount,SizeOf(t.Poly[n].vCount));
   SetLength(t.Poly[n].verts,t.poly[n].vCount);
   for j:=0 to t.Poly[n].vCount-1 do
   begin
    blockread(f,t.Poly[n].Verts[j].x,SizeOf(t.Poly[n].Verts[j].x));
    blockread(f,t.Poly[n].Verts[j].y,SizeOf(t.Poly[n].Verts[j].y));
   end;
  end;

  blockread(f,t.cCount,SizeOf(t.cCount));
  SetLength(t.circle,t.cCount);
  for n:=0 to t.cCount-1 do
  begin
   blockread(f,t.circle[n].p.x,SizeOf(t.circle[n].p.x));
   blockread(f,t.circle[n].p.y,SizeOf(t.circle[n].p.y));
   blockread(f,t.circle[n].r,SizeOf(t.circle[n].r));
  end;

  blockread(f,t.m,SizeOf(t.m));
  blockread(f,t.f,SizeOf(t.f));
  blockread(f,t.e,SizeOf(t.e));
  blockread(f,t.tex,SizeOf(t.tex));

  CloseFile(f);
  result:=t;
end;

procedure obj_SaveData( t: TObjectData; p: ShortString );
var
  f:file;
  n,j:integer;
begin
  Assignfile(f,p);
  rewrite(f,1);

  blockwrite(f,t.pCount,SizeOf(t.pCount));
  for n:=0 to t.pCount-1 do
  begin
   blockwrite(f,t.Poly[n].vCount,SizeOf(t.Poly[n].vCount));
   for j:=0 to t.Poly[n].vCount-1 do
   begin
    blockwrite(f,t.Poly[n].Verts[j].x,SizeOf(t.Poly[n].Verts[j].x));
    blockwrite(f,t.Poly[n].Verts[j].y,SizeOf(t.Poly[n].Verts[j].y));
   end;
  end;

  blockwrite(f,t.cCount,SizeOf(t.cCount));
  for n:=0 to t.cCount-1 do
  begin
   blockwrite(f,t.circle[n].p.x,SizeOf(t.circle[n].p.x));
   blockwrite(f,t.circle[n].p.y,SizeOf(t.circle[n].p.y));
   blockwrite(f,t.circle[n].r,SizeOf(t.circle[n].r));
  end;

  blockwrite(f,t.m,SizeOf(t.m));
  blockwrite(f,t.f,SizeOf(t.f));
  blockwrite(f,t.e,SizeOf(t.e));
  blockwrite(f,t.tex,SizeOf(t.tex));

  CloseFile(f);
end;


function obj_Create( objData: TObjectData; size: single ): PGameObject;
var
 t:PGameObject;
 i:single;
 v: array of cpVect;
 r:single;
 j,n:integer;
 {$IFDEF LE_SUPPORT}
 leGroup:single;
 {$ENDIF}
begin
 new(t);

 t.tex := tex_LoadFromFile( objData.tex,  $FF000000, TEX_DEFAULT_2D);
 t.size:=size;

 {$IFDEF LE_SUPPORT}
 leGroup:=le_GetNewGroup;
 {$ENDIF}
 t.pCount:=objData.pCount;
 t.cCount:=objData.cCount;

 SetLength(t.cpPoly,t.pCount);
 SetLength(t.cpCircle,t.cCount);

 {$IFDEF LE_SUPPORT}
 SetLength(t.lePoly,t.pCount);
 SetLength(t.leCircle,t.cCount);
 {$ENDIF}

 t.Body:= cpBodyNew(objData.m, infinity);
 cpSpaceAddBody( mSpace, t.Body );

 i := 0;
 for j:=0 to t.pCount-1 do
 begin
  SetLength(v,objData.poly[j].vCount);
  for n:=0 to objData.poly[j].vCount-1 do
  begin
   v[n]:=cpvmult(objData.Poly[j].verts[n],t.size);
  end;

  t.cpPoly[j]:= cpPolyShapeNew(t.body, objData.Poly[j].vCount, @v[0], cpvzero); //to-add: change mass center
  cpSpaceAddShape(mSpace, t.cpPoly[j]);
  t.cpPoly[j].e:= objData.e;
  t.cpPoly[j].u:= objData.f;
  i:=i+cpMomentForPoly(objData.m, objData.Poly[j].vCount, @v[0], cpvzero); //to-add: change mass center
  {$IFDEF LE_SUPPORT}
  t.lePoly[j]:=le_CreateShadowShape(t.cpPoly[j], leGroup);
  {$ENDIF}
 end;

 for j:=0 to t.cCount-1 do
 begin
  r:=objData.Circle[0].r*t.size;
  t.cpCircle[j]:= cpCircleShapeNew(t.body, r, cpvzero); //to-add: removal
  cpSpaceAddShape( mSpace, t.cpCircle[j]);
  t.cpCircle[j].e:= objData.e;
  t.cpCircle[j].u:= objData.f;

  i:=i+cpMomentForCircle(objData.m,r,0,cpvzero);

  {$IFDEF LE_SUPPORT}
  t.leCircle[j]:=le_CreateShadowShape(t.cpCircle[j], leGroup);
  {$ENDIF}
end;

 cpBodySetMoment(t.Body, i);

 DataList_Add( obj_List, t );
 result:=t;
end;

procedure obj_Free( t: PGameObject );
var
  i:integer;
begin
  DataList_Free( obj_List, DataList_GetID( obj_List, t ) );
  cpSpaceRemoveBody(mSpace,t.Body);
  for i:=0 to t.pCount-1 do
  begin
   cpSpaceRemoveShape(mSpace,t.cpPoly[i]);
   cpShapeDestroy(t.cpPoly[i]);
   {$IFDEF LE_SUPPORT}
   le_FreeShadowShape(t.lePoly[i]);
   {$ENDIF}
  end;

  for i:=0 to t.cCount-1 do
  begin
   cpSpaceRemoveShape(mSpace,t.cpCircle[i]);
   cpShapeDestroy(t.cpCircle[i]);
   {$IFDEF LE_SUPPORT}
   le_FreeShadowShape(t.leCircle[i]);
   {$ENDIF}
  end;

  tex_del(t.tex);
  cpBodyFree(t.Body);
  Dispose(t);
end;


procedure obj_Draw( t: PGameObject );
var
  ResX,ResY:integer;
begin
  if t.tex=nil then exit;
  ResX:=round(t.tex.Width*t.size);
  ResY:=round(t.tex.Height*t.size);
  ssprite2d_Draw(t.tex,t.body.p.x-ResX/2,t.body.p.y-ResY/2,ResX,ResY,t.body.a*Rad2Deg,255);
end;

procedure obj_Update( t: PGameObject );
begin

end;

procedure obj_Each( p: dl_proc );
begin
  DataList_Each( obj_List, p );
end;

end.
