#include "g_main.h"
#include "m_main.h"
#include <InterfaceKit.h>
#include <GameKit.h>
#include <AppKit.h>
#include <SupportKit.h>
#include <string.h>
#include <memory.h>
#include <unistd.h>
#include "benchm.h"
#define DISPLAY_MODE B_32_BIT_640x480
#define DISPLAY_X 640
#define DISPLAY_Y 480
#define DEMO_X 160
#define DEMO_Y 128

class DemoWin;

void megademo42();

static DemoWin *window=0;
static int32 	error;
bigtime_t system_time();
static cFile *brd=0;
bool nosound=false;

class DemoWin : public BWindowScreen
{
	sem_id 			access_sem;
	int32			flip;
	long     		(*blit_copy)(long,long,long,long,long,long);

	public:
					DemoWin():BWindowScreen("",DISPLAY_MODE,&error), flip(1)
					{
						access_sem = create_sem(0,"access_sem");
						SetFrameBuffer(DISPLAY_X,DISPLAY_Y*2);
						SetSpace(DISPLAY_MODE);
					}

		inline void DupArea(int x1, int y1, int x2, int y2, int w, int h)
					{
						blit_copy(x1,y1,x2,y2,w,h);
					}
					
		inline uint32 BytesPerRow()
					{
						return CardInfo()->bytes_per_row;
					}
					
		inline uint16 *BaseAddress()
					{
						return (uint16 *)CardInfo()->frame_buffer;
					}
		
		void		ScreenConnected(bool state)
					{
						if(state)
						{
							release_sem(access_sem);
							blit_copy =(long (*)(long,long,long,long,long,long))CardHookAt(7);
							memset(BaseAddress(),0,DISPLAY_Y*BytesPerRow());
						}
						else
						{
							acquire_sem(access_sem);
							delete_sem(access_sem);
							be_app->PostMessage(B_QUIT_REQUESTED);
						}
					}
				
		status_t	AcquireAccess()
					{
						return acquire_sem(access_sem);
					}

		void		ReleaseAccess()
					{
						release_sem(access_sem);
					}
					
		bool		QuitRequested()
					{
						be_app->PostMessage(B_QUIT_REQUESTED);
						return true;
					}
};

void g_init(void)
{
	brd=m_loadfile("gfx/border.chk");
	window = new DemoWin();
	window->Show();
}

void g_shutdown(void)
{
	if(brd) m_freefile(brd);
	be_app->PostMessage(B_QUIT_REQUESTED);
}

void g_update(rgb18 *s)
{
#if 1
	static bool first = true;
	if(window->AcquireAccess()==B_NO_ERROR)
	{
		uint32 *dst=(uint32 *)window->BaseAddress();
		uint32 *src=(uint32 *)s;
		uint32 bpr=(window->BytesPerRow()/sizeof(int32))*2;
        if(brd && first)
        {
        	first = false;
	        uint32 *border=(uint32 *)brd->data;
			for(int32 y=0;y<400;y+=2)
			{
				for(int32 x=0;x<640;x+=2)
				{
					uint32 pix = *border++;
#ifdef __POWERPC__
					uint32 pixel = ((pix>>8)&0x0000ff00) | ((pix<<8)&0x00ff0000) | ((pix<<24)&0xff000000);
#else
					uint32 pixel = ((pix&0xFF000000)>>24)| ((pix&0x00FF0000)>>8) | ((pix&0x0000FF00)<<8);
#endif
					dst[x+0] = pixel;
					dst[x+1] = pixel;
				}
				dst+=bpr;
				window->DupArea(0,y,0,y+1,640,1);
			}
		}
		dst=(uint32 *)window->BaseAddress();
		dst+=36*(window->BytesPerRow()/sizeof(int32))*2;
		for(int32 y=36*2;y<(DEMO_Y*2+36*2);y+=2)
		{


#ifdef __INTEL__
		asm
		{
		  mov	esi,src
		  mov	edi,dst
		  mov	ecx,160
	lop:

		
		  mov	al,[esi+1]
		  mov	bl,[esi+5]
		
		  
		  sub	bl,al

		  
		  shl	eax,16
		  shl	ebx,16
		  
		  mov	al,[esi+3]
		  mov	bl,[esi+7]
		
		  mov	ah,[esi+2]
		  mov	bh,[esi+6]
		  
		  sub	bl,al
		  sub	bh,ah
		 
		  shl	eax,2
			  
		  mov	[edi],eax
		  add	eax,ebx
		  mov	[edi+4],eax
		  add	eax,ebx
		  mov	[edi+8],eax
		  add	eax,ebx
		  mov	[edi+12],eax
		    
	
		  
		  add	esi,4
		  add	edi,16
		    
		  dec	ecx
		  jnz	lop
		   
		  	  
		
		
		}
		src+=DEMO_X;
#endif
#ifdef __POWERPC__

			for(int32 x=0;x<DEMO_X*4;x+=4)
			{
				uint32 pix = *src++;
			    uint32 pixel = ((pix>>6)&0x0003fc00) | ((pix<<10)&0x03fc0000) | ((pix<<26)&0xfc000000);

				dst[x+0] = pixel;
				dst[x+1] = pixel;
				dst[x+2] = pixel;
				dst[x+3] = pixel;
			}
#endif

			dst+=bpr;
			window->DupArea(0,y,0,y+1,640,1);
		}
		window->ReleaseAccess();
	}
#else
	static bool first = true;
	if(window->AcquireAccess()==B_NO_ERROR)
	{
		uint32 *dst=(uint32 *)window->BaseAddress();
		dst+=160+(window->BytesPerRow()/4)*140;
		uint32 *src=(uint32 *)s;
		uint32 bpr=(window->BytesPerRow()/sizeof(int32));
        if(brd && first)
        {
        	first = false;
	        uint32 *border=(uint32 *)brd->data;
			for(int32 y=0;y<200;y++)
			{
				for(int32 x=0;x<320;x++)
				{
					uint32 pix = *border++;
#ifdef __POWERPC__
					uint32 pixel = ((pix>>8)&0x0000ff00) | ((pix<<8)&0x00ff0000) | ((pix<<24)&0xff000000);
#else
					uint32 pixel = pix>>8;
#endif
					dst[x] = pixel;
				}
				dst+=bpr;
			}
		}
		dst=(uint32 *)window->BaseAddress();
		dst+=160+(window->BytesPerRow()/4)*140;
		dst+=36*(window->BytesPerRow()/sizeof(int32));
		for(int32 y=120;y<(DEMO_Y*2+120);y+=2)
		{
			for(int32 x=0;x<DEMO_X*2;x+=2)
			{
				uint32 pix = *src++;
#ifdef __POWERPC__
				uint32 pixel = ((pix>>6)&0x0003fc00) | ((pix<<10)&0x03fc0000) | ((pix<<26)&0xfc000000);
#else
				uint32 pixel = pix>>6;
#endif
				dst[x+0] = pixel;
				dst[x+1] = pixel;
			}
			dst+=bpr;
		}
		window->ReleaseAccess();
	}
#endif
}

class MyApp : public BApplication
{	
	public:
				MyApp():BApplication("application/x-vnd.Tracer-demo")
				{
				}
				
		void	ReadyToRun()
				{
					app_info the_info;
					GetAppInfo(&the_info);
					BEntry the_file(&the_info.ref);
					BEntry the_dir;
					the_file.GetParent(&the_dir);
					BPath the_path;
					the_dir.GetPath(&the_path);
					chdir(the_path.Path()); 
					resume_thread(spawn_thread((thread_entry)megademo42,"megademo42",B_NORMAL_PRIORITY,NULL));
				}
				
		bool	QuitRequested()
				{
					g_shutdown();
					b_result();
					return true;
				}
};

int main(int argc, char **argv)
{
	if(argc>1)
	{
		if(strcasecmp(argv[1],"-nosound")==NULL)
		{
			nosound=true;
		}
		else
		{
			nosound=false;
		}
	}
	be_app = new MyApp();
	be_app->Run();
	delete be_app;
	return 0;
}
