Initial commit
This commit is contained in:
		
							
								
								
									
										284
									
								
								graphics/graphics.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								graphics/graphics.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,284 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "graphics.h"
 | 
			
		||||
#include "unifont.h"
 | 
			
		||||
#include "../runtime/stdio.h"
 | 
			
		||||
#include <efiprot.h>
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "../runtime/memcpy.h"
 | 
			
		||||
 | 
			
		||||
const HelosGraphics_Color
 | 
			
		||||
	HelosGraphics_Color_Black   = {0x00, 0x00, 0x00, 0xff},
 | 
			
		||||
	HelosGraphics_Color_White   = {0xff, 0xff, 0xff, 0xff},
 | 
			
		||||
	HelosGraphics_Color_Red     = {0x00, 0x00, 0xff, 0xff},
 | 
			
		||||
	HelosGraphics_Color_Green   = {0x00, 0xff, 0x00, 0xff},
 | 
			
		||||
	HelosGraphics_Color_Blue    = {0xff, 0x00, 0x00, 0xff},
 | 
			
		||||
	HelosGraphics_Color_Cyan    = {0xff, 0xff, 0x00, 0xff},
 | 
			
		||||
	HelosGraphics_Color_Magenta = {0xff, 0x00, 0xff, 0xff},
 | 
			
		||||
	HelosGraphics_Color_Yellow  = {0x00, 0xff, 0xff, 0xff};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static EFI_GUID                      gopID = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
 | 
			
		||||
static EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
 | 
			
		||||
 | 
			
		||||
static EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
 | 
			
		||||
static UINTN                                 sizeofInfo, nModes, nativeMode;
 | 
			
		||||
static HelosGraphics_Mode                    modes[128];
 | 
			
		||||
 | 
			
		||||
void *graphics_DeviceFramebuffer;
 | 
			
		||||
 | 
			
		||||
void *   graphics_Framebuffer;
 | 
			
		||||
uint64_t graphics_FramebufferSize;
 | 
			
		||||
 | 
			
		||||
uint32_t graphics_Doublebuffer[2048 * 1024];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void graphics_Init() {
 | 
			
		||||
	assert(sizeof(HelosGraphics_Color) == sizeof(uint32_t) && "HelosGraphics_Color not packed to be 32-bit(4 bytes)");
 | 
			
		||||
 | 
			
		||||
	EFI_STATUS status = efiBootServices->LocateProtocol(&gopID, NULL, (void **)&gop);
 | 
			
		||||
	if (EFI_ERROR(status)) {
 | 
			
		||||
		io_Printf("graphics_Init: Error locating GOP\r\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	status = gop->QueryMode(gop, gop->Mode == NULL ? 0 : gop->Mode->Mode, &sizeofInfo, &info);
 | 
			
		||||
	if (status == EFI_NOT_STARTED) {
 | 
			
		||||
		status = gop->SetMode(gop, 0);
 | 
			
		||||
	}
 | 
			
		||||
	if (EFI_ERROR(status)) {
 | 
			
		||||
		io_Printf("graphics_Init: Error getting native modes\r\n");
 | 
			
		||||
		return;
 | 
			
		||||
	} else {
 | 
			
		||||
		nativeMode = gop->Mode->Mode;
 | 
			
		||||
		nModes     = gop->Mode->MaxMode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < nModes; i++) {
 | 
			
		||||
		status                 = gop->QueryMode(gop, i, &sizeofInfo, &info);
 | 
			
		||||
		modes[i].Width         = info->HorizontalResolution;
 | 
			
		||||
		modes[i].Height        = info->VerticalResolution;
 | 
			
		||||
		modes[i].PixelsPerLine = info->PixelsPerScanLine;
 | 
			
		||||
		modes[i].PixelFormat   = info->PixelFormat;
 | 
			
		||||
 | 
			
		||||
		if (modes[i].Width == HELOS_GRAPHICS_TARGET_MODE_WIDTH && modes[i].Height == HELOS_GRAPHICS_TARGET_MODE_HEIGHT)
 | 
			
		||||
			nativeMode = i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// set the new mode
 | 
			
		||||
	status = gop->SetMode(gop, nativeMode);
 | 
			
		||||
	if (EFI_ERROR(status)) {
 | 
			
		||||
		io_Printf("graphics_Init: Unable to set mode %d\r\n", nativeMode);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	io_Printf(
 | 
			
		||||
		"graphics_Init: Framebuffer:\r\n  addr %08x len %d, size %dx%d, ppl %d\r\n",
 | 
			
		||||
		graphics_DeviceFramebuffer = (void *)gop->Mode->FrameBufferBase,
 | 
			
		||||
		graphics_FramebufferSize   = gop->Mode->FrameBufferSize,
 | 
			
		||||
		gop->Mode->Info->HorizontalResolution,
 | 
			
		||||
		gop->Mode->Info->VerticalResolution,
 | 
			
		||||
		gop->Mode->Info->PixelsPerScanLine);
 | 
			
		||||
 | 
			
		||||
	// warn the user if the framebuffer is not RGB
 | 
			
		||||
	io_Printf("graphics_Init: Framebuffer format: ");
 | 
			
		||||
#define CASE(v) \
 | 
			
		||||
	break;      \
 | 
			
		||||
	case v: io_Printf(#v "\r\n");
 | 
			
		||||
	switch (gop->Mode->Info->PixelFormat) {
 | 
			
		||||
		CASE(PixelRedGreenBlueReserved8BitPerColor)
 | 
			
		||||
		graphics_SetPixel = graphics_SetPixel_RGB;
 | 
			
		||||
		CASE(PixelBlueGreenRedReserved8BitPerColor)
 | 
			
		||||
		graphics_SetPixel = graphics_SetPixel_BGR;
 | 
			
		||||
		CASE(PixelBitMask)
 | 
			
		||||
		CASE(PixelBltOnly)
 | 
			
		||||
		CASE(PixelFormatMax)
 | 
			
		||||
	}
 | 
			
		||||
#undef CASE
 | 
			
		||||
 | 
			
		||||
	graphics_Framebuffer = (void *)graphics_Doublebuffer;
 | 
			
		||||
	graphics_CursorX = graphics_CursorY = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
graphics_SetPixel_Type *graphics_SetPixel;
 | 
			
		||||
 | 
			
		||||
void graphics_SetPixel_RGB(int posX, int posY, const HelosGraphics_Color *color) {
 | 
			
		||||
	struct {
 | 
			
		||||
		uint8_t R, G, B;
 | 
			
		||||
		uint8_t A;
 | 
			
		||||
	} colorRGB = {color->R, color->G, color->B, 0};
 | 
			
		||||
 | 
			
		||||
	*((uint32_t *)(graphics_Framebuffer + modes[nativeMode].PixelsPerLine * 4 * posY + 4 * posX)) = (*((uint32_t *)&colorRGB));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void graphics_SetPixel_BGR(int posX, int posY, const HelosGraphics_Color *color) {
 | 
			
		||||
	*((uint32_t *)(graphics_Framebuffer + modes[nativeMode].PixelsPerLine * 4 * posY + 4 * posX)) = (*((uint32_t *)color)) & 0x00ffffffu;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void graphics_GetSize(int *sizeX, int *sizeY, int *bitsPerPixel) {
 | 
			
		||||
	*sizeX        = modes[nativeMode].Width;
 | 
			
		||||
	*sizeY        = modes[nativeMode].Height;
 | 
			
		||||
	*bitsPerPixel = 24;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void graphics_ClearBuffer(const HelosGraphics_Color *color) {
 | 
			
		||||
	uint32_t data;
 | 
			
		||||
 | 
			
		||||
	if (*((uint32_t *)color) == *((uint32_t *)&HelosGraphics_Color_Black)) {
 | 
			
		||||
		memset(graphics_Framebuffer, 0, graphics_FramebufferSize);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (modes[nativeMode].PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
 | 
			
		||||
		struct {
 | 
			
		||||
			uint8_t R, G, B;
 | 
			
		||||
			uint8_t A;
 | 
			
		||||
		} colorRGB = {color->R, color->G, color->B, 0};
 | 
			
		||||
		data       = (*(uint32_t *)&colorRGB) & 0x00ffffffu;
 | 
			
		||||
	} else if (modes[nativeMode].PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
 | 
			
		||||
		data = (*(uint32_t *)color) & 0x00ffffffu;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t *buffer = graphics_Framebuffer, *end = graphics_Framebuffer + graphics_FramebufferSize / sizeof(uint32_t);
 | 
			
		||||
	while (buffer != end) {
 | 
			
		||||
		*buffer = data;
 | 
			
		||||
		buffer++;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void graphics_SwapBuffer() {
 | 
			
		||||
	memcpy(graphics_DeviceFramebuffer, graphics_Framebuffer, graphics_FramebufferSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void graphics_FillPixel(int startX, int startY, int endX, int endY, const HelosGraphics_Color *color) {
 | 
			
		||||
	// TODO Optimize this! This is too sloooow
 | 
			
		||||
	if (gop->Mode->Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor)
 | 
			
		||||
		for (int i = startX; i < endX; i++)
 | 
			
		||||
			for (int j = startY; j < endY; j++)
 | 
			
		||||
				*((uint32_t *)(graphics_Framebuffer + modes[nativeMode].PixelsPerLine * 4 * j + 4 * i)) = (*((uint32_t *)color)) & 0x00ffffffu;
 | 
			
		||||
	else if (gop->Mode->Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor)
 | 
			
		||||
		for (int i = startX; i < endX; i++)
 | 
			
		||||
			for (int j = startY; j < endY; j++) {
 | 
			
		||||
				struct {
 | 
			
		||||
					uint8_t B, G, R;
 | 
			
		||||
					uint8_t A;
 | 
			
		||||
				} colorRGB = {color->B, color->G, color->R, 0};
 | 
			
		||||
 | 
			
		||||
				*((uint32_t *)(graphics_Framebuffer + modes[nativeMode].PixelsPerLine * 4 * j + 4 * i)) = (*((uint32_t *)&colorRGB));
 | 
			
		||||
			}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int graphics_CursorX, graphics_CursorY;
 | 
			
		||||
 | 
			
		||||
void graphics_Scroll(int scrollY) {
 | 
			
		||||
	memmove(
 | 
			
		||||
		graphics_Doublebuffer,
 | 
			
		||||
		graphics_Doublebuffer + modes[nativeMode].PixelsPerLine * scrollY,
 | 
			
		||||
		sizeof(uint32_t) * (modes[nativeMode].PixelsPerLine * (modes[nativeMode].Height - scrollY)));
 | 
			
		||||
	// TODO proper memset instead of this sloooow FillPixel
 | 
			
		||||
	/*memset(
 | 
			
		||||
		graphics_Doublebuffer + modes[nativeMode].PixelsPerLine * (modes[nativeMode].Height - scrollY),
 | 
			
		||||
		0,
 | 
			
		||||
		sizeof(uint32_t) * modes[nativeMode].PixelsPerLine * (scrollY));*/
 | 
			
		||||
	graphics_FillPixel(0, modes[nativeMode].Height - scrollY, modes[nativeMode].Width, modes[nativeMode].Height, &HelosGraphics_Color_Black);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void graphics_ElementSize(int sizeX, int sizeY) {
 | 
			
		||||
	if (graphics_CursorX + sizeX >= modes[nativeMode].Width) { // line breaking required
 | 
			
		||||
		graphics_CursorY += sizeY;
 | 
			
		||||
		graphics_CursorX = 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (graphics_CursorY + sizeY >= modes[nativeMode].Height) { // scrolling required
 | 
			
		||||
		graphics_Scroll(sizeY + graphics_CursorY - modes[nativeMode].Height);
 | 
			
		||||
		graphics_CursorY = modes[nativeMode].Height - sizeY;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void graphics_Newline(int advanceY) {
 | 
			
		||||
	graphics_CursorY += advanceY;
 | 
			
		||||
	graphics_CursorX = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void console_WriteChar(const HelosGraphics_Color *color, uint32_t c) {
 | 
			
		||||
	int width;
 | 
			
		||||
	switch (c) {
 | 
			
		||||
		case '\n':
 | 
			
		||||
			graphics_Newline(UNIFONT_CHAR_HEIGHT);
 | 
			
		||||
			break;
 | 
			
		||||
		case '\r':
 | 
			
		||||
			graphics_CursorX = 0;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			width = unifont_IsCharDoublewidth(c) ? UNIFONT_CHAR_WIDTH * 2 : UNIFONT_CHAR_WIDTH;
 | 
			
		||||
			graphics_ElementSize(width, UNIFONT_CHAR_HEIGHT);
 | 
			
		||||
			graphics_FillPixel(graphics_CursorX, graphics_CursorY, graphics_CursorX + width, graphics_CursorY + UNIFONT_CHAR_HEIGHT, &HelosGraphics_Color_Black);
 | 
			
		||||
			unifont_DrawChar(graphics_CursorX, graphics_CursorY, color, c);
 | 
			
		||||
			graphics_CursorX += width;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void console_Write(const HelosGraphics_Color *color, const uint32_t *str, int len) {
 | 
			
		||||
	bool wantSwap = false;
 | 
			
		||||
	if (len == 0) {
 | 
			
		||||
		while (*str != 0) {
 | 
			
		||||
			console_WriteChar(color, *str);
 | 
			
		||||
			if (*str == '\n')
 | 
			
		||||
				wantSwap = true;
 | 
			
		||||
			str++;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for (int i = 0; i < len; i++) {
 | 
			
		||||
			console_WriteChar(color, str[i]);
 | 
			
		||||
			if (str[i] == '\n')
 | 
			
		||||
				wantSwap = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (wantSwap)
 | 
			
		||||
		graphics_SwapBuffer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void console_WriteUTF16(const HelosGraphics_Color *color, const uint16_t *str, int len) {
 | 
			
		||||
	bool wantSwap = false;
 | 
			
		||||
	if (len == 0) {
 | 
			
		||||
		while (*str != 0) {
 | 
			
		||||
			console_WriteChar(color, *str);
 | 
			
		||||
			if (*str == '\n')
 | 
			
		||||
				wantSwap = true;
 | 
			
		||||
			str++;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for (int i = 0; i < len; i++) {
 | 
			
		||||
			console_WriteChar(color, str[i]);
 | 
			
		||||
			if (str[i] == '\n')
 | 
			
		||||
				wantSwap = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (wantSwap)
 | 
			
		||||
		graphics_SwapBuffer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void console_WriteASCII(const HelosGraphics_Color *color, const char *str, int len) {
 | 
			
		||||
	bool wantSwap = false;
 | 
			
		||||
	if (len == 0) {
 | 
			
		||||
		while (*str != 0) {
 | 
			
		||||
			console_WriteChar(color, *str);
 | 
			
		||||
			if (*str == '\n')
 | 
			
		||||
				wantSwap = true;
 | 
			
		||||
			str++;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for (int i = 0; i < len; i++) {
 | 
			
		||||
			console_WriteChar(color, str[i]);
 | 
			
		||||
			if (str[i] == '\n')
 | 
			
		||||
				wantSwap = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (wantSwap)
 | 
			
		||||
		graphics_SwapBuffer();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								graphics/graphics.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								graphics/graphics.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "../main.h"
 | 
			
		||||
#include "efiprot.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// This defines a default target display mode for graphics_Init().
 | 
			
		||||
#define HELOS_GRAPHICS_TARGET_MODE_WIDTH  1600
 | 
			
		||||
#define HELOS_GRAPHICS_TARGET_MODE_HEIGHT 900
 | 
			
		||||
 | 
			
		||||
// HelosGraphics_Color is in ARGB little-endian packed format
 | 
			
		||||
// (B,G,R,A in byte order)
 | 
			
		||||
typedef struct {
 | 
			
		||||
	uint8_t B, G, R;
 | 
			
		||||
	uint8_t A;
 | 
			
		||||
} PACKED HelosGraphics_Color;
 | 
			
		||||
 | 
			
		||||
extern const HelosGraphics_Color
 | 
			
		||||
	HelosGraphics_Color_Black,
 | 
			
		||||
	HelosGraphics_Color_White,
 | 
			
		||||
	HelosGraphics_Color_Red,
 | 
			
		||||
	HelosGraphics_Color_Green,
 | 
			
		||||
	HelosGraphics_Color_Blue,
 | 
			
		||||
	HelosGraphics_Color_Cyan,
 | 
			
		||||
	HelosGraphics_Color_Magenta,
 | 
			
		||||
	HelosGraphics_Color_Yellow;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	int Width, Height;
 | 
			
		||||
	int PixelsPerLine;
 | 
			
		||||
 | 
			
		||||
	EFI_GRAPHICS_PIXEL_FORMAT PixelFormat;
 | 
			
		||||
} HelosGraphics_Mode;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extern void *   graphics_DeviceFramebuffer; // this is the framebuffer directly for the device via memory mapping.
 | 
			
		||||
extern void *   graphics_Framebuffer;       // this is the double-buffered framebuffer (back buffer)
 | 
			
		||||
extern uint64_t graphics_FramebufferSize;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Init() must be called prior to ExitBootServices()
 | 
			
		||||
void graphics_Init();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// bitsPerPixel does not count the alpha bits, i.e., is 24 on most modern monitors
 | 
			
		||||
void graphics_GetSize(int *sizeX, int *sizeY, int *bitsPerPixel);
 | 
			
		||||
void graphics_ClearBuffer(const HelosGraphics_Color *color);
 | 
			
		||||
void graphics_SwapBuffer();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// graphics_SetPixel is set by Init() to match one of SetPixel_RGB/BGR according to the framebuffer format.
 | 
			
		||||
typedef void(graphics_SetPixel_Type)(int posX, int posY, const HelosGraphics_Color *color);
 | 
			
		||||
extern graphics_SetPixel_Type *graphics_SetPixel;
 | 
			
		||||
 | 
			
		||||
// graphics_SetPixel_RGB/BGR writes the given pixel to the framebuffer in RGB/BGR format.
 | 
			
		||||
void graphics_SetPixel_RGB(int posX, int posY, const HelosGraphics_Color *color);
 | 
			
		||||
void graphics_SetPixel_BGR(int posX, int posY, const HelosGraphics_Color *color);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void graphics_FillPixel(int startX, int startY, int endX, int endY, const HelosGraphics_Color *color);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extern int graphics_CursorX, graphics_CursorY;
 | 
			
		||||
 | 
			
		||||
// graphics_Scroll scrolls the display vertically by scrollY pixels.
 | 
			
		||||
void graphics_Scroll(int scrollY);
 | 
			
		||||
// graphics_ElementSize handles size of an graphics element: scrolling, line breaking, etc.
 | 
			
		||||
//
 | 
			
		||||
// It does not change CursorX/Y, however.
 | 
			
		||||
void graphics_ElementSize(int sizeX, int sizeY);
 | 
			
		||||
void graphics_Newline(int advanceY);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void console_WriteChar(const HelosGraphics_Color *color, uint32_t c);
 | 
			
		||||
void console_Write(const HelosGraphics_Color *color, const uint32_t *str, int len);
 | 
			
		||||
void console_WriteUTF16(const HelosGraphics_Color *color, const uint16_t *str, int len);
 | 
			
		||||
void console_WriteASCII(const HelosGraphics_Color *color, const char *str, int len);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
} // extern "C"
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										18
									
								
								graphics/test_unifont.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								graphics/test_unifont.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#include "Unifont.h"
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
	printf("Data at 0x%X\n\n", unifont_Data);
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < 64; i++) {
 | 
			
		||||
		printf("%02d(%02X):", i, i);
 | 
			
		||||
		for (int j = 0; j < 32; j++) {
 | 
			
		||||
			printf("%02X", (unsigned int)unifont_Data[i * 32 + j]);
 | 
			
		||||
		}
 | 
			
		||||
		printf("\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								graphics/unifont.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								graphics/unifont.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
 | 
			
		||||
#include "unifont.h"
 | 
			
		||||
#include "graphics.h"
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
size_t strlen(const char *);
 | 
			
		||||
 | 
			
		||||
void unifont_DrawChar(int posX, int posY, const HelosGraphics_Color *color, uint32_t codepoint) {
 | 
			
		||||
	const unsigned char *data = unifont_Data + codepoint * UNIFONT_CHAR_WIDTH * UNIFONT_CHAR_HEIGHT * 2 / 8;
 | 
			
		||||
	bool                 wide = unifont_IsCharDoublewidth(codepoint);
 | 
			
		||||
 | 
			
		||||
	int charWidth = UNIFONT_CHAR_WIDTH * (wide ? 2 : 1);
 | 
			
		||||
 | 
			
		||||
	for (int x = 0; x < charWidth; x++)
 | 
			
		||||
		for (int y = 0; y < UNIFONT_CHAR_HEIGHT; y++) {
 | 
			
		||||
			int pos = y * charWidth + x;
 | 
			
		||||
			if (data[pos / 8] & (1u << (7 - pos % 8)))
 | 
			
		||||
				graphics_SetPixel(posX + x, posY + y, color);
 | 
			
		||||
		}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void unifont_DrawString(int posX, int posY, const HelosGraphics_Color *color, const uint32_t *codepoints, int count) {
 | 
			
		||||
	for (const uint32_t *end = codepoints + count; codepoints != end; codepoints++) {
 | 
			
		||||
		unifont_DrawChar(posX, posY, color, *codepoints);
 | 
			
		||||
		posX += UNIFONT_CHAR_WIDTH * (unifont_IsCharDoublewidth(*codepoints) ? 2 : 1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
void unifont_DrawStringUTF16(int posX, int posY, const HelosGraphics_Color *color, const uint16_t *codepoints, int count) {
 | 
			
		||||
	for (const uint16_t *end = codepoints + count; codepoints != end; codepoints++) {
 | 
			
		||||
		unifont_DrawChar(posX, posY, color, *codepoints);
 | 
			
		||||
		posX += UNIFONT_CHAR_WIDTH * (unifont_IsCharDoublewidth(*codepoints) ? 2 : 1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
void unifont_DrawStringASCII(int posX, int posY, const HelosGraphics_Color *color, const char *codepoints, int count) {
 | 
			
		||||
	if (count == 0) {
 | 
			
		||||
		count = strlen(codepoints);
 | 
			
		||||
	}
 | 
			
		||||
	for (const char *end = codepoints + count; codepoints != end; codepoints++) {
 | 
			
		||||
		unifont_DrawChar(posX, posY, color, *codepoints);
 | 
			
		||||
		//posX += UNIFONT_CHAR_WIDTH * (unifont_IsCharDoublewidth(*codepoints) ? 2 : 1);
 | 
			
		||||
		posX += UNIFONT_CHAR_WIDTH; // visible ASCII chars are all single-width
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								graphics/unifont.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								graphics/unifont.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "../main.h"
 | 
			
		||||
#include "graphics.h"
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define UNIFONT_MAX_CHAR   (0xffff)
 | 
			
		||||
#define UNIFONT_CHAR_COUNT (0xffff + 1)
 | 
			
		||||
 | 
			
		||||
#define UNIFONT_CHAR_WIDTH  8
 | 
			
		||||
#define UNIFONT_CHAR_HEIGHT 16
 | 
			
		||||
 | 
			
		||||
extern const unsigned char unifont_Data[], unifont_Width[];
 | 
			
		||||
extern const unsigned char unifont_Data_End[], unifont_Width_End[]; // Past-the-end pointers for the data files
 | 
			
		||||
 | 
			
		||||
static inline bool unifont_IsCharDoublewidth(uint32_t codepoint) {
 | 
			
		||||
	const unsigned char *ptr = unifont_Width + codepoint / 8;
 | 
			
		||||
	if (ptr < unifont_Width_End)
 | 
			
		||||
		return (*ptr) & (1u << (7 - codepoint % 8));
 | 
			
		||||
	else
 | 
			
		||||
		return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void unifont_DrawChar(int posX, int posY, const HelosGraphics_Color *color, uint32_t codepoint);
 | 
			
		||||
void unifont_DrawString(int posX, int posY, const HelosGraphics_Color *color, const uint32_t *codepoints, int count);
 | 
			
		||||
void unifont_DrawStringUTF16(int posX, int posY, const HelosGraphics_Color *color, const uint16_t *codepoints, int count);
 | 
			
		||||
void unifont_DrawStringASCII(int posX, int posY, const HelosGraphics_Color *color, const char *codepoints, int count);
 | 
			
		||||
							
								
								
									
										71
									
								
								graphics/xcursor/xcursor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								graphics/xcursor/xcursor.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "../../main.h"
 | 
			
		||||
#include "../graphics.h"
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// XCursor file format - see man page xcursor(3)
 | 
			
		||||
// https://www.x.org/releases/X11R7.7/doc/man/man3/Xcursor.3.xhtml
 | 
			
		||||
 | 
			
		||||
// Header
 | 
			
		||||
typedef struct {
 | 
			
		||||
	char     magic[4];   // Magic string "Xcur"
 | 
			
		||||
	uint32_t headerSize; // Size of the header (16)
 | 
			
		||||
	uint32_t version;    // File version number
 | 
			
		||||
	uint32_t numTOC;     // Number of entries in the Table of Contents
 | 
			
		||||
} PACKED xcursor_Header;
 | 
			
		||||
 | 
			
		||||
// Table of Content Entry
 | 
			
		||||
typedef struct {
 | 
			
		||||
	uint32_t type;    // Entry chunk type (0xfffe0001 = Comment, 0xfffd0002 = Image)
 | 
			
		||||
	uint32_t subtype; // Type specific Subtype, size(width=height) for images
 | 
			
		||||
	uint32_t offset;  // Absolute byte position in the file
 | 
			
		||||
} PACKED xcursor_TOCEntry;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define XCURSOR_CHUNKTYPE_COMMENT 0xfffe0001u
 | 
			
		||||
#define XCURSOR_CHUNKTYPE_IMAGE   0xfffd0002u
 | 
			
		||||
 | 
			
		||||
// Common parts in different types of Chunk Headers
 | 
			
		||||
typedef struct {
 | 
			
		||||
	uint32_t headerSize; // Size of the header
 | 
			
		||||
	uint32_t type;       // Type of the Chunk, matches the Entry Type in the TOC
 | 
			
		||||
	uint32_t subtype;    // Type specific subtype
 | 
			
		||||
	uint32_t version;    // Version number of the chunk type
 | 
			
		||||
} PACKED xcursor_ChunkHeader;
 | 
			
		||||
 | 
			
		||||
#define XCURSOR_COMMENT_SUBTYPE_COPYRIGHT 0x00000001u
 | 
			
		||||
#define XCURSOR_COMMENT_SUBTYPE_LICENSE   0x00000002u
 | 
			
		||||
#define XCURSOR_COMMENT_SUBTYPE_OTHER     0x00000003u
 | 
			
		||||
 | 
			
		||||
// Chunk Header for type Comment
 | 
			
		||||
typedef struct {
 | 
			
		||||
	uint32_t headerSize; // Size of the header
 | 
			
		||||
	uint32_t type;       // Type of the Chunk, matches the Entry Type in the TOC
 | 
			
		||||
	uint32_t subtype;    // Type specific subtype, Copyright, License or Other
 | 
			
		||||
	uint32_t version;    // Version number of the chunk type, =1
 | 
			
		||||
 | 
			
		||||
	uint32_t length;    // Length in bytes of the UTF-8 string
 | 
			
		||||
	char     string[1]; // The UTF-8 string, spanning the rest of the chunk
 | 
			
		||||
} PACKED xcursor_ChunkHeader_Comment;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	uint32_t headerSize; // Size of the header
 | 
			
		||||
	uint32_t type;       // Type of the Chunk, matches the Entry Type in the TOC
 | 
			
		||||
	uint32_t subtype;    // Type specific subtype, Copyright, License or Other
 | 
			
		||||
	uint32_t version;    // Version number of the chunk type, =1
 | 
			
		||||
 | 
			
		||||
	uint32_t            width, height; // Width/Height, <=0x7fff
 | 
			
		||||
	uint32_t            xhot, yhot;    // X/Y hotpoint, <=Width/Height
 | 
			
		||||
	uint32_t            delay;         // Delay between animation frames in milliseconds
 | 
			
		||||
	HelosGraphics_Color pixels[1];     // Packed ARGB little-endian format pixels, with A at the highest byte (BGRA in byte order)
 | 
			
		||||
} PACKED xcursor_ChunkHeader_Image;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
		Reference in New Issue
	
	Block a user