working mouse pointer and ximage.draw

Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
This commit is contained in:
Sergey Isakov 2020-03-07 09:37:19 +03:00
parent c3103859b6
commit 6c592d8004
2 changed files with 75 additions and 89 deletions

View File

@ -54,13 +54,23 @@ XImage::XImage(const XImage& Image, float scale)
{
UINTN SrcWidth = Image.GetWidth();
UINTN SrcHeight = Image.GetHeight();
Width = (UINTN)(SrcWidth * scale);
Height = (UINTN)(SrcHeight * scale);
PixelData.CheckSize(GetWidth()*GetHeight());
PixelData.SetLength(GetWidth()*GetHeight());
if (scale < 1.e-4) return;
CopyScaled(Image, scale);
if (scale < 1.e-4) {
Width = SrcWidth;
Height = SrcHeight;
PixelData.CheckSize(GetWidth()*GetHeight());
PixelData.SetLength(GetWidth()*GetHeight());
for (UINTN y = 0; y < Height; ++y)
for (UINTN x = 0; x < Width; ++x)
PixelData[y * Width + x] = Image.GetPixel(x, y);
} else {
Width = (UINTN)(SrcWidth * scale);
Height = (UINTN)(SrcHeight * scale);
PixelData.CheckSize(Width * Height);
PixelData.SetLength(Width * Height);
CopyScaled(Image, scale);
}
}
#if 0
@ -207,7 +217,11 @@ void XImage::CopyScaled(const XImage& Image, float scale)
}
}
void XImage::Compose(INTN PosX, INTN PosY, const XImage& TopImage, bool Lowest) //lowest image is opaque
/* Place Top image over this image at PosX,PosY
* Lowest means final image is opaque
* else transparency will be multiplied
*/
void XImage::Compose(INTN PosX, INTN PosY, const XImage& TopImage, bool Lowest)
{
UINT32 TopAlpha;
UINT32 RevAlpha;
@ -215,28 +229,29 @@ void XImage::Compose(INTN PosX, INTN PosY, const XImage& TopImage, bool Lowest)
UINT32 Temp;
for (UINTN y = PosY; y < Height && (y - PosY) < TopImage.GetHeight(); ++y) {
EFI_GRAPHICS_OUTPUT_BLT_PIXEL& CompPtr = *GetPixelPtr(PosX, y); // I assign a ref to avoid the operator ->. Compiler will produce the same anyway.
// EFI_GRAPHICS_OUTPUT_BLT_PIXEL& CompPtr = *GetPixelPtr(PosX, y); // I assign a ref to avoid the operator ->. Compiler will produce the same anyway.
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* CompPtr = GetPixelPtr(PosX, y);
for (UINTN x = PosX; x < Width && (x - PosX) < TopImage.GetWidth(); ++x) {
TopAlpha = TopImage.GetPixel(x-PosX, y-PosY).Reserved;
RevAlpha = 255 - TopAlpha;
FinalAlpha = (255*255 - RevAlpha*(255 - CompPtr.Reserved)) / 255;
FinalAlpha = (255*255 - RevAlpha*(255 - CompPtr->Reserved)) / 255;
//final alpha =(1-(1-x)*(1-y)) =(255*255-(255-topA)*(255-compA))/255
Temp = (CompPtr.Blue * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Blue * TopAlpha);
CompPtr.Blue = (UINT8)(Temp / 255);
Temp = (CompPtr->Blue * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Blue * TopAlpha);
CompPtr->Blue = (UINT8)(Temp / 255);
Temp = (CompPtr.Green * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Green * TopAlpha);
CompPtr.Green = (UINT8)(Temp / 255);
Temp = (CompPtr->Green * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Green * TopAlpha);
CompPtr->Green = (UINT8)(Temp / 255);
Temp = (CompPtr.Red * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Red * TopAlpha);
CompPtr.Red = (UINT8)(Temp / 255);
Temp = (CompPtr->Red * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Red * TopAlpha);
CompPtr->Red = (UINT8)(Temp / 255);
if (Lowest) {
CompPtr.Reserved = 255;
CompPtr->Reserved = 255;
} else {
CompPtr.Reserved = (UINT8)FinalAlpha;
CompPtr->Reserved = (UINT8)FinalAlpha;
}
CompPtr++; //faster way to move to next pixel
}
}
}
@ -319,9 +334,8 @@ unsigned XImage::FromSVG(const CHAR8 *SVGData, UINTN FileDataLength, float scale
// Screen operations
/*
* The function to get image from screen. Used in screenshot (full screen), Pointer (small area) and Draw (small area)
* XImage must be created with UGAWidth, UGAHeight as egGetScreenSize(&UGAWidth, &UGAHeight); with PixelData allocated
* egScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution;
* egScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution;
* XImage must be created with Width, Height of Rect
* the rect will be clipped if it intersects the screen edge
*
* be careful about alpha. This procedure can produce alpha = 0 which means full transparent
*/
@ -330,6 +344,7 @@ void XImage::GetArea(const EG_RECT& Rect)
GetArea(Rect.XPos, Rect.YPos, Rect.Width, Rect.Height);
}
void XImage::GetArea(INTN x, INTN y, UINTN W, UINTN H)
{
EFI_STATUS Status;
@ -349,49 +364,41 @@ void XImage::GetArea(INTN x, INTN y, UINTN W, UINTN H)
if (W == 0) W = Width;
if (H == 0) H = Height;
INTN AreaWidth = (x + W > (UINTN)UGAWidth) ? (UGAWidth - x) : W;
INTN AreaHeight = (y + H > (UINTN)UGAHeight) ? ((UINTN)UGAHeight - y) : H;
Width = (x + W > (UINTN)UGAWidth) ? (UGAWidth - x) : W;
Height = (y + H > (UINTN)UGAHeight) ? ((UINTN)UGAHeight - y) : H;
// DBG("x=%d y=%d W=%d h=%d Width=%d Height=%d\n", x,y,W,H,Width,Height);
// INTN LineBytes = Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
PixelData.SetLength(Width * Height); // setLength BEFORE, so &PixelData[0]
if (GraphicsOutput != NULL) {
PixelData.SetLength(AreaWidth*AreaHeight); // setLength BEFORE, so &PixelData[0]
INTN LineBytes = GraphicsOutput->Mode->Info->HorizontalResolution * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
GraphicsOutput->Blt(GraphicsOutput,
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)&PixelData[0],
EfiBltVideoToBltBuffer,
x, y, 0, 0, AreaWidth, AreaHeight, LineBytes);
x, y, 0, 0, Width, Height, 0);
}
else if (UgaDraw != NULL) {
UINT32 LineWidth = 0;
UINT32 UGAScreenHeight = 0;
UINT32 Depth = 0;
UINT32 RefreshRate = 60;
Status = UgaDraw->GetMode(UgaDraw, &LineWidth, &UGAScreenHeight, &Depth, &RefreshRate);
if (EFI_ERROR(Status)) {
return; // graphics not available
}
PixelData.SetLength(AreaWidth*AreaHeight); // setLength BEFORE, so &PixelData[0]
UgaDraw->Blt(UgaDraw,
(EFI_UGA_PIXEL *)&PixelData[0],
(EFI_UGA_PIXEL *)GetPixelPtr(0,0),
EfiUgaVideoToBltBuffer,
x, y, 0, 0, AreaWidth, AreaHeight, LineWidth * sizeof(EFI_UGA_PIXEL));
x, y, 0, 0, Width, Height, 0);
}
Width = AreaWidth;
Height = AreaHeight;
}
void XImage::Draw(INTN x, INTN y, float scale)
{
//prepare images
DBG("1\n");
XImage Top(*this, scale);
XImage Background(UGAWidth, UGAHeight);
DBG("2\n");
XImage Background(Width, Height);
DBG("3\n");
Background.GetArea(x, y, Width, Height);
Background.Compose(0, 0, Top, false);
DBG("4\n");
Background.Compose(0, 0, Top, true);
DBG("5\n");
UINTN AreaWidth = (x + Width > (UINTN)UGAWidth) ? (UGAWidth - x) : Width;
UINTN AreaHeight = (y + Height > (UINTN)UGAHeight) ? (UGAHeight - y) : Height;
DBG("area=%d,%d\n", AreaWidth, AreaHeight);
// prepare protocols
EFI_STATUS Status;
EFI_GUID UgaDrawProtocolGuid = EFI_UGA_DRAW_PROTOCOL_GUID;
@ -408,14 +415,14 @@ void XImage::Draw(INTN x, INTN y, float scale)
}
//output combined image
if (GraphicsOutput != NULL) {
GraphicsOutput->Blt(GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Top.GetPixelPtr(0, 0),
GraphicsOutput->Blt(GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Background.GetPixelPtr(0, 0),
EfiBltBufferToVideo,
0, 0, x, y,
AreaWidth, AreaHeight, UGAWidth * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
0, 0, x, y, AreaWidth, AreaHeight, 0);
//Background.GetWidth() * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
}
else if (UgaDraw != NULL) {
UgaDraw->Blt(UgaDraw, (EFI_UGA_PIXEL *)Background.GetPixelPtr(0, 0), EfiUgaBltBufferToVideo,
0, 0, x, y,
AreaWidth, AreaHeight, UGAWidth * sizeof(EFI_UGA_PIXEL));
0, 0, x, y, AreaWidth, AreaHeight, 0);
// Background.GetWidth() * sizeof(EFI_UGA_PIXEL));
}
}

View File

@ -21,11 +21,9 @@
#define DBG(...) DebugLog(DEBUG_MOUSE, __VA_ARGS__)
#endif
//extern EFI_AUDIO_IO_PROTOCOL *AudioIo;
// make them theme dependent? No, 32 is good value for all.
#define POINTER_WIDTH 32
#define POINTER_HEIGHT 32
// Initial value, but later it will be theme dependent
#define POINTER_WIDTH 64
#define POINTER_HEIGHT 64
XPointer::XPointer()
: PointerImage(NULL),
@ -75,37 +73,28 @@ EFI_STATUS XPointer::MouseBirth()
if (EFI_ERROR(Status)) {
MsgLog("No mouse!\n");
delete PointerImage;
PointerImage = NULL;
if (PointerImage) {
delete PointerImage;
PointerImage = NULL;
}
MouseEvent = NoEvents;
SimplePointerProtocol = NULL;
gSettings.PointerEnabled = FALSE;
return Status;
}
if ( !PointerImage->isEmpty() ) {
//this is impossible after BuiltinIcon
MsgLog(" pointer image! Renew it\n");
//SimplePointerProtocol = NULL;
//Alive = false;
//return EFI_NOT_FOUND;
if (PointerImage && !PointerImage->isEmpty() ) {
delete PointerImage;
PointerImage = nullptr;
}
DBG("Now update image because of other theme\n");
// Now update image because of other theme has other image
PointerImage = new XImage(BuiltinIcon(BUILTIN_ICON_POINTER));
DBG("new image created\n");
LastClickTime = 0; //AsmReadTsc();
LastClickTime = 0;
oldPlace.XPos = (INTN)(UGAWidth >> 2);
oldPlace.YPos = (INTN)(UGAHeight >> 2);
oldPlace.Width = POINTER_WIDTH;
oldPlace.Height = POINTER_HEIGHT;
DBG("init mouse at [%d, %d]\n", oldPlace.XPos, oldPlace.YPos);
oldPlace.Width = PointerImage->GetWidth();
oldPlace.Height = PointerImage->GetHeight();
CopyMem(&newPlace, &oldPlace, sizeof(EG_RECT));
// DBG("newPlace={%d, %d, %d, %d}\n", newPlace.XPos, newPlace.YPos, newPlace.Width, newPlace.Height);
//newImage->Fill(&MenuBackgroundPixel),
// egTakeImage(oldImage, oldPlace.XPos, oldPlace.YPos,
// POINTER_WIDTH, POINTER_HEIGHT); // DrawPointer repeats it
Draw();
MouseEvent = NoEvents;
Alive = true;
@ -115,36 +104,26 @@ EFI_STATUS XPointer::MouseBirth()
VOID XPointer::Draw()
{
// take background image
// take background image for later to restore background
oldImage.GetArea(newPlace);
DBG("got area\n");
CopyMem(&oldPlace, &newPlace, sizeof(EG_RECT)); //can we use oldPlace = newPlace; ?
// CopyMem(newImage->PixelData, oldImage->PixelData, (UINTN)(POINTER_WIDTH * POINTER_HEIGHT * sizeof(EG_PIXEL)));
// newImage.CopyScaled(oldImage, 1.f);
DBG("Draw pointer\n");
// newImage.Compose(0, 0, PointerImage, true);
// newImage.Draw(newPlace.XPos, newPlace.YPos, 1.f);
PointerImage->Draw(newPlace.XPos, newPlace.YPos, 1.f);
PointerImage->Draw(newPlace.XPos, newPlace.YPos, 0.f); //zero means no scale
}
VOID XPointer::KillMouse()
{
// EG_PIXEL pi;
Alive = false;
if (!SimplePointerProtocol) {
return;
}
DBG("KillMouse\n");
// newImage.setEmpty(); // Don't empty them, we'll need them at the next mouse birth
// oldImage.setEmpty();
// DBG("KillMouse\n");
if (PointerImage) {
delete PointerImage;
PointerImage = nullptr;
}
MouseEvent = NoEvents;
SimplePointerProtocol = NULL;
}