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

Module: TiMiniMap

Author: Matt Stelzer

Description:

Mini map

Copyright 2006 Sony Online Entertainment.  All rights reserved.

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

#include "TiMiniMap.h"
#include "TiUI.h"

#define MINIMAP_LOC_X       999
#define MINIMAP_LOC_Y       14

TiMiniMap::TiMiniMap() :
  mRaster(0),
  mMaskSurfaceHandle(0),
  mMapSurfaceHandle(0),
  mOffset(1.0f, 2.0f),
  mScale(3.0f, 4.0f),
  mZoom(2.0f)
{
}

void TiMiniMap::Init(const SyString&  mapBaseName,
                     const SyVect2&   worldPos1,
                     const SyVect2&   worldPos2,
                     const SyVect2&   mapPos1,
                     const SyVect2&   mapPos2,
                     SyRaster*        raster,
                     SyDictionary*    dictionary)
{
  char buf[512];

  // Store the raster device
  mRaster = raster;

  // Set up compass overlay sprite
  mCompassSprite.SetInfo("hud_minimap_reticule.tga");

  // Set up the map mask surface
  if (dictionary->FindTyped(SyHashResourceID("hud_minimap_reticule_alpha.tga"), SYRESOURCETYPE_SURFACE, mMaskSurfaceHandle) == 0)
  {
    mMaskSurfaceHandle = -1;
  }

  // Set up minimap surface
  sprintf(buf, "%s.tga", mapBaseName.AsChar());
  if (dictionary->FindTyped(SyHashResourceID(buf), SYRESOURCETYPE_SURFACE, mMapSurfaceHandle) == 0)
  {
    mMapSurfaceHandle = -1;
  }

  // Calculate offset and scale
  CalculateMapToWorldTransform(worldPos1, worldPos2, mapPos1, mapPos2);
}

void TiMiniMap::Update(const SyVect3& pos, float heading)
{
  mPlayerPos(0) = pos(0);
  mPlayerPos(1) = pos(2);
  mHeading      = heading + SY_PI;
}

void TiMiniMap::Draw() const
{
  SyMatrix33  mat;

  if (mRaster != 0)
  {
    CalculateMapTextureTransform(mat);

    mRaster->MinimapBlit(mMapSurfaceHandle,
                         mMaskSurfaceHandle,
                         -1,
                         SyVect2I(MINIMAP_LOC_X, MINIMAP_LOC_Y),
                         SyVect2I(128, 128),
                         SyVect2I(256, 256),
                         mat);

    mCompassSprite.Draw(TiPoint(MINIMAP_LOC_X, MINIMAP_LOC_Y));
  }
}

void TiMiniMap::CalculateMapToWorldTransform(const SyVect2& worldPos1,
                                             const SyVect2& worldPos2,
                                             const SyVect2& mapPos1,
                                             const SyVect2& mapPos2)
{
  float worldDeltaX = worldPos2(0) - worldPos1(0);
  float worldDeltaY = worldPos2(1) - worldPos1(1);
  float mapDeltaX = mapPos2(0) - mapPos1(0);
  float mapDeltaY = mapPos2(1) - mapPos1(1);

  mScale(0) = mapDeltaX / worldDeltaX;
  mScale(1) = mapDeltaY / worldDeltaY;

  mOffset(0) = mapPos1(0) - (mScale(0) * worldPos1(0));
  mOffset(1) = mapPos1(1) - (mScale(1) * worldPos1(1));

  if ((mRaster != 0) &&
      (mMapSurfaceHandle != -1))
  {
    SySurface* surf = mRaster->Surface(mMapSurfaceHandle);

    if (surf != 0)
    {
      mScale(0) /= surf->Width();
      mScale(1) /= surf->Height();
      mOffset(0) /= surf->Width();
      mOffset(1) /= surf->Height();
    }
  }
}

void TiMiniMap::CalculateMapTextureTransform(SyMatrix33& mat) const
{
  SyVect2     pos;
  SyVect2     pos2;
  SyMatrix33  tex_scale;
  SyMatrix33  tex_trans;
  float       zoom = 1.0f / mZoom;
  SyVect3     temp(-0.5f * zoom, -0.5f * zoom, 0.0f);
  float       s = sinf(mHeading);
  float       c = cosf(mHeading);

  // Convert world coordinates to map texture UVs
  pos = mPlayerPos;
  pos *= mScale;
  pos += mOffset;

  // Texture rotation
  tex_trans.Identity();
  tex_trans(0, 0) =  c;
  tex_trans(0, 1) = -s;
  tex_trans(1, 0) =  s;
  tex_trans(1, 1) =  c;

  // Texture scaling
  tex_scale.Identity();
  tex_scale(0, 0) = zoom;
  tex_scale(1, 1) = zoom;

  // Concatenate the scale and rotation
  mat.Mul(tex_scale, tex_trans);

  // Translate the offset
  SyVect3 temp2;
  tex_trans.Mul(temp, temp2);

  // Set the offset
  mat(2, 0) = temp2.X + pos.X;
  mat(2, 1) = temp2.Y + pos.Y;
  mat(2, 2) = 1.0f;
}
