/*
    DIVE interface for K Video Accelerator
    Copyright (C) 2007 by KO Myung-Hun <komh@chollian.net>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    Changes :
        KO Myung-Hun <komh@chollian.net> 2007/02/07
            - Use kvaClearRect() instead of kvaClearWindow()
            - Changed kvaClearRect() called in kvaSetup()

        KO Myung-Hun <komh@chollian.net> 2007/02/25
            - Added diveQueryAttr() and diveSetAttr(), but they are dummies.
*/

#define INCL_WIN
#define INCL_GPI
#include <os2.h>

#include <mmioos2.h>
#include <fourcc.h>
#include <dive.h>

#include <stdlib.h>
#include <string.h>

#include "kva.h"
#include "kva_internal.h"
#include "kva_dive.h"

static HDIVE            m_hdive = NULLHANDLE;
static ULONG            m_ulBufferNumber = 0;
static SETUP_BLITTER    m_sb = { 0 };

static PFNWP        m_pfnwpOld = NULL;

static APIRET APIENTRY diveDone( VOID );
static APIRET APIENTRY diveLockBuffer( PPVOID ppBuffer, PULONG pulBPL );
static APIRET APIENTRY diveUnlockBuffer( VOID );
static APIRET APIENTRY diveSetup( PKVASETUP pkvas );
static APIRET APIENTRY diveCaps( PKVACAPS pkvac );
static APIRET APIENTRY diveQueryAttr( ULONG ulAttr, PULONG pulValue );
static APIRET APIENTRY diveSetAttr( ULONG ulAttr, PULONG pulValue );

static APIRET destSetup( VOID )
{
    HPS             hps;
    HRGN            hrgn;
    RGNRECT         rgnCtl;
    PRECTL          prcl = NULL;
    ULONG           rc = KVAE_NO_ERROR;

    hps = WinGetPS( g_hwndKVA );

    hrgn = GpiCreateRegion( hps, 0L, NULL );
    if( hrgn )
    {
        WinQueryVisibleRegion( g_hwndKVA, hrgn );

        rgnCtl.ircStart     = 1;
        rgnCtl.ulDirection  = RECTDIR_LFRT_TOPBOT;
        GpiQueryRegionRects( hps, hrgn, NULL, &rgnCtl, NULL );

        if( rgnCtl.crcReturned > 0 )
        {
           rgnCtl.crc = rgnCtl.crcReturned;
           prcl = malloc( sizeof( RECTL ) * rgnCtl.crcReturned );
        }

        /* Get the all ORed rectangles
        */
        if( prcl && GpiQueryRegionRects( hps, hrgn, NULL, &rgnCtl, prcl ))
        {
            SWP     swp;
            POINTL  ptl;
            RECTL   rclSrc, rclDst;

            WinQueryWindowPos( g_hwndKVA, &swp );

            ptl.x = swp.x;
            ptl.y = swp.y;

            WinMapWindowPoints( WinQueryWindow( g_hwndKVA, QW_PARENT ),
                                HWND_DESKTOP,
                                &ptl, 1 );

            rclSrc.xLeft = 0;
            rclSrc.yBottom = 0;
            rclSrc.xRight = rclSrc.xLeft + m_sb.ulSrcWidth;
            rclSrc.yTop = rclSrc.yBottom + m_sb.ulSrcHeight;

            kvaAdjustDstRect( g_hwndKVA, &rclSrc, &rclDst );

            // Tell DIVE about the new settings.

            m_sb.fccDstColorFormat = FOURCC_SCRN;
            m_sb.ulDstWidth        = rclDst.xRight - rclDst.xLeft;
            m_sb.ulDstHeight       = rclDst.yTop - rclDst.yBottom;
            m_sb.lDstPosX          = rclDst.xLeft - ptl.x;
            m_sb.lDstPosY          = rclDst.yBottom - ptl.y;
            m_sb.lScreenPosX       = ptl.x;
            m_sb.lScreenPosY       = ptl.y;
            m_sb.ulNumDstRects     = rgnCtl.crcReturned;
            m_sb.pVisDstRects      = prcl;

            rc = DiveSetupBlitter( m_hdive, &m_sb );

            free( prcl );
        }
        else
            rc = DiveSetupBlitter( m_hdive, 0 );

        GpiDestroyRegion( hps, hrgn );
    }

    WinReleasePS( hps );

    return rc;
}

static MRESULT EXPENTRY diveNewWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
{
    switch( msg )
    {
        case WM_ERASEBACKGROUND :
        {
            HPS     hpsFrame = ( HPS )mp1;
            PRECTL  prcl = ( PRECTL )mp2;

            GpiCreateLogColorTable( hpsFrame, 0, LCOLF_RGB, 0, 0, NULL );
            WinFillRect( hpsFrame, prcl, g_ulKeyColor);

            return FALSE;
        }

        case WM_VRNDISABLED :
            DiveSetupBlitter( m_hdive, 0 );

            return FALSE;

        case WM_VRNENABLED :
            destSetup();

            return FALSE;

        case WM_REALIZEPALETTE :
            DiveSetDestinationPalette ( m_hdive, 0, 0, 0 );

            return FALSE;
    }

    return m_pfnwpOld( hwnd, msg, mp1, mp2 );
}

APIRET APIENTRY diveInit( VOID )
{
    ULONG   rc;

    m_hdive = NULLHANDLE;
    m_ulBufferNumber = 0;
    memset( &m_sb, 0, sizeof( SETUP_BLITTER ));

    m_pfnwpOld = NULL;

    rc = DiveOpen( &m_hdive, FALSE, 0 );
    if( rc )
        return rc;

    m_pfnwpOld = WinSubclassWindow( g_hwndKVA, diveNewWindowProc );

    if( m_pfnwpOld )
    {
        g_pfnDone = diveDone;
        g_pfnLockBuffer = diveLockBuffer;
        g_pfnUnlockBuffer = diveUnlockBuffer;
        g_pfnSetup = diveSetup;
        g_pfnCaps = diveCaps;
        g_pfnQueryAttr = diveQueryAttr;
        g_pfnSetAttr = diveSetAttr;

        WinSetVisibleRegionNotify( g_hwndKVA, TRUE );
    }
    else
        DiveClose( m_hdive );

    return ( m_pfnwpOld ? KVAE_NO_ERROR : KVAE_CANNOT_SUBCLASS );
}

static APIRET APIENTRY diveDone( VOID )
{
    WinSetVisibleRegionNotify( g_hwndKVA, FALSE );

    WinSubclassWindow( g_hwndKVA, m_pfnwpOld );

    return DiveClose( m_hdive );
}

static APIRET APIENTRY diveLockBuffer( PPVOID ppBuffer, PULONG pulBPL )
{
    ULONG   ulScanLines;
    ULONG   rc;

    rc = DiveAllocImageBuffer( m_hdive, &m_ulBufferNumber, m_sb.fccSrcColorFormat,
                               m_sb.ulSrcWidth, m_sb.ulSrcHeight, 0, 0 );
    if( rc )
        return rc;

    rc = DiveBeginImageBufferAccess( m_hdive, m_ulBufferNumber, ( PBYTE * )ppBuffer, pulBPL, &ulScanLines );
    if( rc )
        DiveFreeImageBuffer( m_hdive, m_ulBufferNumber );

    return rc;
}

static APIRET APIENTRY diveUnlockBuffer( VOID )
{
    ULONG rc, rc1;

    rc = DiveEndImageBufferAccess( m_hdive, m_ulBufferNumber );
    if( rc )
        goto exit;

    rc = DiveBlitImage( m_hdive, m_ulBufferNumber, DIVE_BUFFER_SCREEN );
    if( rc == DIVE_ERR_BLITTER_NOT_SETUP ) // occur when entirely covered
        rc = DIVE_SUCCESS;
exit:
    rc1 = DiveFreeImageBuffer( m_hdive, m_ulBufferNumber );
    if( rc )
        rc1 = rc;

    return rc1;
}

static APIRET APIENTRY diveSetup( PKVASETUP pkvas )
{
    m_sb.ulStructLen       = sizeof( SETUP_BLITTER );
    m_sb.fccSrcColorFormat = pkvas->fccSrcColor;
    m_sb.ulSrcWidth        = pkvas->szlSrcSize.cx;
    m_sb.ulSrcHeight       = pkvas->szlSrcSize.cy;
    m_sb.ulSrcPosX         = 0;
    m_sb.ulSrcPosY         = 0;
    m_sb.fInvert           = pkvas->fInvert;
    m_sb.ulDitherType      = ( ULONG )pkvas->fDither;

    return destSetup();
}

#ifndef SHOW_CPAS

static APIRET APIENTRY diveCaps( PKVACAPS pkvac )
{
    FOURCC      fccFormats[ 100 ];
    DIVE_CAPS   diveCaps;
    ULONG       rc;

    diveCaps.ulStructLen = sizeof( DIVE_CAPS );
    diveCaps.pFormatData = fccFormats;
    diveCaps.ulFormatLength = sizeof( fccFormats );

    rc = DiveQueryCaps( &diveCaps, DIVE_BUFFER_SCREEN );
    if( rc )
        return rc;

    pkvac->ulMode = KVAM_DIVE;
    pkvac->ulDepth = diveCaps.ulDepth;
    pkvac->cxScreen = diveCaps.ulHorizontalResolution;
    pkvac->cyScreen = diveCaps.ulVerticalResolution;
    pkvac->fccScreen = diveCaps.fccColorEncoding;

    return KVAE_NO_ERROR;
}
#else
#include <stdio.h>

static APIRET APIENTRY diveCaps( PKVACAPS pkvac )
{
    FOURCC      fccFormats[ 100 ];
    DIVE_CAPS   diveCaps;
    int         i;

    diveCaps.ulStructLen = sizeof( DIVE_CAPS );
    diveCaps.pFormatData = fccFormats;
    diveCaps.ulFormatLength = sizeof( fccFormats );
    if( DiveQueryCaps( &diveCaps, DIVE_BUFFER_SCREEN ))
    {
        printf("DiveQueryCaps error\n");
        return KVAE_NO_ERROR;
    }

    printf("--- DiveCaps ---\n");
    printf("ulPlaneCount = %ld\n", diveCaps.ulPlaneCount );
    printf("fScreenDirect = %ld\n", diveCaps.fScreenDirect );
    printf("fBankSwitched = %ld\n", diveCaps.fBankSwitched );
    printf("ulDepth = %ld\n", diveCaps.ulDepth );
    printf("ulHorizontalResolution = %ld\n", diveCaps.ulHorizontalResolution );
    printf("ulVerticalResolution = %ld\n", diveCaps.ulVerticalResolution );
    printf("ulScanLineBytes = %ld\n", diveCaps.ulScanLineBytes );
    printf("fccColorEncoding = %.4s\n", &diveCaps.fccColorEncoding );
    printf("ulApertureSize = %ld\n", diveCaps.ulApertureSize );
    printf("ulInputFormats = %ld\n", diveCaps.ulInputFormats );
    printf("ulOutputFormats = %ld\n", diveCaps.ulOutputFormats );
    printf("ulFormatLength = %ld\n", diveCaps.ulFormatLength );
    for( i = 0; i < diveCaps.ulFormatLength / sizeof( FOURCC ); i++ )
        printf("%dth format data = %.4s\n", i, (( FOURCC * )diveCaps.pFormatData ) + i );

    return KVAE_NO_ERROR;
}
#endif

APIRET APIENTRY diveQueryAttr( ULONG ulAttr, PULONG pulValue )
{
    return KVAE_NO_ATTRIBUTE;
}

APIRET APIENTRY diveSetAttr( ULONG ulAttr, PULONG pulValue )
{
    return KVAE_NO_ATTRIBUTE;
}

