/********************************************************
 *
 *       Video renderers
 *       Copyright 2000 Eugene Kuznetsov (divx@euro.ru)
 *
 ********************************************************/

#include "default.h"

#if 0

// do not compile

#include "fourcc.h"
#include "Locker.h"
#include "except.h"
#include "renderer.h"
#include "playerwidget.h"
#include "cpuinfo.h"
#include "utils.h"
#include "mmx.h"

#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#ifndef X_DISPLAY_MISSING

#if defined(__FreeBSD__) || defined(__NetBSD__)
#include <machine/param.h>
#include <sys/types.h>
#endif
#include <errno.h>

#include <sys/ipc.h>
#include <sys/shm.h>

#include <X11/Xlib.h>
#include <X11/Xlocale.h>
#include <X11/Xutil.h>
#include <X11/extensions/XInput.h> //XGetExtensionVersion
#include <X11/extensions/XShm.h>

#ifdef HAVE_LIBXV
#include <X11/extensions/Xv.h>
#include <X11/extensions/Xvlib.h>
#endif

#ifdef HAVE_LIBXXF86DGA
#include <X11/extensions/xf86dga.h>
#endif

#ifdef HAVE_LIBXXF86VM
#include <X11/extensions/xf86vmode.h>
#endif

#ifdef HAVE_LIBXFT
#include <X11/Xft/Xft.h>
//#include <X11/extensions/Xrender.h>
#endif

#include <VideoDPMS.h>

/*
#ifdef USE_QT
#include <qfont.h>
#include <qfontmetrics.h>
#endif
*/

#ifdef USE_SDL
/*
#ifdef USE_OPENGL
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
#endif
*/
#include <SDL.h>
#include <SDL_video.h>
#include <SDL_syswm.h>
#include <SDL_mouse.h>

#ifndef SDL_DISABLE
#define SDL_DISABLE 0
#endif

#ifndef SDL_ENABLE
#define SDL_ENABLE 1
#endif

#endif

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <string>

using namespace std;

 /*fold00*/
/*
inline static void qSafeXDestroyImage( XImage *x )
{
    if ( x->data ) {
	free( x->data );
	x->data = 0;
    }
    XDestroyImage( x );
}

class ShmRenderer : public VideoRenderer
{
    bool	       xshminit;
    XShmSegmentInfo xshminfo;
    XImage	      *xshmimg;
    Pixmap	       xshmpm;
    GC 			gc;
    pthread_mutex_t mutex;
    int xpos;
    int screen;

public:
    ShmRenderer() : xshminit(0), xshmimg(0), xshmpm(0)
    {
    	pthread_mutex_init(&mutex, 0);
    }
    void Alloc()
    {
        static int major, minor;
	static Bool pixmaps_ok;
//        int dd	 = dev->x11Depth();
//        dpy 	 = dev->x11Display();
//        vis	 = (Visual*)dev->x11Visual();
	printf("Creating SHM renderer, width %d, height %d\n", pic_w, pic_h);
	printf("Server vendor %s, release %d\n", ServerVendor(_dpy), VendorRelease(_dpy));

	try
	{
    	    XGCValues xcg;
	    xcg.graphics_exposures=false;
	    gc=XCreateGC(_dpy, _vis, GCGraphicsExposures, &xcg);
	    if ( !XShmQueryVersion(_dpy, &major, &minor, &pixmaps_ok) )
		throw FATAL("MIT SHM extension not supported");

	    bool ok;
	    int _pic_w=((pic_w+m_w-1)/m_w)*m_w;
	    int _pic_h=((pic_h+m_h-1)/m_h)*m_h;
    	    xshminfo.shmid = shmget( IPC_PRIVATE,
    			     _pic_w*_pic_h*4,
    			     IPC_CREAT | 0777 );
	    ok = xshminfo.shmid != -1;
	    if(!ok)
		throw FATAL("Can't get shared memory segment");

	    xshminfo.shmaddr = (char*)shmat( xshminfo.shmid, 0, 0 );
	    ok = xshminfo.shmaddr != 0;
	    xshminfo.readOnly = FALSE;

    	    if ( !ok )
		throw FATAL("Can't attach shared memory segment");

	    ok = XShmAttach( _dpy, &xshminfo );
	    if ( !ok )
		throw FATAL("XShmAttach failed");

	    int dd=DefaultDepth(_dpy, DefaultScreen(dpy));
    	    xshmimg = XShmCreateImage( _dpy, _vis, dd, ZPixmap, xshminfo.shmaddr, &xshminfo, _pic_w, _pic_h );

	    if ( !xshmimg )
	        throw FATAL("Can't create shared image");

    	    printf("Video device: %d bpp ( physical %d ), color masks %X,%X,%X\n",
		dd, GetPhysicalDepth(_dpy), _vis->red_mask, _vis->green_mask, _vis->blue_mask);
	}
	catch(...)
	{
	    xshmimg = 0;
	    if ( xshminfo.shmaddr )
		shmdt( xshminfo.shmaddr );
	    if ( xshminfo.shmid != -1 )
		shmctl( xshminfo.shmid, IPC_RMID, 0 );
	    throw;
	}
    }
    int Create(Display *_dpy, Visual *_vis, int x, int y, int _xpos=0, int sub=0)
    {
	dpy=_dpy;
	vis=_vis;
	m_w=x;
        m_h=y;
	pic_w=x;
	pic_h=y;
        width=x;
	height=y;
	xpos=_xpos;
	Alloc();
    }
    int Free()
    {
	cerr<<"Free()"<<endl;
        if ( xshmimg == 0 )
	    return 0;
	XSync(dpy, false);
        if ( xshmpm ) {
	    XFreePixmap( dpy, xshmpm );
	    xshmpm = 0;
        }
        XShmDetach( dpy, &xshminfo ); xshmimg->data = 0;
        qSafeXDestroyImage( xshmimg ); xshmimg = 0;
	shmdt( xshminfo.shmaddr );
        shmctl( xshminfo.shmid, IPC_RMID, 0 );
	XFreeGC(_dpy, gc);

	xshminfo.shmaddr=0;
	xshminfo.shmid=0;
    }
    int Resize(int& new_w, int& new_h)
    {
	if(new_w<0)return -1;
	if(new_h<0)return -1;
	new_w&=(~7);
	new_h&=(~7);
	int xratio=(new_w+m_w-1)/m_w;
	int yratio=(new_h+m_h-1)/m_h;
	int old_xratio=(pic_w+m_w-1)/m_w;
	int old_yratio=(pic_h+m_h-1)/m_h;
	cerr<<"New size: "<<new_w<<" "<<new_h<<endl;
	pic_w=new_w;
	pic_h=new_h;
	if((xratio!=old_xratio)||(yratio!=old_yratio))
	{
	    pthread_mutex_lock(&mutex);
	    Free();
	    Alloc();
	    pthread_mutex_unlock(&mutex);
	}
    }
    virtual int Draw(const CImage* data)
    {
        char* outpic=xshmimg->data;
	if(outpic==0)
	    return 0;
	if(data==0)
	    return 0;

	int bit_depth=GetPhysicalDepth(_dpy);

	if(pthread_mutex_trylock(&mutex)==EBUSY)
	    return -1;
//	pthread_mutex_lock(&mutex);

	sync();
	const char* src;

	if((pic_h==m_h)	&& (pic_w==m_w))
	    memcpy(outpic, data->data(), data->bytes());
	else
	    zoom((short*)outpic, (short*)data->data(), pic_w, pic_h, m_w, m_h, bit_depth, m_w*((pic_w+m_w-1)/m_w));

	XShmPutImage(_dpy, _vis, gc,
		xshmimg, 0, 0, xpos, 0, pic_w, pic_h, true);

	pthread_mutex_unlock(&mutex);

	return 0;
    }
    virtual int sync()
    {
        XSync(_dpy, false);
	return 0;
    }
    virtual ~ShmRenderer()
    {
	Free();
	pthread_mutex_destroy(&mutex);
    }
    virtual int toggle_fullscreen(bool=false);
    virtual int drawSubtitles(const char*);

};
int ShmRenderer::ToggleFullscreen(bool maximize=false)
{
    return 0;
}

int ShmRenderer::DrawSubtitles(const char* sub)
{
    return 0;
}


VideoRenderer* CreateRenderer()
{
    return new ShmRenderer;
}
*/
 /*FOLD00*/

#if 0
 /*FOLD00*/
#ifdef	HAVE_LIBXV
class XvYUVRenderer : public VideoRendererWithLock
{
    Display* dpy;
    Window win;
#ifdef I18N
    XFontSet font;
#else
    XFontStruct* font;
#endif
    int	screen;
    XShmSegmentInfo xshminfo[2];
    XvImage* xvimage[2];
    uint_t xv_format;
    uint_t xv_port;
    const char* title;
    GC gc;
    Pixmap xshmpm;
    XSizeHints hint;
    XVisualInfo vinfo;
    XEvent xev;
    XWindowAttributes attribs;

public:
    XvYUVRenderer(PlayerWidget* pw, Display* _dpy,
		  int width, int height, unsigned long format, bool subtitle = false)
	: VideoRendererWithLock(width, height, subtitle),
	dpy(_dpy), font(0), xv_format(0), xv_port(0), xshmpm(0)
    {
	//g_pw=pw;

	cout << XInitThreads() << endl;

	title = "Xv rulez";
	screen = DefaultScreen(dpy);

	hint.x = 0;
	hint.y = 0;
	hint.width = m_w;
	hint.height = m_h;
	hint.flags = /*PPosition | */PSize;

	XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attribs);
	int depth = GetPhysicalDepth(dpy);

	XMatchVisualInfo(dpy, screen, depth, TrueColor, &vinfo);
	Colormap cmap = XCreateColormap(dpy, RootWindow(dpy, screen),
					vinfo.visual, AllocNone);
	XSetWindowAttributes xswa;
	unsigned long xswamask;

	xswa.background_pixel = 0;
	xswa.border_pixel     = 1;
	xswa.colormap         = cmap;
	xswamask = CWBackPixel | CWBorderPixel |CWColormap;

	XLockDisplay(dpy);
	win = XCreateWindow(dpy, RootWindow(dpy, screen),
			    hint.x, hint.y, hint.width, hint.height, 4,
			    depth, CopyFromParent, vinfo.visual, xswamask, &xswa);

	XSelectInput(dpy, win, StructureNotifyMask);
	XSetStandardProperties(dpy, win, title, title, None, NULL, 0, &hint);

	//if ( fullscreen ) vo_x11_decoration( mydisplay,mywindow,0 );

	/* Map window. */
	XMapWindow(dpy, win);

	/* Wait for map. */
	do
	{
	    XNextEvent(dpy, &xev);
	    //cout << "T: " << xev.xany.type << " w: " << xev.xany.window << endl;

	}
	while (xev.type != MapNotify || xev.xmap.event != win);

	XSelectInput(dpy, win, NoEventMask);

	XFlush(dpy);
	XSync(dpy, False);


	uint_t ver,rel,req,ev,err;
	if (Success != XvQueryExtension(dpy, &ver,&rel,&req,&ev,&err))
	    throw FATAL("Xv: XvQueryExtension failed");

	/* check for Xvideo support */
	uint_t adaptors;
	XvAdaptorInfo *ai;
	if (Success != XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &adaptors,&ai))
	    throw FATAL("Xv: XvQueryAdaptors failed");

	/* check adaptors */
	for (unsigned i = 0; i < adaptors; i++)
	{
	    if (!xv_port && (ai[i].type & XvInputMask) && (ai[i].type & XvImageMask))
		xv_port = ai[i].base_id;
	}

	XvFreeAdaptorInfo(ai);

	/* check image formats */
	if (!xv_port)
	    throw FATAL("Xv: XvQueryAdaptors no port");

	uint_t formats;
	XvImageFormatValues* fo = XvListImageFormats(dpy, xv_port, (int*)&formats);
	for(unsigned i = 0; i < formats; i++)
	{
	    fprintf(stderr, "Xvideo image format: 0x%x (%4.4s) %s\n", fo[i].id,
		    (char*)&fo[i].id, (fo[i].format == XvPacked) ? "packed" : "planar");

	    if (fo[i].id == (signed) format)
		xv_format = fo[i].id;
	}
	if (!xv_format) /* no matching image format not */
	    throw FATAL("Xv: XvQueryAdaptors no port");

	fprintf(stderr,"using Xvideo port %d for hw scaling\n", xv_port);

	//allocate_xvimage(0);
	/* catch window resizes */
	XSelectInput(dpy, win,
		     EnterWindowMask | LeaveWindowMask
		     | PointerMotionMask
		     | StructureNotifyMask | KeyPressMask);
	//XSelectInput(mydisplay, mywindow, StructureNotifyMask);

	// resize:
	XMoveResizeWindow(dpy, win, 0, 0, m_w, m_h);
	XUnlockDisplay(dpy);
	Alloc();
    }

    virtual ~XvYUVRenderer()
    {
	cout <<"XvYUV: Destroy" << endl;
	Lock();
	Free();
    }

    void Alloc()
    {
	printf("Creating Xv renderer, width %d, height %d\n", pic_w, pic_h);
	printf("Server vendor %s, release %d\n",
	       ServerVendor(dpy), VendorRelease(dpy));
	try
	{
	    bool ok = true;
	    int width=((pic_w+m_w-1)/m_w)*m_w;
	    int height=((pic_h+m_h-1)/m_h)*m_h;
	    if (! ok)
		throw FATAL("XShmAttach failed");

	    XGCValues xgcv;
	    xgcv.graphics_exposures = false;
	    XLockDisplay(dpy);
	    gc = XCreateGC(dpy, win, 0L, &xgcv);
	    //int dd = DefaultDepth(dpy, DefaultScreen(dpy));
	    xvimage[0] = XvShmCreateImage(dpy, xv_port, xv_format, 0,
					  width, height, &xshminfo[0]);

	    if (! xvimage[0])
		throw FATAL("Can't create shared image");

	    xshminfo[0].shmid    = shmget(IPC_PRIVATE, xvimage[0]->data_size, IPC_CREAT | 0777);
	    xshminfo[0].shmaddr  = (char *) shmat(xshminfo[0].shmid, 0, 0);
	    xshminfo[0].readOnly = False;

	    xvimage[0]->data = xshminfo[0].shmaddr;
	    XShmAttach(dpy, &xshminfo[0]);
	    XSync(dpy, False);
	    XUnlockDisplay(dpy);
	    shmctl(xshminfo[0].shmid, IPC_RMID, 0);

	    /* so we can do grayscale while testing... */
	    memset(xvimage[0]->data, 128, xvimage[0]->data_size);

	    //printf("Video device: %d bpp ( physical %d ), color masks %lX,%lX,%lX\n",
	    //       dd, GetPhysicalDepth(dpy),
	    //       vis->red_mask, vis->green_mask, vis->blue_mask);
	    //Alloc();
	} catch(...)
	{
	    throw;
	}
    }

    int Free()
    {
	//cout <<"XvYUV: Free()" << endl;

	if (xvimage[0] == 0)
	    return 0;
	XLockDisplay(dpy);
	XFreeGC(dpy, gc);
	XSync(dpy, False);
	XShmDetach(dpy, &xshminfo[0]);
        XUnlockDisplay(dpy);

	XFree(xvimage[0]);
	xvimage[0] = 0;
	shmdt( xshminfo[0].shmaddr );
	shmctl( xshminfo[0].shmid, IPC_RMID, 0 );
        return 0;
    }

    int Resize(int& new_w, int& new_h)
    {
	if (new_w < 0 || new_h < 0)
	    return -1;

	new_w&=(~7);
	new_h&=(~7);
	int xratio=(new_w+m_w-1)/m_w;
	int yratio=(new_h+m_h-1)/m_h;
	int old_xratio=(pic_w+m_w-1)/m_w;
	int old_yratio=(pic_h+m_h-1)/m_h;
	cerr<<"New size: "<<new_w<<" "<<new_h<<endl;
	pic_w=new_w;
	pic_h=new_h;
	if (xratio != old_xratio || yratio != old_yratio)
	{
	    Lock();
	    Free();
	    Alloc();
	    Unlock();
	}
        return 0;
    }

    virtual int Draw(const CImage* data)
    {
	char* outpic = xvimage[0]->data;

	if (outpic==0 || data==0)
	    return 0;

	//int bit_depth=GetPhysicalDepth(dpy);
	if (TryLock()==EBUSY)
	    return -1;

	memcpy(outpic, data->Data(), data->Bytes());
	//cout << "b " << data->bytes();
	XLockDisplay(dpy);
	XvShmPutImage(dpy, xv_port, win, gc, xvimage[0],
		      0, 0, m_w, m_h, 0, 0, pic_w, pic_h, True);
	XFlush(dpy);
        XUnlockDisplay(dpy);

	Unlock();
	return 0;

	int ret=0;
	XEvent         xevent;
	char           buf[100];
	KeySym         keySym;
	XComposeStatus cstat;

	///XNextEvent( dpy, &xevent );
	cout << "T: " << xevent.xany.type << " w: " << xevent.xany.window << endl;
	//cout << XPending( dpy ) << endl;
	//while ( NonblockXPending( dpy ) )
	while ( XPending( dpy ) )
	{
            cout << "event " << endl;
	    XNextEvent( dpy, &xevent );
	    switch( xevent.type )
	    {
	    case EnterNotify:
		cout << "Enter" << endl;
                break;
	    case LeaveNotify:
		cout << "Enter" << endl;
                break;
	    case Expose:
		//ret|=VO_EVENT_EXPOSE;
		break;
	    case ConfigureNotify:
		{
		int width=xevent.xconfigure.width;
		int height=xevent.xconfigure.height;
		//ret|=VO_EVENT_RESIZE;
		cout << "Resize " << width << "  " << height << endl;
		}
		break;
	    case KeyPress:
		XLookupString( &xevent.xkey,buf,sizeof(buf),&keySym,&cstat );
		//vo_x11_putkey( ( (keySym&0xff00) != 0?( (keySym&0x00ff) + 256 ):( keySym ) ) );
		//ret|=VO_EVENT_KEYPRESS;
		break;
	    }
	}

	return 0;
    }
    virtual int Sync()
    {
	//XFlush(dpy);
	return 0;
    }
    virtual int ToggleFullscreen(bool=false)
    {
        return 0;
    }
    virtual int DrawSubtitles(const char*)
    {
	return 0;
    }
    int Refresh()
    {
        return 0;
    }
};

VideoRenderer* CreateXvYUVRenderer(PlayerWidget* pw, Display* dpy,
				   int width, int height,
				   fourcc_t yuv_fmt, bool sub)
{
    return new XvYUVRenderer(pw, dpy, width, height, yuv_fmt, sub);
}

#endif	/* HAVE_LIBXV */
 /*FOLD00*/

#endif
/*
#ifdef USE_OPENGL
struct texts {
    int w;
    int h;
    int u_w;
    int u_h;
    GLuint *texture;
    int quad_1;
    int quad_2;
    int quad_3;
    int quad_4;
    };

class GLFullscreenRenderer: public VideoRenderer
{

    SDL_Surface *screen;
    int dim_w, dim_h;
    int fs;
    int m_sub;
    int zoom_divider;
    int dirty;
    Window wnd;
    pthread_mutex_t mutex;
    struct texts *textures;
    GLuint *textureids;
    GLubyte* pixels;
    int textcount_w;
    int textcount_h;
    int max_texture_size;
public:
    GLFullscreenRenderer():screen(0){}


    virtual int Create(QWidget* w, int width, int height, int xpos=0, int subtitles=0)
    {
    fs=SDL_RESIZABLE | SDL_OPENGL;

    char SDL_windowhack[256];
       dev=w;
       Display *dpy = dev->x11Display();
       ::dpy=dpy;
       unsigned long mask;

  int glxMajorVersion, glxMinorVersion;


  if(SDL_Init(SDL_INIT_VIDEO ) <0)
           throw FATAL("Failed to init SDL");
    m_w=width;

         m_h=height;
    width=1024;
    height=768;
    pic_w=width;
       pic_h=height;
       m_sub=subtitles;
       dirty=0;
       dim_w=pic_w;
       dim_h=pic_h+(subtitles?80:0);
       pthread_mutex_init(&mutex, 0);
//  screen = SDL_SetVideoMode(1024, 768, 0, SDL_OPENGL);    | SDL_INIT_EVENTTHREAD
        screen=SDL_SetVideoMode(dim_w, dim_h, GetPhysicalDepth(dev), fs);
       if(screen )
       {
//         SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
//         SDL_SetEventFilter(EventFilter);
           valid_filter=1;
           SDL_WM_SetCaption("Movie window", 0);

           SDL_SysWMinfo info;

           SDL_VERSION(&info.version);
           SDL_GetWMInfo(&info);
           Display *dpy=dev->x11Display();

      GLint maxsize=0;
      GLboolean b= false;
        SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
      glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
      cerr<<"Texturemaxsize="<<max_texture_size<<endl;
      glGetIntegerv(GL_RED_BITS, &maxsize);
      cerr<<"RED BITS="<<maxsize<<endl;
      glGetIntegerv(GL_BLUE_BITS, &maxsize);
      cerr<<"BLUE BITS="<<maxsize<<endl;
      glGetIntegerv(GL_GREEN_BITS, &maxsize);
      cerr<<"GREEN BITS="<<maxsize<<endl;
      glGetIntegerv(GL_ALPHA_BITS, &maxsize);
      cerr<<"ALPHA BITS="<<maxsize<<endl;
      glGetIntegerv(GL_MAX_TEXTURE_STACK_DEPTH, &maxsize);
      cerr<<"MAX_TEXTURE_STACK_DEPTH="<<maxsize<<endl;
      glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxsize);
      cerr<<"MAX_TEXTURE_UNITS="<<maxsize<<endl;
      glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &maxsize);
      cerr<<"MAX_VIEWPORT_DIMS="<<maxsize<<endl;
      glGetBooleanv(GL_DOUBLEBUFFER, &b);
      if (b)
        cerr<<"DOUBLBUFFER IS OK"<<endl;
      else
        cerr<<"NO DOUBELBUFFER"<<endl;
      glGetBooleanv(GL_RGBA_MODE, &b);
      if (b)
        cerr<<"RGBA IS TRUE"<<endl;
      else
        cerr<<"RGBA IS FALSE"<<endl;
      glXQueryVersion(::dpy, &glxMajorVersion, &glxMinorVersion);
        cerr<<"glX-Version "<<glxMajorVersion<<"."<<glxMinorVersion<<endl;
      if (glXIsDirect(::dpy, glXGetCurrentContext()))
        cerr<<"Congrats, you have Direct Rendering!"<<endl;
      else {
        cerr<<"Sorry, no Direct Rendering possible!"<<endl;
        screen = false;
        }

        glEnable( GL_TEXTURE_2D );
        glViewport(0,0,pic_w, pic_h);
        if (createTextures()>0) {
          cerr<<"Fatal Error : can't create Textures"<<endl;
          screen=false;
        }
        else {
          gluOrtho2D(0, m_w, m_h, 0);
           int error = glGetError( );
          if (error)
                cerr<<"Initerror :"<<error<<endl;

//          glShadeModel(GL_SMOOTH);                   // Enables Smooth Color Shading


          glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
          glEnable( GL_TEXTURE_2D );
          if (error)
                cerr<<"Initerror :"<<error<<endl;
        }

           return 0;
       }
       if(!screen)
           throw FATAL("Failed to set up video mode");
       throw FATAL("Failed to set up fullscreen mode");

    }

    GLenum createTextures()
    {

      int skip_w=0;
      int skip_h=0;
      textcount_w=0;
      textcount_h=0;
      // This look how many textures we need in width
      while(skip_w<(m_w-8)) {
        skip_w += getPowerOf2(m_w-skip_w);
        textcount_w++;
      }
      // This look how many textures we need in height
      while(skip_h<(m_h-8)) {
        skip_h += getPowerOf2(m_h-skip_h);
        textcount_h++;
      }
      // A Backround will be set, if not the texture will not shown later
      pixels = (GLubyte*) malloc( m_w * m_h * 4);
           memset( pixels, 128, m_w * m_h * 4 );
      if (!pixels) {
        return GL_OUT_OF_MEMORY;
      }

      textures = new texts[textcount_w * textcount_h];       // Here we stores all informatio n
of the textures
      textureids = new GLuint[textcount_w * textcount_h];    // The Textureids so we can
 create all textures at once
      glGenTextures( textcount_w * textcount_h, textureids); // And here their will created
      skip_h=0;                                              // Stores the Rows to skip
      int i=0;                                               // only needed for pointerarithmetic
      for(int h=0; h<textcount_h;h++) {
        skip_w=0;                                            // the pixels in row to skip
        int text_size_h = getPowerOf2(m_h-skip_h);
        for(int w=0; w<textcount_w;w++) {
            int text_size_w = getPowerOf2(m_w-skip_w);
            (textures+i)->w = text_size_w;                   // width and height of texture
            (textures+i)->h = text_size_h;
            cerr<<"Texturesize("<<i<<") :"<<text_size_w<<"; "<<text_size_h<<endl;
            (textures+i)->u_w = skip_w;                      // Pixels zu skip in row
            (textures+i)->u_h = skip_h;                      // Rows to skip
            (textures+i)->texture = (textureids+i);
            (textures+i)->quad_1 = skip_w;                   // is the vortex of the texture,
 so we can
            (textures+i)->quad_2 = skip_h;                   // draw faster (later)
            (textures+i)->quad_3 = (textures+i)->quad_1 + (textures+i)->w;
            (textures+i)->quad_4 = (textures+i)->quad_2 + (textures+i)->h;
            skip_w +=text_size_w;

            glBindTexture( GL_TEXTURE_2D, (GLuint) (textures+i)->texture);

            glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
//GL_DECAL

            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

            glTexImage2D( GL_TEXTURE_2D,  0,  GL_RGB, (textures+i)->w, (textures+i)->h, 0,
 GL_RGBA,  GL_UNSIGNED_BYTE, pixels );
            int error = glGetError( );
            if (error) return error;
            i++;
        }
        skip_h +=text_size_h;
      }

      // Simple state setup at the end.
      glClearColor( 0.0, 0.0, 0.0, 0.0 );

      return glGetError( );
    }

    int getPowerOf2(int value)
    {
        int i,e;
        for(i=1;((i<=value) && (i<=max_texture_size)) ; i*=2)
         e=i;
        return e;
    }

    int Resize(int& new_w, int& new_h)
    {
       if(new_w<0)return -1;
       if(new_h<0)return -1;
       if(new_h<m_h/4)
           return -1;
       if(new_w<m_w/4)
           return -1;
       pic_w=new_w;
       pic_h=new_h;
       dim_w=pic_w;
       dim_h=pic_h+(m_sub?fm_height*4:0);
       pthread_mutex_lock(&mutex);

  if(screen){ SDL_FreeSurface(screen); screen=0;}
       screen=SDL_SetVideoMode(dim_w, dim_h, 0, fs);
  if (screen)
    glViewport(0,0,pic_w, pic_h);


       pthread_mutex_unlock(&mutex);
    }






    virtual int Draw(const CImage* data)
    {
           if(!screen)return -1;
           if(pthread_mutex_trylock(&mutex)==EBUSY) return -1;
        // copy the picture and swap BGR to RGB
        memcpy(pixels, data->Data(), data->Bytes());
        for (int i=0;i<data->Bytes();i+=3)
        {
         GLubyte tmp;
          tmp = *(pixels+i);
          *(pixels+i)=* (pixels+i+2);
          *(pixels+i+2)=tmp;
        }
        // load picture in textures and draw them
        for(int i=0; i<(textcount_w*textcount_h); i++) {
           glBindTexture( GL_TEXTURE_2D, (GLuint)(textures+i)->texture);
           glPixelStorei( GL_UNPACK_SKIP_PIXELS, (textures+i)->u_w );
           glPixelStorei( GL_UNPACK_SKIP_ROWS, (textures+i)->u_h );
           glPixelStorei( GL_UNPACK_ROW_LENGTH, m_w );

           glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0,  (textures+i)->w, (textures+i)->h, GL_RGB,
 GL_UNSIGNED_BYTE, pixels );

           glBegin( GL_QUADS );
           glTexCoord2f( 0.0, 0.0 );
           glVertex2i((textures+i)->quad_1, (textures+i)->quad_2);
           glTexCoord2f( 0.0, 1.0 );
           glVertex2i( (textures+i)->quad_1, (textures+i)->quad_4);
           glTexCoord2f( 1.0, 1.0 );
           glVertex2i( (textures+i)->quad_3, (textures+i)->quad_4 );
           glTexCoord2f( 1.0, 0.0 );
           glVertex2i((textures+i)->quad_3, (textures+i)->quad_2 );
           glEnd( );
           int error = glGetError( );
           if (error)
                cerr<<"Drawerror :"<<error<<endl;
      }
      SDL_GL_SwapBuffers();
           pthread_mutex_unlock(&mutex);
      SDL_Event event;
      while(SDL_PollEvent(&event))
        EventFilter(&event);
           return 0;
    }

    virtual int sync()
    {
       if(dirty)
       {
           SDL_UpdateRect(screen, 0, 0, dim_w, dim_h-(m_sub?fm_height*4:0));
           dirty=0;
       }
       return 0;
    }
    virtual ~GLFullscreenRenderer()
    {
       pthread_mutex_lock(&mutex);

           free(pixels);
      SDL_SetEventFilter(0);
      SDL_QuitSubSystem(SDL_INIT_VIDEO);
      valid_filter=0;
      pthread_mutex_unlock(&mutex);
      pthread_mutex_destroy(&mutex);

    }
    virtual int toggle_fullscreen(bool maximize=false)
    {
       pthread_mutex_lock(&mutex);
       fs=fs^SDL_FULLSCREEN;
       if(screen){ SDL_FreeSurface(screen); screen=0;}
       screen=SDL_SetVideoMode(dim_w, dim_h, GetPhysicalDepth(dev), SDL_OPENGL | fs);
       if(!screen)
       {
           fs=fs^SDL_FULLSCREEN;
           screen=SDL_SetVideoMode(dim_w, dim_h, GetPhysicalDepth(dev), SDL_OPENGL |fs);
       }
  else
      glViewport(0, 0, pic_w, pic_h);

       if(fs&SDL_FULLSCREEN)
       {
               SDL_ShowCursor(0);
       }
       else
       {
               SDL_ShowCursor(1);
       }

#ifdef HAVE_LIBXXF86VM
       if(maximize && (fs&SDL_FULLSCREEN))
       {
           XF86VidModeModeLine mode;
           int unused;
           int w, h;
           double ratio_x, ratio_y;
           if ( XF86VidModeGetModeLine(dev->x11Display(), dev->x11Screen(), &unused, &mode) )
           {
               w = mode.hdisplay;
               h = mode.vdisplay-(m_sub?fm_height*4:0);
               ratio_x=double(w)/pic_w;
               ratio_y=double(h)/pic_h;
               double ratio=(ratio_x<ratio_y)?ratio_x:ratio_y;
               w=int(ratio*pic_w);
               h=int(ratio*pic_h);
               cerr<<mode.hdisplay<<" "<<mode.vdisplay<<" "<<w<<" "<<h<<endl;
               pthread_mutex_unlock(&mutex);
               Resize(w, h);

               return ((fs&SDL_FULLSCREEN)==0)?0:1;
           }
        }
#endif
       pthread_mutex_unlock(&mutex);


       return ((fs&SDL_FULLSCREEN)==0)?0:1;

    }
    virtual int drawSubtitles(const char* text)
    {
       static char* old_text=0;
       if(!m_sub)return 0;
       if(!text)return 0;
       if((!old_text) && (!text[0]))return 0;

       SDL_SysWMinfo info;
       XGCValues gcv;

       SDL_VERSION(&info.version);
       SDL_GetWMInfo(&info);
       Window win;
       if(fs & SDL_FULLSCREEN)
           win=info.info.x11.fswindow;
       else
           win=info.info.x11.window;
       Display *dpy=dev->x11Display();
       gcv.graphics_exposures = False;
       win=info.info.x11.window;

       if(old_text && (!strcmp(text, old_text)))
           return 0;

       QFont font=RegAccess::ReadFont();
       GC gc=XCreateGC(dpy, win, GCGraphicsExposures, &gcv);
#ifndef I18N
       XSetFont(dpy, gc, font.handle());
#endif
       XSetForeground(dpy, gc, 0x0);
       if(old_text && strcmp(text, old_text))
           XFillRectangle(dpy, win, gc, 0, dim_h-80, dim_w, 80);
       XSetForeground(dpy, gc, 0xFFFFFFFF);
       if(old_text)delete old_text;
       old_text=new char[strlen(text)+1];
       strcpy(old_text, text);
       char* sub=new char[strlen(text)+1];
       char* sub_orig=sub;
       strcpy(sub, text);
       char* run=sub;
       int line=0;
       while(*run!=0)
       {
           run=strchr(run, '|');
           if(run)*run=0;
//         XDrawString16(dpy, win, gc,
//             dim_w/2-6*strlen(sub)/2, dim_h-65+20*line,
//                 (XChar2b*)(short*)QString::fromLocal8Bit(sub).unicode(), strlen(sub));
           XDrawString(dpy, win, gc,
               dim_w/2-6*strlen(sub)/2, dim_h-65+20*line,
                   sub, strlen(sub));
           if(run==0)break;
           line++;
           run++;
           sub=run;
       }
       delete sub_orig;
       XFreeGC(dpy, gc);
       return 0;
    }
};

VideoRenderer* CreateGLFullscreenRenderer()
{
    return new GLFullscreenRenderer;
}
#endif //USE_OPENGL
*/
#ifdef HAVE_LIBXXF86DGA
#ifdef HAVE_LIBXXF86VM
/********************************************************

	DGA video renderer
	Copyright 2000 Heinrich Langos

*********************************************************/
/*
#define INT32 __my_int32
#define INT8 __my_int8
// damn qglobal.h defines INT32 and INT8 without saying anything about signs
// thanx to roots__ from #c for helping me out with this.

//#include "mmx_dga.cpp"
#include <X11/Xproto.h>
#include <X11/Xmd.h>
#include <X11/extensions/xf86dga.h>
#include <X11/extensions/xf86dgastr.h>

#define VIDMODE_SWITCHING_DELAY 100

#include <X11/extensions/xf86vmode.h>
#include <X11/extensions/xf86vmstr.h>

class DGARenderer: public VideoRenderer
  // vm_* videomode variables
  // vp_* vievport variables
{
  Display *dpy;
  int ppl;    //pixel per line (scan line, not frame line !! )
  char* base; //frame buffer base address

  int zoom_divider;


  int  vm_count;  //number of available videomodes
  XF86VidModeModeInfo **vm_modelines;  // the modes themself
  bool vm_switched; //only used to decide if we have to switch back on quit

  int vp_width,vp_height;  // the viewport size
  int vp_flip_offset;      // memory offset to the next frame in framebuffer
  int vp_current;          // currently used viewport (0..vp_frames-1)
  const static int vp_frames=2; // the number of viewports that we use.
  int bit_depth,byte_depth;  //self explaining ...
  char *conversionbuf;  // only used if we dont render directly into the framebuffer


  void set_vidmode(int nr)
  {
    printf("switching video mode to %dx%d/%d now\n",
	   vm_modelines[nr]->hdisplay,
	   vm_modelines[nr]->vdisplay,
	   vm_modelines[nr]->dotclock);

//    XF86VidModeSwitchToMode(dpy,XDefaultScreen(dpy),vm_modelines[nr]);
    avm_usleep(VIDMODE_SWITCHING_DELAY*1000);
  }

public:
  DGARenderer()
  {}
  int toggle_fullscreen()
  {}
  virtual int Create(QWidget* w, int x, int y, int zoom=1, int xpos=0, int sub=0)
  {
    zoom_divider=zoom;
    if(zoom!=1 && zoom!=2)throw FATAL("Unsupported zoom factor");
    vp_current=0;
    dev=(QPaintDevice*)w;
    dpy = dev->x11Display();
    m_w=x;
    m_h=y;
    width=x;
    height=y;
    Visual  *vis = (Visual*)dev->x11Visual();
    bool have_dga=false;
    int minor, major, bank, ram, flags;



    int i,bestmatch, diff_x=99999, diff_y=99999;
    XF86VidModeGetAllModeLines(dpy,XDefaultScreen(dpy),
			       &vm_count,&vm_modelines);
    for (i = 0; i < vm_count; i++) {
      if ((width/zoom_divider  <= vm_modelines[i]->hdisplay) &&
	  (height/zoom_divider <= vm_modelines[i]->vdisplay))
	if  ( ( (vm_modelines[i]->hdisplay - width/zoom_divider)  <= diff_x) &&
	      ( (vm_modelines[i]->vdisplay - height/zoom_divider) <= diff_y) ) {
	  bestmatch=i;
	  diff_x =vm_modelines[i]->hdisplay - width/zoom_divider ;
	  diff_y =vm_modelines[i]->vdisplay - height/zoom_divider ;
	}
    }
    i=bestmatch;
    if (i != 0 && i != vm_count) {
      set_vidmode(i);
      vm_switched = 1;
      vp_width = vm_modelines[i]->hdisplay;
      vp_height = vm_modelines[i]->vdisplay;
    } else {
      vm_switched = 0;
      vp_width = vm_modelines[0]->hdisplay;
      vp_height = vm_modelines[0]->vdisplay;
    }
//    XWarpPointer(dpy, None, RootWindow(dpy, DefaultScreen(dpy)),
//		 0, 0, 0, 0, 0,0);
    XF86VidModeSetViewPort(dpy,XDefaultScreen(dpy),0,0);
    if(XF86DGAQueryExtension(dpy, &major, &minor))
      {
	XF86DGAQueryDirectVideo(dpy, XDefaultScreen(dpy), &flags);
	if(flags & XF86DGADirectPresent)
	  {
	    have_dga=true;
	    XF86DGAGetVideo(dpy, DefaultScreen(dpy),  &base, &ppl, &bank, &ram);
	    if(!base)
	      return -1;

	    // This is quoted from xmms-1.0.1 dga.c
  	    // The things we must go through to get a proper depth...
	    //   If I find the idiot that thought making 32bit report 24bit
	    //   was a good idea, there may be one less `programmer' in this
	    //   world...
	    {
	      XImage *img;

	      img = XGetImage(dpy, RootWindow(dpy, DefaultScreen(dpy)),
			      0, 0, 1, 1, AllPlanes, ZPixmap);
	      bit_depth = img->bits_per_pixel;
	      XDestroyImage(img);
	    }
	    byte_depth = (bit_depth+7)/8;
	    // end quote :-)
	    XF86DGAGetViewPortSize(dpy, DefaultScreen(dpy), &vp_width, &vp_height);
	  }

      }

    if(have_dga) {


      //      printf("DGA: base:%x , ppl:%d, bank:%d, ram:%d \n",base, ppl, bank, ram );
      //      flip_offset=ppl*vp_height*byte_depth;

      vp_flip_offset=vp_height*ppl*byte_depth;
      XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectGraphics);

      //			     XF86DGADirectMouse|
      //			     XF86DGADirectKeyb);

      XF86DGASetViewPort(dpy, DefaultScreen(dpy), 0, 0);

      //
h}%@h}% zero=0;
        for (int v=0;v<vp_flip_offset*vp_frames; v+=4)
      	  memcpy((void*)(base+v), &zero, 4);

      return 0;
    }else {
//      conversionbuf=(char *)malloc(x*y*byte_depth);
//      if (!conversionbuf)
//	return -1;
    }
  }

  virtual int Draw(const CImage* data)
  {
    //    printf("Drawing %d lines to base %x ppl: %d width: %d \n",height,base,ppl, width);
    bit_depth++;
    bit_depth/=8;
    int bpl=::width*bit_depth;
//    conversionbuf+=bpl*(height-1);
    sync();
//    for(int y=::height-1; y>0; y--)
//    {
//        memcpy(conversionbuf, data, bpl);
//        data+=bpl;
//        conversionbuf-=bpl;
//    }
    for(int i=0; i<height; i++)
	memcpy((void*)(base+i*ppl*byte_depth), data->at(i), data->bpl());

    return 0;
  };
  virtual int sync()
  {
    Display *dpy = dev->x11Display();
    XSync(dpy, false);
    return 0;
  };
  virtual ~DGARenderer(){
    Display *dpy = dev->x11Display();
    if (vm_switched)
       set_vidmode(0);
    XF86DGASetViewPort(dpy, DefaultScreen(dpy), 0, 0);
    XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
//    free(conversionbuf);
  }
     virtual int drawSubtitles(const char*)
     {
        return 0;
     }
};

VideoRenderer* CreateDGARenderer()
{
h}%@h}%@rn new DGARenderer;
}
*/
#endif	/*HAVE_LIBXXF86VM*/
#endif  /*HAVE_LIBXXF86DGA*/
#endif  /*X_DISPLAY_MISSING*/
/*
vim: tabstop=8
*/

#endif  // do not compile
