// task.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "task.h"
#include "Solver.h"


// Global variables
//

controlobj* g_pModule = NULL;
HANDLE moduleh;


void testresultt::init()
{
  solvingtick=0;
  prerenderingtick=0;
  renderingtick=0;
  framequ=0;
}


// CTaskFpu class implementation
//

void controlobj::outtext(string s, i32 x, i32 y, byte r, byte g, byte b)
{
    SetTextColor(dc1,RGB(r,g,b));
    SetTextColor(dc2,RGB(r,g,b));

//    TextOut(dc1,x,y,fillstr,100);             
    TextOut(dc1,x,y,s.data(),s.length());             
//    TextOut(dc2,x,y,fillstr,100);             
  if (!flwindow)
      TextOut(dc2,x,y,s.data(),s.length());             
} 

void controlobj::showparameters()
{
    string curfpsstr,minfpsstr,fpsstr;
    string s,s1;
  char str[50]; 
  w32 surf1,surf2;
  i32 sy,dy;


    if  (curframequ==10)
    {
        /*
    curtime=GetTickCount();

        t=curtime-timedemo.curstarttime;
        if (t<=0) t=1;
        timedemo.curfps=10.0*1000.0/t;

        timedemo.curframequ=0;
        timedemo.curstarttime=curtime;
                                                                                          

        timedemo.framequ+=10;
        t=curtime-timedemo.starttime;
        if (t<=0) t=1;
        timedemo.fps=timedemo.framequ*1000.0/t;
    */

//        FillMemory(fillstr,100,32);

    cineenergy=solver.getcinenergy();
    potentialenergy=solver.getpotenergy();
    energyleak=solver.getenergyleak();
    impulsex=solver.getimpulse().x;
    impulsey=solver.getimpulse().y;
    impulsez=solver.getimpulse().z;

    curframequ=0;
  }


    surf1=ddrawgetbacksurface();
    surf2=ddrawgetprimarysurface();

    dc1=ddrawgetdc(surf1);
    dc2=ddrawgetdc(surf2);

    SelectObject(dc1,infofont);
    SetBkMode(dc1,TRANSPARENT);
//    SetBkColor(dc1,RGB(0,0,0));

    SelectObject(dc2,infofont);
    SetBkMode(dc2,TRANSPARENT);                   
//    SetBkColor(dc2,RGB(0,0,0));


  sy=viewscreeny0+10;
  dy=23;

    _gcvt(framequ,7,str);
    s1=str;
  s="Frame : "+s1;
  outtext(s,viewscreenx0+10,sy,255,255,0);
  sy+=dy;

    _gcvt(cineenergy,7,str);
    s1=str;
  s="Cine Energy : "+s1;
  outtext(s,viewscreenx0+10,sy,255,255,0);
  sy+=dy;

    _gcvt(potentialenergy,7,str);
    s1=str;
  s="Potential Energy : "+s1;
  outtext(s,viewscreenx0+10,sy,255,255,0);
  sy+=dy;

    _gcvt(energyleak,7,str);
    s1=str;
  s="Energy Leak: "+s1;
  outtext(s,viewscreenx0+10,sy,255,255,0);
  sy+=dy;

    _gcvt(impulsex,7,str);
    s1=str;
  s="Impulse X : "+s1;
  outtext(s,viewscreenx0+10,sy,255,255,0);
  sy+=dy;
    
  _gcvt(impulsey,7,str);
    s1=str;
  s="Impulse Y : "+s1;
  outtext(s,viewscreenx0+10,sy,255,255,0);
  sy+=dy;

    _gcvt(impulsez,7,str);
    s1=str;
  s="Impulse Z : "+s1;
  outtext(s,viewscreenx0+10,sy,255,255,0);
  sy+=dy;
        

    ddrawreleasedc(surf1,dc1);
    ddrawreleasedc(surf2,dc2);


  curframequ++;
}

bool controlobj::control()
{
  renderinfot renderinfo;
  lightguidt lightguid;
  sphguidt skysphguid;
  i64 solvingtick;
  void* bufp;
  POINT cursorpos;
  rnumt mdx,mdy;
  i32 i;


  if (flquit)
    return true;

  systemtime=timeGetTime()-startsystemtime;
  framequ++;

  if ((!fltest)&&(framequ>=starttestframenum))
  {
    testresults.init();
    clearrenderstat(renderguid);
    fltest=true;
  }


  sceneguid=seallocatescene(1000,10,pixelformat);
  attachtexturertoscene(sceneguid,texturerguid);


  solvingtick=-getcpucount();

  for (i=0; i<iterationqu; i++)
  {
    
#if defined(TASK_SSE2) 
    solver.devaluate();
#else
    solver.evaluate();
#endif

    solver.step(step);
  }
                                           
  solvingtick+=getcpucount();


  solver.drawobjects(sceneguid,framequ*0.05);


  skysphguid=scenegetskysphere(sceneguid);
  setspheretexture(skysphguid,0,1);
  setspherebgillum3f(skysphguid,1,1,1);
  enablesphereownbgillum(skysphguid,true);

/*
  lightguid=sceneallocatelight(sceneguid);
  setlightcenter3f(lightguid,-300000,0,0);
  setlightdistance(lightguid,10000000);
  setlightcoef(lightguid,1,0.000001,0);
  setlightintense(lightguid,1);
  enablelight(lightguid,true);
*/

//  bufp=malloc(1600*1200*4);


  if ((flfreeview)&&(!flwindow))
    if (GetCursorPos(&cursorpos))
    {
      mdx=cursorpos.x-screenw/2;
      mdy=-cursorpos.y+screenh/2;

      rotateviewright(mdx*0.06*deltat);
      rotateviewup(mdy*0.06*deltat);

      SetCursorPos(screenw/2,screenh/2);
    }
  viewbasis.normalizecolumns();


  renderinfo.viewbasis=viewbasis;
  renderinfo.viewpoint=viewpoint;
  renderinfo.flautointersection=true;
  renderinfo.instructionset=renderiset;
  renderinfo.flsseapproximation=false;
  renderinfo.flshadows=flshadows;
  renderinfo.flqualityshadows=flqualityshadows;
  renderinfo.fltextures=fltextures;
  renderinfo.x0=viewscreenx0;
  renderinfo.y0=viewscreeny0;
  renderinfo.flinternalddraw=true;
  renderinfo.flexternalddrawsurface=false;
  renderinfo.ddrawsurface=0;
  renderinfo.screensurfacep=0;
  renderinfo.wpitch=0;

//  renderinfo.flinternalddraw=false;
//  renderinfo.screensurfacep=(w32)bufp;
//  renderinfo.wpitch=1200;

  try
  {
//    ddrawclear(ddrawgetprimarysurface());
//    ddrawclear(ddrawgetbacksurface());
    renderscene(renderguid,sceneguid,renderinfo);
    showparameters();
    ddrawscreen();
  }
  catch ( ... )
  {
    flquit=true;
    return false;
  }

//  free(bufp);

  seunallocatescene(sceneguid);


  if (fltest)
  {
    testresults.solvingtick+=solvingtick;
    testresults.framequ++;
  }

  if (framequ>=finishtestframenum)
  {
    renderstatinfot renderstatinfo;

    getrenderstat(renderguid,&renderstatinfo);
    testresults.prerenderingtick=renderstatinfo.prerenderingtick;
    testresults.renderingtick=renderstatinfo.raytracingtick;
    fltestperformed=true;

    flquit=true;
  }

  return false;
}


void controlobj::shiftviewleft(rnumt l)
{
  viewpoint-=l*viewbasis.v1();
}

void controlobj::shiftviewright(rnumt l)
{
  viewpoint+=l*viewbasis.v1();
}

void controlobj::shiftviewup(rnumt l)
{
  viewpoint+=l*viewbasis.v2();
}

void controlobj::shiftviewdown(rnumt l)
{
  viewpoint-=l*viewbasis.v2();
}

void controlobj::shiftviewforward(rnumt l)
{
  viewpoint+=l*viewbasis.v3();
}

void controlobj::shiftviewbackward(rnumt l)
{
  viewpoint-=l*viewbasis.v3();
}

//=====================================================================

void controlobj::rotateviewleft(rnumt phi)
{
  viewbasis.rotatey(-phi);
}

void controlobj::rotateviewright(rnumt phi)
{
  viewbasis.rotatey(phi);
}

void controlobj::rotateviewup(rnumt phi)
{
  viewbasis.rotatex(-phi);
}

void controlobj::rotateviewdown(rnumt phi)
{
  viewbasis.rotatex(phi);
}

void controlobj::rotateviewaxialforward(rnumt phi)
{
  viewbasis.rotatez(phi);
}

void controlobj::rotateviewaxialbackward(rnumt phi)
{
  viewbasis.rotatez(-phi);
}

//=====================================================================

void controlobj::rotatescene(i32 axis, rnumt phi)
{
  basisobj r,t;

  switch (axis)
  {
    case 0:
    {
      r.setrx(phi);
      break;
    }
    case 1:
    {
      r.setry(phi);
      break;
    }
    case 2:
    {
      r.setrz(phi);
      break;
    }
  }

  t=viewbasis*r*viewbasis.gettransposed();

  viewpoint=t.transform(viewpoint);
  viewbasis=viewbasis*r;
  viewbasis.normalizecolumns();
}


void controlobj::rotatesceneleft(rnumt phi)
{
  rotatescene(1,-phi);
}

void controlobj::rotatesceneright(rnumt phi)
{
  rotatescene(1,phi);
}

void controlobj::rotatesceneup(rnumt phi)
{
  rotatescene(0,-phi);
}

void controlobj::rotatescenedown(rnumt phi)
{
  rotatescene(0,phi);
}

void controlobj::roatesceneaxialforward(rnumt phi)
{
  rotatescene(2,phi);
}

void controlobj::rotatesceneaxialbackward(rnumt phi)
{
  rotatescene(2,-phi);
}


STDMETHODIMP controlobj::ProcessMessage(HWND, UINT message, WPARAM wparam, LPARAM, LRESULT* lresult)
{
  double time;
  static double time1=-1.0;
  bool shift;
  rnumt scale;
  POINT cursorpos;
  rnumt mdx,mdy;


  scale=100000.0;


  if (time1!=-1.0)
  {
    time=timeGetTime()/1000.0;
    deltat=time-time1;
    time1=time;
  }
  else
  {
    time1=timeGetTime()/1000.0;
    deltat=0.0;
  }


  switch (message)
  {
    case WM_KEYDOWN:
    {
      if (wparam==VK_ESCAPE)
      {
        flquit=true;
        break;                
      } 


      if (!flfreeview) break;

      shift=GetAsyncKeyState(VK_SHIFT);

      switch (wparam)
      {
        case VK_LEFT:
        {
          if (!shift)
            rotatesceneleft(1.0*deltat);
          else
            rotateviewleft(1.0*deltat);

          break;
        }
        case VK_RIGHT:
        {
          if (!shift)
            rotatesceneright(1.0*deltat);
          else
            rotateviewright(1.0*deltat);

          break;
        }
        case VK_UP:
        {
          if (!shift)
            rotatesceneup(1.0*deltat);
          else
            rotateviewup(1.0*deltat);

          break;
        }
        case VK_DOWN:
        {
          if (!shift)
            rotatescenedown(1.0*deltat);
          else
            rotateviewdown(1.0*deltat);

          break;
        }
        case 0x57: shiftviewforward(1.0*scale*deltat); break;
        case 0x58: shiftviewbackward(1.0*scale*deltat); break;
        case 0x51: shiftviewup(1.0*scale*deltat); break;
        case 0x5a: shiftviewdown(1.0*scale*deltat); break;
        case 0x41: shiftviewleft(1.0*scale*deltat); break;
        case 0x44: shiftviewright(1.0*scale*deltat); break;

//        case VK_MBUTTON: shiftviewforward(1.0*scale*deltat); break;
      }

      break;
    }

    case WM_MOUSEMOVE:
    {
      break;
    }
  }


  try
  {
    if (message=WM_STEP)
      *lresult=control();
    else
      *lresult=0;
  }
  catch ( ... )
  {
    return S_FALSE;
  }
  return S_OK;
}
    

STDMETHODIMP controlobj::SetData(void* data)
{
  DATABUNDLE d;


  d=*(LPDATABUNDLE)data;


  screenw=d.rp.di.width;
  screenh=d.rp.di.height;
  screenscalex=d.rp.vp.cx/100.0;
  screenscaley=d.rp.vp.cy/100.0;
  renderiset=d.rp.is+1;
  flshadows=d.rp.flag&RENDER_SHADOWS;
  flqualityshadows=d.rp.flag&RENDER_SHADOWS_SUPER;
  fltextures=d.rp.flag&RENDER_TEXTURE;
  flwindow=d.rp.win;
  flsystemmemory=d.rp.flag&RENDER_OFFSCREEN;
  strcpy(modelname,d.tp.model);
  starttestframenum=d.tp.ttp.cx*1;
  finishtestframenum=d.tp.ttp.cy*1;
  step=d.tp.tts/500000.0;
  iterationqu=d.tp.tin;
  flfreeview=d.rp.camera;


  return S_OK;
}

STDMETHODIMP controlobj::GetData(void* data)
{
  LPRESULTS pr;
  
  pr=(LPRESULTS)data;

  pr->framesqu=testresults.framequ;
  pr->prerenderingtickcount=testresults.prerenderingtick;
  pr->renderingtickcount=testresults.renderingtick;
  pr->solvingtickcount=testresults.solvingtick;

  if (fltestperformed)
    return S_OK;
  else
    return S_FALSE;
}


void controlobj::init()
{
  char cfgfn[MAX_PATH];
  FILE* cfgfh;
  i32 modeltype;
  i32 randseed;
  float l0;


  modeltype=5;
  randseed=1;
  l0=750000;
  

  strcpy(cfgfn,progdir);
  strcat(cfgfn,"Models\\");
  strcat(cfgfn,modelname);
  strcat(cfgfn,".sph");
  cfgfh=fopen(cfgfn,"r");

  if (cfgfh!=NULL)
  {
    fscanf(cfgfh,"%ld",&modeltype);         
    fscanf(cfgfh,"%ld",&randseed);
    fscanf(cfgfh,"%f",&l0);
    fclose(cfgfh);
  }  

  solver.init(modeltype,randseed);

  viewpoint=rvectort(0,0,-l0);
  viewbasis.sete();
}


STDMETHODIMP controlobj::Initialize(void)
{
  ddrawinfot createddrawinfo;
  initrenderinfot initrenderinfo;
  char tx1name[MAX_PATH];
  char tx2name[MAX_PATH];
  bool flddrawcreate;


  try {

  flddrawcreate=false;

  fltestperformed=false;

  activatesphericalengine(1000);


  if (!flwindow)
  {
    SetWindowLong(m_hWnd,GWL_EXSTYLE,WS_EX_TOPMOST);
    SetWindowLong(m_hWnd,GWL_STYLE,WS_POPUP | WS_MAXIMIZE);
    SetMenu(m_hWnd,0);
    SetWindowPos(m_hWnd,m_hWnd,0,0,screenw,screenh,0);
    ShowWindow(m_hWnd,SW_SHOW);

    ShowCursor(false);
    SetCursorPos(screenw/2,screenh/2);
  }
  else
  {
    SetWindowPos(m_hWnd,m_hWnd,0,0,screenw,screenh,0);
    ShowWindow(m_hWnd,SW_SHOW);
  }

  createddrawinfo.screensizex=screenw;
  createddrawinfo.screensizey=screenh;
  createddrawinfo.flwindow=flwindow;
  createddrawinfo.flddrawwait=true;
  createddrawinfo.flsystemmemory=flsystemmemory;
  createddrawinfo.bpp=32;
  createddrawinfo.ddrawwinh=m_hWnd;
                                                    
/* */
  if (!ddrawcreate(createddrawinfo))
  {
    ShowWindow(m_hWnd,SW_HIDE);

    ShowCursor(true);

    deactivatesphericalengine();

    MessageBox(NULL,"Error initializing DirectDraw.","Error initializing DirectDraw.",MB_OK|MB_APPLMODAL);
    return S_FALSE;
  }
/* */
  flddrawcreate=true;

  viewscreenw=screenw*screenscalex;
  viewscreenh=screenh*screenscaley;
  viewscreenx0=(screenw-viewscreenw)>>1;
  viewscreenx0&=0xfffffffe;
  viewscreeny0=(screenh-viewscreenh)>>1;
  viewscreeny0&=0xfffffffe;

  viewsizex=2*sqrt(1.0/3.0);
  viewsizey=((float)viewscreenh/(float)viewscreenw)*((float)viewsizex);


  renderguid=seallocaterender(1000);

  initrenderinfo.viewsizex=viewsizex;
  initrenderinfo.viewsizey=viewsizey;
  initrenderinfo.screensizex=viewscreenw;
  initrenderinfo.screensizey=viewscreenh;
  initrenderinfo.bpp=32;
  initrender(renderguid,initrenderinfo);


//  sceneguid=seallocatescene(1000,1,initsysteminfo.pixelformat);

  init();


  framequ=0;
  fltest=false;
  flquit=false;
  
  cineenergy=0;
  potentialenergy=0;
  energyleak=0;
  impulsex=0;
  impulsey=0;
  impulsez=0;
  curframequ=0;

  initcpucounter();


  pixelformat.rpos=2;
  pixelformat.gpos=1;
  pixelformat.bpos=0;
  pixelformat.apos=3;
  texturerguid=seallocatetexturer(1000,pixelformat);

  strcpy(tx1name,progdir);
  strcpy(tx2name,progdir);
  strcat(tx1name,"//Textures//t1");
  strcat(tx2name,"//Textures//t2");
  texturerinserttexture(texturerguid,0,tx1name);
  texturerinserttexture(texturerguid,1,tx2name);
  
  PostMessage(m_hWnd,WM_START,0,0);          

  flsystemactive=true;

  startsystemtime=timeGetTime();

  }
  catch ( ... )
  {
    if (flddrawcreate)
    {
      try
      {
        ddrawdestroy();
      }
      catch ( ... )
      {
      }
    }

    return S_FALSE;
  }

  return S_OK;
}

STDMETHODIMP controlobj::Terminate(void)
{
  if (!flsystemactive) return S_OK;


  try {

  flsystemactive=false;


  if (!flwindow)
    ShowCursor(true);


//  seunallocatescene(sceneguid);


  ddrawdestroy();
//  ShowWindow(m_hWnd,SW_HIDE);

  seunallocatetexturer(texturerguid);

  seunallocaterender(renderguid);
  deactivatesphericalengine();

  }
  catch ( ... )
  {
    return S_FALSE;
  }
    
  return S_OK;
}


STDMETHODIMP controlobj::Connect(HWND hwnd)
{
  m_hWnd=hwnd;

  flsystemactive=false;

  try {

  ::GetModuleFileName((HMODULE)moduleh,progdir,MAX_PATH);
  *(strrchr(progdir, '\\') + 1) = '\0';

  FillMemory(fillstr,100,32);
  infofont=CreateFont(20,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET,
                      OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
                      DEFAULT_QUALITY,0,/*"System"*/ "MS Sans Serif");

  }
  catch ( ... )
  {
    return S_FALSE;
  }
    
  return S_OK;
}

STDMETHODIMP controlobj::Disconnect()
{
  DeleteObject(infofont);

  return S_OK;
}



IObject* WINAPI CreateObject()
{
    g_pModule = new controlobj();

    return (IObject*)g_pModule;
}


BOOL WINAPI DllMain(HINSTANCE hModule, DWORD reason, LPVOID)
{
  switch (reason)
  {
    case DLL_PROCESS_ATTACH:
    {
      ::DisableThreadLibraryCalls(hModule);
      moduleh=hModule;
      break;
    }

    case DLL_PROCESS_DETACH:
    {
      if (g_pModule)
      {
        delete g_pModule;
        g_pModule=0;
      }
      break;
    }
  }

  return TRUE;
}



