diff options
Diffstat (limited to 'pui.c')
-rw-r--r-- | pui.c | 91 |
1 files changed, 91 insertions, 0 deletions
@@ -0,0 +1,91 @@ +/* + * Copyright (C) 2020 Mikhail Burakov. This file is part of Pui. + * + * Pui 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 3 of the License, or + * (at your option) any later version. + * + * Pui 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 Pui. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "pui.h" + +#include <assert.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +struct PuiHeader { + uint8_t w, h, scale, count; +}; + +struct PuiElement { + uint8_t x, y, w, h; +}; + +static_assert(sizeof(struct PuiHeader) == 4, "Invalid PuiHeader size"); +static_assert(sizeof(struct PuiElement) == 4, "Invalid PuiElement size"); + +int PuiGetWidth(const void* pui_data) { + const struct PuiHeader* pui_header = pui_data; + int sx = pui_header->scale >> 4; + return pui_header->w << sx; +} + +int PuiGetHeight(const void* pui_data) { + const struct PuiHeader* pui_header = pui_data; + int sy = pui_header->scale & 0xf; + return pui_header->h << sy; +} + +int PuiHitTest(const void* pui_data, int x, int y) { + int result = 0; + const struct PuiHeader* pui_header = pui_data; + x >>= pui_header->scale >> 4; + y >>= pui_header->scale & 0xf; + int count = pui_header->count >> 4; + for (int i = 0; i < count; ++i) { + const struct PuiElement* element = + (const struct PuiElement*)pui_data + 1 + i; + int hit = element->x <= x && x < element->x + element->w && + element->y <= y && y < element->y + element->h; + result |= hit << i; + } + return result; +} + +void PuiRender(const void* pui_data, void* buffer, int stride, int active) { + const struct PuiHeader* pui_header = pui_data; + int width = pui_header->w << (pui_header->scale >> 4); + int height = pui_header->h << (pui_header->scale & 0xf); + int elements = pui_header->count >> 4; + int colors = pui_header->count & 0xf; + const uint32_t* palettes[] = { + (const uint32_t*)pui_data + 1 + elements, + (const uint32_t*)pui_data + 1 + elements + colors, + }; + const uint8_t* bitmap_data = + (const uint8_t*)pui_data + 4 * (1 + elements + 2 * colors); + for (int idx = 0, counter = 0, offset = 0; offset < width * height; idx++) { + int value = bitmap_data[idx >> 1]; + if (~idx & 1) value = value >> 4; + if (value & 0x8) { + counter = counter << 3 | (value & 0x7); + continue; + } + for (counter = counter ? counter + 2 : 1; counter-- > 0; offset++) { + int x = offset % width; + int y = offset / width; + int palette = !!(PuiHitTest(pui_data, x, y) & active); + ((uint32_t*)buffer)[x + y * stride] = palettes[palette][value & 0x7]; + } + counter = 0; + } +} |