/*
 * Mandel2.c - Vivid 24 to Amiga speed comparison
 *
 */

#define CONFIG_VAL 0xefa00434
#define MODE 6  /* 800 x 600 */
#define HRES 800
#define VRES 600
#define SRAM_FILE "MANDEL.ABS"

/* Uncomment this line to have the Amiga render to the Vivid rather */
/*  than its own screen.                                            */
//#define AMIGA2VIVID

#define FAST

#include <exec/types.h>
#include <exec/memory.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>

#include <time.h>
#include <stdio.h>

#include <sage/sage_proto.h>
#include <sage/sage_pragma.h>

#include <sage/tms340/gsptypes.h>
#include <sage/tms340/gspreg.h>
#include <sage/tms340/tms340.h>
#include <sage/vivid/iodata.h>

#include <sage/tms340/colors.h>

// tms340 library
#include <sage/tms340/tms340_proto.h>
#include <sage/tms340/tms340_pragma.h>

// macros
#include <sage/tms340/tms340_defines.h>

#include "/extSRAM/extSRAMpragma.h"
#include "/extSRAM/extSRAMprotos.h"
#include "/extSRAM/extSRAM.h"

struct Library *SAGEBase;
struct Library *TMS340Base;
struct Library *extSRAMBase;

struct iodata *TMS340io;
struct iodata *extio;
SAGEList *sagelist;
SAGEList *sl;
SAGEInfo sageinfo;

CONFIG config;

extern void ReverseBytes(ULONG *, int);
extern void LoadSRAMCode(LONG, ULONG *, LONG);

struct Screen *Screen;
struct Window *Window;


void ComputeFractal(void)
{
  UWORD Row, Column;
  float DeltaI = 2.0 / (float)VRES;
  float DeltaR = 3.0 / (float)HRES;
  float AR, AR2, AI, AI2;
  float ConstI, ConstR;

#ifdef AMIGA2VIVID
  ULONG Color;
  ULONG *PixelData;
  ULONG *screenAddr = (ULONG *)TMS340io->baddr->mem_base;
  clear_frame_buffer(0x00);
  PixelData = AllocMem(HRES * sizeof(ULONG), MEMF_ANY);
#else
#ifdef FAST
  UBYTE Color;
  struct RastPort *rastPort = &Screen->RastPort;
  UBYTE *PixelData;
  struct RastPort tempRastPort;
  struct BitMap tempBitMap;
  int plane;
  PixelData = AllocMem((HRES * sizeof(UBYTE)) + 15, MEMF_ANY);
//  InitRastPort(&tempRastPort);
tempRastPort = *rastPort;
  tempRastPort.Layer = NULL;
  InitBitMap(&tempBitMap, 8, HRES, VRES);
  tempRastPort.BitMap = &tempBitMap;
  for(plane = 0; plane < 8; plane++)
  {
    tempBitMap.Planes[plane] = AllocMem((((HRES + 15) >> 4) << 1), MEMF_CHIP | MEMF_CLEAR);
  }
#else
  UBYTE Color;
  struct RastPort *rastPort = &Screen->RastPort;
#endif
#endif

  for(Row = 0; Row < VRES; Row++)
  {
    ConstI = (DeltaI * (float)Row) - 1;
    ConstR = -2;
    for(Column = 0; Column < HRES; Column++)
    {
      AR = AI = AR2 = AI2 = 0;
      for(Color = 128; Color > 0; Color--)
      {
        AI = (AR * AI * 2) + ConstI;
        AR = AR2 - AI2 + ConstR;
        AR2 = AR * AR;
        AI2 = AI * AI;
        if((AR2 + AI2) > 4)
          break;
      }
#ifdef AMIGA2VIVID
      PixelData[Column] = Color;
#else 
#ifdef FAST
      PixelData[Column] = Color;
#else     
      SetAPen(rastPort, Color);
      WritePixel(rastPort, Column, Row);
#endif
#endif
      ConstR += DeltaR;
    }
#ifdef AMIGA2VIVID
    CopyMemQuick((APTR)PixelData, (APTR)(screenAddr + (Row << 10)), HRES << 2);
#endif
#ifdef FAST
    WritePixelLine8(&Screen->RastPort, 0, Row, HRES, PixelData, &tempRastPort);
#endif
  }
#ifdef AMIGA2VIVID
  FreeMem(PixelData, HRES * sizeof(ULONG));
#endif
#ifdef FAST
  FreeMem(PixelData, (HRES * sizeof(UBYTE)) + 15);
  for(plane = 0; plane < 8; plane++)
  {
    FreeMem(tempBitMap.Planes[plane], (((HRES + 15) >> 4) << 1));
  }
#endif
}


void main(void)
{
  long data, prog;
  long *dataAddr, *progAddr;
  int SAGEAlive = 0;
  struct FileInfoBlock fib;
  BPTR handle;
  unsigned int clock1[2], clock2[2], clock3[2];
  unsigned int amigaTime, vividTime;
  
  printf("Vivid 24, Mandelbrot calculation comparison program.\n");
  printf("\tCopyright ©1993 - Digital Micronics, Inc.\n\n");
  printf("\tThis program is being used to compare rendering speed and\n");
  printf("\tprocessing power of the Amiga to the Vivid 24 rendering\n");
  printf("\tengine.  It is released as freely redistributalbe to show we\n");
  printf("\tare not using \"smoke and mirrors\" when we compare the\n");
  printf("\tVivid 24 to your Amiga.  The Mandelbrot routines are not\n");
  printf("\tas highly optimized as some code, but since the Vivid 24\n");
  printf("\tis running the identical code (see included source), it is\n");
  printf("\ta fair comparison of RELATIVE performance.  This code will\n");
  printf("\trun with our without a Vivid 24 installed.  Without the\n");
  printf("\tboard, it will test your Amiga and display the results as\n");
  printf("\tcompared to the various configuration of the Vivid 24.  With\n");
  printf("\ta Vivid 24 card installed, you will be given the times\n");
  printf("\tyourself so you can make your own comparison.\n\n");
  
  printf("Attempting to load Vivid 24 environment.\n");
  if(SAGEBase = OpenLibrary("sage.library", 0))
  {
    if(!GetSAGEList(&sagelist, "TMS340"))
    {
      if(!OpenSAGE(&sageinfo, 0, sagelist->LibName, 1, 0, 0))
      {
        TMS340Base = sageinfo.LibBase;
        TMS340io = sageinfo.iodata;
        if(!open_gsp_library(sageinfo.iodata, &extio, "extSRAM", 0, 0))
        {
          extSRAMBase = get_libbase(extio);
          get_config(&config);
          if(config.sys_flags & 0x0000000f)
          {
            if(handle = Open(SRAM_FILE, MODE_OLDFILE))
            {
              ExamineFH(handle, &fib);
              if(prog = gsp_malloc(fib.fib_Size + 8))
              {
                prog += 64;
                if(data = gsp_malloc(256 + 8))
                {
                  data += 64;
                  progAddr = (ULONG *)(((prog - 0xf0000000) >> 3) +
                                                   extio->baddr->mem_base);
                  dataAddr = (ULONG *)(((data - 0xf0000000) >> 3) +
                                                   extio->baddr->mem_base);
                  if(Read(handle, progAddr, fib.fib_Size) == fib.fib_Size)
                  {
                    SAGEAlive = ~0;
                    ReverseBytes(progAddr, fib.fib_Size);
                    set_config(MODE, 1);
                    set_coloring_mode(INDEXCOLOR);
                    clear_frame_buffer(0x00);
                    Init082Int(extio, TMS340Base);
                    *dataAddr = *(dataAddr + 1) = CONFIG_VAL;
                    if(config.sys_flags & 0x00000001)
                    {
                      Abort082(extio, TMS340Base, 0);
                      Set082Regs(extio, TMS340Base, 0, CR_CONFIG, data, 1);
                      LoadSRAMCode(0, progAddr, fib.fib_Size >> 2);
                    }
                    if(config.sys_flags & 0x00000002)
                    {
                      Abort082(extio, TMS340Base, 1);
                      Set082Regs(extio, TMS340Base, 1, CR_CONFIG, data, 1);
                      LoadSRAMCode(1, progAddr, fib.fib_Size >> 2);
                    }
                    if(config.sys_flags & 0x00000004)
                    {
                      Abort082(extio, TMS340Base, 2);
                      Set082Regs(extio, TMS340Base, 2, CR_CONFIG, data, 1);
                      LoadSRAMCode(2, progAddr, fib.fib_Size >> 2);
                    }
                    if(config.sys_flags & 0x00000008)
                    {
                      Abort082(extio, TMS340Base, 3);
                      Set082Regs(extio, TMS340Base, 3, CR_CONFIG, data, 1);
                      LoadSRAMCode(3, progAddr, fib.fib_Size >> 2);
                    }
                  }
                  else
                  {
                    printf("Error reading SRAM file.\n");
                    data -= 64;
                    gsp_free(data);
                    prog -= 64;
                    gsp_free(prog);
                    CloseSAGE(&sageinfo);
                    FreeSAGEList(sagelist);
                    CloseLibrary(SAGEBase);
                  }
                }
                else
                {
                  printf("Unable to allocate working DRAM.\n");
                  prog -= 64;
                  gsp_free(prog);
                  CloseSAGE(&sageinfo);
                  FreeSAGEList(sagelist);
                  CloseLibrary(SAGEBase);
                }
              }
              else
              {
                printf("Unable to allocate enough DRAM for SRAM code.\n");
                CloseSAGE(&sageinfo);
                FreeSAGEList(sagelist);
                CloseLibrary(SAGEBase);
              }
              Close(handle);
            }
            else
            {
              printf("Unable to open %s.\n", SRAM_FILE);
              CloseSAGE(&sageinfo);
              FreeSAGEList(sagelist);
              CloseLibrary(SAGEBase);
            }
          }
          else
          {
            printf("No coprocessors found on your Vivid card.\n");
            CloseSAGE(&sageinfo);
            FreeSAGEList(sagelist);
            CloseLibrary(SAGEBase);
          }
        }
        else
        {
          printf("Unable to open extSRAM.library.\n");
          CloseSAGE(&sageinfo);
          FreeSAGEList(sagelist);
          CloseLibrary(SAGEBase);
        }
      }
      else
      {
        printf("Unable to load vivid.library and initialize board.\n");
        FreeSAGEList(sagelist);
        CloseLibrary(SAGEBase);
      }
    }
    else
    {
      printf("SAGEList not found.\n");
      CloseLibrary(SAGEBase);
    }
  }
  else
  {
    printf("sage.library not found.\n");
  }

  if(!(Screen = OpenScreenTags(NULL,
                               SA_Width, 800,
                               SA_Height, 600,
                               SA_Depth, 8,
                               SA_DisplayID, 0x00089024,
                               TAG_END)))
  {
    Screen = OpenScreenTags(NULL,
                            SA_AutoScroll, TRUE,
                            SA_Width, 800,
                            SA_Height, 600,
                            SA_Depth, 4,
                            SA_DisplayID, 0x00008004,
//                            SA_Overscan, OSCAN_VIDEO,
                            TAG_END);
  }
  
  if(!Screen)
  {
    printf("Unable to open 800 x 600 screen.\n");
  }
  else
  {
    Window = OpenWindowTags(NULL,
                            WA_CustomScreen, Screen,
                            WA_Width, 800,
                            WA_Height, 600,
                            WA_Flags, WFLG_BACKDROP | WFLG_BORDERLESS | WFLG_ACTIVATE | WFLG_RMBTRAP,
                            TAG_END);
  }
  
  if(config.sys_flags & 0x0000000f)
  {
    printf("Testing Vivid 24 at 800 x 600.\n");
    timer(clock1);
    Mandel(extio, TMS340Base, HRES, VRES);
    synchronize();
  }
  
  timer(clock2);
  
  if(Screen)
  {
    printf("Testing Amiga at 800 x 600.\n");
    ComputeFractal();
    timer(clock3);
  }
  
  
  if(SAGEAlive)
  {
    if(Screen)
    {
      vividTime = clock2[0] - clock1[0];
      amigaTime = clock3[0] - clock2[0];
      printf("TIMES -> Amiga: %d seconds (%02d:%02d), Vivid 24: %d seconds (%02d:%02d).\n",
          amigaTime, amigaTime / 60, amigaTime % 60,
          vividTime, vividTime / 60, vividTime % 60);
      printf("The Vivid was %d times as fast as the Amiga!\n",
             amigaTime / vividTime);
    }
    else
    {
      vividTime = clock2[0] - clock1[0];
      printf("TIME -> Vivid 24: %d seconds (%02d:%02d).\n",
             vividTime, vividTime / 60, vividTime % 60);
    }
  }
  else
  {
    amigaTime = clock3[0] - clock2[0];
    printf("TIME -> Amiga: %d seconds (%02d:%02d).\n",
           amigaTime, amigaTime / 60, amigaTime % 60);
    printf("Compare: Vivid 24 with 1 copro:  15 seconds (00:15) = %d times your Amiga!\n", amigaTime / 15);
    printf("         Vivid 24 with 2 copro:  7 seconds (00:07) = %d times your Amiga!\n", amigaTime / 8);
    printf("         Vivid 24 with 4 copro:  4 seconds (00:04) = %d times your Amiga!\n", amigaTime / 4);
  }
  
  if(Screen)
  {
    ScreenToBack(Screen);
    printf("Press <Enter> to continue.\n");
    getch();
    if(Window)
      CloseWindow(Window);
    CloseScreen(Screen);
  }
  
  if(SAGEAlive)
  {
    synchronize();
    close_gsp_library(extio);
    CloseSAGE(&sageinfo);
    FreeSAGEList(sagelist);
    CloseLibrary(SAGEBase);
  }
}
