rendering improvements
This commit is contained in:
parent
789bb307d5
commit
7f46ac13fa
14 changed files with 296 additions and 179 deletions
|
|
@ -340,10 +340,12 @@ void Device::PointerListenerHandleMotion(void* data, wl_pointer* wl_pointer, std
|
||||||
if(element) {
|
if(element) {
|
||||||
if(Device::focusedWindow->currentMousePos.x >= element->scaled.position.x && Device::focusedWindow->currentMousePos.x <= element->scaled.position.x+element->scaled.size.x && Device::focusedWindow->currentMousePos.y > element->scaled.position.y && Device::focusedWindow->currentMousePos.y < element->scaled.position.y+element->scaled.size.y) {
|
if(Device::focusedWindow->currentMousePos.x >= element->scaled.position.x && Device::focusedWindow->currentMousePos.x <= element->scaled.position.x+element->scaled.size.x && Device::focusedWindow->currentMousePos.y > element->scaled.position.y && Device::focusedWindow->currentMousePos.y < element->scaled.position.y+element->scaled.size.y) {
|
||||||
element->onMouseMove.Invoke();
|
element->onMouseMove.Invoke();
|
||||||
if(!(Device::focusedWindow->lastMousePos.x >= element->scaled.position.x && Device::focusedWindow->lastMousePos.x <= element->scaled.position.x+element->scaled.size.x && Device::focusedWindow->lastMousePos.y > element->scaled.position.y && Device::focusedWindow->lastMousePos.y < element->scaled.position.y+element->scaled.size.y)) {
|
if(!element->mouseHover) {
|
||||||
|
element->mouseHover = true;
|
||||||
element->onMouseEnter.Invoke();
|
element->onMouseEnter.Invoke();
|
||||||
}
|
}
|
||||||
} else if(Device::focusedWindow->lastMousePos.x >= element->scaled.position.x && Device::focusedWindow->lastMousePos.x <= element->scaled.position.x+element->scaled.size.x && Device::focusedWindow->lastMousePos.y > element->scaled.position.y && Device::focusedWindow->lastMousePos.y < element->scaled.position.y+element->scaled.size.y) {
|
} else if(element->mouseHover) {
|
||||||
|
element->mouseHover = false;
|
||||||
element->onMouseLeave.Invoke();
|
element->onMouseLeave.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -352,8 +354,12 @@ void Device::PointerListenerHandleMotion(void* data, wl_pointer* wl_pointer, std
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::PointerListenerHandleEnter(void* data, wl_pointer* wl_pointer, std::uint32_t serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
void Device::PointerListenerHandleEnter(void* data, wl_pointer* wl_pointer, std::uint32_t serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
||||||
|
Device::wlPointer = wl_pointer;
|
||||||
for(Window* window : windows) {
|
for(Window* window : windows) {
|
||||||
if(window->surface == surface) {
|
if(window->surface == surface) {
|
||||||
|
if(window->cursorSurface != nullptr) {
|
||||||
|
wl_pointer_set_cursor(wl_pointer, serial, window->cursorSurface, 0, 0);
|
||||||
|
}
|
||||||
focusedWindow = window;
|
focusedWindow = window;
|
||||||
window->onMouseEnter.Invoke();
|
window->onMouseEnter.Invoke();
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ using namespace Crafter;
|
||||||
|
|
||||||
Font::Font(const std::filesystem::path& fontFilePath) {
|
Font::Font(const std::filesystem::path& fontFilePath) {
|
||||||
// 1. Load the font file into memory
|
// 1. Load the font file into memory
|
||||||
std::ifstream fontFile("inter.ttf", std::ios::binary | std::ios::ate);
|
std::ifstream fontFile(fontFilePath, std::ios::binary | std::ios::ate);
|
||||||
if (!fontFile.is_open()) {
|
if (!fontFile.is_open()) {
|
||||||
std::cerr << "Failed to open font file\n";
|
std::cerr << "Failed to open font file\n";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,6 @@ void GridElement::UpdatePositionScaled(RendertargetBase& window) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridElement::UpdatePosition(RendertargetBase& window) {
|
|
||||||
ScaleElement(window.transform);
|
|
||||||
UpdatePositionScaled(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GridElement::UpdatePosition(RendertargetBase& window, Transform2D& parent) {
|
void GridElement::UpdatePosition(RendertargetBase& window, Transform2D& parent) {
|
||||||
ScaleElement(parent);
|
ScaleElement(parent);
|
||||||
UpdatePositionScaled(window);
|
UpdatePositionScaled(window);
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@ module Crafter.Graphics:RenderingElement3D_impl;
|
||||||
import :RenderingElement3D;
|
import :RenderingElement3D;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
|
#ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN
|
||||||
using namespace Crafter;
|
using namespace Crafter;
|
||||||
|
|
||||||
#ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN
|
|
||||||
|
|
||||||
std::vector<RenderingElement3D*> RenderingElement3D::elements;
|
std::vector<RenderingElement3D*> RenderingElement3D::elements;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,6 @@ Transform2D::Transform2D(Anchor2D anchor) : anchor(anchor) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transform2D::UpdatePosition(RendertargetBase& window) {
|
|
||||||
ScaleElement(window.transform);
|
|
||||||
for(Transform2D* child : children) {
|
|
||||||
child->UpdatePosition(window, *this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Transform2D::UpdatePosition(RendertargetBase& window, Transform2D& parent) {
|
void Transform2D::UpdatePosition(RendertargetBase& window, Transform2D& parent) {
|
||||||
ScaleElement(parent);
|
ScaleElement(parent);
|
||||||
for(Transform2D* child : children) {
|
for(Transform2D* child : children) {
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,6 @@ using namespace Crafter;
|
||||||
|
|
||||||
|
|
||||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||||
#ifdef CRAFTER_GRAPHICS_RENDERER_SOFTWARE
|
|
||||||
void randname(char *buf) {
|
void randname(char *buf) {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
clock_gettime(CLOCK_REALTIME, &ts);
|
clock_gettime(CLOCK_REALTIME, &ts);
|
||||||
|
|
@ -113,7 +112,6 @@ int create_shm_file(off_t size) {
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WIN32
|
#ifdef CRAFTER_GRAPHICS_WINDOW_WIN32
|
||||||
CrafterKeys vk_to_crafter_key(WPARAM vk)
|
CrafterKeys vk_to_crafter_key(WPARAM vk)
|
||||||
|
|
@ -304,10 +302,12 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||||
if(element) {
|
if(element) {
|
||||||
if(window->currentMousePos.x >= element->scaled.position.x && window->currentMousePos.x <= element->scaled.position.x+element->scaled.size.x && window->currentMousePos.y > element->scaled.position.y && window->currentMousePos.y < element->scaled.position.y+element->scaled.size.y) {
|
if(window->currentMousePos.x >= element->scaled.position.x && window->currentMousePos.x <= element->scaled.position.x+element->scaled.size.x && window->currentMousePos.y > element->scaled.position.y && window->currentMousePos.y < element->scaled.position.y+element->scaled.size.y) {
|
||||||
element->onMouseMove.Invoke();
|
element->onMouseMove.Invoke();
|
||||||
if(!(window->lastMousePos.x >= element->scaled.position.x && window->lastMousePos.x <= element->scaled.position.x+element->scaled.size.x && window->lastMousePos.y > element->scaled.position.y && window->lastMousePos.y < element->scaled.position.y+element->scaled.size.y)) {
|
if(!element->mouseHover) {
|
||||||
|
element->mouseHover = true;
|
||||||
element->onMouseEnter.Invoke();
|
element->onMouseEnter.Invoke();
|
||||||
}
|
}
|
||||||
} else if(window->lastMousePos.x >= element->scaled.position.x && window->lastMousePos.x <= element->scaled.position.x+element->scaled.size.x && window->lastMousePos.y > element->scaled.position.y && window->lastMousePos.y < element->scaled.position.y+element->scaled.size.y) {
|
} else if(element->mouseHover) {
|
||||||
|
element->mouseHover = false
|
||||||
element->onMouseLeave.Invoke();
|
element->onMouseLeave.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -380,7 +380,7 @@ Window::Window(std::uint32_t width, std::uint32_t height, const std::string_view
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CRAFTER_GRAPHICS_RENDERER_SOFTWARE
|
#ifdef CRAFTER_GRAPHICS_RENDERER_SOFTWARE
|
||||||
Window::Window(std::uint32_t width, std::uint32_t height) : width(width), height(height) : Rendertarget(width, height) {
|
Window::Window(std::uint32_t width, std::uint32_t height) : width(width), height(height), renderer(width, height) {
|
||||||
#else
|
#else
|
||||||
Window::Window(std::uint32_t width, std::uint32_t height) : width(width), height(height) {
|
Window::Window(std::uint32_t width, std::uint32_t height) : width(width), height(height) {
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -420,9 +420,7 @@ Window::Window(std::uint32_t width, std::uint32_t height) : width(width), height
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map the shared memory file
|
// Map the shared memory file
|
||||||
renderer.buffer = reinterpret_cast<Vector<std::uint8_t, 4>*>(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
renderer.buffer = reinterpret_cast<Vector<std::uint8_t, 4, 4>*>(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||||
renderer.sizeX = width;
|
|
||||||
renderer.sizeY = height;
|
|
||||||
if (renderer.buffer == MAP_FAILED) {
|
if (renderer.buffer == MAP_FAILED) {
|
||||||
throw std::runtime_error("mmap failed");
|
throw std::runtime_error("mmap failed");
|
||||||
}
|
}
|
||||||
|
|
@ -563,6 +561,61 @@ void Window::SetTitle(const std::string_view title) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::SetCusorImage(std::uint16_t sizeX, std::uint16_t sizeY) {
|
||||||
|
new (&cursorRenderer) Rendertarget<std::uint8_t, 4, 4>(sizeX, sizeY);
|
||||||
|
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||||
|
if(cursorSurface == nullptr) {
|
||||||
|
cursorSurface = wl_compositor_create_surface(Device::compositor);
|
||||||
|
} else {
|
||||||
|
wl_buffer_destroy(cursorWlBuffer);
|
||||||
|
munmap(cursorRenderer.buffer, cursorBufferOldSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int stride = sizeX * 4;
|
||||||
|
int size = stride * sizeY;
|
||||||
|
cursorBufferOldSize = size;
|
||||||
|
|
||||||
|
// Allocate a shared memory file with the right size
|
||||||
|
int fd = create_shm_file(size);
|
||||||
|
if (fd < 0) {
|
||||||
|
throw std::runtime_error(std::format("creating a buffer file for {}B failed", size));
|
||||||
|
}
|
||||||
|
|
||||||
|
cursorRenderer.buffer = reinterpret_cast<Vector<std::uint8_t, 4, 4>*>(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||||
|
if (cursorRenderer.buffer == MAP_FAILED) {
|
||||||
|
throw std::runtime_error("mmap failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_shm_pool *pool = wl_shm_create_pool(Device::shm, fd, size);
|
||||||
|
cursorWlBuffer = wl_shm_pool_create_buffer(pool, 0, sizeX, sizeY, stride, WL_SHM_FORMAT_ARGB8888);
|
||||||
|
wl_shm_pool_destroy(pool);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
wl_surface_attach(cursorSurface, cursorWlBuffer, 0, 0);
|
||||||
|
wl_surface_damage(cursorSurface, 0, 0, sizeX, sizeY);
|
||||||
|
wl_surface_commit(cursorSurface);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::SetCusorImageDefault() {
|
||||||
|
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||||
|
wl_buffer_destroy(cursorWlBuffer);
|
||||||
|
wl_surface_destroy(cursorSurface);
|
||||||
|
cursorSurface = nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::UpdateCursorImage() {
|
||||||
|
cursorRenderer.Render();
|
||||||
|
for(std::uint32_t i = 0; i < cursorBufferOldSize / 4; i++) {
|
||||||
|
std::swap(cursorRenderer.buffer[i].b, cursorRenderer.buffer[i].r);
|
||||||
|
}
|
||||||
|
wl_surface_attach(cursorSurface, cursorWlBuffer, 0, 0);
|
||||||
|
wl_surface_damage(cursorSurface, 0, 0, 9999999, 99999999);
|
||||||
|
wl_surface_commit(cursorSurface);
|
||||||
|
}
|
||||||
|
|
||||||
void Window::StartSync() {
|
void Window::StartSync() {
|
||||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||||
while (open && wl_display_dispatch(Device::display) != -1) {
|
while (open && wl_display_dispatch(Device::display) != -1) {
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ export namespace Crafter {
|
||||||
inline static xkb_context* xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
inline static xkb_context* xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||||
inline static xkb_state* xkb_state;
|
inline static xkb_state* xkb_state;
|
||||||
inline static std::vector<Window*> windows;
|
inline static std::vector<Window*> windows;
|
||||||
|
inline static wl_pointer* wlPointer;
|
||||||
|
|
||||||
static void seat_handle_capabilities(void* data, wl_seat* seat, uint32_t capabilities);
|
static void seat_handle_capabilities(void* data, wl_seat* seat, uint32_t capabilities);
|
||||||
static void xdg_surface_handle_preferred_scale(void* data, wp_fractional_scale_v1*, std::uint32_t scale);
|
static void xdg_surface_handle_preferred_scale(void* data, wp_fractional_scale_v1*, std::uint32_t scale);
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ export namespace Crafter {
|
||||||
std::int32_t paddingY;
|
std::int32_t paddingY;
|
||||||
GridElement(std::uint32_t columns, std::uint32_t rows, std::int32_t spacingX, std::int32_t spacingY, std::int32_t paddingX, std::int32_t paddingY, Anchor2D anchor);
|
GridElement(std::uint32_t columns, std::uint32_t rows, std::int32_t spacingX, std::int32_t spacingY, std::int32_t paddingX, std::int32_t paddingY, Anchor2D anchor);
|
||||||
void UpdatePositionScaled(RendertargetBase& window);
|
void UpdatePositionScaled(RendertargetBase& window);
|
||||||
void UpdatePosition(RendertargetBase& window) override;
|
|
||||||
void UpdatePosition(RendertargetBase& window, Transform2D& parent) override;
|
void UpdatePosition(RendertargetBase& window, Transform2D& parent) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -35,6 +35,7 @@ export namespace Crafter {
|
||||||
Event<void> onMouseLeftHold;
|
Event<void> onMouseLeftHold;
|
||||||
Event<void> onMouseRightRelease;
|
Event<void> onMouseRightRelease;
|
||||||
Event<void> onMouseLeftRelease;
|
Event<void> onMouseLeftRelease;
|
||||||
|
bool mouseHover = false;
|
||||||
|
|
||||||
MouseElement();
|
MouseElement();
|
||||||
MouseElement(Window& window);
|
MouseElement(Window& window);
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ import :Types;
|
||||||
import :Window;
|
import :Window;
|
||||||
|
|
||||||
export namespace Crafter {
|
export namespace Crafter {
|
||||||
template<bool Scaling, bool Owning, bool Rotating> requires ((!Rotating || Scaling) && (!Owning || Scaling))
|
template<bool Scaling, bool Owning, bool Rotating, std::uint8_t Alignment = 0> requires ((!Rotating || Scaling) && (!Owning || Scaling))
|
||||||
struct RenderingElement2D : RenderingElement2DBase, ScalingBase<Scaling, Owning>, RotatingBase<Rotating> {
|
struct RenderingElement2D : RenderingElement2DBase, ScalingBase<Scaling, Owning, Alignment>, RotatingBase<Rotating> {
|
||||||
RenderingElement2D() = default;
|
RenderingElement2D() = default;
|
||||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque) : RenderingElement2DBase(anchor, opaque) {
|
RenderingElement2D(Anchor2D anchor, OpaqueType opaque) : RenderingElement2DBase(anchor, opaque) {
|
||||||
|
|
||||||
|
|
@ -38,22 +38,22 @@ export namespace Crafter {
|
||||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t rotation) requires(Rotating) : RenderingElement2DBase(anchor, opaque), RotatingBase<Rotating>(rotation) {
|
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t rotation) requires(Rotating) : RenderingElement2DBase(anchor, opaque), RotatingBase<Rotating>(rotation) {
|
||||||
|
|
||||||
}
|
}
|
||||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4>* scalingBuffer) requires(Scaling && !Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning>(bufferWidth, bufferHeight, scalingBuffer) {
|
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4, Alignment>* scalingBuffer) requires(Scaling && !Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight, scalingBuffer) {
|
||||||
|
|
||||||
}
|
}
|
||||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4>* scalingBuffer, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning>(bufferWidth, bufferHeight, scalingBuffer), RotatingBase<Rotating>(rotation) {
|
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4, Alignment>* scalingBuffer, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight, scalingBuffer), RotatingBase<Rotating>(rotation) {
|
||||||
|
|
||||||
}
|
}
|
||||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight) requires(Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning>(bufferWidth, bufferHeight) {
|
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight) requires(Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight) {
|
||||||
|
|
||||||
}
|
}
|
||||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, std::uint32_t rotation) requires(Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning>(bufferWidth, bufferHeight) , RotatingBase<Rotating>(rotation) {
|
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, std::uint32_t rotation) requires(Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight) , RotatingBase<Rotating>(rotation) {
|
||||||
|
|
||||||
}
|
}
|
||||||
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4>> texture) requires(!Owning && Scaling) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase<Scaling, Owning>(texture.sizeX, texture.sizeY, texture.pixels) {
|
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4, Alignment>>& texture) requires(!Owning && Scaling) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase<Scaling, Owning, Alignment>(texture.pixels.data(), texture.sizeX, texture.sizeY) {
|
||||||
|
|
||||||
}
|
}
|
||||||
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4>> texture, std::uint32_t rotation) requires(!Owning && Scaling && Rotating) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase<Scaling, Owning>(texture.sizeX, texture.sizeY, texture.pixels), RotatingBase<Rotating>(rotation) {
|
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4, Alignment>>& texture, std::uint32_t rotation) requires(!Owning && Scaling && Rotating) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase<Scaling, Owning, Alignment>(texture.pixels.data(), texture.sizeX, texture.sizeY), RotatingBase<Rotating>(rotation) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,10 +62,10 @@ export namespace Crafter {
|
||||||
|
|
||||||
void ScaleNearestNeighbor() requires(Scaling) {
|
void ScaleNearestNeighbor() requires(Scaling) {
|
||||||
for (std::uint32_t y = 0; y < scaled.size.y; y++) {
|
for (std::uint32_t y = 0; y < scaled.size.y; y++) {
|
||||||
std::uint32_t srcY = y * ScalingBase<true, Owning>::bufferHeight / scaled.size.y;
|
std::uint32_t srcY = y * ScalingBase<true, Owning, Alignment>::bufferHeight / scaled.size.y;
|
||||||
for (std::uint32_t x = 0; x < scaled.size.x; x++) {
|
for (std::uint32_t x = 0; x < scaled.size.x; x++) {
|
||||||
std::uint32_t srcX = x * ScalingBase<true, Owning>::bufferWidth / scaled.size.x;
|
std::uint32_t srcX = x * ScalingBase<true, Owning, Alignment>::bufferWidth / scaled.size.x;
|
||||||
buffer[y * scaled.size.x + x] = ScalingBase<true, Owning>::scalingBuffer[srcY * ScalingBase<true, Owning>::bufferWidth + srcX];
|
buffer[y * scaled.size.x + x] = ScalingBase<true, Owning, Alignment>::scalingBuffer[srcY * ScalingBase<true, Owning, Alignment>::bufferWidth + srcX];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -97,15 +97,15 @@ export namespace Crafter {
|
||||||
const float dstCy = (static_cast<float>(scaled.size.y) - 1.0) * 0.5;
|
const float dstCy = (static_cast<float>(scaled.size.y) - 1.0) * 0.5;
|
||||||
|
|
||||||
// Source center
|
// Source center
|
||||||
const float srcCx = (static_cast<float>(ScalingBase<true, Owning>::bufferWidth) - 1.0) * 0.5;
|
const float srcCx = (static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferWidth) - 1.0) * 0.5;
|
||||||
const float srcCy = (static_cast<float>(ScalingBase<true, Owning>::bufferHeight) - 1.0) * 0.5;
|
const float srcCy = (static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferHeight) - 1.0) * 0.5;
|
||||||
|
|
||||||
const float c = std::cos(RotatingBase<true>::rotation);
|
const float c = std::cos(RotatingBase<true>::rotation);
|
||||||
const float s = std::sin(RotatingBase<true>::rotation);
|
const float s = std::sin(RotatingBase<true>::rotation);
|
||||||
|
|
||||||
// Scale factors (destination → source)
|
// Scale factors (destination → source)
|
||||||
const float scaleX = static_cast<float>(ScalingBase<true, Owning>::bufferWidth) / dstWidth;
|
const float scaleX = static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferWidth) / dstWidth;
|
||||||
const float scaleY = static_cast<float>(ScalingBase<true, Owning>::bufferHeight) / dstHeight;
|
const float scaleY = static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferHeight) / dstHeight;
|
||||||
|
|
||||||
for (std::uint32_t yB = 0; yB < scaled.size.y; ++yB) {
|
for (std::uint32_t yB = 0; yB < scaled.size.y; ++yB) {
|
||||||
for (std::uint32_t xB = 0; xB < scaled.size.x; ++xB) {
|
for (std::uint32_t xB = 0; xB < scaled.size.x; ++xB) {
|
||||||
|
|
@ -122,8 +122,8 @@ export namespace Crafter {
|
||||||
const std::int32_t srcX = static_cast<std::int32_t>(std::round(sx));
|
const std::int32_t srcX = static_cast<std::int32_t>(std::round(sx));
|
||||||
const std::int32_t srcY = static_cast<std::int32_t>(std::round(sy));
|
const std::int32_t srcY = static_cast<std::int32_t>(std::round(sy));
|
||||||
|
|
||||||
if (srcX >= 0 && srcX < ScalingBase<true, Owning>::bufferWidth && srcY >= 0 && srcY < ScalingBase<true, Owning>::bufferHeight) {
|
if (srcX >= 0 && srcX < ScalingBase<true, Owning, Alignment>::bufferWidth && srcY >= 0 && srcY < ScalingBase<true, Owning, Alignment>::bufferHeight) {
|
||||||
buffer[yB * scaled.size.x + xB] = ScalingBase<true, Owning>::scalingBuffer[srcY * ScalingBase<true, Owning>::bufferWidth + srcX];
|
buffer[yB * scaled.size.x + xB] = ScalingBase<true, Owning, Alignment>::scalingBuffer[srcY * ScalingBase<true, Owning, Alignment>::bufferWidth + srcX];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -139,13 +139,14 @@ export namespace Crafter {
|
||||||
} else if(oldScale.position.x != scaled.position.x || oldScale.position.y != scaled.position.y) {
|
} else if(oldScale.position.x != scaled.position.x || oldScale.position.y != scaled.position.y) {
|
||||||
renderer.AddDirtyRect(oldScale);
|
renderer.AddDirtyRect(oldScale);
|
||||||
renderer.AddDirtyRect(scaled);
|
renderer.AddDirtyRect(scaled);
|
||||||
if(ScalingBase<true, Owning>::bufferUpdated) {
|
if(ScalingBase<true, Owning, Alignment>::bufferUpdated) {
|
||||||
ScaleNearestNeighbor();
|
ScaleNearestNeighbor();
|
||||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||||
}
|
}
|
||||||
} else if(ScalingBase<true, Owning>::bufferUpdated) {
|
} else if(ScalingBase<true, Owning, Alignment>::bufferUpdated) {
|
||||||
ScaleNearestNeighbor();
|
ScaleNearestNeighbor();
|
||||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||||
|
renderer.AddDirtyRect(scaled);
|
||||||
}
|
}
|
||||||
} else if constexpr(Rotating) {
|
} else if constexpr(Rotating) {
|
||||||
if(oldScale.size.x != scaled.size.x || oldScale.size.y != scaled.size.y) {
|
if(oldScale.size.x != scaled.size.x || oldScale.size.y != scaled.size.y) {
|
||||||
|
|
@ -156,15 +157,16 @@ export namespace Crafter {
|
||||||
} else if(oldScale.position.x != scaled.position.x || oldScale.position.y != scaled.position.y) {
|
} else if(oldScale.position.x != scaled.position.x || oldScale.position.y != scaled.position.y) {
|
||||||
renderer.AddDirtyRect(oldScale);
|
renderer.AddDirtyRect(oldScale);
|
||||||
renderer.AddDirtyRect(scaled);
|
renderer.AddDirtyRect(scaled);
|
||||||
if(ScalingBase<true, Owning>::bufferUpdated || RotatingBase<true>::rotationUpdated) {
|
if(ScalingBase<true, Owning, Alignment>::bufferUpdated || RotatingBase<true>::rotationUpdated) {
|
||||||
ScaleRotating();
|
ScaleRotating();
|
||||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||||
RotatingBase<true>::rotationUpdated = false;
|
RotatingBase<true>::rotationUpdated = false;
|
||||||
}
|
}
|
||||||
} else if(ScalingBase<true, Owning>::bufferUpdated || RotatingBase<true>::rotationUpdated) {
|
} else if(ScalingBase<true, Owning, Alignment>::bufferUpdated || RotatingBase<true>::rotationUpdated) {
|
||||||
ScaleRotating();
|
ScaleRotating();
|
||||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||||
RotatingBase<true>::rotationUpdated = false;
|
RotatingBase<true>::rotationUpdated = false;
|
||||||
|
renderer.AddDirtyRect(scaled);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(oldScale.size.x != scaled.size.x || oldScale.size.y != scaled.size.y) {
|
if(oldScale.size.x != scaled.size.x || oldScale.size.y != scaled.size.y) {
|
||||||
|
|
@ -179,15 +181,6 @@ export namespace Crafter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdatePosition(RendertargetBase& window) override {
|
|
||||||
ScaleData2D oldScale = scaled;
|
|
||||||
ScaleElement(window.transform);
|
|
||||||
UpdatePosition(window, oldScale);
|
|
||||||
for(Transform2D* child : children) {
|
|
||||||
child->UpdatePosition(window, *this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdatePosition(RendertargetBase& window, Transform2D& parent) override {
|
void UpdatePosition(RendertargetBase& window, Transform2D& parent) override {
|
||||||
ScaleData2D oldScale = scaled;
|
ScaleData2D oldScale = scaled;
|
||||||
ScaleElement(parent);
|
ScaleElement(parent);
|
||||||
|
|
@ -197,7 +190,7 @@ export namespace Crafter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string_view> ResizeText(Window& window, const std::string_view text, float size, Font& font, TextOverflowMode overflowMode = TextOverflowMode::Clip, TextScaleMode scaleMode = TextScaleMode::None, Transform2D* parent = nullptr) {
|
std::vector<std::string_view> ResizeText(RendertargetBase& window, Transform2D& parent, const std::string_view text, float& size, Font& font, TextOverflowMode overflowMode = TextOverflowMode::Clip, TextScaleMode scaleMode = TextScaleMode::None) {
|
||||||
float scale = stbtt_ScaleForPixelHeight(&font.font, size);
|
float scale = stbtt_ScaleForPixelHeight(&font.font, size);
|
||||||
int baseline = (int)(font.ascent * scale);
|
int baseline = (int)(font.ascent * scale);
|
||||||
|
|
||||||
|
|
@ -241,14 +234,16 @@ export namespace Crafter {
|
||||||
anchor.height = lineHeight * logicalPerPixelY;
|
anchor.height = lineHeight * logicalPerPixelY;
|
||||||
anchor.width = maxWidth * logicalPerPixelX;
|
anchor.width = maxWidth * logicalPerPixelX;
|
||||||
if(oldHeight != anchor.height || oldwidth != anchor.width) {
|
if(oldHeight != anchor.height || oldwidth != anchor.width) {
|
||||||
if(parent) {
|
UpdatePosition(window, parent);
|
||||||
UpdatePosition(window, *parent);
|
|
||||||
} else {
|
|
||||||
UpdatePosition(window);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if(scaleMode == TextScaleMode::Font) {
|
} else if(scaleMode == TextScaleMode::Font) {
|
||||||
//todo
|
float lineHeightPerFont = lineHeight / size;
|
||||||
|
float lineWidthPerFont = maxWidth / size;
|
||||||
|
|
||||||
|
float maxFontHeight = scaled.size.y / lineHeightPerFont;
|
||||||
|
float maxFontWidth = scaled.size.x / lineWidthPerFont;
|
||||||
|
|
||||||
|
size = std::min(maxFontHeight, maxFontWidth);
|
||||||
} else if(scaleMode == TextScaleMode::Buffer) {
|
} else if(scaleMode == TextScaleMode::Buffer) {
|
||||||
if constexpr(Scaling && Owning) {
|
if constexpr(Scaling && Owning) {
|
||||||
std::uint32_t neededHeight = lines.size() * lineHeight;
|
std::uint32_t neededHeight = lines.size() * lineHeight;
|
||||||
|
|
@ -256,12 +251,12 @@ export namespace Crafter {
|
||||||
ScalingBase<true, true>::bufferHeight = neededHeight;
|
ScalingBase<true, true>::bufferHeight = neededHeight;
|
||||||
ScalingBase<true, true>::bufferWidth = maxWidth;
|
ScalingBase<true, true>::bufferWidth = maxWidth;
|
||||||
ScalingBase<true, true>::bufferUpdated = true;
|
ScalingBase<true, true>::bufferUpdated = true;
|
||||||
ScalingBase<true, Owning>::scalingBuffer.resize(neededHeight*maxWidth);
|
ScalingBase<true, Owning, Alignment>::scalingBuffer.resize(neededHeight*maxWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if constexpr(Scaling) {
|
if constexpr(Scaling) {
|
||||||
lines.resize(ScalingBase<true, Owning>::bufferHeight / lines.size());
|
lines.resize(ScalingBase<true, Owning, Alignment>::bufferHeight / lines.size());
|
||||||
} else {
|
} else {
|
||||||
lines.resize(scaled.size.y / lines.size());
|
lines.resize(scaled.size.y / lines.size());
|
||||||
}
|
}
|
||||||
|
|
@ -330,26 +325,23 @@ export namespace Crafter {
|
||||||
float oldHeight = anchor.height;
|
float oldHeight = anchor.height;
|
||||||
anchor.height = lineHeight * logicalPerPixelY;
|
anchor.height = lineHeight * logicalPerPixelY;
|
||||||
if(oldHeight != anchor.height) {
|
if(oldHeight != anchor.height) {
|
||||||
if(parent) {
|
UpdatePosition(window, parent);
|
||||||
UpdatePosition(window, *parent);
|
|
||||||
} else {
|
|
||||||
UpdatePosition(window);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if(scaleMode == TextScaleMode::Font) {
|
} else if(scaleMode == TextScaleMode::Font) {
|
||||||
//todo
|
float lineHeightPerFont = lineHeight / size;
|
||||||
|
size = scaled.size.y / lineHeightPerFont;
|
||||||
} else if(scaleMode == TextScaleMode::Buffer) {
|
} else if(scaleMode == TextScaleMode::Buffer) {
|
||||||
if constexpr(Scaling && Owning) {
|
if constexpr(Scaling && Owning) {
|
||||||
float neededHeight = lines.size() * lineHeight;
|
float neededHeight = lines.size() * lineHeight;
|
||||||
if(neededHeight != ScalingBase<true, true>::bufferHeight) {
|
if(neededHeight != ScalingBase<true, true>::bufferHeight) {
|
||||||
ScalingBase<true, true>::bufferHeight = neededHeight;
|
ScalingBase<true, true>::bufferHeight = neededHeight;
|
||||||
ScalingBase<true, true>::bufferUpdated = true;
|
ScalingBase<true, true>::bufferUpdated = true;
|
||||||
ScalingBase<true, Owning>::scalingBuffer.resize(neededHeight*ScalingBase<true, true>::bufferWidth);
|
ScalingBase<true, Owning, Alignment>::scalingBuffer.resize(neededHeight*ScalingBase<true, true>::bufferWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if constexpr(Scaling) {
|
if constexpr(Scaling) {
|
||||||
lines.resize(ScalingBase<true, Owning>::bufferHeight / lines.size());
|
lines.resize(ScalingBase<true, Owning, Alignment>::bufferHeight / lines.size());
|
||||||
} else {
|
} else {
|
||||||
lines.resize(scaled.size.y / lines.size());
|
lines.resize(scaled.size.y / lines.size());
|
||||||
}
|
}
|
||||||
|
|
@ -358,7 +350,7 @@ export namespace Crafter {
|
||||||
|
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
void RenderText(Window& window, std::span<const std::string_view> lines, float size, Vector<std::uint8_t, 4> color, Font& font, TextAlignment alignment = TextAlignment::Left, std::uint32_t offsetX = 0, std::uint32_t offsetY = 0) {
|
void RenderText(std::span<const std::string_view> lines, float size, Vector<std::uint8_t, 4> color, Font& font, TextAlignment alignment = TextAlignment::Left, std::uint32_t offsetX = 0, std::uint32_t offsetY = 0, OpaqueType opaque = OpaqueType::FullyOpaque) {
|
||||||
float scale = stbtt_ScaleForPixelHeight(&font.font, size);
|
float scale = stbtt_ScaleForPixelHeight(&font.font, size);
|
||||||
int baseline = (int)(font.ascent * scale);
|
int baseline = (int)(font.ascent * scale);
|
||||||
std::uint32_t lineHeight = (font.ascent - font.descent) * scale;
|
std::uint32_t lineHeight = (font.ascent - font.descent) * scale;
|
||||||
|
|
@ -372,19 +364,18 @@ export namespace Crafter {
|
||||||
lineWidth += (int)(advance * scale);
|
lineWidth += (int)(advance * scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t startX = 0;
|
std::uint32_t x = 0;
|
||||||
switch (alignment) {
|
switch (alignment) {
|
||||||
case TextAlignment::Left:
|
case TextAlignment::Left:
|
||||||
startX = 0;
|
x = 0;
|
||||||
break;
|
break;
|
||||||
case TextAlignment::Center:
|
case TextAlignment::Center:
|
||||||
startX = (scaled.size.x - lineWidth) / 2;
|
x = (scaled.size.x - lineWidth) / 2;
|
||||||
break;
|
break;
|
||||||
case TextAlignment::Right:
|
case TextAlignment::Right:
|
||||||
startX = scaled.size.x - lineWidth;
|
x = scaled.size.x - lineWidth;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::uint32_t x = startX;
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < line.size(); ++i) {
|
for (std::size_t i = 0; i < line.size(); ++i) {
|
||||||
int codepoint = line[i];
|
int codepoint = line[i];
|
||||||
|
|
@ -403,6 +394,8 @@ export namespace Crafter {
|
||||||
stbtt_MakeCodepointBitmap(&font.font, bitmap.data(), w, h, w, scale, scale, codepoint);
|
stbtt_MakeCodepointBitmap(&font.font, bitmap.data(), w, h, w, scale, scale, codepoint);
|
||||||
|
|
||||||
// Only render characters that fit within the scaled bounds
|
// Only render characters that fit within the scaled bounds
|
||||||
|
switch(opaque) {
|
||||||
|
case OpaqueType::FullyOpaque: {
|
||||||
for (int j = 0; j < h; j++) {
|
for (int j = 0; j < h; j++) {
|
||||||
for (int i = 0; i < w; i++) {
|
for (int i = 0; i < w; i++) {
|
||||||
int bufferX = x + i + c_x1 + offsetX;
|
int bufferX = x + i + c_x1 + offsetX;
|
||||||
|
|
@ -410,8 +403,8 @@ export namespace Crafter {
|
||||||
|
|
||||||
// Only draw pixels that are within our scaled buffer bounds
|
// Only draw pixels that are within our scaled buffer bounds
|
||||||
if constexpr(Scaling) {
|
if constexpr(Scaling) {
|
||||||
if (bufferX >= 0 && bufferX < ScalingBase<true, Owning>::bufferWidth && bufferY >= 0 && bufferY < ScalingBase<true, Owning>::bufferHeight) {
|
if (bufferX >= 0 && bufferX < ScalingBase<true, Owning, Alignment>::bufferWidth && bufferY >= 0 && bufferY < ScalingBase<true, Owning, Alignment>::bufferHeight) {
|
||||||
ScalingBase<true, Owning>::scalingBuffer[bufferY * ScalingBase<true, Owning>::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
ScalingBase<true, Owning, Alignment>::scalingBuffer[bufferY * ScalingBase<true, Owning, Alignment>::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bufferX >= 0 && bufferX < (int)scaled.size.x && bufferY >= 0 && bufferY < (int)scaled.size.y) {
|
if (bufferX >= 0 && bufferX < (int)scaled.size.x && bufferY >= 0 && bufferY < (int)scaled.size.y) {
|
||||||
|
|
@ -420,11 +413,74 @@ export namespace Crafter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpaqueType::SemiOpaque: {
|
||||||
|
for (int j = 0; j < h; j++) {
|
||||||
|
for (int i = 0; i < w; i++) {
|
||||||
|
int bufferX = x + i + c_x1 + offsetX;
|
||||||
|
int bufferY = currentY + j + c_y1 + offsetY;
|
||||||
|
|
||||||
|
// Only draw pixels that are within our scaled buffer bounds
|
||||||
|
if constexpr(Scaling) {
|
||||||
|
if (bufferX >= 0 && bufferX < ScalingBase<true, Owning, Alignment>::bufferWidth && bufferY >= 0 && bufferY < ScalingBase<true, Owning, Alignment>::bufferHeight) {
|
||||||
|
ScalingBase<true, Owning, Alignment>::scalingBuffer[bufferY * ScalingBase<true, Owning, Alignment>::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (bufferX >= 0 && bufferX < (int)scaled.size.x && bufferY >= 0 && bufferY < (int)scaled.size.y) {
|
||||||
|
std::uint8_t alpha = bitmap[j * w + i];
|
||||||
|
if(alpha != 0) {
|
||||||
|
buffer[bufferY * scaled.size.x + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpaqueType::Transparent: {
|
||||||
|
for (int j = 0; j < h; j++) {
|
||||||
|
for (int i = 0; i < w; i++) {
|
||||||
|
int bufferX = x + i + c_x1 + offsetX;
|
||||||
|
int bufferY = currentY + j + c_y1 + offsetY;
|
||||||
|
|
||||||
|
// Only draw pixels that are within our scaled buffer bounds
|
||||||
|
if constexpr(Scaling) {
|
||||||
|
if (bufferX >= 0 && bufferX < ScalingBase<true, Owning, Alignment>::bufferWidth && bufferY >= 0 && bufferY < ScalingBase<true, Owning, Alignment>::bufferHeight) {
|
||||||
|
ScalingBase<true, Owning, Alignment>::scalingBuffer[bufferY * ScalingBase<true, Owning, Alignment>::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (bufferX >= 0 && bufferX < (int)scaled.size.x && bufferY >= 0 && bufferY < (int)scaled.size.y) {
|
||||||
|
std::uint8_t alpha = bitmap[j * w + i];
|
||||||
|
|
||||||
|
if(alpha == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<std::uint8_t, 4, Alignment> dst = buffer[bufferY * scaled.size.x + bufferX];
|
||||||
|
|
||||||
|
float srcA = (alpha / 255.0f) * (color.a / 255.0f);
|
||||||
|
float dstA = dst.a / 255.0f;
|
||||||
|
|
||||||
|
float outA = srcA + dstA * (1.0f - srcA);
|
||||||
|
buffer[bufferY * scaled.size.x + bufferX] = Vector<std::uint8_t, 4, Alignment>(
|
||||||
|
static_cast<std::uint8_t>((color.r * srcA + dst.r * dstA * (1.0f - srcA)) / outA),
|
||||||
|
static_cast<std::uint8_t>((color.g * srcA + dst.g * dstA * (1.0f - srcA)) / outA),
|
||||||
|
static_cast<std::uint8_t>((color.b * srcA + dst.b * dstA * (1.0f - srcA)) / outA),
|
||||||
|
static_cast<std::uint8_t>(outA * 255)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
x += (int)(ax * scale);
|
x += (int)(ax * scale);
|
||||||
|
|
||||||
if (i + 1 < line.size()) {
|
if (i + 1 < line.size()) {
|
||||||
x += (int)stbtt_GetCodepointKernAdvance(&font.font, codepoint, line[i+1]);
|
x += (int)stbtt_GetGlyphKernAdvance(&font.font, codepoint, line[i+1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentY += lineHeight;
|
currentY += lineHeight;
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,9 @@ export namespace Crafter {
|
||||||
Buffer
|
Buffer
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<std::uint8_t Alignment = 0>
|
||||||
struct RenderElement2DScalingOwning {
|
struct RenderElement2DScalingOwning {
|
||||||
std::vector<Vector<std::uint8_t, 4>> scalingBuffer;
|
std::vector<Vector<std::uint8_t, 4, Alignment>> scalingBuffer;
|
||||||
std::uint32_t bufferWidth;
|
std::uint32_t bufferWidth;
|
||||||
std::uint32_t bufferHeight;
|
std::uint32_t bufferHeight;
|
||||||
bool bufferUpdated = true;
|
bool bufferUpdated = true;
|
||||||
|
|
@ -53,13 +54,14 @@ export namespace Crafter {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<std::uint8_t Alignment = 0>
|
||||||
struct RenderElement2DScalingNonOwning {
|
struct RenderElement2DScalingNonOwning {
|
||||||
Vector<std::uint8_t, 4>* scalingBuffer;
|
Vector<std::uint8_t, 4, Alignment>* scalingBuffer;
|
||||||
std::uint32_t bufferWidth;
|
std::uint32_t bufferWidth;
|
||||||
std::uint32_t bufferHeight;
|
std::uint32_t bufferHeight;
|
||||||
bool bufferUpdated = true;
|
bool bufferUpdated = true;
|
||||||
RenderElement2DScalingNonOwning() = default;
|
RenderElement2DScalingNonOwning() = default;
|
||||||
RenderElement2DScalingNonOwning(Vector<std::uint8_t, 4>* scalingBuffer, std::uint32_t bufferWidth, std::uint32_t bufferHeight) : scalingBuffer(scalingBuffer), bufferWidth(bufferWidth), bufferHeight(bufferHeight) {
|
RenderElement2DScalingNonOwning(Vector<std::uint8_t, 4, Alignment>* scalingBuffer, std::uint32_t bufferWidth, std::uint32_t bufferHeight) : scalingBuffer(scalingBuffer), bufferWidth(bufferWidth), bufferHeight(bufferHeight) {
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -77,13 +79,13 @@ export namespace Crafter {
|
||||||
struct EmptyScalingBase {};
|
struct EmptyScalingBase {};
|
||||||
struct EmptyRotatingBase {};
|
struct EmptyRotatingBase {};
|
||||||
|
|
||||||
template<bool Scaling, bool Owning>
|
template<bool Scaling, bool Owning, std::uint8_t Alignment = 0>
|
||||||
using ScalingBase =
|
using ScalingBase =
|
||||||
std::conditional_t<
|
std::conditional_t<
|
||||||
Scaling,
|
Scaling,
|
||||||
std::conditional_t<Owning,
|
std::conditional_t<Owning,
|
||||||
RenderElement2DScalingOwning,
|
RenderElement2DScalingOwning<Alignment>,
|
||||||
RenderElement2DScalingNonOwning>,
|
RenderElement2DScalingNonOwning<Alignment>>,
|
||||||
EmptyScalingBase
|
EmptyScalingBase
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ export namespace Crafter {
|
||||||
Transform2D transform;
|
Transform2D transform;
|
||||||
std::int32_t sizeX;
|
std::int32_t sizeX;
|
||||||
std::int32_t sizeY;
|
std::int32_t sizeY;
|
||||||
std::vector<RenderingElement2DBase*> elements;
|
std::vector<Transform2D*> elements;
|
||||||
std::vector<ClipRect> dirtyRects;
|
std::vector<ClipRect> dirtyRects;
|
||||||
RendertargetBase() = default;
|
RendertargetBase() = default;
|
||||||
RendertargetBase(std::int16_t sizeX, std::int16_t sizeY) : sizeX(sizeX), sizeY(sizeY), transform({0, 0, 1, 1, 0, 0, 0}){
|
RendertargetBase(std::int16_t sizeX, std::int16_t sizeY) : sizeX(sizeX), sizeY(sizeY), transform({0, 0, 1, 1, 0, 0, 0}){
|
||||||
|
|
@ -42,13 +42,7 @@ export namespace Crafter {
|
||||||
transform.scaled.position.y = 0;
|
transform.scaled.position.y = 0;
|
||||||
}
|
}
|
||||||
void AddDirtyRect(ScaleData2D scale) {
|
void AddDirtyRect(ScaleData2D scale) {
|
||||||
ClipRect rect {
|
dirtyRects.emplace_back(std::max(scale.position.x, std::int32_t(0)), std::min(scale.position.x + scale.size.x, sizeX), std::max(scale.position.y, std::int32_t(0)), std::min(scale.position.y + scale.size.y, sizeY));
|
||||||
.left = std::max(scale.position.x, std::int32_t(0)),
|
|
||||||
.right = std::min(scale.position.x + scale.size.x, sizeX),
|
|
||||||
.top = std::max(scale.position.y, std::int32_t(0)),
|
|
||||||
.bottom = std::min(scale.position.y + scale.size.y, sizeY),
|
|
||||||
};
|
|
||||||
dirtyRects.push_back(rect);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -59,7 +53,9 @@ export namespace Crafter {
|
||||||
Rendertarget(std::int16_t sizeX, std::int16_t sizeY) : RendertargetBase(sizeX, sizeY) {
|
Rendertarget(std::int16_t sizeX, std::int16_t sizeY) : RendertargetBase(sizeX, sizeY) {
|
||||||
|
|
||||||
}
|
}
|
||||||
void RenderElement(RenderingElement2DBase* element) {
|
void RenderElement(Transform2D* elementTransform) {
|
||||||
|
RenderingElement2DBase* element = dynamic_cast<RenderingElement2DBase*>(elementTransform);
|
||||||
|
if(element) {
|
||||||
#ifdef CRAFTER_TIMING
|
#ifdef CRAFTER_TIMING
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -141,7 +137,15 @@ export namespace Crafter {
|
||||||
renderTimings.push_back({element, element->scaled.size.x, element->scaled.size.y, end-start});
|
renderTimings.push_back({element, element->scaled.size.x, element->scaled.size.y, end-start});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
std::sort(elementTransform->children.begin(), elementTransform->children.end(), [](Transform2D* a, Transform2D* b){ return a->anchor.z < b->anchor.z; });
|
||||||
|
for(Transform2D* child : elementTransform->children) {
|
||||||
|
this->RenderElement(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
void Render() {
|
void Render() {
|
||||||
|
elements.erase(std::remove(elements.begin(), elements.end(), static_cast<Transform2D*>(nullptr)), elements.end());
|
||||||
|
std::sort(elements.begin(), elements.end(), [](Transform2D* a, Transform2D* b){ return a->anchor.z < b->anchor.z; });
|
||||||
|
|
||||||
//std::vector<ClipRect> newClip;
|
//std::vector<ClipRect> newClip;
|
||||||
// for (std::uint32_t i = 0; i < dirtyRects.size(); i++) {
|
// for (std::uint32_t i = 0; i < dirtyRects.size(); i++) {
|
||||||
// ClipRect rect = dirtyRects[i];
|
// ClipRect rect = dirtyRects[i];
|
||||||
|
|
@ -250,7 +254,7 @@ export namespace Crafter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(RenderingElement2DBase* child : elements) {
|
for(Transform2D* child : elements) {
|
||||||
RenderElement(child);
|
RenderElement(child);
|
||||||
}
|
}
|
||||||
dirtyRects.clear();
|
dirtyRects.clear();
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ export namespace Crafter {
|
||||||
Transform2D& operator=(Transform2D&) = delete;
|
Transform2D& operator=(Transform2D&) = delete;
|
||||||
virtual ~Transform2D() = default;
|
virtual ~Transform2D() = default;
|
||||||
void ScaleElement(Transform2D& parent);
|
void ScaleElement(Transform2D& parent);
|
||||||
virtual void UpdatePosition(RendertargetBase& window);
|
|
||||||
virtual void UpdatePosition(RendertargetBase& window, Transform2D& parent);
|
virtual void UpdatePosition(RendertargetBase& window, Transform2D& parent);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +96,9 @@ export namespace Crafter {
|
||||||
bool mouseRightHeld = false;
|
bool mouseRightHeld = false;
|
||||||
std::vector<MouseElement*> mouseElements;
|
std::vector<MouseElement*> mouseElements;
|
||||||
std::vector<MouseElement*> pendingMouseElements;
|
std::vector<MouseElement*> pendingMouseElements;
|
||||||
|
Rendertarget<std::uint8_t, 4, 4> cursorRenderer;
|
||||||
|
|
||||||
|
Window() = default;
|
||||||
Window(std::uint32_t width, std::uint32_t height);
|
Window(std::uint32_t width, std::uint32_t height);
|
||||||
Window(std::uint32_t width, std::uint32_t height, const std::string_view title);
|
Window(std::uint32_t width, std::uint32_t height, const std::string_view title);
|
||||||
Window(Window&) = delete;
|
Window(Window&) = delete;
|
||||||
|
|
@ -110,6 +112,9 @@ export namespace Crafter {
|
||||||
void Resize(std::uint32_t width, std::uint32_t height);
|
void Resize(std::uint32_t width, std::uint32_t height);
|
||||||
void Render();
|
void Render();
|
||||||
void Update();
|
void Update();
|
||||||
|
void UpdateCursorImage();
|
||||||
|
void SetCusorImage(std::uint16_t sizeX, std::uint16_t sizeY);
|
||||||
|
void SetCusorImageDefault();
|
||||||
|
|
||||||
#ifdef CRAFTER_TIMING
|
#ifdef CRAFTER_TIMING
|
||||||
std::chrono::nanoseconds totalUpdate;
|
std::chrono::nanoseconds totalUpdate;
|
||||||
|
|
@ -135,6 +140,9 @@ export namespace Crafter {
|
||||||
wl_buffer* backBuffer = nullptr;
|
wl_buffer* backBuffer = nullptr;
|
||||||
xdg_surface* xdgSurface = nullptr;
|
xdg_surface* xdgSurface = nullptr;
|
||||||
wl_callback* cb = nullptr;
|
wl_callback* cb = nullptr;
|
||||||
|
wl_surface* cursorSurface = nullptr;
|
||||||
|
wl_buffer* cursorWlBuffer = nullptr;
|
||||||
|
std::uint32_t cursorBufferOldSize = 0;
|
||||||
|
|
||||||
static void xdg_surface_handle_preferred_scale(void* data, wp_fractional_scale_v1*, std::uint32_t scale);
|
static void xdg_surface_handle_preferred_scale(void* data, wp_fractional_scale_v1*, std::uint32_t scale);
|
||||||
static void wl_surface_frame_done(void *data, wl_callback *cb, uint32_t time);
|
static void wl_surface_frame_done(void *data, wl_callback *cb, uint32_t time);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue