/******************************************************************
  
  Module:  graphic.cpp
  
  Author: Sean Craig
  
  Copyright 2005 Sony Online Entertainment.  All rights reserved.
  
*******************************************************************/

//-------------------------------------------------------- Includes
#include "graphic.h"
#include "gameobj.h" 
#include "registry.h"
#include "stats.h"
#include "titan.h"
#include "syscene.h"
#include "SyEsfParse.h"

#include "animdefs.h"
#include "physics.h"

#include "inventory.h"
#include "SyNameSprite.h"

//---------------------------------------------- Class Declarations

//---------------------------------------------- cGraphic

cGraphic::cGraphic()
{
  InitPropObject( mCLASSID );
}

void 
cGraphic::SetOwner(cGameObject *owner)
{
  mOwner = owner;
}


int           
cGraphic::InitPropClass()
{

/* Add the class */

  AddClass( mCLASSID, 
            "cGraphic", 
            Creator, 
            mCLASSID, 
            0 ); 
  return 0;
}

SyPropObject* 
cGraphic::Creator()
{
  SyPropObject *pObject;

  pObject = SyNew cGraphic();
  if(pObject == NULL)
  {                            
    SyAssert(0);
    return(NULL);
  }

  return(pObject);
}

void cGraphic::SetVisible(bool bVisible)
{
  SyActorHandle handle = GetActorHandle();
  
  if (handle != SyActorNull)
  {
    SyScene *scene = mOwner->GetRegistry()->GetTitan()->GetScene();

    scene->SetActorVisibility(handle, bVisible);
  }
}

//---------------------------------------------- cGraphicActor
cGraphicActor::cGraphicActor()   : 
  mActorHandle(NULL)
{
  InitPropObject( mCLASSID );
}

cGraphicActor::~cGraphicActor()
{
  Release();
};

void 
cGraphicActor::Release()
{
  if (mActorHandle != NULL)
  {
    SyScene *scene = mOwner->GetTitan()->GetScene();

    scene->ReleaseActor(mActorHandle);

    mActorHandle = NULL;
  }
}
int           
cGraphicActor::InitPropClass()
{

/* Add the class */

  AddSubClass( mCLASSID, 
               cGraphic::mCLASSID,
               mCLASSID,
               "cGraphicActor", 
               Creator, 
               mCLASSID, 
               0 ); 
  return 0;
}

SyPropObject* 
cGraphicActor::Creator()
{
  SyPropObject *pObject;

  pObject = SyNew cGraphicActor();
  if(pObject == NULL)
  {                            
    SyAssert(0);
    return(NULL);
  }

  return(pObject);
}

void  
cGraphicActor::Init()
{
  // load up model...note that resource should already be loaded 
  // if we're loading from an esf file, and this should just hook
  // 'em up.

  if (mActorHandle != NULL)
  {

    return; // already init
  }

  const char *path = mOwner->GetModel();

  if (path == NULL)
  {
    //SyAssert(0);
    return;
  }

  SyScene *scene = mOwner->GetTitan()->GetScene();

  SyESFParse Parser;
  int32 SpriteTemplateHandle = Parser.ParseSprite(path, *scene );

  if (SpriteTemplateHandle == -1)
  {
    SyAssertf(0,"Can't Parse .ESF file '%s'",path); 
    return;
  }

  const SyVect3 &ActorLoc = mOwner->GetLocation();
  const SyVect3 &ActorHPR = mOwner->GetHPR();

  float32 ActorScale = 1.0f;

  mActorHandle   = scene->CreateActor( ActorLoc, ActorHPR, ActorScale, SpriteTemplateHandle );

}



void  
cGraphicActor::Prerender()
{
  // update location of graphic...
  if (mActorHandle == NULL)
  {
    return;
  }
  SyScene *scene = mOwner->GetTitan()->GetScene();

  if (mOwner->IsRemote())
  {
    scene->SetActorLocation(mActorHandle,mOwner->GetPhysics()->GetRenderLocation());
    SyVect3 hpr = mOwner->GetHPR();
    hpr.X = mOwner->GetPhysics()->GetRenderHeading();
    scene->SetActorHPR(mActorHandle,hpr);

  }
  else
  {
    scene->SetActorLocation(mActorHandle,mOwner->GetLocation());
    scene->SetActorHPR(mActorHandle,mOwner->GetHPR());
  }
}

void          
cGraphicActor::SetAlpha(float alpha)
{
  if (mActorHandle == NULL)
  {
    return;
  }
  static const float ALPHA_THRESHOLD = 0.99f;
  SyScene *scene = mOwner->GetRegistry()->GetTitan()->GetScene();
  scene->SetActorSpriteAlphaBlend( mActorHandle, (alpha < ALPHA_THRESHOLD), alpha );
}
//---------------------------------------------- cGraphicCharacter
cGraphicCharacter::cGraphicCharacter()   : 
  mAnimController(NULL),
  mAnimDisplacement(0,0,0),
  mDirty(false),
  mNameSpriteHandle(0),
  mNameSpriteHandle2(0)
{
  InitPropObject( mCLASSID );
}

cGraphicCharacter::~cGraphicCharacter()
{
  delete mAnimController;
  mAnimController = NULL;
};

int           
cGraphicCharacter::InitPropClass()
{
/* Add the class */

  AddSubClass( mCLASSID, 
               cGraphicActor::mCLASSID,
               mCLASSID,
               "cGraphicCharacter", 
               Creator, 
               mCLASSID, 
               0 ); 

  return 0;
}

SyPropObject* 
cGraphicCharacter::Creator()
{
  SyPropObject *pObject;

  pObject = SyNew cGraphicCharacter();
  if(pObject == NULL)
  {                            
    SyAssert(0);
    return(NULL);
  }

  return(pObject);
}

void  
cGraphicCharacter::Create()
{
}

void  
cGraphicCharacter::Init()
{
  // load up model...note that resource should already be loaded 
  // if we're loading from an esf file, and this should just hook
  // 'em up.

  if (mActorHandle != NULL)
  {
    return; // already init
  }

  cGraphicActor::Init();

  mAnimController = cAnimCharControllerInterface::Allocate();
  mAnimController->Init(mOwner);
}


void          
cGraphicCharacter::Reset()
{
  mAnimController->Reset();
}



void  
cGraphicCharacter::Update(float delta)
{

  mAnimController->Update(delta);

  if (mDirty)
  {
    RecalculateWeaponAttachments();
    mDirty = false;
  }

  SyScene *scene = mOwner->GetRegistry()->GetTitan()->GetScene();
  SyCSprite* cSprite = (SyCSprite*)  scene->GetActorSpritePtr( mActorHandle);
  SyAssert(cSprite!=NULL); 

  if (mOwner->GetTitan()->GetDebugLabel())
  {
    char status[120];

    cStatsCharacter * stats = (cStatsCharacter *)mOwner->GetStats();
    sprintf(status,"%s HP: %d Block: %d",stats->GetMaster()->mID.GetName(),stats->GetHealth(),stats->GetBlock());
    AddDebugText(mAnimController->GetAnimStateName(),status);
  }
  else if (mNameSpriteHandle != 0)
  {
    cSprite->Detach(mNameAttachIndex,*scene );
    cSprite->Detach(mNameAttachIndex2,*scene );
    mNameSpriteHandle = 0;
  }

  SyMatrix44 transform;
  SyVect3 Rotation,Scale, Translation;
  cSprite->CalcMotionDeltaTransform(*scene,transform);
  transform.ConvertTo(Rotation, Scale, Translation);
  float heading = mOwner->GetHeading();

  mAnimDisplacement.X = (SY_SIN(heading) * Translation.Z + SY_COS(heading) * Translation.X);
  mAnimDisplacement.Y = 0;
  mAnimDisplacement.Z = (SY_COS(heading) * Translation.Z - SY_SIN(heading) * Translation.X);
}

const SyVect3 &                  
cGraphicCharacter::GetDisplacement() 
{
  return mAnimDisplacement;
}

void 
cGraphicCharacter::EnterScope()
{
  // Called when object comes into focus

  // throws away motion transforms, as object is paw
  SyScene *scene = mOwner->GetRegistry()->GetTitan()->GetScene();
  SyCSprite* cSprite = (SyCSprite*)  scene->GetActorSpritePtr( mActorHandle);
  SyAssert(cSprite!=NULL); 
  SyMatrix44 transform;
  SyVect3 Rotation,Scale, Translation;
  cSprite->CalcMotionDeltaTransform(*scene,transform);
}

void                  
cGraphicCharacter::RecalculateWeaponAttachments()
{
  typedef enum
  {
    ATTACH_MELEE=1,
    ATTACH_RANGED,
    ATTACH_HEAD,
    ATTACH_BODY,
    ATTACH_FEET,
    ATTACH_ACCESSORY
  } eAttachSlots;

  static const int lSlots[] =
  {
    ATTACH_MELEE, // Equip_Melee
    ATTACH_RANGED, // Equip_Ranged
    ATTACH_HEAD, // Equip_Head
    ATTACH_BODY, // Equip_Body
    ATTACH_FEET, // Equip_Feet
    ATTACH_ACCESSORY // Equip_Accessory
  };

  SyScene *scene = mOwner->GetRegistry()->GetTitan()->GetScene();
  SyCSprite* cSprite = (SyCSprite*)  scene->GetActorSpritePtr( mOwner->GetGraphic()->GetActorHandle());
  SyAssert(cSprite!=NULL); 

  cInventoryCharacter *inv = (cInventoryCharacter*) mOwner->GetInventory();
  for (int ii=EQUIP_MELEE;ii!=EQUIP_UNEQUIPPED;++ii)
  {
    cItem *item = inv->GetEquippedItem((eEquipSlot)ii);
    if (item == NULL)
    {
      cSprite->DetachFromSlot(lSlots[ii],*scene );
      continue;
    }

    const char * path = item->GetMaster()->mAttachModel;
    if (path == NULL || path[0] == '\0')
    {
      cSprite->DetachFromSlot(lSlots[ii],*scene );
      continue;
    }

    SyESFParse Parser;
    int32 attach_id = Parser.ParseSprite(path, *scene );
    cSprite->AttachToSlot(attach_id,lSlots[ii],*scene );
  }
}


void                  
cGraphicCharacter::AddDebugText(const char *line1, const char *line2)
{
  SyScene *scene = mOwner->GetRegistry()->GetTitan()->GetScene();
  SyCSprite* CSprite = (SyCSprite*)  scene->GetActorSpritePtr( mOwner->GetGraphic()->GetActorHandle());
  SyAssert(CSprite!=NULL); 

  SyNameSprite *pNameSprite;
  if (mNameSpriteHandle == 0)
  {
    mNameSpriteHandle = scene->CreateSprite(SYSPRITETYPE_NAME,false);
    pNameSprite = (SyNameSprite *) scene->Sprite(mNameSpriteHandle);
    pNameSprite->Init(line1,0/*font resource id*/,SyColor32F(1.0f,1.0f,1.0f,1.0f),scene->GetRasterDev());
    SyMatrix44 offset;
    float scale = CSprite->GetDefaultScale();
    float distance = 2.0f / scale;
 
    offset.Translate(SyVect3(0,distance*1.5,0));
    
    mNameAttachIndex =  CSprite->Attach(mNameSpriteHandle,CSprite->Root(),offset,*scene);

    mNameSpriteHandle2 = scene->CreateSprite(SYSPRITETYPE_NAME,false);
    pNameSprite = (SyNameSprite *) scene->Sprite(mNameSpriteHandle2);
    pNameSprite->Init(line2,0/*font resource id*/,SyColor32F(1.0f,1.0f,1.0f,1.0f),scene->GetRasterDev());
    offset.Translate(SyVect3(0,distance*1.7f,0));
    mNameAttachIndex2 =  CSprite->Attach(mNameSpriteHandle2,CSprite->Root(),offset,*scene);
   }
  else
  {
    pNameSprite = (SyNameSprite *) scene->Sprite(mNameSpriteHandle);
    pNameSprite->SetName(line1);
    pNameSprite = (SyNameSprite *) scene->Sprite(mNameSpriteHandle2);
    pNameSprite->SetName(line2);
  }

}

//---------------------------------------------- cGraphicProp
cGraphicProp::cGraphicProp()
: cGraphicActor(),
  mAnimController(NULL)
{
  InitPropObject( mCLASSID );
}

cGraphicProp::~cGraphicProp()
{
  delete mAnimController;
  mAnimController = NULL;
};

int           
cGraphicProp::InitPropClass()
{
  /* Add the class */

  AddSubClass( mCLASSID, 
    cGraphicActor::mCLASSID,
    mCLASSID,
    "cGraphicProp", 
    Creator, 
    mCLASSID, 
    0 ); 
  return 0;
}

SyPropObject* 
cGraphicProp::Creator()
{
  SyPropObject *pObject;

  pObject = SyNew cGraphicProp();
  if(pObject == NULL)
  {                            
    SyAssert(0);
    return(NULL);
  }

  return(pObject);
}

void  
cGraphicProp::Init()
{
  // load up model...note that resource should already be loaded 
  // if we're loading from an esf file, and this should just hook
  // 'em up.

  cGraphicActor::Init();

  SyScene *scene = mOwner->GetRegistry()->GetTitan()->GetScene();

  if (mActorHandle != NULL &&
      scene->GetActorSpriteType(mActorHandle) == SYSPRITETYPE_CSPRITE &&
      mAnimController == NULL)
  {
    // only create anim controller if we support anims
    mAnimController = cAnimPropControllerInterface::Allocate();
    SyAssert(mAnimController);
    if (mAnimController != NULL)
    {
      mAnimController->Init(mOwner);
    }
  }
}

void  
cGraphicProp::Reset()
{
  if (mAnimController)
  {
    mAnimController->Reset();
  }
}


void  
cGraphicProp::Update(float delta)
{
  if (mAnimController)
  {
    mAnimController->Update(delta);
  }
}

void
cGraphicProp::NetworkReceiveBroadcast(const char *packet, int size)
{
  if (mAnimController)
  {
    mAnimController->NetworkReceiveBroadcast(packet,size);
  }
}


//--------------------------------------------------------- Globals
//----------------------------------------- Functions Declarations
void 
RegPropClasses_Graphic()
{
  cGraphic::InitPropClass();
  cGraphicActor::InitPropClass();
  cGraphicCharacter::InitPropClass();
  cGraphicProp::InitPropClass();
}
//------------------------------------ Member Functions Definitions


// EOF
