mirror of
https://github.com/Kapendev/parin.git
synced 2025-04-27 21:49:57 +03:00
Removed bad idea from gdag and added text alignment.
This commit is contained in:
parent
21a50491b8
commit
d47e02b1d3
4 changed files with 68 additions and 203 deletions
|
@ -1,84 +0,0 @@
|
||||||
/// This example shows how to use the scene manager of Parin.
|
|
||||||
|
|
||||||
import parin;
|
|
||||||
import parin.scene;
|
|
||||||
|
|
||||||
auto sceneManager = SceneManager();
|
|
||||||
|
|
||||||
// The first scene.
|
|
||||||
struct Scene1 {
|
|
||||||
mixin extendScene;
|
|
||||||
|
|
||||||
float counter = 0;
|
|
||||||
|
|
||||||
void ready() {
|
|
||||||
// The scene manager generates a unique tag for each scene.
|
|
||||||
printfln("Entering scene 1 with tag {}.", sceneManager.tag);
|
|
||||||
setBackgroundColor(gray1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool update(float dt) {
|
|
||||||
if (Keyboard.space.isPressed) {
|
|
||||||
sceneManager.enter!Scene2();
|
|
||||||
}
|
|
||||||
|
|
||||||
counter += 5 * dt;
|
|
||||||
|
|
||||||
drawDebugText("Press space to change scene.", resolution * Vec2(0.5), DrawOptions(Hook.center));
|
|
||||||
drawDebugText("Scene 1\nCounter: {}".format(cast(int) counter), Vec2(8));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void finish() {
|
|
||||||
// The scene tag can be used to free all resources associated with the current scene.
|
|
||||||
// In this example, no resources will be freed as there are none to free.
|
|
||||||
printfln("Exiting scene 1 with tag {}.", sceneManager.tag);
|
|
||||||
freeResources(sceneManager.tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The second scene.
|
|
||||||
struct Scene2 {
|
|
||||||
mixin extendScene;
|
|
||||||
|
|
||||||
void ready() {
|
|
||||||
// The scene manager generates a unique tag for each scene.
|
|
||||||
printfln("Entering scene 2 with tag {}.", sceneManager.tag);
|
|
||||||
setBackgroundColor(gray2);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool update(float dt) {
|
|
||||||
if (Keyboard.space.isPressed) {
|
|
||||||
sceneManager.enter!Scene1();
|
|
||||||
}
|
|
||||||
|
|
||||||
drawDebugText("Press space to change scene.", resolution * Vec2(0.5), DrawOptions(Hook.center));
|
|
||||||
drawDebugText("Scene 2\nNo counter here.", Vec2(8));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void finish() {
|
|
||||||
// The scene tag can be used to free all resources associated with the current scene.
|
|
||||||
// In this example, no resources will be freed as there are none to free.
|
|
||||||
printfln("Exiting scene 2 with tag {}.", sceneManager.tag);
|
|
||||||
freeResources(sceneManager.tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ready() {
|
|
||||||
lockResolution(320, 180);
|
|
||||||
// Enter the first scene. This will call the ready function of that scene.
|
|
||||||
sceneManager.enter!Scene1();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool update(float dt) {
|
|
||||||
// Update the current scene.
|
|
||||||
return sceneManager.update(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void finish() {
|
|
||||||
// Free the scene manager. This will call the finish function of the current scene.
|
|
||||||
sceneManager.free();
|
|
||||||
}
|
|
||||||
|
|
||||||
mixin runGame!(ready, update, finish);
|
|
|
@ -6,7 +6,6 @@
|
||||||
// Version: v0.0.29
|
// Version: v0.0.29
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
// TODO: Add way to align text. I neeed this for the UI.
|
|
||||||
// TODO: Test the resource loading code.
|
// TODO: Test the resource loading code.
|
||||||
// TODO: Think about the sound API.
|
// TODO: Think about the sound API.
|
||||||
// TODO: Make sounds loop based on a variable and not on the file type.
|
// TODO: Make sounds loop based on a variable and not on the file type.
|
||||||
|
@ -44,7 +43,7 @@ enum Layout : ubyte {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type representing alignment orientations.
|
/// A type representing alignment orientations.
|
||||||
enum Align : ubyte {
|
enum Alignment : ubyte {
|
||||||
left, /// Align to the left.
|
left, /// Align to the left.
|
||||||
center, /// Align to the center.
|
center, /// Align to the center.
|
||||||
right, /// Align to the right.
|
right, /// Align to the right.
|
||||||
|
@ -195,6 +194,7 @@ struct DrawOptions {
|
||||||
float rotation = 0.0f; /// The rotation of the drawn object, in degrees.
|
float rotation = 0.0f; /// The rotation of the drawn object, in degrees.
|
||||||
Color color = white; /// The color of the drawn object.
|
Color color = white; /// The color of the drawn object.
|
||||||
Hook hook = Hook.topLeft; /// A value representing the origin point of the drawn object when origin is set to zero.
|
Hook hook = Hook.topLeft; /// A value representing the origin point of the drawn object when origin is set to zero.
|
||||||
|
Alignment alignment = Alignment.left; /// A value represeting alignment orientations.
|
||||||
Flip flip = Flip.none; /// A value representing flipping orientations.
|
Flip flip = Flip.none; /// A value representing flipping orientations.
|
||||||
|
|
||||||
@safe @nogc nothrow:
|
@safe @nogc nothrow:
|
||||||
|
@ -219,6 +219,11 @@ struct DrawOptions {
|
||||||
this.hook = hook;
|
this.hook = hook;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initializes the options with the given alignment.
|
||||||
|
this(Alignment alignment) {
|
||||||
|
this.alignment = alignment;
|
||||||
|
}
|
||||||
|
|
||||||
/// Initializes the options with the given flip.
|
/// Initializes the options with the given flip.
|
||||||
this(Flip flip) {
|
this(Flip flip) {
|
||||||
this.flip = flip;
|
this.flip = flip;
|
||||||
|
@ -976,13 +981,13 @@ struct EngineState {
|
||||||
@safe @nogc nothrow:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
void free() {
|
void free() {
|
||||||
debug {
|
// debug {
|
||||||
println("Resources that will be freed automatically:");
|
// println("Resources that will be freed automatically:");
|
||||||
println(" Text count: ", resources.texts.length != 0 ? resources.texts.length - 1 : 0);
|
// println(" Text count: ", resources.texts.length != 0 ? resources.texts.length - 1 : 0);
|
||||||
println(" Texture count: ", resources.textures.length != 0 ? resources.textures.length - 1 : 0);
|
// println(" Texture count: ", resources.textures.length != 0 ? resources.textures.length - 1 : 0);
|
||||||
println(" Font count: ", resources.fonts.length != 0 ? resources.fonts.length - 1 : 0);
|
// println(" Font count: ", resources.fonts.length != 0 ? resources.fonts.length - 1 : 0);
|
||||||
println(" Sound count: ", resources.sounds.length != 0 ? resources.sounds.length - 1 : 0);
|
// println(" Sound count: ", resources.sounds.length != 0 ? resources.sounds.length - 1 : 0);
|
||||||
}
|
// }
|
||||||
viewport.free();
|
viewport.free();
|
||||||
resources.free();
|
resources.free();
|
||||||
tempText.free();
|
tempText.free();
|
||||||
|
@ -1858,6 +1863,8 @@ float deltaWheel() {
|
||||||
Vec2 measureTextSize(Font font, IStr text, DrawOptions options = DrawOptions()) {
|
Vec2 measureTextSize(Font font, IStr text, DrawOptions options = DrawOptions()) {
|
||||||
if (font.isEmpty || text.length == 0) return Vec2();
|
if (font.isEmpty || text.length == 0) return Vec2();
|
||||||
|
|
||||||
|
// NOTE: No idea what is happening here. Maybe I should try to make it look more like the drawText function.
|
||||||
|
|
||||||
auto result = Vec2();
|
auto result = Vec2();
|
||||||
auto tempByteCounter = 0; // Used to count longer text line num chars.
|
auto tempByteCounter = 0; // Used to count longer text line num chars.
|
||||||
auto byteCounter = 0;
|
auto byteCounter = 0;
|
||||||
|
@ -2266,9 +2273,29 @@ void drawRune(FontId font, dchar rune, Vec2 position, DrawOptions options = Draw
|
||||||
/// Draws the specified text with the given font at the given position using the provided draw options.
|
/// Draws the specified text with the given font at the given position using the provided draw options.
|
||||||
@trusted
|
@trusted
|
||||||
void drawText(Font font, IStr text, Vec2 position, DrawOptions options = DrawOptions()) {
|
void drawText(Font font, IStr text, Vec2 position, DrawOptions options = DrawOptions()) {
|
||||||
|
static linesBuffer = FixedList!(IStr, 128)();
|
||||||
|
static linesWidthBuffer = FixedList!(short, 128)();
|
||||||
|
|
||||||
if (font.isEmpty || text.length == 0) return;
|
if (font.isEmpty || text.length == 0) return;
|
||||||
// TODO: Make it work with negative scale values.
|
|
||||||
auto origin = Rect(measureTextSize(font, text)).origin(options.hook);
|
// Get some info about the text.
|
||||||
|
linesBuffer.clear();
|
||||||
|
linesWidthBuffer.clear();
|
||||||
|
auto maxLineWidth = 0;
|
||||||
|
auto lineStartIndex = 0;
|
||||||
|
foreach (i, c; text) {
|
||||||
|
if (c == '\n' || i == text.length - 1) {
|
||||||
|
linesBuffer.append(text[lineStartIndex .. i + (c != '\n')]);
|
||||||
|
linesWidthBuffer.append(cast(short) measureTextSize(font, linesBuffer[$ - 1]).x);
|
||||||
|
if (maxLineWidth < linesWidthBuffer[$ - 1]) maxLineWidth = linesWidthBuffer[$ - 1];
|
||||||
|
lineStartIndex = cast(int) i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lineStartIndex = 0;
|
||||||
|
|
||||||
|
// Prepare the the text for drawing.
|
||||||
|
auto textSize = measureTextSize(font, text);
|
||||||
|
auto origin = Rect(textSize).origin(options.hook);
|
||||||
rl.rlPushMatrix();
|
rl.rlPushMatrix();
|
||||||
if (isPixelSnapped || isPixelPerfect) {
|
if (isPixelSnapped || isPixelPerfect) {
|
||||||
rl.rlTranslatef(floor(position.x), floor(position.y), 0.0f);
|
rl.rlTranslatef(floor(position.x), floor(position.y), 0.0f);
|
||||||
|
@ -2278,31 +2305,35 @@ void drawText(Font font, IStr text, Vec2 position, DrawOptions options = DrawOpt
|
||||||
rl.rlRotatef(options.rotation, 0.0f, 0.0f, 1.0f);
|
rl.rlRotatef(options.rotation, 0.0f, 0.0f, 1.0f);
|
||||||
rl.rlScalef(options.scale.x, options.scale.y, 1.0f);
|
rl.rlScalef(options.scale.x, options.scale.y, 1.0f);
|
||||||
rl.rlTranslatef(floor(-origin.x), floor(-origin.y), 0.0f);
|
rl.rlTranslatef(floor(-origin.x), floor(-origin.y), 0.0f);
|
||||||
auto textOffsetY = 0.0f; // Offset between lines (on linebreak '\n').
|
// Draw the text.
|
||||||
auto textOffsetX = 0.0f; // Offset X to next character to draw.
|
auto textOffsetY = 0; // Offset between lines (on linebreak '\n').
|
||||||
auto i = 0;
|
foreach (i, line; linesBuffer) {
|
||||||
while (i < text.length) {
|
auto textOffsetX = 0; // Offset X to next character to draw.
|
||||||
|
if (options.alignment == Alignment.center) {
|
||||||
|
textOffsetX = maxLineWidth / 2 - linesWidthBuffer[i] / 2;
|
||||||
|
} else if (options.alignment == Alignment.right) {
|
||||||
|
textOffsetX = maxLineWidth - linesWidthBuffer[i];
|
||||||
|
}
|
||||||
|
auto codepointIndex = 0;
|
||||||
|
while (codepointIndex < line.length) {
|
||||||
// Get next codepoint from byte string and glyph index in font.
|
// Get next codepoint from byte string and glyph index in font.
|
||||||
auto codepointByteCount = 0;
|
auto codepointByteCount = 0;
|
||||||
auto codepoint = rl.GetCodepointNext(&text[i], &codepointByteCount);
|
auto codepoint = rl.GetCodepointNext(&line[codepointIndex], &codepointByteCount);
|
||||||
auto index = rl.GetGlyphIndex(font.data, codepoint);
|
auto glyphIndex = rl.GetGlyphIndex(font.data, codepoint);
|
||||||
if (codepoint == '\n') {
|
|
||||||
textOffsetY += font.lineSpacing;
|
|
||||||
textOffsetX = 0.0f;
|
|
||||||
} else {
|
|
||||||
if (codepoint != ' ' && codepoint != '\t') {
|
if (codepoint != ' ' && codepoint != '\t') {
|
||||||
auto runeOptions = DrawOptions();
|
auto runeOptions = DrawOptions();
|
||||||
runeOptions.color = options.color;
|
runeOptions.color = options.color;
|
||||||
drawRune(font, codepoint, Vec2(textOffsetX, textOffsetY), runeOptions);
|
rl.DrawTextCodepoint(font.data, codepoint, rl.Vector2(textOffsetX, textOffsetY), font.size, options.color.toRl());
|
||||||
}
|
}
|
||||||
if (font.data.glyphs[index].advanceX == 0) {
|
if (font.data.glyphs[glyphIndex].advanceX) {
|
||||||
textOffsetX += font.data.recs[index].width + font.runeSpacing;
|
textOffsetX += font.data.glyphs[glyphIndex].advanceX + font.runeSpacing;
|
||||||
} else {
|
} else {
|
||||||
textOffsetX += font.data.glyphs[index].advanceX + font.runeSpacing;
|
textOffsetX += cast(int) (font.data.recs[glyphIndex].width) + font.runeSpacing;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Move text bytes counter to next codepoint.
|
// Move text bytes counter to next codepoint.
|
||||||
i += codepointByteCount;
|
codepointIndex += codepointByteCount;
|
||||||
|
}
|
||||||
|
textOffsetY += font.lineSpacing;
|
||||||
}
|
}
|
||||||
rl.rlPopMatrix();
|
rl.rlPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
// ---
|
|
||||||
// Copyright 2024 Alexandros F. G. Kapretsos
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Email: alexandroskapretsos@gmail.com
|
|
||||||
// Project: https://github.com/Kapendev/parin
|
|
||||||
// Version: v0.0.29
|
|
||||||
// ---
|
|
||||||
|
|
||||||
// NOTE(Kapendev): I am not a fan of this module and I would remove it, but maybe someone is using it.
|
|
||||||
// TODO: Update all the doc comments here.
|
|
||||||
|
|
||||||
/// The `scene` module provides a simple scene manager.
|
|
||||||
module parin.scene;
|
|
||||||
|
|
||||||
import stdc = joka.stdc;
|
|
||||||
import joka.types;
|
|
||||||
|
|
||||||
@safe:
|
|
||||||
|
|
||||||
struct Scene {
|
|
||||||
void delegate() @trusted ready;
|
|
||||||
bool delegate(float dt) @trusted update;
|
|
||||||
void delegate() @trusted finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SceneManager {
|
|
||||||
Scene* scene;
|
|
||||||
Scene* nextScene;
|
|
||||||
Sz tag;
|
|
||||||
|
|
||||||
@trusted:
|
|
||||||
|
|
||||||
void enter(T)() {
|
|
||||||
if (nextScene) return;
|
|
||||||
auto temp = cast(T*) stdc.malloc(T.sizeof);
|
|
||||||
*temp = T();
|
|
||||||
temp.prepare();
|
|
||||||
nextScene = cast(Scene*) temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool update(float dt) {
|
|
||||||
if (nextScene) {
|
|
||||||
if (scene) {
|
|
||||||
if (scene.finish) scene.finish();
|
|
||||||
stdc.free(scene);
|
|
||||||
}
|
|
||||||
scene = nextScene;
|
|
||||||
nextScene = null;
|
|
||||||
tag = (tag + 1) % Sz.max;
|
|
||||||
if (tag == 0) tag = 1;
|
|
||||||
if (scene.ready) scene.ready();
|
|
||||||
if (scene.update) return scene.update(dt);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (scene && scene.update) return scene.update(dt);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free() {
|
|
||||||
if (scene) {
|
|
||||||
if (scene.finish) scene.finish();
|
|
||||||
stdc.free(scene);
|
|
||||||
scene = null;
|
|
||||||
}
|
|
||||||
if (nextScene) {
|
|
||||||
stdc.free(nextScene);
|
|
||||||
nextScene = null;
|
|
||||||
}
|
|
||||||
tag = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mixin template extendScene() {
|
|
||||||
Scene base;
|
|
||||||
|
|
||||||
@trusted
|
|
||||||
void prepare() {
|
|
||||||
auto base = mixin("&", this.tupleof[0].stringof);
|
|
||||||
base.ready = cast(void delegate() @trusted) &this.ready;
|
|
||||||
base.update = cast(bool delegate(float dt) @trusted) &this.update;
|
|
||||||
base.finish = cast(void delegate() @trusted) &this.finish;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,6 +7,7 @@
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
// TODO: Clean maybe the UiState struct and prepareUi func.
|
// TODO: Clean maybe the UiState struct and prepareUi func.
|
||||||
|
// TODO: Think about overlapping UI items.
|
||||||
// TODO: Add way to get item point for some stuff. This is nice when making lists.
|
// TODO: Add way to get item point for some stuff. This is nice when making lists.
|
||||||
// TODO: Add focus style.
|
// TODO: Add focus style.
|
||||||
// TODO: Add way to align text in buttons.
|
// TODO: Add way to align text in buttons.
|
||||||
|
@ -67,7 +68,6 @@ struct UiState {
|
||||||
Gamepad gamepadClickAction = Gamepad.a;
|
Gamepad gamepadClickAction = Gamepad.a;
|
||||||
bool isActOnPress;
|
bool isActOnPress;
|
||||||
|
|
||||||
Vec2 mousePressedPoint;
|
|
||||||
Vec2 viewportPoint;
|
Vec2 viewportPoint;
|
||||||
Vec2 viewportSize;
|
Vec2 viewportSize;
|
||||||
Vec2 viewportScale = Vec2(1);
|
Vec2 viewportScale = Vec2(1);
|
||||||
|
@ -78,6 +78,7 @@ struct UiState {
|
||||||
Vec2 layoutStartPointOffest;
|
Vec2 layoutStartPointOffest;
|
||||||
Vec2 layoutMaxItemSize;
|
Vec2 layoutMaxItemSize;
|
||||||
|
|
||||||
|
Vec2 mousePressedPoint;
|
||||||
Vec2 itemDragOffset;
|
Vec2 itemDragOffset;
|
||||||
Vec2 itemPoint;
|
Vec2 itemPoint;
|
||||||
Vec2 itemSize;
|
Vec2 itemSize;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue