
/*

PolyCSG 001
-----------

. Basic render framework up and running

PolyCSG 002
-----------

  . Added Image class
  . Converted buffer to Image class

> First draft of polygon class

  . Polygon edge rendering (scanline based)
  . Not yet tested

PolyCSG 003
-----------

  . Solid rendering

  . Added scanline class
  . Use scanline class for polygon rendering
  . Moved classes to seperate cpp & h files

  . Pass polygon into buffer to render

PolyCSG 004
-----------

  . Removed Poly.render - have to use Image.drawPolygon
  . Added first CSG option - XOR
  . XORPoly.render used to render

PolyCSG 005
-----------

  . Get poly subclass rendering working ( Image.drawPolygon )
  . Add ANDPoly class
  . Polygon intersection (AND) up and running!

PolyCSG 006
-----------

  . Fix in ANDPoly class ( oka && okb -> oka || okb )
  . Added SUBPoly
  . Added ORPoly

PolyCSG 007
-----------

  2002/08/26 01:00 (while smackdown was on after playing cards at the house - Steve won)

  . Added getVScanline function to all polys
  . Added or,and,sub class declarations to main file
  . Renamed Image.drawPolygon to Image.fillPolygon
  . Renamed Image.drawScanline to Image.fillScanline + made private
  . Added Image.drawPolygon, Image.drawScanline, Image.drawVScanline
  . Removed Poly.render (use Image.fillPolygon instead)

  NOW SUPPORTS RENDERING FILLED AND UNFILLED POLYS

PolyCSG 008
-----------

  ~ Antialiased poly functions
  . Added Image.blendCol
  . Initial AA tests.. need edge gradients stored in scanline points

  . RotatePoly class added
  . Poly.firstPoint, nextPoint & peekPoint added

  POLYGON ROTATION WORKING

  . Added pixel text functions to Image

PolyCSG 009
-----------

  . Added TranslatePoly class
  . Fixed memory leak in Redraw() - was not deleting all Poly's

  > Interesting poly shapes



Motion 001
----------

  . Moved classes to Classes folder


RTRay 010
---------

  . Added more detailed frame rate indicators

*/



#include <windows.h>
#include <mmsystem.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>



//--- CONSTANTS --------------------------------------------------------------//

//- Settings

#define FULL_WINDOW_DRAG
#define ROUND_IMAGE_SIZE



//---- CLASS DECLARATIONS ----------------------------------------------------//

class Image;
class Scanline;
class Poly;
class Raytrace;

#include "Classes\Image.h"
#include "Classes\Scanline.h"
#include "Classes\Poly.h"
#include "Classes\Raytrace.h"

  class XORPoly;
  class ANDPoly;
  class ORPoly;
  class SUBPoly;

  #include "Classes\Poly\XORPoly.h"
  #include "Classes\Poly\ANDPoly.h"
  #include "Classes\Poly\ORPoly.h"
  #include "Classes\Poly\SUBPoly.h"

  class TranslatePoly;
  class RotatePoly;

  class RegularPoly;
  //class StarPoly;

  #include "Classes\Poly\TranslatePoly.h"
  #include "Classes\Poly\RotatePoly.h"

  #include "Classes\Poly\RegularPoly.h"
  //#include "Classes\Poly\StarPoly.h"



//--- DATA -------------------------------------------------------------------//

//---- Windows data

HINSTANCE hMainInstance;
HWND hMainWindow = NULL;

char szAppName[40] = "RTRay 010";

int mouse_x = 0, mouse_y = 0;
int mouse_xstart = 0, mouse_ystart = 0;

bool mouse_drag = false;

float rx=0, ry=0, rrx=-1, rry=-1;



//---- Speed

int frame_rate = 4100;    //  Defines framerate
bool idlemode = true;  //  Set to true to make Redraw get called as often as possible



//---- Image buffer data

int width = 1600;
int height = 1200;

Image *im, *im2;

double mass[];
double vx[];
double vy[];



//---- Display ---------------------------------------------------------------//

void Display(HDC dc, int *buf, int w, int h)
{
  BITMAPINFO bmi;

  bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  bmi.bmiHeader.biWidth = w;
  bmi.bmiHeader.biHeight = -h;
  bmi.bmiHeader.biPlanes = 1;
  bmi.bmiHeader.biBitCount = 32;
  bmi.bmiHeader.biCompression = BI_RGB;
  bmi.bmiHeader.biSizeImage = 0;
  bmi.bmiHeader.biXPelsPerMeter = 1000;
  bmi.bmiHeader.biYPelsPerMeter = 1000;
  bmi.bmiHeader.biClrUsed = 0;
  bmi.bmiHeader.biClrImportant = 0;

  StretchDIBits(
    dc,
    0, 0, w, h,
    0, 0, w, h,
    (LPVOID)buf,
    (LPBITMAPINFO)&bmi,
    DIB_RGB_COLORS, SRCCOPY
  );

}



//---- Startup ---------------------------------------------------------------//

void Startup()
{
  //- Allocate image

  #ifdef ROUND_IMAGE_SIZE

  width = (width+7) & -8;
  height = (height+7) & -8;

  #endif

  im = new Image( width, height );
  im2 = new Image( width, height );

  mass = new double[ width*height ];
  vx = new double[ width*height ];
  vy = new double[ width*height ];

  int r1 = 0x1823A978, r2 = 0xFA510091;

  for( int i=0; i<width*height; i++)
  {
    im->buf[i] = (i*r1 + i*i*r2) ^ r1;
    im2->buf[i] = (((i*r2 - i*i*r1 ) ^ r2)/731) & 1;

    r1 += (r2<<7)^0x9181723;
    r2 += (r1<<7)*(r2>>5) - ((i*i*i*i)^0xFA881721);

	mass[i] = 0;
	vx[i] = 0;
	vy[i] = 0;
  }
}



//---- Shutdown --------------------------------------------------------------//

void Shutdown()
{
  delete im;
  delete im2;
}



//---- Redraw ----------------------------------------------------------------//

void Redraw(HDC dc)
{
  static int frame = 0;

//  im->clear( 0xFFFFFF*(frame&1) );
//  int i1 = width*(frame%height);
//for( int i=0; i<width; i++ ) im->buf[i1+i] = -1;




/*
for( int i=width; i<width*height-width; i++ )
  {
    im->buf[i] = ((
      
      im->buf[i-width]+
      im->buf[i-1]+
      im->buf[i+1]+
      im->buf[i+width]+
      0x040507
      
      ) >> 2) & 0x3F3F3F3F;
  }
*/

/*
  for( int i = width*height-1; i >= 0; i-- )
  {
	  im->buf[i] += 0x01070305;
  }
*/

  //  Frame rate indicator

  frame ++;

  int f_i, f_j;

  for(f_j=0; f_j<8; f_j++) for(f_i=0; f_i<8; f_i++)
  {
    im->buf[f_j*width+f_i] = ((-(((f_i+f_j+frame)>>2)&1)) ^ 0xFFFF00 );
  }

  //  FPS based on current frame

  static int lastTime = 0;
  int time = timeGetTime();
  float fps = time > lastTime ? (1000.0 / (time-lastTime)) : 0.0;
  lastTime = time;

  static int times[10] ={0,0,0,0,0,0,0,0,0,0};
  static int timeptr = 0;

  int time10 = time-times[timeptr];

  times[timeptr] = time;
  timeptr = (timeptr+1)%10;

  char s[64];

  sprintf( s, "%d %.02f %.03f %.01f", frame, fps, 0.001 * time10, 10000.0 / time10 );
  im->drawText( 9, 1, s, 0xFFFFFF );

  //- Display

  Display(dc, im->buf, width, height);
}



//---- WinProc ---------------------------------------------------------------//

LRESULT CALLBACK WinProc(HWND hwnd, UINT uiMsg, UINT wParam, LONG lParam)
{
  HDC dc;
  PAINTSTRUCT ps;

  switch(uiMsg) {

  case WM_CREATE:
    Startup();
    SetTimer(hwnd, 1, 1000/frame_rate, NULL);
    break;

  case WM_TIMER:
    dc = GetDC(hwnd);
    Redraw(dc);
    ReleaseDC(hwnd, dc);
    return 0L;

  case WM_PAINT:
    dc = BeginPaint(hwnd, &ps);
    Redraw(dc);
    EndPaint(hwnd, &ps);
    return 0L;

  case WM_LBUTTONDOWN:
    mouse_xstart = HIWORD(lParam);
    mouse_ystart = LOWORD(lParam);
    mouse_drag = true;
    SetCapture(hwnd);
    return 0L;

  case WM_MOUSEMOVE:
    mouse_x = HIWORD(lParam);
    mouse_y = LOWORD(lParam);

    if(mouse_drag)
    {
      ry -= (mouse_y-mouse_ystart) * 0.004;
      rx += (mouse_x-mouse_xstart) * 0.004;
      mouse_xstart = mouse_x;
      mouse_ystart = mouse_y;
    }
    return 0L;

  case WM_LBUTTONUP:
    mouse_drag = false;
    ReleaseCapture();
    return 0L;

  #ifdef FULL_WINDOW_DRAG

  case WM_NCHITTEST:
    return HTCAPTION;

  #endif

  case WM_KEYDOWN:
    if( wParam == VK_ESCAPE ) DestroyWindow( hwnd );
    return 0L;

  case WM_DESTROY:
	  Shutdown();
    KillTimer(hwnd, 1);
    PostQuitMessage(0);
    return 0L;

  }

  return DefWindowProc(hwnd, uiMsg, wParam, lParam);
}




//---- WinMain ---------------------------------------------------------------//

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASS wndclass;
  char cSwitch;
  MSG msg;
  RECT rc;

  hMainInstance = hInstance;

  if(hPrevInstance) return 1;

  //- Create window class

  wndclass.style         = CS_HREDRAW | CS_VREDRAW;
  wndclass.lpfnWndProc   = WinProc;
  wndclass.cbClsExtra    = 0;
  wndclass.cbWndExtra    = 0;
  wndclass.hInstance     = hInstance;
  wndclass.hIcon         = NULL;
  wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  wndclass.lpszMenuName  = NULL;
  wndclass.lpszClassName = szAppName;

  if(!RegisterClass(&wndclass)) return 1;

  //- Create main window

  GetWindowRect(GetDesktopWindow(), &rc);

  hMainWindow = CreateWindowEx(
    0,
    szAppName,
    szAppName,
    WS_POPUP,
    (rc.right-width)/2,
    (rc.bottom-height)/2,
    width,
    height,
    NULL,
    NULL,
    hInstance,
    NULL
  );

  if(!hMainWindow) return 1;

  ShowWindow(hMainWindow, SW_SHOW);

  //- Message loop

  bool quit = false;

  do {

    //  Blocking message loop

    while((!idlemode) && GetMessage(&msg, NULL, 0, 0)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }

    if(!idlemode) quit = TRUE;

    //  Idle message loop

    while(idlemode && (!quit)) {
      while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
        if(msg.message == WM_QUIT) quit = TRUE;
      }
      //main_idle(hMainWindow);
    }

  } while(!quit);

  return 0;
}



//---- END OF FILE -----------------------------------------------------------//




