// add these prototypes to DXSmithIO.h, in the public graphics section.
// right after Blit() is a good spot.

    int Pixel(int x, int y, DWORD color, HDC hdc=NULL);
    int HorzLine(int x, int y, int len, DWORD colour, HDC hdc=NULL);
    int VertLine(int x, int y, int len, DWORD colour, HDC hdc=NULL);
    int RectFillv(int x, int y, int width, int height, DWORD colour, HDC hdc=NULL);
    int CgsdxIO::Linev(int x0, int y0, int x1, int y1, DWORD colour, HDC hdc=NULL);

// add these functions to DXSmithIO.cpp at the end
// some of these do NOT have GDI enabled.
// NONE of them have been tested under GDI, only fullscreen mode

int CgsdxIO::Pixel(int x, int y, DWORD colour, HDC hdc)
{
    HWND hwnd;
    HDC lhdc;
    HPEN pen, oldPen;
    HRESULT hr;
    int err=0;
    long offset;
    DDSURFACEDESC2 surface;
    int pixelWidth;

    //TRACE("[Pixel] at %d %d\n", x, y);
    if ( m_graphicsMode & GSDX_FULL_SCREEN )
        {
        //TRACE("[Pixel] fullscreen\n");
        surface.dwSize=sizeof(surface);
        hr=m_backSurface->Lock(NULL, &surface, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
        // not even TRACE will work when locked!
        if ( hr != DD_OK )
            {
		    TRACE("[Pixel] lock failed %d 0x%x\n", hr, hr);
            err=m_lastErrorCode=GSDX_ERROR_LOCKFAILED;
            m_lastErrorStr="[Pixel] Lock Failed";
#if _DEBUG
            DDError(hr);
#endif
            }
        else
            {
            pixelWidth=surface.ddpfPixelFormat.dwRGBBitCount/8;
            offset=x*pixelWidth + y*surface.lPitch;
            memcpy(((BYTE *)surface.lpSurface)+offset, &colour, pixelWidth);
            m_backSurface->Unlock(NULL);
//TRACE("[Pixel] pixelWidth = %d\n", pixelWidth);
            }
        }
    else
        {
        if ( m_graphicsMode & GSDX_WINDOWED_GDI )
            {
            if ( hdc == NULL )
                {
                hwnd=GetHwndDX();
                lhdc=GetDC(hwnd);
                }
            else
                lhdc=hdc;

            // GDI, draw pixel
            if ( (pen=CreatePen(PS_SOLID, 1, colour)) )
                {
                oldPen=(HPEN )SelectObject(lhdc, pen);
                MoveToEx(lhdc, x, y, NULL);
                LineTo(lhdc, x+1, y+1);
                SelectObject(lhdc, oldPen);
                DeleteObject(pen);
                }
            else
                {
                err=m_lastErrorCode=GSDX_ERROR_CREATEPENFAILED;
                TRACE("[Line] CreatePen failed\n");
                m_lastErrorStr="[Line] createpen failed";
                }

            if ( hdc == NULL )
                ReleaseDC(hwnd, lhdc);
            }
        else
            {
		    TRACE("[Pixel] invalid mode\n");
            err=m_lastErrorCode=GSDX_ERROR_INVALIDMODE;
            m_lastErrorStr="[Pixel] invalid mode";
            }
        }

    return err;
}

int CgsdxIO::Linev(int x0, int y0, int x1, int y1, DWORD colour, HDC hdc)
{
	int  inc1, inc2, i;
	int cnt, y_adj, dy, dx, x_adj;
	unsigned char far *p;
//    HWND hwnd;
//    HDC lhdc;
//    HPEN pen, oldPen;
    HRESULT hr;
    int err=0;
    DDSURFACEDESC2 surface;
    int pixelWidth;

    TRACE("[Linev] at %d %d\n", x0, y0);
    if ( m_graphicsMode & GSDX_FULL_SCREEN )
        {
        TRACE("[Linev] fullscreen\n");
        surface.dwSize=sizeof(surface);
        hr=m_backSurface->Lock(NULL, &surface, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
        // not even TRACE will work when locked!
        if ( hr != DD_OK )
            {
		    TRACE("[Linev] lock failed %d 0x%x\n", hr, hr);
            err=m_lastErrorCode=GSDX_ERROR_LOCKFAILED;
            m_lastErrorStr="[Linev] Lock Failed";
#if _DEBUG
            DDError(hr);
#endif
            }
        else
            {
            pixelWidth=surface.ddpfPixelFormat.dwRGBBitCount/8;
	        if ( x0 == x1 )
		        {
		        // vertical line
		        if ( y0 > y1 )
			        {
			        i=y0;
			        y0=y1;
			        y1=i;
			        }

		        p=(BYTE *)surface.lpSurface + y0*surface.lPitch + x0*pixelWidth;
		        i=y1 - y0 + 1;
		        while ( i-- )
			        {
			        memcpy(p, &colour, pixelWidth);
			        p+=surface.lPitch;
			        }
		        }
	        else
		        {
		        if ( y0 == y1 )
			        {
			        // horizontal line
			        if ( x0 > x1 )
				        {
				        i=x0;
				        x0=x1;
				        x1=i;
				        }
			        p=(BYTE *)surface.lpSurface + y0*surface.lPitch + x0;
			        i=x1 - x0 + 1;
                    while ( i-- )
                        {
                        memcpy(p, &colour, pixelWidth);
                        p+=pixelWidth;
                        }
			        }
		        else
			        {
			        // general line --------------------------------------
			        dy=y1 - y0; 
			        dx=x1 - x0; 
			        // is it a shallow, or steep line?
			        if ( abs(dy) < abs(dx) )
				        {
				        // lo slope, shallow line
				        // we always want to draw from left to right
				        if ( x0 > x1 )
					        {
					        // swap x's, and y's
					        i=x0;
					        x0=x1;
					        x1=i;
					        i=y0;
					        y0=y1;
					        y1=i;
					        }
				        dy=y1 - y0;  // dy is used to calculate the increments
				        dx=x1 - x0;  // dx is line length
				        if ( dy < 0 )
					        {
					        // going up the screen
					        dy=-dy;
					        y_adj=-surface.lPitch;
					        }
				        else
					        y_adj=surface.lPitch;	 // going down

				        // calulate the increments
				        inc1=dy<<1;
				        inc2=(dy - dx)<<1;
				        cnt=(dy<<1) - dx;

				        // set p to start pixel
				        p=(BYTE *)surface.lpSurface + y0*surface.lPitch + x0*pixelWidth;
				        dx++;
				        while ( dx-- )  // for the length of the line
					        {
					        memcpy(p, &colour, pixelWidth); // *p++=colour; 
                            p+=pixelWidth;
					        // set one pixel, move right one pixel

					        if ( cnt >= 0 ) // is it time to adjust y?
						        {
						        cnt+=inc2;
						        p+=y_adj;
						        }
					        else
						        cnt+=inc1;
					        }
				        }
			        else
				        {
				        // hi slope - like lo slope turned on its side
				        // always draw top to bottom
				        if ( y0 > y1 )
					        {
					        // swap x's, and y's
					        i=x0;
					        x0=x1;
					        x1=i;
					        i=y0;
					        y0=y1;
					        y1=i;
					        }

				        dy=y1 - y0;  // dy is line length
				        dx=x1 - x0;  // dx is used to calculate incr's

				        if ( dx < 0)
					        {
					        dx=-dx;
					        x_adj=-pixelWidth;  // moving left
					        }
				        else
					        x_adj=pixelWidth;   // moving right

				        inc1=dx<<1;
				        inc2=(dx - dy)<<1;
				        cnt=(dx<<1) - dy;

				        // set p to first pixel position
				        p=(BYTE *)surface.lpSurface + y0*surface.lPitch + x0*pixelWidth;
				        dy++;
				        while ( dy-- )  // for height of line
					        {
					        memcpy(p, &colour, pixelWidth); // *p=colour;   // set one pixel
					        p+=surface.lPitch;  // move down one pixel

					        if ( cnt >= 0 )  // is it time to move x?
						        {
						        cnt+=inc2;
						        p+=x_adj;
						        }
					        else
						        cnt+=inc1;
					        }
				        }

			        }
		        }

            m_backSurface->Unlock(NULL);
TRACE("[Linev] pixelWidth = %d\n", pixelWidth);
            }
        }
    else
        {
		TRACE("[Linev] invalid mode\n");
        err=m_lastErrorCode=GSDX_ERROR_INVALIDMODE;
        m_lastErrorStr="[Linev] invalid mode";
        }

    return err;

}

// just for testing
int CgsdxIO::RectFillv(int x, int y, int width, int height, DWORD colour, HDC hdc)
{
    HWND hwnd;
    HDC lhdc;
    HPEN pen, oldPen;
    HRESULT hr;
    int err=0, w;
    long offset;
    DDSURFACEDESC2 surface;
    int pixelWidth, adjust;

    TRACE("[RectFillv] at %d %d\n", x, y);
    if ( m_graphicsMode & GSDX_FULL_SCREEN )
        {
        TRACE("[RectFillv] fullscreen\n");
        surface.dwSize=sizeof(surface);
        hr=m_backSurface->Lock(NULL, &surface, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
        // not even TRACE will work when locked!
        if ( hr != DD_OK )
            {
		    TRACE("[RectFillv] lock failed %d 0x%x\n", hr, hr);
            err=m_lastErrorCode=GSDX_ERROR_LOCKFAILED;
            m_lastErrorStr="[RectFillv] Lock Failed";
#if _DEBUG
            DDError(hr);
#endif
            }
        else
            {
            pixelWidth=surface.ddpfPixelFormat.dwRGBBitCount/8;
            offset=x*pixelWidth + y*surface.lPitch;
            adjust=surface.lPitch - width*pixelWidth;
            w=width;
            while ( height-- )
                {
                while ( width-- )
                    {
                    memcpy(((BYTE *)surface.lpSurface)+offset, &colour, pixelWidth);
                    offset+=pixelWidth;
                    }
                offset+=adjust;
                width=w;
                }
            m_backSurface->Unlock(NULL);
TRACE("[RectFillv] pixelWidth = %d\n", pixelWidth);
            }
        }
    else
        {
        if ( m_graphicsMode & GSDX_WINDOWED_GDI )
            {
            if ( hdc == NULL )
                {
                hwnd=GetHwndDX();
                lhdc=GetDC(hwnd);
                }
            else
                lhdc=hdc;

            // GDI, draw pixel
            if ( (pen=CreatePen(PS_SOLID, 1, colour)) )
                {
                oldPen=(HPEN )SelectObject(lhdc, pen);
                MoveToEx(lhdc, x, y, NULL);
                LineTo(lhdc, x+width, y);
                SelectObject(lhdc, oldPen);
                DeleteObject(pen);
                }
            else
                {
                err=m_lastErrorCode=GSDX_ERROR_CREATEPENFAILED;
                TRACE("[Line] CreatePen failed\n");
                m_lastErrorStr="[Line] createpen failed";
                }

            if ( hdc == NULL )
                ReleaseDC(hwnd, lhdc);
            }
        else
            {
		    TRACE("[RectFillv] invalid mode\n");
            err=m_lastErrorCode=GSDX_ERROR_INVALIDMODE;
            m_lastErrorStr="[RectFillv] invalid mode";
            }
        }

    return err;
}


// just for testing
int CgsdxIO::HorzLine(int x, int y, int len, DWORD colour, HDC hdc)
{
    HWND hwnd;
    HDC lhdc;
    HPEN pen, oldPen;
    HRESULT hr;
    int err=0;
    long offset;
    DDSURFACEDESC2 surface;
    int pixelWidth;

    TRACE("[HorzLine] at %d %d\n", x, y);
    if ( m_graphicsMode & GSDX_FULL_SCREEN )
        {
        TRACE("[HorzLine] fullscreen\n");
        surface.dwSize=sizeof(surface);
        hr=m_backSurface->Lock(NULL, &surface, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
        // not even TRACE will work when locked!
        if ( hr != DD_OK )
            {
		    TRACE("[HorzLine] lock failed %d 0x%x\n", hr, hr);
            err=m_lastErrorCode=GSDX_ERROR_LOCKFAILED;
            m_lastErrorStr="[HorzLine] Lock Failed";
#if _DEBUG
            DDError(hr);
#endif
            }
        else
            {
            pixelWidth=surface.ddpfPixelFormat.dwRGBBitCount/8;
            offset=x*pixelWidth + y*surface.lPitch;
            while ( len-- )
                {
                memcpy(((BYTE *)surface.lpSurface)+offset, &colour, pixelWidth);
                offset+=pixelWidth;
                }
            m_backSurface->Unlock(NULL);
TRACE("[HorzLine] pixelWidth = %d\n", pixelWidth);
            }
        }
    else
        {
        if ( m_graphicsMode & GSDX_WINDOWED_GDI )
            {
            if ( hdc == NULL )
                {
                hwnd=GetHwndDX();
                lhdc=GetDC(hwnd);
                }
            else
                lhdc=hdc;

            // GDI, draw pixel
            if ( (pen=CreatePen(PS_SOLID, 1, colour)) )
                {
                oldPen=(HPEN )SelectObject(lhdc, pen);
                MoveToEx(lhdc, x, y, NULL);
                LineTo(lhdc, x+len, y);
                SelectObject(lhdc, oldPen);
                DeleteObject(pen);
                }
            else
                {
                err=m_lastErrorCode=GSDX_ERROR_CREATEPENFAILED;
                TRACE("[Line] CreatePen failed\n");
                m_lastErrorStr="[Line] createpen failed";
                }

            if ( hdc == NULL )
                ReleaseDC(hwnd, lhdc);
            }
        else
            {
		    TRACE("[HorzLine] invalid mode\n");
            err=m_lastErrorCode=GSDX_ERROR_INVALIDMODE;
            m_lastErrorStr="[HorzLine] invalid mode";
            }
        }

    return err;
}
// just for testing
int CgsdxIO::VertLine(int x, int y, int len, DWORD colour, HDC hdc)
{
    HWND hwnd;
    HDC lhdc;
    HPEN pen, oldPen;
    HRESULT hr;
    int err=0;
    long offset;
    DDSURFACEDESC2 surface;
    int pixelWidth;

    TRACE("[VertLine] at %d %d\n", x, y);
    if ( m_graphicsMode & GSDX_FULL_SCREEN )
        {
        TRACE("[VertLine] fullscreen\n");
        surface.dwSize=sizeof(surface);
        hr=m_backSurface->Lock(NULL, &surface, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
        // not even TRACE will work when locked!
        if ( hr != DD_OK )
            {
		    TRACE("[VertLine] lock failed %d 0x%x\n", hr, hr);
            err=m_lastErrorCode=GSDX_ERROR_LOCKFAILED;
            m_lastErrorStr="[VertLine] Lock Failed";
#if _DEBUG
            DDError(hr);
#endif
            }
        else
            {
            pixelWidth=surface.ddpfPixelFormat.dwRGBBitCount/8;
            offset=x*pixelWidth + y*surface.lPitch;
            while ( len-- )
                {
                memcpy(((BYTE *)surface.lpSurface)+offset, &colour, pixelWidth);
                offset+=surface.lPitch;
                }
            m_backSurface->Unlock(NULL);
TRACE("[VertLine] pixelWidth = %d\n", pixelWidth);
            }
        }
    else
        {
        if ( m_graphicsMode & GSDX_WINDOWED_GDI )
            {
            if ( hdc == NULL )
                {
                hwnd=GetHwndDX();
                lhdc=GetDC(hwnd);
                }
            else
                lhdc=hdc;

            // GDI, draw pixel
            if ( (pen=CreatePen(PS_SOLID, 1, colour)) )
                {
                oldPen=(HPEN )SelectObject(lhdc, pen);
                MoveToEx(lhdc, x, y, NULL);
                LineTo(lhdc, x, y+len);
                SelectObject(lhdc, oldPen);
                DeleteObject(pen);
                }
            else
                {
                err=m_lastErrorCode=GSDX_ERROR_CREATEPENFAILED;
                TRACE("[Line] CreatePen failed\n");
                m_lastErrorStr="[Line] createpen failed";
                }

            if ( hdc == NULL )
                ReleaseDC(hwnd, lhdc);
            }
        else
            {
		    TRACE("[VertLine] invalid mode\n");
            err=m_lastErrorCode=GSDX_ERROR_INVALIDMODE;
            m_lastErrorStr="[VertLine] invalid mode";
            }
        }

    return err;
}

