浏览代码

Made a procedural font API to separate interface from internal implementation.

David Piuva 5 年之前
父节点
当前提交
c502a727a7

+ 109 - 0
Source/DFPSR/api/fontAPI.cpp

@@ -0,0 +1,109 @@
+// zlib open source license
+//
+// Copyright (c) 2020 David Forsgren Piuva
+// 
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// 
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 
+//    1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would be
+//    appreciated but is not required.
+// 
+//    2. Altered source versions must be plainly marked as such, and must not be
+//    misrepresented as being the original software.
+// 
+//    3. This notice may not be removed or altered from any source
+//    distribution.
+
+#include "fontAPI.h"
+#include "imageAPI.h"
+#include "../font/Font.h"
+#include "../font/defaultFont.h"
+
+namespace dsr {
+
+bool font_exists(const RasterFont font) {
+	return font.get() != nullptr;
+}
+
+static const RasterFont defaultFont = RasterFontImpl::createLatinOne(U"UbuntuMono", image_fromAscii(defaultFontAscii));
+
+RasterFont font_getDefault() {
+	return defaultFont;
+}
+
+RasterFont font_createLatinOne(const String& name, const ImageU8& atlas) {
+	if (!image_exists(atlas)) {
+		throwError("Cannot create the Latin-1 font called ", name, " from an empty image handle.\n");
+	} else if (image_getWidth(atlas) % 16 == 0 && image_getHeight(atlas) % 16 == 0
+		&& image_getWidth(atlas) >= 16 && image_getHeight(atlas) >= 16) {
+		throwError("Cannot create the Latin-1 font called ", name, " from an image of ", image_getWidth(atlas), "x", image_getHeight(atlas), " pixels.\n");
+	}
+	return RasterFontImpl::createLatinOne(name, atlas);
+}
+
+String font_getName(const RasterFont font) {
+	if (!font_exists(font)) {
+		throwError("font_getName: font must exist!");
+	}
+	return font->name;
+}
+
+int32_t font_getSize(const RasterFont font) {
+	if (!font_exists(font)) {
+		throwError("font_getSize: font must exist!");
+	}
+	return font->size;
+}
+
+int32_t font_getCharacterWidth(const RasterFont font, DsrChar unicodeValue) {
+	if (!font_exists(font)) {
+		throwError("font_getCharacterWidth: font must exist!");
+	}
+	return font->getCharacterWidth(unicodeValue);
+}
+
+int32_t font_getLineWidth(const RasterFont font, const ReadableString& content) {
+	if (!font_exists(font)) {
+		throwError("font_getLineWidth: font must exist!");
+	}
+	return font->getLineWidth(content);
+}
+
+int32_t font_printCharacter(ImageRgbaU8& target, const RasterFont font, DsrChar unicodeValue, const IVector2D& location, const ColorRgbaI32& color) {
+	if (!image_exists(target)) {
+		throwError("font_printCharacter: target must exist!");
+	} else if (!font_exists(font)) {
+		throwError("font_printCharacter: font must exist!");
+	}
+	return font->printCharacter(target, unicodeValue, location, color);
+}
+
+void font_printLine(ImageRgbaU8& target, const RasterFont font, const ReadableString& content, const IVector2D& location, const ColorRgbaI32& color) {
+	if (!image_exists(target)) {
+		throwError("font_printLine: target must exist!");
+	} else if (!font_exists(font)) {
+		throwError("font_printLine: font must exist!");
+	} else {
+		font->printLine(target, content, location, color);
+	}
+}
+
+void font_printMultiLine(ImageRgbaU8& target, const RasterFont font, const ReadableString& content, const IRect& bound, const ColorRgbaI32& color) {
+	if (!image_exists(target)) {
+		throwError("font_printMultiLine: target must exist!");
+	} else if (!font_exists(font)) {
+		throwError("font_printMultiLine: font must exist!");
+	} else {
+		font->printMultiLine(target, content, bound, color);
+	}
+}
+
+}
+

+ 76 - 0
Source/DFPSR/api/fontAPI.h

@@ -0,0 +1,76 @@
+// zlib open source license
+//
+// Copyright (c) 2020 David Forsgren Piuva
+// 
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// 
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 
+//    1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would be
+//    appreciated but is not required.
+// 
+//    2. Altered source versions must be plainly marked as such, and must not be
+//    misrepresented as being the original software.
+// 
+//    3. This notice may not be removed or altered from any source
+//    distribution.
+
+#ifndef DFPSR_API_FONT
+#define DFPSR_API_FONT
+
+#include "types.h"
+#include "../base/text.h"
+
+namespace dsr {
+	// Get a handle to the default font
+	RasterFont font_getDefault();
+	// Create a new font mapped to the Latin-1 character sub-set using a fixed size grid of 16 x 16 sub-images
+	//   atlas contains 16 x 16 character images starting with character codes 0 to 15 and continuing left to right on the next cell rows in the atlas
+	// Pre-conditions:
+	//   * atlas must exist
+	//   * atlas must have dimensions evenly divisible by 16
+	//     image_getWidth(atlas) % 16 == 0
+	//     image_getHeight(atlas) % 16 == 0
+	//   * Each cell must include at least one pixel
+	//     image_getWidth(atlas) >= 16
+	//     image_getHeight(atlas) >= 16
+	RasterFont font_createLatinOne(const String& name, const ImageU8& atlas);
+	// Post-condition: Returns true iff font exists
+	bool font_exists(const RasterFont font);
+	// Pre-condition: font must exist
+	// Post-condition: Returns font's name, as given on construction
+	String font_getName(const RasterFont font);
+	// Pre-condition: font must exist
+	// Post-condition:
+	//   Returns the font's size, which is the height of an individual character image before cropping
+	//   If ceated using font_createLatinOne then it's image_getHeight(atlas) / 16
+	int32_t font_getSize(const RasterFont font);
+	// Pre-condition: font must exist
+	// Post-condition: Returns the width of a character including spacing in pixels
+	int32_t font_getCharacterWidth(const RasterFont font, DsrChar unicodeValue);
+	// Pre-condition: font must exist
+	// Post-condition: Returns the total length of content in pixels while ignoring line-breaks
+	int32_t font_getLineWidth(const RasterFont font, const ReadableString& content);
+	// Pre-condition: font and target must exist
+	// Side-effects: Prints a character and returns the horizontal stride in pixels
+	int32_t font_printCharacter(ImageRgbaU8& target, const RasterFont font, DsrChar unicodeValue, const IVector2D& location, const ColorRgbaI32& color);
+	// Pre-condition: font and target must exist
+	// Side-effects: Prints content from location while ignoring line-breaks
+	void font_printLine(ImageRgbaU8& target, const RasterFont font, const ReadableString& content, const IVector2D& location, const ColorRgbaI32& color);
+	// Pre-condition: font and target must exist
+	// Side-effects: Prints multiple lines of text within bound
+	// Guarantees that:
+	//   * No characters are clipped against bound
+	//     It may however clip against the target image's bound if you make the bound larger than the image for partial updates or scrolling effects
+	//   * No pixels are drawn outside of bound
+	void font_printMultiLine(ImageRgbaU8& target, const RasterFont font, const ReadableString& content, const IRect& bound, const ColorRgbaI32& color);
+}
+
+#endif
+

+ 4 - 0
Source/DFPSR/api/types.h

@@ -84,6 +84,10 @@ using Component = std::shared_ptr<VisualComponent>;
 class VisualThemeImpl;
 using VisualTheme = std::shared_ptr<VisualThemeImpl>;
 
+// A handle to a raster font
+class RasterFontImpl;
+using RasterFont = std::shared_ptr<RasterFontImpl>;
+
 // A handle to a media machine.
 //   Media machines can be used to generate, filter and analyze images.
 //   Everything running in a media machine is guaranteed to be 100% deterministic to the last bit.

+ 11 - 19
Source/DFPSR/gui/Font.cpp → Source/DFPSR/font/Font.cpp

@@ -23,39 +23,31 @@
 
 #include <stdint.h>
 #include "Font.h"
-#include "defaultFont.h"
 #include "../api/imageAPI.h"
 #include "../api/drawAPI.h"
 
 using namespace dsr;
 
-std::shared_ptr<RasterFont> defaultFont = RasterFont::createLatinOne(U"UbuntuMono", image_fromAscii(defaultFontAscii));;
-
-std::shared_ptr<RasterFont> dsr::font_getDefault() {
-	return defaultFont;
-}
-
-
 RasterCharacter::RasterCharacter(const ImageU8& image, DsrChar unicodeValue, int32_t offsetY)
 : image(image), unicodeValue(unicodeValue), width(image_getWidth(image)), offsetY(offsetY) {}
 
-RasterFont::RasterFont(const String& name, int32_t size, int32_t spacing, int32_t spaceWidth)
+RasterFontImpl::RasterFontImpl(const String& name, int32_t size, int32_t spacing, int32_t spaceWidth)
  : name(name), size(size), spacing(spacing), spaceWidth(spaceWidth), tabWidth(spaceWidth * 4) {
 	for (int i = 0; i < 65536; i++) {
 		this->indices[i] = -1;
 	}
 }
 
-RasterFont::~RasterFont() {}
+RasterFontImpl::~RasterFontImpl() {}
 
-std::shared_ptr<RasterFont> RasterFont::createLatinOne(const String& name, const ImageU8& atlas) {
+std::shared_ptr<RasterFontImpl> RasterFontImpl::createLatinOne(const String& name, const ImageU8& atlas) {
 	int32_t size = image_getHeight(atlas) / 16;
-	std::shared_ptr<RasterFont> result = std::make_shared<RasterFont>(name, size, size / 16, size / 2);
+	std::shared_ptr<RasterFontImpl> result = std::make_shared<RasterFontImpl>(name, size, size / 16, size / 2);
 	result->registerLatinOne16x16(atlas);
 	return result;
 }
 
-void RasterFont::registerCharacter(const ImageU8& image, DsrChar unicodeValue, int32_t offsetY) {
+void RasterFontImpl::registerCharacter(const ImageU8& image, DsrChar unicodeValue, int32_t offsetY) {
 	if (this->indices[unicodeValue] == -1) {
 		// Add the unicode character
 		this->characters.pushConstruct(image, unicodeValue, offsetY);
@@ -87,7 +79,7 @@ static IRect getCharacterBound(const ImageU8& image, const IRect& searchRegion)
 }
 
 // Call after construction to register up to 256 characters in a 16x16 grid from the atlas
-void RasterFont::registerLatinOne16x16(const ImageU8& atlas) {
+void RasterFontImpl::registerLatinOne16x16(const ImageU8& atlas) {
 	int32_t charWidth = image_getWidth(atlas) / 16;
 	int32_t charHeight = image_getWidth(atlas) / 16;
 	for (int y = 0; y < 16; y++) {
@@ -103,7 +95,7 @@ void RasterFont::registerLatinOne16x16(const ImageU8& atlas) {
 	}
 }
 
-int32_t RasterFont::getCharacterWidth(DsrChar unicodeValue) const {
+int32_t RasterFontImpl::getCharacterWidth(DsrChar unicodeValue) const {
 	if (unicodeValue == 0 || unicodeValue == 10 || unicodeValue == 13) {
 		return 0;
 	} else {
@@ -117,7 +109,7 @@ int32_t RasterFont::getCharacterWidth(DsrChar unicodeValue) const {
 }
 
 // Prints a character and returns the horizontal stride in pixels
-int32_t RasterFont::printCharacter(ImageRgbaU8& target, DsrChar unicodeValue, const IVector2D& location, const ColorRgbaI32& color) const {
+int32_t RasterFontImpl::printCharacter(ImageRgbaU8& target, DsrChar unicodeValue, const IVector2D& location, const ColorRgbaI32& color) const {
 	if (unicodeValue < 65536) {
 		int32_t index = this->indices[unicodeValue];
 		if (index > -1) {
@@ -141,7 +133,7 @@ static void tabJump(int &x, int leftOrigin, int tabWidth) {
 	x += remainder;
 }
 
-void RasterFont::printLine(ImageRgbaU8& target, const ReadableString& content, const IVector2D& location, const ColorRgbaI32& color) const {
+void RasterFontImpl::printLine(ImageRgbaU8& target, const ReadableString& content, const IVector2D& location, const ColorRgbaI32& color) const {
 	IVector2D currentLocation = location;
 	for (int i = 0; i < content.length(); i++) {
 		DsrChar code = content[i];
@@ -154,7 +146,7 @@ void RasterFont::printLine(ImageRgbaU8& target, const ReadableString& content, c
 	}
 }
 
-void RasterFont::printMultiLine(ImageRgbaU8& target, const ReadableString& content, const IRect& bound, const ColorRgbaI32& color) const {
+void RasterFontImpl::printMultiLine(ImageRgbaU8& target, const ReadableString& content, const IRect& bound, const ColorRgbaI32& color) const {
 	int y = bound.top(); // The upper vertical location of the currently printed row in pixels.
 	int lineWidth = 0; // The size of the currently scanned row, to make sure that it can be printed.
 	int rowStartIndex = 0; // The start of the current row or the unprinted remainder that didn't fit inside the bound.
@@ -214,7 +206,7 @@ void RasterFont::printMultiLine(ImageRgbaU8& target, const ReadableString& conte
 	this->printLine(target, content.from(rowStartIndex), IVector2D(bound.left(), y), color);
 }
 
-int32_t RasterFont::getLineWidth(const ReadableString& content) const {
+int32_t RasterFontImpl::getLineWidth(const ReadableString& content) const {
 	int32_t result = 0;
 	for (int i = 0; i < content.length(); i++) {
 		DsrChar code = content[i];

+ 8 - 11
Source/DFPSR/gui/Font.h → Source/DFPSR/font/Font.h

@@ -47,7 +47,7 @@ public:
 	~RasterCharacter() {}
 };
 
-class RasterFont {
+class RasterFontImpl {
 public:
 	// Font identity
 	const String name;
@@ -65,19 +65,19 @@ public:
 	int32_t indices[65536];
 public:
 	// Constructor
-	RasterFont(const String& name, int32_t size, int32_t spacing, int32_t spaceWidth);
-	static std::shared_ptr<RasterFont> createLatinOne(const String& name, const ImageU8& atlas);
+	RasterFontImpl(const String& name, int32_t size, int32_t spacing, int32_t spaceWidth);
+	static std::shared_ptr<RasterFontImpl> createLatinOne(const String& name, const ImageU8& atlas);
 	// Destructor
-	~RasterFont();
+	~RasterFontImpl();
 public:
 	// Allready registered unicode characters will be ignored if reused, so load overlapping sets in order of priority
 	void registerCharacter(const ImageU8& image, DsrChar unicodeValue, int32_t offsetY);
 	// Call after construction to register up to 256 characters in a 16x16 grid from the atlas
 	void registerLatinOne16x16(const ImageU8& atlas);
-	// Gets the width of a character including spacing
+	// Returns the width of a character including spacing in pixels
 	int32_t getCharacterWidth(DsrChar unicodeValue) const;
-	// Gets the width of a whole line
-	// Precondition: No linebreaks in content, just a single line
+	// Returns the total length of characters in pixels as if printing content
+	// If multiple lines exists it will simply keep adding to the total by ignoring line-breaks
 	int32_t getLineWidth(const ReadableString& content) const;
 	// Prints a character and returns the horizontal stride in pixels
 	int32_t printCharacter(ImageRgbaU8& target, DsrChar unicodeValue, const IVector2D& location, const ColorRgbaI32& color) const;
@@ -87,10 +87,7 @@ public:
 	void printMultiLine(ImageRgbaU8& target, const ReadableString& content, const IRect& bound, const ColorRgbaI32& color) const;
 };
 
-// Font API
-std::shared_ptr<RasterFont> font_getDefault();
-
-// TODO: Duplicate functionality with a procedural API for consistent style
+// See DFPSR/api/fontAPI.h for the procedural interface
 
 }
 

+ 0 - 0
Source/DFPSR/gui/defaultFont.h → Source/DFPSR/font/defaultFont.h


+ 4 - 4
Source/DFPSR/gui/components/Button.cpp

@@ -50,17 +50,17 @@ bool Button::isContainer() const {
 	return false;
 }
 
-static OrderedImageRgbaU8 generateButtonImage(MediaMethod imageGenerator, int pressed, int width, int height, ColorRgbI32 backColor, String text, const std::shared_ptr<RasterFont>& font) {
+static OrderedImageRgbaU8 generateButtonImage(MediaMethod imageGenerator, int pressed, int width, int height, ColorRgbI32 backColor, String text, RasterFont font) {
 	// Create a scaled image
 	OrderedImageRgbaU8 result;
  	imageGenerator(width, height, pressed, backColor.red, backColor.green, backColor.blue)(result);
 	if (text.length() > 0) {
-		int left = (image_getWidth(result) - font->getLineWidth(text)) / 2;
-		int top = (image_getHeight(result) - font->size) / 2;
+		int left = (image_getWidth(result) - font_getLineWidth(font, text)) / 2;
+		int top = (image_getHeight(result) - font_getSize(font)) / 2;
 		if (pressed) {
 			top += 1;
 		}
-		font->printLine(result, text, IVector2D(left, top), ColorRgbaI32(0, 0, 0, 255));
+		font_printLine(result, font, text, IVector2D(left, top), ColorRgbaI32(0, 0, 0, 255));
 	}
 	return result;
 }

+ 2 - 2
Source/DFPSR/gui/components/Button.h

@@ -25,7 +25,7 @@
 #define DFPSR_GUI_COMPONENT_BUTTON
 
 #include "../VisualComponent.h"
-#include "../Font.h"
+#include "../../api/fontAPI.h"
 
 namespace dsr {
 
@@ -43,7 +43,7 @@ private:
 	bool inside = false;
 	// Given from the style
 	MediaMethod button;
-	std::shared_ptr<RasterFont> font;
+	RasterFont font;
 	void completeAssets();
 	void generateGraphics();
 	// Generated

+ 1 - 1
Source/DFPSR/gui/components/Label.cpp

@@ -59,7 +59,7 @@ void Label::drawSelf(ImageRgbaU8& targetImage, const IRect &relativeLocation) {
 		// Uncomment to draw a white background for debugging
 		//draw_rectangle(targetImage, relativeLocation, ColorRgbaI32(255, 255, 255, 255));
 		// Print the text directly each time without buffering, because the biggest cost is to fill pixels
-		this->font->printMultiLine(targetImage, this->text.value, relativeLocation, ColorRgbaI32(this->color.value, this->opacity.value));
+		font_printMultiLine(targetImage, this->font, this->text.value, relativeLocation, ColorRgbaI32(this->color.value, this->opacity.value));
 	}
 }
 

+ 2 - 2
Source/DFPSR/gui/components/Label.h

@@ -25,7 +25,7 @@
 #define DFPSR_GUI_COMPONENT_LABEL
 
 #include "../VisualComponent.h"
-#include "../Font.h"
+#include "../../api/fontAPI.h"
 
 namespace dsr {
 
@@ -45,7 +45,7 @@ private:
 	bool pressed = false;
 	bool inside = false;
 	// Given from the style
-	std::shared_ptr<RasterFont> font;
+	RasterFont font;
 	void completeAssets();
 public:
 	Label();

+ 10 - 9
Source/DFPSR/gui/components/ListBox.cpp

@@ -66,9 +66,9 @@ void ListBox::generateGraphics() {
 	if (width < 1) { width = 1; }
 	if (height < 1) { height = 1; }
 	if (!this->hasImages) {
-		completeAssets();
+		this->completeAssets();
 	 	this->scalableImage_listBox(width, height, this->color.value.red, this->color.value.green, this->color.value.blue)(this->image);
-		int verticalStep = this->font->size;
+		int verticalStep = font_getSize(this->font);
 		int left = textBorderLeft;
 		int top = textBorderTop;
 		for (int64_t i = this->firstVisible; i < this->list.value.length() && top < height; i++) {
@@ -83,7 +83,7 @@ void ListBox::generateGraphics() {
 			if (i == this->selectedIndex.value) {
 				draw_rectangle(this->image, IRect(left, top, width - (textBorderLeft * 2), verticalStep), ColorRgbaI32(0, 0, 0, 255));
 			}
-			this->font->printLine(this->image, this->list.value[i], IVector2D(left, top), textColor);
+			font_printLine(this->image, this->font, this->list.value[i], IVector2D(left, top), textColor);
 			top += verticalStep;
 		}
 		if (this->hasVerticalScroll) {
@@ -132,7 +132,7 @@ void ListBox::receiveMouseEvent(const MouseEvent& event) {
 	this->inside = this->pointIsInside(event.position);
 	bool onScrollBar = this->hasVerticalScroll && event.position.x >= this->location.width() - scrollWidth;
 	int64_t maxIndex = this->list.value.length() - 1;
-	int64_t hoverIndex = this->firstVisible + ((event.position.y - this->location.top() - textBorderTop) / this->font->size);
+	int64_t hoverIndex = this->firstVisible + ((event.position.y - this->location.top() - textBorderTop) / font_getSize(this->font));
 	if (hoverIndex > maxIndex) {
 		hoverIndex = -1;
 	}
@@ -215,9 +215,12 @@ void ListBox::completeAssets() {
 	if (this->scalableImage_listBox.methodIndex == -1) {
 		this->loadTheme(theme_getDefault());
 	}
-	if (this->font.get() == nullptr) {
+	if (!font_exists(this->font)) {
 		this->font = font_getDefault();
 	}
+	if (!font_exists(this->font)) {
+		throwError("Failed to load the default font for a ListBox!\n");
+	}
 }
 
 void ListBox::changedLocation(IRect &oldLocation, IRect &newLocation) {
@@ -260,7 +263,8 @@ void ListBox::limitSelection() {
 }
 
 int64_t ListBox::getVisibleScrollRange() {
-	int64_t verticalStep = this->font->size;
+	this->completeAssets();
+	int64_t verticalStep = font_getSize(this->font);
 	return (this->location.height() - textBorderTop * 2) / verticalStep;
 }
 
@@ -294,9 +298,6 @@ IRect ListBox::getKnobLocation() {
 void ListBox::limitScrolling(bool keepSelectedVisible) {
 	// Try to load the font before estimating how big the view is
 	this->completeAssets();
-	if (this->font.get() == nullptr) {
-		throwError("Cannot get the font size because ListBox failed to get a font!\n");
-	}
 	int64_t itemCount = this->list.value.length();
 	int64_t visibleRange = this->getVisibleScrollRange();
 	int64_t maxScroll;

+ 2 - 2
Source/DFPSR/gui/components/ListBox.h

@@ -25,7 +25,7 @@
 #define DFPSR_GUI_COMPONENT_LISTBOX
 
 #include "../VisualComponent.h"
-#include "../Font.h"
+#include "../../api/fontAPI.h"
 
 namespace dsr {
 
@@ -51,7 +51,7 @@ private:
 	// Given from the style
 	MediaMethod scalableImage_listBox;
 	MediaMethod scalableImage_scrollButton;
-	std::shared_ptr<RasterFont> font;
+	RasterFont font;
 	void completeAssets();
 	void generateGraphics();
 	// Generated

+ 1 - 1
Source/DFPSR/includeFramework.h

@@ -19,13 +19,13 @@
 	// GUI API
 	#include "api/guiAPI.h" // Handling windows, interfaces and components
 	#include "api/mediaMachineAPI.h" // A machine for running image functions
+	#include "api/fontAPI.h" // Printing text to images
 	// Convenient API
 	#include "api/timeAPI.h" // Methods for time and delays
 	#include "api/configAPI.h" // Making it easy to load your application's settings from configuration files
 
 	// TODO: Create more APIs
 	#include "gui/VisualTheme.h" // Place in the gui API
-	#include "gui/Font.h" // Place in the gui API
 
 #endif
 

+ 3 - 3
Source/SDK/sandbox/sandbox.cpp

@@ -407,9 +407,9 @@ void sandbox_main() {
 			debugText("Draw GUI: ", (time_getSeconds() - startTime) * 1000.0, " ms\n");
 
 			IVector2D writer = IVector2D(10, 55);
-			font_getDefault()->printLine(colorBuffer, string_combine(U"FPS: ", profileFrameRate), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;
-			font_getDefault()->printLine(colorBuffer, string_combine(U"avg ms: ", 1000.0f / profileFrameRate), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;
-			font_getDefault()->printLine(colorBuffer, string_combine(U"max ms: ", 1000.0f * lastMaxFrameTime), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;
+			font_printLine(colorBuffer, font_getDefault(), string_combine(U"FPS: ", profileFrameRate), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;
+			font_printLine(colorBuffer, font_getDefault(), string_combine(U"avg ms: ", 1000.0f / profileFrameRate), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;
+			font_printLine(colorBuffer, font_getDefault(), string_combine(U"max ms: ", 1000.0f * lastMaxFrameTime), writer, ColorRgbaI32(255, 255, 255, 255)); writer.y += 20;
 		}
 
 		startTime = time_getSeconds();