/*********************************************************************
----------------------------------------------------------------------

		mplay.c
	
		amiga window interface 

		1.0	-  7.8.98 (bifat)	- introduced version number
		1.1 - 10.9.98 (Copper)  - PPC Port
		1.2	- 12.9.98 (bifat)	- fixed 68k timer handling
		1.3 - 19.2.99 (Copper)  - add save frame
----------------------------------------------------------------------
*********************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <fcntl.h>

#include <utility/tagitem.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <intuition/intuition.h>
#include <guigfx/guigfx.h>
#include <libraries/picasso96.h>

#include <clib/macros.h>

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/guigfx.h>
#include <proto/wb.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/guigfx.h>
#include <proto/picasso96.h>
#include <clib/alib_protos.h>

#ifndef __PPC__
#include <proto/asyncio.h>
#include <devices/timer.h>
#include "timer.h"
#else
//#include <powerup/ppclib/interface.h>
#include <powerup/ppclib/time.h>
#endif


#include "MPlay.h"
#include "yuvconversion.h"
#include "commandline.h"
#include "screen.h"


#include "config.h"
#undef GLOBAL
#include "global.h"


/********************************************************************/

struct Library *GuiGFXBase = NULL;
struct Library *P96Base = NULL;
struct Library *CyberGfxBase = NULL;

#ifndef __PPC__
struct Library *AsyncIOBase = NULL;
#endif

ULONG *staticpalette = NULL;
ULONG *greypalette = NULL;

#ifndef __PPC__
struct AsyncFile	*AsyncInfile;
#endif

static char versionstring[] = "$VER: " PROGNAME __VERSION__ "";

unsigned char outbfr[4096];
unsigned char *outptr;

/*********************************************************************
----------------------------------------------------------------------

	global
	
	open libraries,
	create a static palette,
	initialize buffers

----------------------------------------------------------------------
*********************************************************************/

void CloseGlobal(void)
{
	if (greypalette)
	{
		free(greypalette);
		greypalette = NULL;
	}

	if (staticpalette)
	{
		free(staticpalette);
		staticpalette = NULL;
	}

#ifndef __PPC__
	CloseLibrary(AsyncIOBase);
	AsyncIOBase = NULL;
#endif

	CloseLibrary(CyberGfxBase);
	CyberGfxBase = NULL;

	CloseLibrary(P96Base);
	P96Base = NULL;

	CloseLibrary(GuiGFXBase);
	GuiGFXBase = NULL;
}


BOOL InitGlobal(void)
{

#ifndef __PPC__
	if (!(AsyncIOBase = OpenLibrary("asyncio.library", ASYNCIO_VERSION)))
	{
		printf("could not open asyncio.library v%ld.\n", ASYNCIO_VERSION);
	}
#endif

	if (!(GuiGFXBase = OpenLibrary("guigfx.library", GUIGFX_VERSION)))
	{
		printf("could not open guigfx.library v%ld.\n", GUIGFX_VERSION);
	}

	CyberGfxBase = OpenLibrary("cybergraphics.library", CGFX_VERSION);

	P96Base = OpenLibrary("Picasso96API.library", P96_VERSION);

	if (staticpalette = malloc(4*4*4*sizeof(ULONG)))
	{
		ULONG *p = staticpalette;
		int r,g,b;
		for (r = 0; r < 4; ++r)
		{
			for (g = 0; g < 4; ++g)
			{
				for (b = 0; b < 4; ++b)
				{
					//	%RRrr::..GGgg::..BBbb::..

					*p++ = (r << 22) + (r << 20) + (r << 18) + (r << 16)
						+ (g << 14) + (g << 12) + (g << 10) + (g << 8)
						+ (b << 6) + (b << 4) + (b << 2) + b;
				}
			}
		}
	}
	
	if (greypalette = malloc(256 * sizeof(ULONG)))
	{
		int i;
		for (i = 0; i < 256; ++i)
		{
			greypalette[i] = (i<<16) + (i<<8) + i;
		}
	}


#ifdef __PPC__
	if (GuiGFXBase && staticpalette && greypalette)
#else 
	if (GuiGFXBase && AsyncIOBase && staticpalette && greypalette)
#endif
	{
		inityuv2rgb();
		return TRUE;
	}
	else
	{
		CloseGlobal();
		return FALSE;
	}
}




/*********************************************************************
----------------------------------------------------------------------

	void UpdateWindowParameters(mvwindow)

	get current window parameters

----------------------------------------------------------------------
*********************************************************************/

void UpdateWindowParameters(struct mvwindow *win)
{
	win->winleft = win->window->LeftEdge;
	win->wintop = win->window->TopEdge;
	win->winwidth = win->window->Width;
	win->winheight = win->window->Height;
	win->innerleft = win->window->BorderLeft;
	win->innertop = win->window->BorderTop;
	win->innerwidth = win->winwidth - win->innerleft - win->window->BorderRight;
	win->innerheight = win->winheight - win->innertop - win->window->BorderBottom;
}


/*********************************************************************
----------------------------------------------------------------------

	DeleteMVWindow (mvwindow)

----------------------------------------------------------------------
*********************************************************************/

void DeleteMVWindow (struct mvwindow *win)
{
	if (win)
	{
		if (win->window)
		{		
			ReleasePen(win->screen->screen->ViewPort.ColorMap, win->whitepen);
			ReleasePen(win->screen->screen->ViewPort.ColorMap, win->blackpen);
		
#ifndef __PPC__
			if (win->timeHandle)
			{
				timerstop(win->timeHandle);
			}
#endif	
			if (win->directdrawhandle)
			{
				DeleteDirectDrawHandle(win->directdrawhandle);
			}
		
			if (win->bufferpic)
			{
				DeletePicture(win->bufferpic);
			}

			if (win->rgbbuffer)
			{
				free(win->rgbbuffer);
			}

			if (win->drawhandle) 
			{
				ReleaseDrawHandle(win->drawhandle);
			}
			
			if (win->psm)
			{
				DeletePenShareMap(win->psm);
			}

			Forbid();

			if (win->appwindow && win->appmsgport)
			{
				struct AppMessage *appmsg;
			
				while (appmsg = (struct AppMessage *) GetMsg(win->appmsgport))
				{
					ReplyMsg((struct Message *) appmsg);
				}
			
				RemoveAppWindow(win->appwindow);
			}
	
			DeleteMsgPort(win->appmsgport);

			Permit();

			if (win->window)
			{
				if (win->pipwindow)
				{
					p96PIP_Close(win->window);
				}
				else
				{
					CloseWindow(win->window);
				}
			}

			if (win->title)
			{
				free(win->title);
			}
		}
		
		free(win);
	}
}



/*********************************************************************
----------------------------------------------------------------------

	mvwindow = CreateMVWindow (screen)

----------------------------------------------------------------------
*********************************************************************/

static BOOL checkoptkeyword(int index, char *name)
{
	if (opts[index])
	{
		if (!stricmp((char *) opts[index], name))
		{
			return TRUE;
		}
	}
	
	return FALSE;
}

#define inserttag(x,t,d) {(x)->ti_Tag=(t);((x)++)->ti_Data=(ULONG)(d);}

struct mvwindow *CreateMVWindow (struct mvscreen *screen, BOOL tryPip, 
	int sourcewidth, int sourceheight, BOOL gray, char *wintitle, int framerate)
{
	struct mvwindow *win;

	if (win = malloc(sizeof(struct mvwindow)))
	{
		BOOL success = FALSE;
		struct TagItem *taglist;
		char tbuf[100];

		memset(win, 0, sizeof(struct mvwindow));
		
		win->gray = gray;
		win->sourcewidth = sourcewidth;
		win->sourceheight = sourceheight;
		win->sourcewidth16 = ((sourcewidth + 15) >> 4) << 4;
		win->screen = screen;
		win->bright = 0;
		win->halted = FALSE;

		sprintf(tbuf, "%s [%ld×%ld]", wintitle, horizontal_size, vertical_size);
		
		win->title = strdup(tbuf);

		if(win->appmsgport = CreateMsgPort())
		{
			win->appSignal = 1L << win->appmsgport->mp_SigBit;

			if(taglist = AllocateTagItems(30))
			{
				UWORD visibleMidX, visibleMidY;
				UWORD visibleLeft, visibleTop;
				WORD winwidth, winheight, wintop, winleft;
				struct TagItem *tp = taglist;
				ULONG modeID;
				
				win->visibleWidth = screen->screen->Width;
				win->visibleHeight = screen->screen->Height;
		
				if ((modeID = GetVPModeID(&screen->screen->ViewPort)) != INVALID_ID)
				{
					DisplayInfoHandle dih;
			
					if(dih = FindDisplayInfo(modeID))
					{
						struct DimensionInfo di;	
			
						if(GetDisplayInfoData(dih, (UBYTE*) &di, sizeof(di), DTAG_DIMS, modeID))
						{
							win->visibleWidth = di.TxtOScan.MaxX - di.TxtOScan.MinX;
							win->visibleHeight = di.TxtOScan.MaxY - di.TxtOScan.MinY;
							
							if (!tryPip)
							{
								// frechheit
							
								win->visibleWidth++;
								win->visibleHeight++;
							}
							
							// printf("visibleheight/width: %ld,%ld\n", visibleWidth, visibleHeight);
						}
					}
				}
		
				visibleLeft = -screen->screen->ViewPort.DxOffset;
				visibleTop = -screen->screen->ViewPort.DyOffset;

				visibleMidX = win->visibleWidth / 2 - screen->screen->ViewPort.DxOffset;
				visibleMidY = win->visibleHeight / 2 - screen->screen->ViewPort.DyOffset;

				if (visibleTop < screen->screen->BarHeight )
				{
					visibleTop += screen->screen->BarHeight ;
					win->visibleHeight -= screen->screen->BarHeight ;
					visibleMidY += (screen->screen->BarHeight )/2;
				}


				if (checkoptkeyword(OPT_WINSIZEMODE, "HALF"))
				{
					winwidth = win->visibleWidth / 2;
					winheight = win->visibleHeight / 2;
					inserttag(tp, WA_Width, winwidth);
					inserttag(tp, WA_Height, winheight);
				}
				else if (checkoptkeyword(OPT_WINSIZEMODE, "LARGE"))
				{
					winwidth = win->visibleWidth * 2 / 3;
					winheight = win->visibleHeight * 2 / 3;
					inserttag(tp, WA_Width, winwidth);
					inserttag(tp, WA_Height, winheight);
				}
				else if (checkoptkeyword(OPT_WINSIZEMODE, "SMALL"))
				{
					winwidth = win->visibleWidth / 3;
					winheight = win->visibleHeight / 3;
					inserttag(tp, WA_Width, winwidth);
					inserttag(tp, WA_Height, winheight);
				}
				else if (checkoptkeyword(OPT_WINSIZEMODE, "VISIBLE"))
				{
					winwidth = win->visibleWidth;
					winheight = win->visibleHeight;
					inserttag(tp, WA_Width, winwidth);
					inserttag(tp, WA_Height, winheight);
				}
				else if (checkoptkeyword(OPT_WINSIZEMODE, "FULL"))
				{
					winwidth = screen->screen->Width;
					winheight = screen->screen->Height;
					inserttag(tp, WA_Width, winwidth);
					inserttag(tp, WA_Height, winheight);
				}
				else
				{
					winwidth = win->visibleWidth / 2;
					winheight = win->visibleHeight / 2;
					inserttag(tp, WA_Width, winwidth);
					inserttag(tp, WA_Height, winheight);
				}
		
				winleft = visibleMidX - winwidth/2;
				wintop = visibleMidY - winheight/2;
				inserttag(tp, WA_Left, winleft);
				inserttag(tp, WA_Top, wintop);
	
				win->otherwinpos[0] = visibleLeft;
				win->otherwinpos[1] = visibleTop;
				win->otherwinpos[2] = win->visibleWidth;
				win->otherwinpos[3] = win->visibleHeight;


				inserttag(tp, WA_PubScreen, screen->screen);

				if (!opts[OPT_BORDERLESS])
				{
					inserttag(tp, WA_Zoom, &win->otherwinpos);

					if (win->title)
					{
						inserttag(tp, WA_Title, win->title);
					}
					else
					{
						inserttag(tp, WA_Title, DEFAULT_WINTITLE);
					}
				}
		
				inserttag(tp, WA_NewLookMenus, TRUE);
		
		
				inserttag(tp, WA_Flags, 
							(opts[OPT_BORDERLESS] ? WFLG_BORDERLESS :
							WFLG_SIZEBBOTTOM | WFLG_DRAGBAR |
							WFLG_SIZEGADGET | WFLG_DEPTHGADGET |
							WFLG_CLOSEGADGET) | WFLG_ACTIVATE | WFLG_SIMPLE_REFRESH);

				win->idcmp = IDCMP_CLOSEWINDOW | IDCMP_NEWSIZE |
							IDCMP_VANILLAKEY | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS;

				inserttag(tp, WA_IDCMP, win->idcmp);
			
				inserttag(tp, WA_MinWidth, DEFAULT_MINWIDTH);
				inserttag(tp, WA_MinHeight, DEFAULT_MINHEIGHT);
				inserttag(tp, WA_MaxWidth, DEFAULT_MAXWIDTH);
		 		inserttag(tp, WA_MaxHeight, DEFAULT_MAXHEIGHT);



				if (tryPip)
				{
					if (P96Base)
					{
						inserttag(tp, P96PIP_SourceFormat, RGBFB_Y4U2V2);
						inserttag(tp, P96PIP_SourceWidth, sourcewidth);
						inserttag(tp, P96PIP_SourceHeight, sourceheight);
						inserttag(tp, TAG_DONE, 0);
					
						if (win->window = p96PIP_OpenTagList(taglist))
						{
//							struct TagItem gtTags[] = { {P96PIP_SourceBitMap,0},{TAG_DONE, 0} };
//							struct RenderInfo renderinfo;
//							struct BitMap *bitmap;
//							LONG lock;
	
							win->pipwindow = TRUE;
			
//            				gtTags[0].ti_Data = (ULONG)&bitmap;

/*
							p96PIP_GetTagList(win->window, gtTags);
							lock = p96LockBitMap(bitmap, (UBYTE *) &renderinfo, sizeof(struct RenderInfo));
	
							win->p96address = (unsigned char *) renderinfo.Memory;

							p96UnlockBitMap(bitmap, lock);
*/
						}
					}
					else
					{
						printf("could not open Picasso96API.library v%ld.\n", P96_VERSION);
					}
				}
				else
				{
					inserttag(tp, TAG_DONE, 0);
					win->window = OpenWindowTagList(NULL, taglist);
				}
				
				if (win->window)
				{
					struct TagItem obpTags[] = { {OBP_Precision, PRECISION_GUI}, {TAG_DONE, 0} };

					success = TRUE;
					
					win->blackpen = ObtainBestPenA(screen->screen->ViewPort.ColorMap, 0,0,0, obpTags);
					win->whitepen = ObtainBestPenA(screen->screen->ViewPort.ColorMap, -1,-1,-1, obpTags);
				
					if (!win->pipwindow)
					{
						success = FALSE;

						if (win->rgbbuffer = malloc(win->sourcewidth16 * sourceheight * sizeof(ULONG)))
						{
							struct TagItem mpTags[] = { {GGFX_PixelFormat, PIXFMT_0RGB_32}, {TAG_DONE, 0} };
							if (win->bufferpic = MakePictureA(win->rgbbuffer, win->sourcewidth16,
								sourceheight, mpTags))
							{
								success = TRUE;
							}
						}
					}

					if (success)
					{				
						win->idcmpSignal = 1L << win->window->UserPort->mp_SigBit;
						UpdateWindowParameters(win);
						win->appwindow = AddAppWindowA(0, 0, win->window, win->appmsgport, NULL);
					}
				}
		
				FreeTagItems(taglist);
			}
		}
		
		if (!success)
		{
			DeleteMVWindow(win);
			win = NULL;
		}
	}

	return win;
}

#undef inserttag


/*********************************************************************
----------------------------------------------------------------------

	mplay

----------------------------------------------------------------------
*********************************************************************/

BOOL mplay(struct mvwindow *win, unsigned char **srcbuffer)
{
	BOOL weiter = FALSE;

	if (win && srcbuffer)
	{
		ULONG signals;
		struct IntuiMessage *imsg;

		char timetext[100];
		unsigned int start_time[2];

		weiter = TRUE;
	
		win->frame = ++win->frame;
		
		if (!win->pipwindow)
		{
	
			// render to a normal window
	
			if (win->gray)
			{
				yuv2rgbgrey(srcbuffer, win->rgbbuffer, win->sourcewidth16, win->sourceheight, win->bright);
			}
			else
			{
				yuv2rgb(srcbuffer, win->rgbbuffer, win->sourcewidth16, win->sourceheight, win->bright);
			}
			
			if (!win->drawhandle)
			{
				static struct TagItem odhTags[] = { {GGFX_AutoDither, FALSE},
					{GGFX_DitherMode, DITHERMODE_NONE}, {GGFX_ModeID, 0}, {TAG_DONE, 0} };
				
				odhTags[2].ti_Data = win->screen->modeID;
			

				if (!win->psm)
				{
					static struct TagItem cpsmTags[] = { {GGFX_HSType, HSTYPE_12BIT_TURBO}, {TAG_DONE, 0} };

					if (win->psm = CreatePenShareMapA(cpsmTags))
					{					
						struct TagItem apaTags[] = { {GGFX_PixelFormat, PIXFMT_0RGB_32}, {TAG_DONE, 0} };
						struct TagItem apTags[] = { {GGFX_Weight, 1}, {TAG_DONE, 0} };

						if (win->gray)
						{
							//	create a pen-sharemap from a grey palette

							AddPixelArrayA(win->psm, greypalette, 256, 1, apaTags); 
						}
						else
						{

							//	create a pen-sharemap by composing it from 50% of
							//	the static palette and 50% of the first frame

							AddPictureA(win->psm, win->bufferpic, apTags);
							AddPixelArrayA(win->psm, staticpalette, 4*4*4, 1, apaTags); 
						}
					}
				}
	
				//	create a drawhandle from the pen-sharemap for our rastport/colormap
	
				win->drawhandle = ObtainDrawHandleA(win->psm, win->window->RPort,
					win->screen->screen->ViewPort.ColorMap, odhTags);
	
				UpdateWindowParameters(win);

				if (win->screen->ham)
				{
					Move(win->window->RPort, win->innerleft, win->innertop);
					SetAPen(win->window->RPort, 0);
					Draw(win->window->RPort, win->innerleft, win->innertop+win->innerheight-1);
				}
			}
			
			if (!win->screen->ham)
			{
				if (!win->directdrawhandle)
				{
					//	derive a 'direct'-drawhandle for optimized rendering
			
					win->directdrawhandle = CreateDirectDrawHandleA(win->drawhandle,
						win->sourcewidth, win->sourceheight, win->innerwidth, win->innerheight,
						NULL);
				}
			}
			
			if (win->directdrawhandle)
			{
				static struct TagItem ddtcTags[] = { {GGFX_SourceWidth, 0}, {TAG_DONE, 0} };
				
				ddtcTags[0].ti_Data = (ULONG)win->sourcewidth16;

				DirectDrawTrueColorA(win->directdrawhandle, win->rgbbuffer, win->innerleft,
					win->innertop, ddtcTags);
			}
			else
			{
				static struct TagItem dptags[] = { {GGFX_DestWidth, 0}, {GGFX_DestHeight, 0}, {TAG_DONE} };
				int x;
				dptags[1].ti_Data = (ULONG) win->innerheight;

				if (win->screen->ham)
				{
					dptags[0].ti_Data = (ULONG) win->innerwidth - 1;
					x = win->innerleft + 1;
				}
				else
				{
					dptags[0].ti_Data = (ULONG) win->innerwidth;
					x = win->innerleft;
				}
			
				DrawPictureA(win->drawhandle, win->bufferpic, x, win->innertop, dptags);
			}
		}
		else
		{
			// render to PIP
		
		 	int x, y;
			unsigned char *address;
			struct TagItem gtTags[] = { {P96PIP_SourceBitMap,0},{TAG_DONE, 0} };
			struct RenderInfo renderinfo;
			struct BitMap *bitmap;
			LONG lock;

			// schreibe YUV werte in bitmap
	
			gtTags[0].ti_Data = (ULONG)&bitmap;

			p96PIP_GetTagList(win->window, gtTags);
			lock = p96LockBitMap(bitmap, (UBYTE *) &renderinfo, sizeof(struct RenderInfo));
	
			address = (unsigned char *) renderinfo.Memory;

//			address = win->p96address;

			if (!win->gray)
			{
				y = (win->sourceheight/2)-1;
				x = (win->sourcewidth16/2)-1;

				yuv2pip(address, srcbuffer, x, y, win->bright);

			}
			else   //mache nur ein graubild 
			{

				y = (win->sourceheight*win->sourcewidth16)/2;

				yuv2pipgrey(address, srcbuffer, y, win->bright);

			}
	
			p96UnlockBitMap(bitmap, lock);

		}
	
	
		//	get signals


		do
		{
			if (win->halted)
			{
				signals = Wait(win->idcmpSignal | win->appSignal | SIGBREAKF_CTRL_C);
			}
			else
			{
				signals = SetSignal(0, win->idcmpSignal | win->appSignal);
			}

			if (signals & win->idcmpSignal)
			{
				while (imsg = (struct IntuiMessage *) GetMsg(win->window->UserPort))
				{
					ULONG iclass = imsg->Class;
					ULONG icode = imsg->Code;

					ReplyMsg((struct Message *) imsg);

					switch (iclass)
					{
						case CLOSEWINDOW:
							weiter = FALSE;
							break;
			
						case NEWSIZE:
							if ((win->window->Width != win->winwidth) ||
								(win->window->Height != win->winheight))
							{
								UpdateWindowParameters(win);
								RefreshWindowFrame(win->window);
								DeleteDirectDrawHandle(win->directdrawhandle);
								win->directdrawhandle = NULL;
							}
							break;
		
						case VANILLAKEY:
						{
							switch (icode)
							{
								case 's':
								case 'S':
									saveframe(srcbuffer,win);
									break;
								case 'g':
								case 'G':
									SetAPen(win->window->RPort, 0);
									RectFill(win->window->RPort, win->innerleft, win->innertop,
									win->innerleft + win->innerwidth-1, win->innertop + win->innerheight-1);
									win->gray = !win->gray;
									DeleteDirectDrawHandle(win->directdrawhandle);
									win->directdrawhandle = NULL;
									ReleaseDrawHandle(win->drawhandle);
   									win->drawhandle = NULL;
									DeletePenShareMap(win->psm);
									win->psm = NULL;
									opts[OPT_GREY] = win->gray;
	
									if (win->pipwindow)
									{
										SizeWindow(win->window,1,0);
										SizeWindow(win->window,-1,0);
									}
									
									break;
							
								case 27:
									weiter = FALSE;
									break;
							
								case 't':
								case 'T':
									opts[OPT_FPS] = !opts[OPT_FPS];
									if ((win->pipwindow) && !opts[OPT_FPS])
									{
										RectFill(win->window->RPort, win->innerleft, win->innertop + win->innerheight - win->window->RPort->TxHeight + win->window->RPort->TxBaseline,
										win->innerleft + win->innerwidth-1, win->innertop + win->innerheight-1);
										SizeWindow(win->window,1,0);
										SizeWindow(win->window,-1,0);
									}
									break;
								case '+':
									win->bright = ++win->bright > 255 ? 255 : win->bright;
									break;
								case '-':
									win->bright = --win->bright < -255 ? -255 : win->bright;
									break;
								case '#':
									win->bright = 0;
									break;
								
								case '0':
									win->framerate = 0;
									break;
								case '1':
									win->framerate = 5;
									break;
								case '2':
									win->framerate = 10;
									break;
								case '3':
									win->framerate = 15;
									break;
								case '4':
									win->framerate = 20;
									break;
								case '5':
									win->framerate = 25;
									break;
								case '6':
									win->framerate = 30;
									break;
								case '7':
									win->framerate = 50;
									break;
								case '8':
									win->framerate = 60;
									break;
								case '9':
									win->framerate = 100000;
									break;
									
								case 32:
									win->halted = !win->halted;
									break;
	
								case 9:
									ZipWindow(win->window);
									break;
							}
							break;
						}
						
						case RAWKEY:
						{
							if (icode >= 80 && icode <= 85)
							{
								int newWidth, newHeight;
								int borderWidth, borderHeight;
								UpdateWindowParameters(win);
	
								borderWidth = win->winwidth - win->innerwidth;
								borderHeight = win->winheight - win->innerheight;
								newWidth = win->winwidth;
								newHeight = win->winheight;
								
								switch (icode)
								{
									case 80:
									{
										//	snap size
										
										newWidth = win->sourcewidth;
										newHeight = win->sourceheight;
										break;
									}
									case 81:
									{
										//	small size
										
										newWidth = win->visibleWidth / 3;
										newHeight = win->visibleHeight / 3;
										break;
									}
									case 82:
									{
										//	half size
										
										newWidth = win->visibleWidth / 2;
										newHeight = win->visibleHeight / 2;
										break;
									}
									case 83:
									{
										//	large size
										
										newWidth = win->visibleWidth * 2 / 3;
										newHeight = win->visibleHeight * 2 / 3;
										break;
									}
									case 84:
									{
										//	visible size
										
										newWidth = win->visibleWidth;
										newHeight = win->visibleHeight;
										break;
									}
									case 85:
									{
										//	full size
										
										newWidth = win->screen->screen->Width;
										newHeight = win->screen->screen->Height;
										break;
									}
								}
								
								
								if (newWidth < win->winwidth)
								{
									SizeWindow(win->window,
										(newWidth + borderWidth) - win->winwidth, 0);
									MoveWindow(win->window,
										-((newWidth + borderWidth) - win->winwidth)/2, 0);
								}
								else if (newWidth > win->winwidth)
								{
									MoveWindow(win->window,
										-((newWidth + borderWidth) - win->winwidth)/2, 0);
									SizeWindow(win->window,
										(newWidth + borderWidth) - win->winwidth, 0);
								}
	
								if (newHeight < win->winheight)
								{
									SizeWindow(win->window, 0,
										(newHeight + borderHeight) - win->winheight);
									MoveWindow(win->window, 0,
										-((newHeight + borderHeight) - win->winheight)/2);
								}
								else if (newHeight > win->winheight)
								{
									MoveWindow(win->window, 0,
										-((newHeight + borderHeight) - win->winheight)/2);
									SizeWindow(win->window, 0,
										(newHeight + borderHeight) - win->winheight);
								}
							}
							break;
						}
					}
				}
			}
			
			if (signals & SIGBREAKF_CTRL_C)
			{
				weiter = FALSE;
			}

	
#ifdef __PPC__
			if (win->timerObject)
			{
				ULONG *Time[2];
				int waitTime = 0;
				long displayTime;
				int sollTime;
				static int sumTime = 0;
				static int numFrames = 0;
				int time;
		
				PPCSetTimerObject(win->timerObject,PPCTIMERTAG_STOP,NULL);
				PPCGetTimerObject(win->timerObject,PPCTIMERTAG_DIFFTICKS,&Time);
	
			    displayTime = (long)Time[1];
				displayTime = displayTime/win->ticks;
				time		= displayTime;
	
				if (!opts[OPT_IGNOREFPS])
				{
		
					if (win->framerate)
					{
						sollTime = (int)((double) 1000 / (double) win->framerate);
					}
					else
					{
						sollTime = (int)((double) 1000 / frame_rate_Table[frame_rate_code]);
					}
	
					if ((waitTime = sollTime - time) > 0)
					{
						displayTime = sollTime;
					}
				}
				
				if (numFrames != 0)
				{
				 	sumTime+= (int) displayTime;
				}
					numFrames++;

				if (opts[OPT_FPS])
				{
					Move(win->window->RPort, win->innerleft, 
						win->innertop + win->innerheight - win->window->RPort->TxHeight + win->window->RPort->TxBaseline);
					PPCsprintf(timetext, "%3ld %.2f %.2f",win->frame, 
						(double)1000/(double)displayTime,
						(double)(1000 * numFrames) / (double) sumTime);
					SetABPenDrMd(win->window->RPort, win->whitepen, win->blackpen, JAM2);
					Text(win->window->RPort, timetext, strlen(timetext));
				}
	
				if (waitTime > 0)
				{
//					static unsigned int start_time[2];
					unsigned int tmp;
	
					tmp = waitTime*win->ticks;
	
					ppctimer(start_time);
	
					if (!(tmp > win->ticks*1000))
					{
						for (;;)
						{
							static unsigned int stop_time[2];
	
							ppctimer(stop_time);
	
							if ((stop_time[0]-start_time[0]) == 0)
							{
								if (((stop_time[1]-start_time[1]) > tmp)||(start_time[1] > stop_time[1]))
								{
									break;
								}
							}
							else
							{
								ppctimer(start_time);
							}
						}
					}
				}
	
				PPCSetTimerObject(win->timerObject,PPCTIMERTAG_START,NULL);
			}

#else

			if (win->timeHandle)
			{
				int time;
				int waitTime = 0;
				int displayTime;
				int sollTime;
				static float sumTime = 0.0;
				static int numFrames = 0;
		
				displayTime = (time = timerstop(win->timeHandle));
				win->timeHandle = NULL;
	
				if (!opts[OPT_IGNOREFPS])
				{
		
					if (win->framerate)
					{
						sollTime = (int)((double) 1000 / (double) win->framerate);
					}
					else
					{
						sollTime = (int)((double) 1000 / frame_rate_Table[frame_rate_code]);
					}
	
					if ((waitTime = sollTime - time) > 0)
					{
						displayTime = sollTime;
					}
				}
				
				sumTime += (float) displayTime;
				numFrames++;
						
				if (opts[OPT_FPS])
				{
					Move(win->window->RPort, win->innerleft, 
						win->innertop + win->innerheight - win->window->RPort->TxHeight + win->window->RPort->TxBaseline);
					sprintf(timetext, "%3ld %.2f %.2f",win->frame, 
						(double)1000/(double)displayTime, 
						(double)(1000 * numFrames) / (double) sumTime);
					SetABPenDrMd(win->window->RPort, win->whitepen, win->blackpen, JAM2);
					
					Text(win->window->RPort, timetext, strlen(timetext));
				}
	
				if (waitTime > 0)
				{
					TimeDelay(UNIT_MICROHZ, 0, waitTime * 1000);
				}
			}
	
#endif

		} while (win->halted && weiter);

#ifdef __PPC__
		ppctimer(start_time);
#else
		win->timeHandle = timerstart();
#endif
	}

	return weiter;
}

/*****************************************************************************************/
/* Speichert aktuellen Frame */
void saveframe(unsigned char **srcbuffer,struct mvwindow *win)
{
  char outname[FILENAME_LENGTH];
  char header[20],r,g,b;
  int outfile,i,j;
  ULONG *buffer,triple;
  
	if (win->pipwindow) 
	{
		if (!win->rgbbuffer)
		{
		win->rgbbuffer = malloc(win->sourcewidth16 * win->sourceheight * sizeof(ULONG));
		}
		yuv2rgb(srcbuffer, win->rgbbuffer, win->sourcewidth16, win->sourceheight, win->bright);
	}
	
/* fülle filename */

    sprintf(outname,"%s%d",Main_Bitstream_Filename,win->frame);
	strcat(outname, ".ppm");

	if ((outfile = open(outname,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666)) != -1)
	{
/* save as ppm header*/
    	sprintf(header,"P6\n%d %d\n255\n",win->sourcewidth,win->sourceheight);

    	outptr = outbfr;

    	for (i=0; header[i]!=0; i++)
			savebyte(header[i],outfile);

/* nun den rest */

		buffer = win->rgbbuffer;
		for (i=0; i<win->sourceheight; i++)
		{
			for (j=0; j<win->sourcewidth; j++)
			{
				triple=*buffer++;
				r = (triple&0x00ff0000)>>16;
				g = (triple&0x0000ff00)>>8;
				b = (triple&0x000000ff);
				savebyte(r,outfile);
				savebyte(g,outfile);
				savebyte(b,outfile);
			}

			buffer = buffer + (win->sourcewidth16 - win->sourcewidth);

		}

		if (outptr!=outbfr)
		write(outfile,outbfr,outptr-outbfr);

		close(outfile);
	}
}
	
void savebyte(int c,int outfile)
{
  *outptr++ = c;

  if (outptr == outbfr+4096)
  {
    write(outfile,outbfr,4096);
    outptr = outbfr;
  }
}
