/* Crafter®.Graphics Copyright (C) 2025 Catcrafts® catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3.0 as published by the Free Software Foundation; This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module Crafter.Graphics:Window_impl; import :Window; import :Transform; import std; using namespace Crafter; Window::Window(std::int_fast32_t width, std::int_fast32_t height) : width(width), height(height) { } void Window::ScaleElement(Transform& element) { element.scaled.width = MappedToPixel(element.relativeWidth, width); element.scaled.height = MappedToPixel(element.relativeHeight, height); element.scaled.x = MappedToPixel(element.anchorX, width) - MappedToPixel(element.anchorOffsetX, element.scaled.width); element.scaled.y = MappedToPixel(element.anchorY, height) - MappedToPixel(element.anchorOffsetY, element.scaled.height); } void Window::ScaleElement(Transform& element, Transform& parent) { element.scaled.width = MappedToPixel(element.relativeWidth, parent.scaled.width); element.scaled.height = MappedToPixel(element.relativeHeight, parent.scaled.height); element.scaled.x = MappedToPixel(element.anchorX, parent.scaled.width) - MappedToPixel(element.anchorOffsetX, element.scaled.width) + parent.scaled.x; element.scaled.y = MappedToPixel(element.anchorY, parent.scaled.height) - MappedToPixel(element.anchorOffsetY, element.scaled.height) + parent.scaled.y; } void Window::ScaleMouse(Transform& element, Transform& parent) { std::int_fast32_t boundlessWidth = PixelToMappedBoundless(parent.scaled.width, width); std::int_fast32_t boundlessHeight = PixelToMappedBoundless(parent.scaled.height, height); element.scaled.width = BoundToBoundless(MappedToPixel(element.relativeWidth, PixelToMapped(parent.scaled.width, width))); element.scaled.height = BoundToBoundless(MappedToPixel(element.relativeHeight, PixelToMapped(parent.scaled.height, height))); element.scaled.x = MappedToPixelBoundless(element.anchorX, boundlessWidth) - MappedToPixelBoundless(element.anchorOffsetX, element.scaled.width) + PixelToMappedBoundless(parent.scaled.x, width); element.scaled.y = MappedToPixelBoundless(element.anchorY, boundlessHeight) - MappedToPixelBoundless(element.anchorOffsetY, element.scaled.height) + PixelToMappedBoundless(parent.scaled.y, height); } void Window::ScaleMouse(Transform& element) { // std::int_fast32_t boundlessWidth = PixelToMappedBoundless(parent.scaled.width, width); // std::int_fast32_t boundlessHeight = PixelToMappedBoundless(parent.scaled.height, height); // element.scaled.width = BoundToBoundless(MappedToPixel(element.relativeWidth, width)); // element.scaled.height = BoundToBoundless(MappedToPixel(element.relativeHeight, height)); // element.scaled.x = MappedToPixelBoundless(element.anchorX, boundlessWidth) - MappedToPixelBoundless(element.anchorOffsetX, element.scaled.width) + PixelToMappedBoundless(parent.scaled.x, width); // element.scaled.y = MappedToPixelBoundless(element.anchorY, boundlessHeight) - MappedToPixelBoundless(element.anchorOffsetY, element.scaled.height) + PixelToMappedBoundless(parent.scaled.y, height); } #ifdef CRAFTER_TIMING void Window::LogTiming() { std::cout << std::format("Update: {}", duration_cast(totalUpdate)) << std::endl; for (const std::pair*, std::chrono::nanoseconds>& entry : updateTimings) { std::cout << std::format("\t{} {}", reinterpret_cast(entry.first), duration_cast(entry.second)) << std::endl; } std::cout << std::format("Render: {}", duration_cast(totalRender)) << std::endl; for (const std::tuple& entry : renderTimings) { std::cout << std::format("\t{} {}x{} {}", reinterpret_cast(std::get<0>(entry)), std::get<1>(entry), std::get<2>(entry), duration_cast(std::get<3>(entry))) << std::endl; } std::cout << std::format("Total: {}", duration_cast(totalUpdate+totalRender)) << std::endl; std::cout << std::format("Vblank: {}", duration_cast(vblank)) << std::endl; // Add 100-frame average and min-max timing info if (!frameTimes.empty()) { // Calculate average std::chrono::nanoseconds sum(0); for (const auto& frameTime : frameTimes) { sum += frameTime; } auto average = sum / frameTimes.size(); // Find min and max auto min = frameTimes.front(); auto max = frameTimes.front(); for (const auto& frameTime : frameTimes) { if (frameTime < min) min = frameTime; if (frameTime > max) max = frameTime; } std::cout << std::format("Last 100 Frame Times - Avg: {}, Min: {}, Max: {}", duration_cast(average), duration_cast(min), duration_cast(max)) << std::endl; } } #endif void Window::AddDirtyRect(ScaleData scale) { ClipRect rect { .left = std::max(scale.x, std::int_fast32_t(0)), .right = std::min(scale.x + scale.width, width), .top = std::max(scale.y, std::int_fast32_t(0)), .bottom = std::min(scale.y + scale.height, height), }; if (rect.left >= rect.right || rect.top >= rect.bottom) { return; } for (ClipRect& existingRect : dirtyRects) { if (rect.left <= existingRect.right && rect.right >= existingRect.left && rect.top <= existingRect.bottom && rect.bottom >= existingRect.top) { existingRect.left = std::min(existingRect.left, rect.left); existingRect.right = std::max(existingRect.right, rect.right); existingRect.top = std::min(existingRect.top, rect.top); existingRect.bottom = std::max(existingRect.bottom, rect.bottom); return; } } dirtyRects.push_back(rect); }