/* $Id: Exp $
***************************************************************************

   X server for LibGLTEX - primary output handling functions

   Copyright (C) 2002 Christopher Alexander North-Keys
                      http://www.talisman.org/~erlkonig/

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

/* The key function in the file is InitOutput,
 * called by main in dix/main.c during server startup
 */

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "X11/Xos.h"

#define PSZ 8
#include "cfb.h"
#include "../../hw/xfree86/common/cfb16.h"
#include "../../hw/xfree86/common/cfb24.h"
#include "../../hw/xfree86/common/cfb32.h"

#include "scrnintstr.h"
#include "servermd.h"
#include "colormapst.h"
#include "mipointer.h"

#include "xgltex.h"

#ifdef DDXTIME /* from ServerOSDefines */
CARD32 GetTimeInMillis(void)
{
	struct timeval  tp;
	X_GETTIMEOFDAY(&tp);
#define TVAL2TIME(tv)	((tv).tv_sec*1000 + (tv).tv_usec/1000)
	return TVAL2TIME(tp);
#undef TVAL2TIME
}
#endif

static void *safe_alloc(long siz)
{
	void *ret = xalloc(siz);
	if( ! ret) FatalError("Unable to allocate %d bytes of memory\n", siz);

	return ret;
}


static void xgltexExit(void)
{
	xgltexVarsClear();
}

void AbortDDX(void)
{
	xgltexExit();
}

void ddxGiveUp(void)
{
	xgltexExit();
}


void OsVendorInit(void)
{
}

void OsVendorFatalError(void)
{
	xgltexExit();
}

void ddxUseMsg(void)
{
	xgltexUsage();
}

int ddxProcessArgument(int argc, char *argv[], int argi)
{
	return xgltexProcessArg(argc, argv, argi);
}

#define MAX_COLORS 256 /* For the PseudoColor modes.. */
static ColormapPtr InstalledMaps[MAXSCREENS];

static void xgltexStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs)
{
	int i;
	fprintf(stderr, __FUNCTION__": entry\n");

	if (pmap != InstalledMaps[pmap->pScreen->myNum])
		return;

	if ((pmap->pVisual->class | DynamicClass) == DirectColor)
		return;
	/* here's the evil section */
	ErrorF(__FUNCTION__": incompletely implemented - see source\n");
/*-------------------- old code
	{
		static xggiScreenInfo_t xggiScreen;
		ggi_color ggimap[MAX_COLORS];

		ggiGetPalette(xggiScreen.vis, 0, MAX_COLORS, ggimap);

		for (i = 0; i < ndef; i++) {
			if (pdefs[i].pixel >= MAX_COLORS) continue;
			if (pdefs[i].flags & DoRed)
				ggimap[pdefs[i].pixel].r = pdefs[i].red;
			if (pdefs[i].flags & DoGreen)
				ggimap[pdefs[i].pixel].g = pdefs[i].green;
			if (pdefs[i].flags & DoBlue)
				ggimap[pdefs[i].pixel].b = pdefs[i].blue;
		}

		ggiSetPalette(xggiScreen.vis, 0, MAX_COLORS, ggimap);
	}
---------------------------*/
	fprintf(stderr, __FUNCTION__": exit\n");
}

static int xgltexListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps)
{
	/* By the time we are processing requests, we can guarantee that there
	 * is always a colormap installed */
	*pmaps = InstalledMaps[pScreen->myNum]->mid;
	return (1);
}

static void xgltexInstallColormap(ColormapPtr pmap)
{
	int index = pmap->pScreen->myNum;
	ColormapPtr oldpmap = InstalledMaps[index];

	if (pmap != oldpmap) {
		int         entries;
		VisualPtr  pVisual;
		Pixel      * ppix;
		xrgb       * prgb;
		xColorItem * defs;
		int          i;

		if (oldpmap != (ColormapPtr)None)
			WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid);
		/* Install pmap */
		InstalledMaps[index] = pmap;
		WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);

		entries = pmap->pVisual->ColormapEntries;
		pVisual = pmap->pVisual;

		ppix = (Pixel *)     ALLOCATE_LOCAL(entries * sizeof(Pixel));
		prgb = (xrgb *)      ALLOCATE_LOCAL(entries * sizeof(xrgb));
		defs = (xColorItem *)ALLOCATE_LOCAL(entries * sizeof(xColorItem));

		for (i = 0; i < entries; i++)  ppix[i] = i;
		/* XXX truecolor */
		QueryColors(pmap, entries, ppix, prgb);

		for (i = 0; i < entries; i++) { /* convert xrgbs to xColorItems */
			defs[i].pixel  = ppix[i] & 0xff; /* change pixel to index */
			defs[i].red    = prgb[i].red;
			defs[i].green  = prgb[i].green;
			defs[i].blue   = prgb[i].blue;
			defs[i].flags  = DoRed | DoGreen | DoBlue;
		}
		(*pmap->pScreen->StoreColors)(pmap, entries, defs);

		DEALLOCATE_LOCAL(ppix);
		DEALLOCATE_LOCAL(prgb);
		DEALLOCATE_LOCAL(defs);
	}
}

static void xgltexUninstallColormaps(ColormapPtr pmap)
{
	ColormapPtr curpmap = InstalledMaps[pmap->pScreen->myNum];

	if (pmap == curpmap) {
		if (pmap->mid != pmap->pScreen->defColormap) {
			curpmap = (ColormapPtr)
				LookupIDByType(pmap->pScreen->defColormap,
							   RT_COLORMAP);
			(*pmap->pScreen->InstallColormap)(curpmap);
		}
	}
}

static Bool xgltexSaveScreen(ScreenPtr pScreen, int on)
{
#if 0
	switch (what) {
	case SCREEN_SAVER_ON:		    break;
	case SCREEN_SAVER_OFF:		    break;
	case SCREEN_SAVER_FORCER:		break;
	case SCREEN_SAVER_CYCLE:		break;
	}
#endif
	return TRUE;
}

static Bool xgltexCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
{
	/* no interscreen movement for now */
	return FALSE;
}

static void	xgltexCrossScreen(ScreenPtr pScreen, Bool entering)
{
}

static miPointerScreenFuncRec xgltexPointerCursorFuncs =
{
	xgltexCursorOffScreen,
	xgltexCrossScreen,
	miPointerWarpCursor
};

static Bool xgltexFBInitProc(int index, ScreenPtr pScreen,
							  int argc, char **argv)
{
	xgltexTexture_t *tex = &(xgltexVars.tex);
	const int dpix = 100, dpiy = 100;
	int scr = index;
	Bool ret;

	tex->xscreen = pScreen;
	if( ! xgltexScreenInit(tex->xscreen, /* pScreen */
						   tex->image,
						   tex->xsize,
						   tex->ysize,
						   dpix, dpiy,
						   tex->ysize,
						   tex->ysize /* FB pixel width for miScreenInit() */
						   ))
	{
		ErrorF("xgltexScreenInit failed\n");
		return FALSE;
	}

	pScreen->SaveScreen = xgltexSaveScreen;

	switch (tex->comp_bits) {
	case 1:
		pScreen->InstallColormap        = mfbInstallColormap;
		pScreen->UninstallColormap      = mfbUninstallColormap;
		pScreen->ListInstalledColormaps = mfbListInstalledColormaps;
		pScreen->StoreColors            = (void (*)())NoopDDA;
		break;
	case 16:
	case 24:
	case 32:
		pScreen->InstallColormap        = cfbInstallColormap;
		pScreen->UninstallColormap      = cfbUninstallColormap;
		pScreen->ListInstalledColormaps = cfbListInstalledColormaps;
		pScreen->StoreColors            = (void (*)())NoopDDA;
		break;
	default:
		pScreen->InstallColormap        = xgltexInstallColormap;
		pScreen->UninstallColormap      = xgltexUninstallColormaps;
		pScreen->ListInstalledColormaps = xgltexListInstalledColormaps;
		pScreen->StoreColors            = xgltexStoreColors;
		break;
	}

	miDCInitialize(pScreen, &xgltexPointerCursorFuncs);

	if (tex->zsize == 1) {
		ret = mfbCreateDefColormap(pScreen);
	} else {
		ret = cfbCreateDefColormap(pScreen);
	}
	if (!ret) ErrorF("[c|m]fbCreateDefColormap failed\n");

	return ret;
} 

/* The argc/argv has already be stripped of items known to dix/main.c
   They\'ve also been copied into argcGlobal and argvGlobal
   The rather alarming Screen structure and screenInfo are set up in
   dix/main.c, but is a global from dix/globals.c
   screenInfo's members are: */
#if 0
typedef struct _ScreenInfo {
    int     imageByteOrder;
    int     bitmapScanlineUnit;
    int     bitmapScanlinePad;
    int     bitmapBitOrder;
    int     numPixmapFormats;
    PixmapFormatRec formats[MAXFORMATS];
    int     arraySize;
    int     numScreens;
    ScreenPtr   screens[MAXSCREENS];
    int     numVideoScreens;
} ScreenInfo;
extern ScreenInfo screenInfo;
#endif  /* 0 */

void InitOutput(ScreenInfo *screenInfo, int argc, char *argv[])
{
	int i;
	xgltexVarsPrint(stderr);
	if( ! xgltexVars.initted)
		xgltexVarsActivate();

	/* add each format, increment the format count as we go
	   each format has only three members (all unsigned char):
	   -> depth, bitsPerPixel, and scanlinePad
	*/
	screenInfo->numPixmapFormats = 0;  /* incremented below */
	screenInfo->formats[0].depth        = 1;
	screenInfo->formats[0].bitsPerPixel = 1;
	screenInfo->formats[0].scanlinePad  = BITMAP_SCANLINE_PAD;
	++(screenInfo->numPixmapFormats);
	screenInfo->formats[1].depth        = (xgltexVars.tex.zsize * xgltexVars.tex.comp_bits);
	screenInfo->formats[1].bitsPerPixel = xgltexVars.tex.pixel_bits;
	screenInfo->formats[1].scanlinePad  = BITMAP_SCANLINE_PAD;
	++(screenInfo->numPixmapFormats);

	screenInfo->imageByteOrder     = IMAGE_BYTE_ORDER;
	screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT;
	screenInfo->bitmapScanlinePad  = BITMAP_SCANLINE_PAD;
	screenInfo->bitmapBitOrder     = BITMAP_BIT_ORDER;

	/* Add screens */
	if (AddScreen(xgltexFBInitProc, argc, argv) == -1)
		FatalError("Couldn't add screen");
}

/*-------------------------------------------------------------- eof --- */

