503 lines
13 KiB
C
Executable File
503 lines
13 KiB
C
Executable File
/*****************************************************************************
|
|
*
|
|
* This program is free software ; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* $Id: overlay_gapi.c 543 2006-01-07 22:06:24Z picard $
|
|
*
|
|
* The Core Pocket Media Player
|
|
* Copyright (c) 2004-2005 Gabor Kovacs
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "../common.h"
|
|
|
|
#ifdef TARGET_WINCE
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#ifndef STRICT
|
|
#define STRICT
|
|
#endif
|
|
#include <windows.h>
|
|
|
|
typedef struct GXDisplayProperties
|
|
{
|
|
int cxWidth;
|
|
int cyHeight;
|
|
int cbxPitch;
|
|
int cbyPitch;
|
|
int cBPP;
|
|
int ffFormat;
|
|
} GXDisplayProperties;
|
|
|
|
#define SHFS_SHOWTASKBAR 0x0001
|
|
#define SHFS_HIDETASKBAR 0x0002
|
|
#define SHFS_SHOWSIPBUTTON 0x0004
|
|
#define SHFS_HIDESIPBUTTON 0x0008
|
|
#define SHFS_SHOWSTARTICON 0x0010
|
|
#define SHFS_HIDESTARTICON 0x0020
|
|
|
|
#define GX_FULLSCREEN 0x01
|
|
#define kfLandscape 0x08
|
|
#define kfPalette 0x10
|
|
#define kfDirect 0x20
|
|
#define kfDirect555 0x40
|
|
#define kfDirect565 0x80
|
|
#define kfDirect888 0x100
|
|
#define kfDirect444 0x200
|
|
#define kfDirectInverted 0x400
|
|
|
|
typedef struct gapi
|
|
{
|
|
overlay Overlay;
|
|
|
|
bool_t Windows;
|
|
bool_t Opened;
|
|
bool_t DRAM;
|
|
void* Wnd;
|
|
int AdjustPtr;
|
|
uint8_t* DirectPtr;
|
|
uint8_t* Pointer;
|
|
HMODULE GX;
|
|
HMODULE AygShell;
|
|
GXDisplayProperties Info;
|
|
|
|
int (*GXOpenDisplay)(HWND hWnd, DWORD dwFlags);
|
|
int (*GXCloseDisplay)();
|
|
void* (*GXBeginDraw)();
|
|
int (*GXEndDraw)();
|
|
GXDisplayProperties (*GXGetDisplayProperties)();
|
|
int (*GXSetViewport)(DWORD dwTop, DWORD dwHeight, DWORD, DWORD);
|
|
BOOL (*GXIsDisplayDRAMBuffer)();
|
|
BOOL (WINAPI* SHFullScreen)(HWND, DWORD);
|
|
|
|
} gapi;
|
|
|
|
static const datatable Params[] =
|
|
{
|
|
{ GAPI_WIDTH, TYPE_INT, DF_SETUP | DF_RDONLY | DF_HIDDEN },
|
|
{ GAPI_HEIGHT, TYPE_INT, DF_SETUP | DF_RDONLY | DF_HIDDEN },
|
|
{ GAPI_PITCHX, TYPE_INT, DF_SETUP | DF_RDONLY | DF_HIDDEN },
|
|
{ GAPI_PITCHY, TYPE_INT, DF_SETUP | DF_RDONLY | DF_HIDDEN },
|
|
{ GAPI_BPP, TYPE_INT, DF_SETUP | DF_RDONLY | DF_HIDDEN },
|
|
{ GAPI_FORMAT, TYPE_INT, DF_SETUP | DF_RDONLY|DF_HEX | DF_HIDDEN },
|
|
{ GAPI_DRAM, TYPE_BOOL, DF_SETUP | DF_RDONLY | DF_HIDDEN },
|
|
{ GAPI_POINTER, TYPE_INT, DF_SETUP | DF_RDONLY|DF_HEX | DF_HIDDEN },
|
|
|
|
DATATABLE_END(GAPI_ID)
|
|
};
|
|
|
|
static int Enum(gapi* p, int* No, datadef* Param)
|
|
{
|
|
if (OverlayEnum(&p->Overlay,No,Param)==ERR_NONE)
|
|
return ERR_NONE;
|
|
return NodeEnumTable(No,Param,Params);
|
|
}
|
|
|
|
static int Get(gapi* p,int No,void* Data,int Size)
|
|
{
|
|
int Result = OverlayGet(&p->Overlay,No,Data,Size);
|
|
switch (No)
|
|
{
|
|
case GAPI_WIDTH: GETVALUE(p->Info.cxWidth,int); break;
|
|
case GAPI_HEIGHT: GETVALUE(p->Info.cyHeight,int); break;
|
|
case GAPI_PITCHX: GETVALUE(p->Info.cbxPitch,int); break;
|
|
case GAPI_PITCHY: GETVALUE(p->Info.cbyPitch,int); break;
|
|
case GAPI_BPP: GETVALUE(p->Info.cBPP,int); break;
|
|
case GAPI_FORMAT: GETVALUE(p->Info.ffFormat,int); break;
|
|
case GAPI_DRAM: GETVALUE(p->DRAM,bool_t); break;
|
|
case GAPI_POINTER: GETVALUE((int)p->Pointer,int); break;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
static bool_t LoadDriver(gapi* p)
|
|
{
|
|
HMODULE GX;
|
|
tchar_t Path[MAXPATH];
|
|
|
|
if (p->Windows)
|
|
GetSystemPath(Path,TSIZEOF(Path),T("gx.dll"));
|
|
else
|
|
tcscpy_s(Path,TSIZEOF(Path),T("gx.dll"));
|
|
|
|
if ((GX = LoadLibrary(Path))==NULL)
|
|
{
|
|
if (!p->Windows)
|
|
{
|
|
p->Windows = 1;
|
|
return LoadDriver(p);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (p->GX)
|
|
FreeLibrary(p->GX);
|
|
p->GX = GX;
|
|
|
|
GetProc(&p->GX,&p->GXOpenDisplay,T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z"),0);
|
|
GetProc(&p->GX,&p->GXCloseDisplay,T("?GXCloseDisplay@@YAHXZ"),0);
|
|
GetProc(&p->GX,&p->GXBeginDraw,T("?GXBeginDraw@@YAPAXXZ"),0);
|
|
GetProc(&p->GX,&p->GXEndDraw,T("?GXEndDraw@@YAHXZ"),0);
|
|
GetProc(&p->GX,&p->GXGetDisplayProperties,T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ"),0);
|
|
GetProc(&p->GX,&p->GXSetViewport,T("?GXSetViewport@@YAHKKKK@Z"),1);
|
|
GetProc(&p->GX,&p->GXIsDisplayDRAMBuffer,T("?GXIsDisplayDRAMBuffer@@YAHXZ"),1);
|
|
|
|
return p->GX!=NULL;
|
|
}
|
|
|
|
static int Init(gapi* p)
|
|
{
|
|
GXDisplayProperties Info;
|
|
video GDI;
|
|
int Caps = QueryPlatform(PLATFORM_CAPS);
|
|
|
|
if (!p->Opened)
|
|
{
|
|
ShowError(p->Overlay.Node.Class,GAPI_ID,GAPI_OPEN_ERROR);
|
|
return ERR_NOT_SUPPORTED; // don't show device error
|
|
}
|
|
|
|
Info = p->Info;
|
|
|
|
if (Info.cxWidth == GetSystemMetrics(SM_CXSCREEN) &&
|
|
Info.cyHeight < GetSystemMetrics(SM_CYSCREEN))
|
|
{
|
|
// HPC devices we need the taskbar counted in the height too
|
|
RECT WorkArea;
|
|
SystemParametersInfo(SPI_GETWORKAREA,0,&WorkArea,0);
|
|
if (WorkArea.top == 0 && WorkArea.bottom == Info.cyHeight)
|
|
Info.cyHeight = GetSystemMetrics(SM_CYSCREEN);
|
|
}
|
|
|
|
p->Overlay.Output.Format.Video.Direction = 0;
|
|
p->Overlay.Output.Format.Video.Aspect = ASPECT_ONE;
|
|
|
|
if (Info.ffFormat & kfPalette)
|
|
{
|
|
QueryDesktop(&GDI);
|
|
p->Overlay.Output.Format.Video.Pixel.Flags = PF_PALETTE;
|
|
p->Overlay.Output.Format.Video.Pixel.BitCount = Info.cBPP;
|
|
p->Overlay.Output.Format.Video.Pixel.Palette = GDI.Pixel.Palette;
|
|
}
|
|
else
|
|
if (Info.ffFormat & kfDirect444)
|
|
DefaultRGB(&p->Overlay.Output.Format.Video.Pixel,Info.cBPP,4,4,4,0,0,0);
|
|
else
|
|
if (Info.ffFormat & kfDirect565)
|
|
{
|
|
if (Caps & CAPS_ONLY12BITRGB)
|
|
DefaultRGB(&p->Overlay.Output.Format.Video.Pixel,Info.cBPP,4,4,4,1,2,1);
|
|
else
|
|
DefaultRGB(&p->Overlay.Output.Format.Video.Pixel,Info.cBPP,5,6,5,0,0,0);
|
|
}
|
|
else
|
|
if (Info.ffFormat & kfDirect555)
|
|
DefaultRGB(&p->Overlay.Output.Format.Video.Pixel,Info.cBPP,5,5,5,0,0,0);
|
|
else
|
|
if (Info.ffFormat & kfDirect888)
|
|
DefaultRGB(&p->Overlay.Output.Format.Video.Pixel,Info.cBPP,8,8,8,0,0,0);
|
|
|
|
if (Info.ffFormat & kfDirectInverted)
|
|
p->Overlay.Output.Format.Video.Pixel.Flags |= PF_INVERTED;
|
|
|
|
// get signed x/y pitches in bits
|
|
Info.cbxPitch <<= 3;
|
|
Info.cbyPitch <<= 3;
|
|
|
|
// one pitch is probably zero when BPP<8
|
|
if (!Info.cbxPitch)
|
|
if (Info.cbyPitch < 0)
|
|
Info.cbxPitch = -Info.cBPP;
|
|
else
|
|
Info.cbxPitch = Info.cBPP;
|
|
else
|
|
if (!Info.cbyPitch)
|
|
if (Info.cbxPitch < 0)
|
|
Info.cbyPitch = Info.cBPP;
|
|
else
|
|
Info.cbyPitch = -Info.cBPP;
|
|
|
|
// one of the pitches absolute value must be BPP
|
|
if (abs(Info.cbyPitch) < abs(Info.cbxPitch))
|
|
{
|
|
if (abs(Info.cbxPitch) < Info.cyHeight*Info.cBPP &&
|
|
abs(Info.cbxPitch) >= Info.cxWidth*Info.cBPP) //swapped gapi resolution
|
|
SwapInt(&Info.cxWidth,&Info.cyHeight);
|
|
|
|
Info.ffFormat |= kfLandscape;
|
|
Info.cbyPitch = Info.cbyPitch<0 ? -Info.cBPP : Info.cBPP;
|
|
}
|
|
else
|
|
{
|
|
if (abs(Info.cbyPitch) < Info.cxWidth*Info.cBPP &&
|
|
abs(Info.cbyPitch) >= Info.cyHeight*Info.cBPP) //swapped gapi resolution
|
|
SwapInt(&Info.cxWidth,&Info.cyHeight);
|
|
|
|
Info.ffFormat &= ~kfLandscape;
|
|
Info.cbxPitch = Info.cbxPitch<0 ? -Info.cBPP : Info.cBPP;
|
|
}
|
|
|
|
p->Overlay.Output.Format.Video.Width = Info.cxWidth;
|
|
p->Overlay.Output.Format.Video.Height = Info.cyHeight;
|
|
|
|
// we need the physical start of the framebuffer
|
|
p->AdjustPtr = 0;
|
|
if (Info.cbxPitch<0)
|
|
p->AdjustPtr += (Info.cbxPitch * (Info.cxWidth-1)) >> 3;
|
|
if (Info.cbyPitch<0)
|
|
p->AdjustPtr += (Info.cbyPitch * (Info.cyHeight-1)) >> 3;
|
|
|
|
if (Info.ffFormat & kfLandscape)
|
|
{
|
|
p->Overlay.Output.Format.Video.Direction |= DIR_SWAPXY;
|
|
p->Overlay.Output.Format.Video.Pitch = abs(Info.cbxPitch) >> 3;
|
|
SwapInt(&p->Overlay.Output.Format.Video.Width,&p->Overlay.Output.Format.Video.Height);
|
|
|
|
if (Info.cbxPitch<0)
|
|
p->Overlay.Output.Format.Video.Direction |= DIR_MIRRORUPDOWN;
|
|
if (Info.cbyPitch<0)
|
|
p->Overlay.Output.Format.Video.Direction |= DIR_MIRRORLEFTRIGHT;
|
|
}
|
|
else
|
|
{
|
|
p->Overlay.Output.Format.Video.Pitch = abs(Info.cbyPitch) >> 3;
|
|
|
|
if (Info.cbxPitch<0)
|
|
p->Overlay.Output.Format.Video.Direction |= DIR_MIRRORLEFTRIGHT;
|
|
if (Info.cbyPitch<0)
|
|
p->Overlay.Output.Format.Video.Direction |= DIR_MIRRORUPDOWN;
|
|
}
|
|
|
|
if (!p->DRAM)
|
|
{
|
|
p->Overlay.SetFX = BLITFX_AVOIDTEARING;
|
|
|
|
if ((Info.cxWidth > Info.cyHeight) && (Caps & CAPS_PORTRAIT))
|
|
p->Overlay.SetFX |= BLITFX_VMEMROTATED;
|
|
|
|
if ((Info.cyHeight > Info.cxWidth) && (Caps & CAPS_LANDSCAPE))
|
|
p->Overlay.SetFX |= BLITFX_VMEMROTATED;
|
|
}
|
|
else
|
|
p->Overlay.ClearFX = BLITFX_ONLYDIFF;
|
|
|
|
// wm2003se gapi emulation?
|
|
if (QueryPlatform(PLATFORM_VER) >= 421)
|
|
{
|
|
if (p->Overlay.Output.Format.Video.Width == 240 && p->Overlay.Output.Format.Video.Height == 320 && p->Overlay.Output.Format.Video.Pitch == 640)
|
|
p->Overlay.Output.Format.Video.Pitch = 480;
|
|
}
|
|
|
|
if (Info.cxWidth == 240 && Info.cyHeight == 320)
|
|
AdjustOrientation(&p->Overlay.Output.Format.Video,0);
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static void Done(gapi* p)
|
|
{
|
|
}
|
|
|
|
static int Reset(gapi* p)
|
|
{
|
|
Done(p);
|
|
Init(p);
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static int Lock(gapi* p, planes Planes, bool_t OnlyAligned)
|
|
{
|
|
if (!p->Opened)
|
|
return ERR_INVALID_PARAM;
|
|
|
|
if (p->DirectPtr)
|
|
p->Pointer = p->DirectPtr + p->AdjustPtr;
|
|
else
|
|
{
|
|
if (p->DRAM && p->GXSetViewport)
|
|
{
|
|
int Top,Height;
|
|
if (OnlyAligned)
|
|
{
|
|
Top = p->Overlay.GUIAlignedRect.y;
|
|
Height = p->Overlay.GUIAlignedRect.Height;
|
|
}
|
|
else
|
|
{
|
|
Top = p->Overlay.Viewport.y;
|
|
Height = p->Overlay.Viewport.Height;
|
|
}
|
|
|
|
if (p->Overlay.Output.Format.Video.Pixel.Flags & PF_PIXELDOUBLE)
|
|
{
|
|
Top >>= 1;
|
|
Height >>= 1;
|
|
}
|
|
|
|
p->GXSetViewport(Top,Height,0,0); // coords in windows space
|
|
}
|
|
|
|
p->Pointer = (uint8_t*)p->GXBeginDraw();
|
|
if (!p->Pointer)
|
|
return ERR_NOT_SUPPORTED;
|
|
|
|
p->Pointer += p->AdjustPtr;
|
|
}
|
|
|
|
Planes[0] = p->Pointer;
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static int Unlock(gapi* p)
|
|
{
|
|
if (!p->DirectPtr)
|
|
p->GXEndDraw();
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static int UpdateWnd(gapi* p)
|
|
{
|
|
void* Wnd = Context()->Wnd;
|
|
if (p->Wnd != Wnd)
|
|
{
|
|
p->Wnd = Wnd;
|
|
if (p->Wnd && !p->Opened)
|
|
{
|
|
HWND WndTask;
|
|
|
|
while (!p->GX || !p->GXOpenDisplay(p->Wnd,GX_FULLSCREEN))
|
|
{
|
|
if (!p->Windows)
|
|
{
|
|
p->Windows = 1; // try gx.dll in \windows directory (HPC with .NET)
|
|
if (LoadDriver(p))
|
|
continue;
|
|
}
|
|
return ERR_NOT_SUPPORTED;
|
|
}
|
|
|
|
// just in case GXOpenDisplay hides these things
|
|
if (p->SHFullScreen)
|
|
{
|
|
p->SHFullScreen(p->Wnd,SHFS_SHOWSTARTICON);
|
|
p->SHFullScreen(p->Wnd,SHFS_SHOWTASKBAR);
|
|
}
|
|
|
|
WndTask = FindWindow(T("HHTaskbar"),NULL);
|
|
if (WndTask)
|
|
ShowWindow(WndTask,SW_SHOWNA);
|
|
|
|
p->Info = p->GXGetDisplayProperties();
|
|
if (!p->Info.cxWidth || !p->Info.cyHeight) // this shouldn't happen
|
|
{
|
|
p->GXCloseDisplay();
|
|
return ERR_DEVICE_ERROR;
|
|
}
|
|
|
|
p->DirectPtr = NULL;
|
|
p->Opened = 1;
|
|
p->DRAM = 0;
|
|
|
|
if (p->GXIsDisplayDRAMBuffer)
|
|
p->DRAM = p->GXIsDisplayDRAMBuffer() != 0;
|
|
|
|
// detect fake DRAM
|
|
if (p->DRAM && !(p->Info.ffFormat & kfLandscape) && QueryPlatform(PLATFORM_MODEL)==MODEL_SPV_C500_ORIGROM)
|
|
{
|
|
p->GXSetViewport(0,0,0,0);
|
|
p->DirectPtr = p->GXBeginDraw();
|
|
}
|
|
|
|
if (QueryPlatform(PLATFORM_VER) >= 421)
|
|
IsOrientationChanged(); // force requery of orientation (GXOpenDisplay changes to portrait)
|
|
|
|
Init(p); // we need the output format
|
|
}
|
|
else
|
|
if (p->Opened && !p->Wnd && !p->DirectPtr)
|
|
{
|
|
p->GXCloseDisplay();
|
|
p->Opened = 0;
|
|
}
|
|
}
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static int Set(gapi* p,int No,const void* Data,int Size)
|
|
{
|
|
int Result = OverlaySet(&p->Overlay,No,Data,Size);
|
|
switch (No)
|
|
{
|
|
case NODE_SETTINGSCHANGED:
|
|
Result = UpdateWnd(p);
|
|
break;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
static int Create(gapi* p)
|
|
{
|
|
if (NodeEnumObject(NULL,RAW_ID))
|
|
return ERR_NOT_SUPPORTED;
|
|
|
|
p->Overlay.Node.Enum = Enum;
|
|
p->Overlay.Node.Get = Get;
|
|
p->Overlay.Node.Set = Set;
|
|
p->Overlay.Lock = Lock;
|
|
p->Overlay.Unlock = Unlock;
|
|
p->Overlay.Init = Init;
|
|
p->Overlay.Done = Done;
|
|
p->Overlay.Reset = Reset;
|
|
p->Overlay.Node.Get = Get;
|
|
p->Overlay.Node.Enum = Enum;
|
|
|
|
if (!LoadDriver(p))
|
|
return ERR_NOT_SUPPORTED;
|
|
|
|
p->AygShell = LoadLibrary(T("aygshell.dll"));
|
|
GetProc(&p->AygShell,&p->SHFullScreen,T("SHFullScreen"),1);
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static void Delete(gapi* p)
|
|
{
|
|
if (p->GX)
|
|
FreeLibrary(p->GX);
|
|
if (p->AygShell)
|
|
FreeLibrary(p->AygShell);
|
|
}
|
|
|
|
static const nodedef GAPI =
|
|
{
|
|
sizeof(gapi)|CF_GLOBAL,
|
|
GAPI_ID,
|
|
OVERLAY_CLASS,
|
|
PRI_DEFAULT+50,
|
|
(nodecreate)Create,
|
|
(nodedelete)Delete,
|
|
};
|
|
|
|
void OverlayGAPI_Init()
|
|
{
|
|
NodeRegisterClass(&GAPI);
|
|
}
|
|
|
|
void OverlayGAPI_Done()
|
|
{
|
|
NodeUnRegisterClass(GAPI_ID);
|
|
}
|
|
|
|
#endif
|