2025-11-25 02:21:06 +01:00
/*
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 ;
2025-11-25 20:30:54 +01:00
import : Transform ;
2025-11-25 02:21:06 +01:00
import std ;
using namespace Crafter ;
2025-11-26 18:48:58 +01:00
Window : : Window ( std : : int_fast32_t width , std : : int_fast32_t height ) : width ( width ) , height ( height ) {
2025-11-25 02:21:06 +01:00
2025-11-25 18:52:32 +01:00
}
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 ) ;
}
2025-11-25 19:43:40 +01:00
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);
}
2025-11-25 23:29:48 +01:00
# ifdef CRAFTER_TIMING
void Window : : LogTiming ( ) {
std : : cout < < std : : format ( " Update: {} " , duration_cast < std : : chrono : : milliseconds > ( totalUpdate ) ) < < std : : endl ;
for ( const std : : pair < const EventListener < FrameTime > * , std : : chrono : : nanoseconds > & entry : updateTimings ) {
std : : cout < < std : : format ( " \t {} {} " , reinterpret_cast < const void * > ( entry . first ) , duration_cast < std : : chrono : : microseconds > ( entry . second ) ) < < std : : endl ;
}
std : : cout < < std : : format ( " Render: {} " , duration_cast < std : : chrono : : milliseconds > ( totalRender ) ) < < std : : endl ;
for ( const std : : tuple < const RenderingElement * , std : : uint_fast32_t , std : : uint_fast32_t , std : : chrono : : nanoseconds > & entry : renderTimings ) {
std : : cout < < std : : format ( " \t {} {}x{} {} " , reinterpret_cast < const void * > ( std : : get < 0 > ( entry ) ) , std : : get < 1 > ( entry ) , std : : get < 2 > ( entry ) , duration_cast < std : : chrono : : microseconds > ( std : : get < 3 > ( entry ) ) ) < < std : : endl ;
}
2025-11-25 23:36:43 +01:00
std : : cout < < std : : format ( " Total: {} " , duration_cast < std : : chrono : : milliseconds > ( totalUpdate + totalRender ) ) < < std : : endl ;
2025-11-25 23:29:48 +01:00
std : : cout < < std : : format ( " Vblank: {} " , duration_cast < std : : chrono : : milliseconds > ( vblank ) ) < < std : : endl ;
2025-11-25 23:36:43 +01:00
// 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 < std : : chrono : : milliseconds > ( average ) ,
duration_cast < std : : chrono : : milliseconds > ( min ) ,
duration_cast < std : : chrono : : milliseconds > ( max ) ) < < std : : endl ;
}
2025-11-25 23:29:48 +01:00
}
2025-11-26 18:48:58 +01:00
# endif
2025-11-26 20:15:25 +01:00
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 ) ,
} ;
2025-11-26 18:48:58 +01:00
2025-11-26 20:15:25 +01:00
if ( rect . left > = rect . right | | rect . top > = rect . bottom ) {
return ;
}
2025-11-26 20:41:54 +01:00
//merging logic should work so that no pixel is drawn twice, and that no pixel not marked dirty is drawn.
//so lets say there is already an existing horizontal bar and the new rect is a vertical bar making a cross shape, the center of the cross will currently be drawn twice
//so we need to turn it into 3 rects, the top part of the vertical bar, the horizontal bar, and the bottom part of the vertical bar
//in this way no pixel is drawn twice and no area not marked dirty is included
2025-11-26 18:48:58 +01:00
2025-11-26 20:15:25 +01:00
dirtyRects . push_back ( rect ) ;
2025-11-26 18:48:58 +01:00
}