#ifdef RecordRaces
#include once "zlib.bi"

enum BlendTypes
  RecNoBlend
  RecBlendAlpha
  RecBlendAdd
end enum

#macro rec_PutStruct(_Type,_Parms...)  
  *cptr(rec._Type ptr,rec.pRecording+rec.iSize) = type(_Type##ID,_Parms)
  rec.iSize += sizeof(rec._Type)  
#endmacro

#define rec_PutTexture(_Tex) rec.LastTex=_Tex  
#define rec_PutBlend(_Blend) rec.LastBlend=_Blend
#macro rec_PutPoints()
#endmacro
#macro rec_PutLines()
#endmacro

enum tRecTypes  
  tRecNull
  tRecFrameID
  tRecTriangleID
  tRecPointsID
  tRecLinesID
  tRecTexBlendID  
  tRecHeaderID = cvi("RREC")
end enum

namespace rec    
  type RecPoint
    as ulong uColor
    as short wSX,wSY    
  end type
  type RecLine
    as ulong uColor
    as short wSX1,wSY1
    as short wSX2,wSY2
  end type
  type tRecHeader
    as ulong wtype
    as short wWidth,wHeight
    as ulongint iTextures(1 to 32)
  end type
  type tRecFrame
    as byte btype,bResv
    iSize as ushort
    fTime as single    
  end type
  type tRecTriangle
    as byte bType    
    as byte bTex   :5
    as byte bBlend :3
    '
    as ubyte bU1,bV1
    as ubyte bSX1,bSY1
    as ushort wW1,wColor1
    '
    as ubyte bU2,bV2
    as ubyte bSX2,bSY2
    as ushort wW2,wColor2
    '
    as ubyte bU3,bV3
    as ubyte bSX3,bSY3
    as ushort wW3,wColor3
  end type
  type tRecPoints
    as short wType,wCount    
    as RecPoint rPoints(1023)
  end type
  type tRecLines
    as short wType,wCount
    as RecLine rLines(1023)
  end type

  dim shared as byte LastTex,LastBlend
  dim shared as tRecFrame ptr pCurFrame
  dim shared as any ptr pRecording,pBackBuff,pCompress,pRawBuff
  dim shared as integer iFile,iSize,iTexCnt
  dim shared as double StartTime,FrameTime
  dim shared as integer iTexAdded(255),iCurSize
  dim shared as integer FrameHash,FrameHit,iRawBuffSz
  dim shared as any ptr pMutex,pCompressMutex,pCompressThread
  dim shared as handle pEvent
  
  sub CompressFrame(ID as any ptr)    
    do
      WaitForSingleObject(pEvent,INFINITE)
      if iFile=0 then exit do
      mutexlock(pCompressMutex)  
      dim as integer iBufSz = 1024*1024
      compress2(pCompress,@iBufSz,pRawBuff,iRawBuffSz,9)    
      printf(!"in:%i out:%i\n",iRawBuffSz,iBufSz)
      put #iFile,,iBufSz
      put #iFile,,*cptr(ubyte ptr,pCompress),iBufSz
      mutexunlock(pCompressMutex)
    loop
  end sub
  sub BeginRecord(iWid as integer,iHei as integer)
    if iFile then exit sub
    var sFile = date$+"_"+time$
    for CNT as integer = 0 to len(sFile)-1
      if cuint(sFile[CNT]-asc("0"))>9 then sFile[CNT] = asc("_")
    next CNT
    for CNT as integer = lbound(iTexAdded) to ubound(iTexAdded)
      iTexAdded(CNT)=0
    next CNT
    sFile = "Recording_"+sFile+".rec"
    iFile = freefile()
    if open(sFile for binary access write as #iFile) then
      iFile=0: exit sub
    end if
    if pRecording then deallocate(pRecording):pRecording=0
    if pCompress then deallocate(pCompress):pCompress=0
    if pBackBuff then deallocate(pBackBuff):pBackBuff=0
    if pMutex=0 then pMutex=mutexcreate()
    if pEvent=0 then pEvent=CreateEvent(null,false,false,null)
    mutexlock(pMutex)
    pCompress = allocate(1024*1024)
    pRecording = allocate(2048*1024): iSize = 0
    pBackBuff = allocate(2048*1024)
    StartTime = timer : iTexCnt = 0 : FrameTime = 0
    LastTex=-1 : LastBlend=-1 
    FrameHash = -1 : FrameHit = 0
    rec_PutStruct(tRecHeader,iWid,iHei)
    put #iFile,,*cptr(ubyte ptr,pRecording),iSize: iSize = 0
    pCurFrame = pRecording+iSize: iCurSize = iSize
    rec_PutStruct(tRecFrame,0,65535,0.0)
    pCompressThread = ThreadCreate(@CompressFrame,0)
    mutexunlock(pMutex)
  end sub
  sub FrameRecord(iFlush as integer=false)    
    if iFile=0 then exit sub
    dim as integer iNewHash,iLastSize = cuint(pRecording+iSize)-cuint(pCurFrame)
    static as integer iSwap
    iSwap xor= 1: if iFlush then iSwap=1
    if iSwap then
      asm      
        mov ecx,[iLastSize]
        xor eax,eax
        shr ecx,2
        mov esi,[pCurFrame]
        shr ecx,1
        mov edx,eax
        jnc 0f
        add eax,[esi]
        add esi,4
        rol eax, 3
        0:
        add eax,[esi]
        add edx,[esi+4]
        rol eax, 3
        add esi,8
        ror edx, 1
        dec ecx
        jnz 0b
        add eax,edx
        mov [iNewHash],eax
      end asm
      'printf(!"%x %x (%i) \n",FrameHash,iNewHash,iSize)
    end if
    if iSwap andalso iNewHash <> FrameHash then
      FrameHash = iNewHash: FrameHit += 1      
      pCurFrame->fTime = timer-StartTime
      pCurFrame->iSize = (cuint(pRecording+iSize)-cuint(pCurFrame))/2
    else
      iSize = iCurSize
    end if
    if iFlush then FrameHit=1:FrameTime -= 1/60
    if FrameTime=0 then 
      FrameTime=timer
    elseif (timer-FrameTime) >= 1/60 andalso FrameHit then
      FrameTime += 1/60
      mutexlock(pCompressMutex)
      pRawBuff = pRecording: iRawBuffSz = iSize
      SetEvent(pEvent)
      swap pRecording,pBackBuff
      iSize=0:FrameHit=0:iCurSize=0
      mutexunlock(pCompressMutex)      
    end if
    iCurSize = iSize: pCurFrame = pRecording+iSize
    rec_PutStruct(tRecFrame,0,65535,0)    
  end sub
  sub EndRecord()
    if iFile=0 then exit sub
    if iSize then FrameRecord(true) 
    mutexlock(pCompressMutex)    
    close #iFile: iFile = 0 : StartTime = 0
    SetEvent(pEvent)
    mutexunlock(pCompressMutex)
    ThreadWait(pCompressThread):pCompressThread=0
    deallocate(pRecording):pRecording=0 
    deallocate(pCompress):pCompress=0    
  end sub
end namespace
#endif