graphics: render mouse using copying overlay, optimize copying

This commit is contained in:
Edgaru089 2021-10-22 00:28:13 +08:00
parent 986b135403
commit a0c2b8d8fd
3 changed files with 127 additions and 26 deletions

View File

@ -2,6 +2,7 @@
#include "graphics.h" #include "graphics.h"
#include "color.h" #include "color.h"
#include "internal_helpers.h"
#include "unifont.h" #include "unifont.h"
#include "../runtime/stdio.h" #include "../runtime/stdio.h"
#include "../util/minmax.h" #include "../util/minmax.h"
@ -36,8 +37,11 @@ void * graphics_Framebuffer;
uint64_t graphics_FramebufferSize; uint64_t graphics_FramebufferSize;
uint32_t graphics_Doublebuffer[2048 * 1024]; uint32_t graphics_Doublebuffer[2048 * 1024];
#define MOUSE_OVERLAY_SIZE 32
xcursor_ChunkHeader_Image *graphics_Cursor; xcursor_ChunkHeader_Image *graphics_Cursor;
int graphics_MouseCursorX, graphics_MouseCursorY; int graphics_MouseCursorX, graphics_MouseCursorY;
static int __lastMouseX, __lastMouseY; // Last of mouse **IMAGE** position
static uint32_t __mouseOverlay[MOUSE_OVERLAY_SIZE * MOUSE_OVERLAY_SIZE];
void graphics_Init() { void graphics_Init() {
@ -160,36 +164,35 @@ void graphics_ClearBuffer(const HelosGraphics_Color *color) {
} }
} }
void graphics_SwapBuffer() { static void __graphics__UpdateMouse() {
memcpy(graphics_DeviceFramebuffer, graphics_Framebuffer, graphics_FramebufferSize); if (!graphics_Cursor)
return;
if (graphics_Cursor) { int imgX = graphics_MouseCursorX - graphics_Cursor->xhot + 1;
// TODO Optimize mouse cursor overlay render int imgY = graphics_MouseCursorY - graphics_Cursor->yhot + 1;
/*if (graphics_SystemVideoMode.PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { if (imgX != __lastMouseX || imgY != __lastMouseY) { // moved
for (int i = 0; i < graphics_Cursor->height; i++) { __graphics_CopyBuffer32(
if (graphics_MouseCursorY + i >= graphics_SystemVideoMode.Height) __mouseOverlay, 0, 0, MOUSE_OVERLAY_SIZE, MOUSE_OVERLAY_SIZE,
break; graphics_Framebuffer, __lastMouseX, __lastMouseY, graphics_SystemVideoMode.Width, graphics_SystemVideoMode.Height,
memcpy( graphics_Cursor->width, graphics_Cursor->height);
graphics_DeviceFramebuffer + graphics_SystemVideoMode.PixelsPerLine * 4 * graphics_CursorY + 4 * graphics_CursorX, __graphics_CopyBuffer32(
&graphics_Cursor->pixels[i * graphics_Cursor->width], graphics_Framebuffer, imgX, imgY, graphics_SystemVideoMode.Width, graphics_SystemVideoMode.Height,
min(graphics_Cursor->width, graphics_SystemVideoMode.Width - graphics_MouseCursorX) * 4); __mouseOverlay, 0, 0, MOUSE_OVERLAY_SIZE, MOUSE_OVERLAY_SIZE,
} graphics_Cursor->width, graphics_Cursor->height);
} else {*/ __graphics_RenderBuffer32(
int imgX = graphics_MouseCursorX - graphics_Cursor->xhot + 1; graphics_Cursor->pixels, 0, 0, graphics_Cursor->width, graphics_Cursor->height,
int imgY = graphics_MouseCursorY - graphics_Cursor->yhot + 1; graphics_Framebuffer, imgX, imgY, graphics_SystemVideoMode.Width, graphics_SystemVideoMode.Height,
for (int y = intmax(imgY, 0); y < intmin(imgY + graphics_Cursor->height, graphics_SystemVideoMode.Height); y++) { graphics_Cursor->width, graphics_Cursor->height);
for (int x = intmax(imgX, 0); x < intmin(imgX + graphics_Cursor->width, graphics_SystemVideoMode.Width); x++) { __lastMouseX = imgX;
//graphics_SetPixel_RGB(x + graphics_MouseCursorX, y + graphics_MouseCursorY, &graphics_Cursor->pixels[y * graphics_Cursor->width + x]); __lastMouseY = imgY;
HelosGraphics_Color *pixel = &graphics_Cursor->pixels[(y - imgY) * graphics_Cursor->width + (x - imgX)];
if (pixel->A <= 0x7f)
continue;
*((uint32_t *)(graphics_DeviceFramebuffer + graphics_SystemVideoMode.PixelsPerLine * 4 * y + 4 * x)) = (*((uint32_t *)pixel)) & 0x00ffffffu;
}
}
//}
} }
} }
void graphics_SwapBuffer() {
__graphics__UpdateMouse();
memcpy(graphics_DeviceFramebuffer, graphics_Framebuffer, graphics_FramebufferSize);
}
void graphics_FillPixel(int startX, int startY, int endX, int endY, const HelosGraphics_Color *color) { void graphics_FillPixel(int startX, int startY, int endX, int endY, const HelosGraphics_Color *color) {
// TODO Optimize this! This is too sloooow // TODO Optimize this! This is too sloooow
if (graphics_SystemVideoMode.PixelFormat == PixelBlueGreenRedReserved8BitPerColor) if (graphics_SystemVideoMode.PixelFormat == PixelBlueGreenRedReserved8BitPerColor)
@ -221,6 +224,7 @@ void graphics_Scroll(int scrollY) {
0, 0,
sizeof(uint32_t) * graphics_SystemVideoMode.PixelsPerLine * (scrollY));*/ sizeof(uint32_t) * graphics_SystemVideoMode.PixelsPerLine * (scrollY));*/
graphics_FillPixel(0, graphics_SystemVideoMode.Height - scrollY, graphics_SystemVideoMode.Width, graphics_SystemVideoMode.Height, &HelosGraphics_Color_Black); graphics_FillPixel(0, graphics_SystemVideoMode.Height - scrollY, graphics_SystemVideoMode.Width, graphics_SystemVideoMode.Height, &HelosGraphics_Color_Black);
__lastMouseY -= scrollY;
} }
void graphics_ElementSize(int sizeX, int sizeY) { void graphics_ElementSize(int sizeX, int sizeY) {

View File

@ -0,0 +1,73 @@
#pragma once
#include "../util/minmax.h"
#include "color.h"
#include "stdint.h"
#include "string.h"
static inline void __graphics_CopyBuffer32(
void *from, // Source image of the copy
int fromOffsetX, // OffsetX of the region to copy from
int fromOffsetY, // OffsetY of the region to copy from
int fromSizeX, // SizeX of the entire source image
int fromSizeY, // SizeY of the entire source image
void *to, // Destination image of the copy
int toOffsetX, // OffsetX of the target region
int toOffsetY, // OffsetY of the target region
int toSizeX, // SizeX of the entire destination image
int toSizeY, // SizeY of the entire destination image
int countX, // Size of the copying region
int countY) {
int beginX = intmax3(0, -fromOffsetX, -toOffsetX), beginY = intmax3(0, -fromOffsetY, -toOffsetY);
int endX = intmin3(countX, fromSizeX - fromOffsetX, toSizeX - toOffsetX),
endY = intmin3(countY, fromSizeY - fromOffsetY, toSizeY - toOffsetY);
#define PIXEL_BYTES ((intptr_t)4)
for (int i = beginY; i < endY; i++)
memcpy(
((intptr_t)toOffsetX + beginX + (intptr_t)toSizeX * (toOffsetY + i)) * PIXEL_BYTES + (uint8_t *)to,
((intptr_t)fromOffsetX + beginX + (intptr_t)fromSizeX * (fromOffsetY + i)) * PIXEL_BYTES + (uint8_t *)from,
(endX - beginX) * PIXEL_BYTES);
#undef PIXEL_BYTES
}
// Blends ARGB Premultiplied Alpha image onto (opaque) buffer
// See: https://apoorvaj.io/alpha-compositing-opengl-blending-and-premultiplied-alpha/
static inline void __graphics_RenderBuffer32(
void *from, // Source image of the render
int fromOffsetX, // OffsetX of the region to render from
int fromOffsetY, // OffsetY of the region to render from
int fromSizeX, // SizeX of the entire source image
int fromSizeY, // SizeY of the entire source image
void *to, // Destination image of the render
int toOffsetX, // OffsetX of the target region
int toOffsetY, // OffsetY of the target region
int toSizeX, // SizeX of the entire destination image
int toSizeY, // SizeY of the entire destination image
int countX, // Size of the render region
int countY) {
int beginX = intmax3(0, -fromOffsetX, -toOffsetX), beginY = intmax3(0, -fromOffsetY, -toOffsetY);
int endX = intmin3(countX, fromSizeX - fromOffsetX, toSizeX - toOffsetX),
endY = intmin3(countY, fromSizeY - fromOffsetY, toSizeY - toOffsetY);
for (int x = beginX; x < endX; x++)
for (int y = beginY; y < endY; y++) {
HelosGraphics_Color
*src = ((intptr_t)fromOffsetX + x + (intptr_t)fromSizeX * (fromOffsetY + y)) + (HelosGraphics_Color *)from,
*dest = ((intptr_t)toOffsetX + x + (intptr_t)toSizeX * (toOffsetY + y)) + (HelosGraphics_Color *)to;
if (src->A == 0)
continue;
else if (src->A == 0xff)
*(uint32_t *)dest = *(uint32_t *)src & 0x00ffffffu;
else { // blend
HelosGraphics_Color color = {
.B = (uint8_t)(src->B + ((int)dest->B) * (0xff - src->A) / 0xff),
.G = (uint8_t)(src->G + ((int)dest->G) * (0xff - src->A) / 0xff),
.R = (uint8_t)(src->R + ((int)dest->R) * (0xff - src->A) / 0xff),
.A = 0};
*dest = color;
}
}
}

View File

@ -8,3 +8,27 @@ static inline int intmin(int x, int y) {
static inline int intmax(int x, int y) { static inline int intmax(int x, int y) {
return x > y ? x : y; return x > y ? x : y;
} }
static inline int intmin3(int x, int y, int z) {
if (x < y)
if (x < z)
return x;
else
return z;
else if (y < z)
return y;
else
return z;
}
static inline int intmax3(int x, int y, int z) {
if (x > y)
if (x > z)
return x;
else
return z;
else if (y > z)
return y;
else
return z;
}