diff --git a/README.md b/README.md index 4e466d6..b8d4663 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Parin +# 🍩 Parin A delightfully simple and lightweight 2D game engine for the D programming language. @@ -24,9 +24,11 @@ mixin runGame!(ready, update, finish); Parin is packed with powerful features to get you started quickly: * Intuitive immediate mode UI +* Efficient tile map structures * Flexible dialogue system with a stack-oriented scripting language * Atlas-based animation library * Pixel-perfect physics engine +* Cross-language support for the core library * ...and more! ## Cross-Platform diff --git a/dub.json b/dub.json index 921ba3e..27d347a 100644 --- a/dub.json +++ b/dub.json @@ -13,7 +13,6 @@ "source" ], "subPackages" : [ - "packages/mapy", "packages/rin", "packages/setup", "packages/web" diff --git a/scripts/capi.d b/scripts/capi.d new file mode 100755 index 0000000..27f39fc --- /dev/null +++ b/scripts/capi.d @@ -0,0 +1,813 @@ +#!/bin/env -S dmd -run + +// [Noby Script] + +enum outputFileBaseName = "parin.h"; + +int main(string[] args) { + logw("Not done yet."); + return 1; + auto tempPath = pathConcat("source", "parin", "engine.d"); + if (!tempPath.isF) { echo("Can't find parin file."); return 1; } + + Str api = null; + api.reserve(8192); + api ~= "#ifndef PARIN_H\n#define PARIN_H\n\n"; + auto parinContent = cat(tempPath); + auto hasApiPart = false; + while (parinContent.length) { + auto line = parinContent.skipLine(); + if (0) { + } else if (hasApiPart) { + hasApiPart = false; + api ~= line; + api ~= '\n'; + } else if (line.startsWith("extern(C)")) { + hasApiPart = true; + } + } + api ~= "\n#endif // PARIN_H\n"; + paste(outputFileBaseName, api); + return 0; +} + +// [Noby Library] + +Level minLogLevel = Level.info; +bool isCmdLineHidden = false; + +enum cloneExt = "._clone"; + +enum Level : ubyte { + none, + info, + warning, + error, +} + +bool isX(IStr path) { + import std.file; + return path.exists; +} + +bool isF(IStr path) { + import std.file; + return path.isX && path.isFile; +} + +bool isD(IStr path) { + import std.file; + return path.isX && path.isDir; +} + +void echo(A...)(A args) { + import std.stdio; + writeln(args); +} + +void echon(A...)(A args) { + import std.stdio; + write(args); +} + +void echof(A...)(IStr text, A args) { + import std.stdio; + writefln(text, args); +} + +void echofn(A...)(IStr text, A args) { + import std.stdio; + writef(text, args); +} + +void cp(IStr source, IStr target) { + import std.file; + copy(source, target); +} + +void rm(IStr path) { + import std.file; + if (path.isX) remove(path); +} + +void mv(IStr source, IStr target) { + cp(source, target); + rm(source); +} + +void mkdir(IStr path, bool isRecursive = false) { + import std.file; + if (!path.isX) { + if (isRecursive) mkdirRecurse(path); + else std.file.mkdir(path); + } +} + +void rmdir(IStr path, bool isRecursive = false) { + import std.file; + if (path.isX) { + if (isRecursive) rmdirRecurse(path); + else std.file.rmdir(path); + } +} + +IStr pwd() { + import std.file; + return getcwd(); +} + +IStr cat(IStr path) { + import std.file; + return path.isX ? readText(path) : ""; +} + +IStr[] ls(IStr path = ".", bool isRecursive = false) { + import std.file; + IStr[] result = []; + foreach (file; dirEntries(cast(string) path, isRecursive ? SpanMode.breadth : SpanMode.shallow)) { + result ~= file.name; + } + return result; +} + +IStr[] find(IStr path, IStr ext, bool isRecursive = false) { + import std.file; + IStr[] result = []; + foreach (file; dirEntries(cast(string) path, isRecursive ? SpanMode.breadth : SpanMode.shallow)) { + if (file.endsWith(ext)) result ~= file.name; + } + return result; +} + +IStr read() { + import std.stdio; + return readln().trim(); +} + +IStr readYesNo(IStr text, IStr firstValue = "?") { + auto result = firstValue; + while (true) { + if (result.length == 0) result = "Y"; + if (result.isYesOrNo) break; + echon(text, " [Y/n] "); + result = read(); + } + return result; +} + +IStr format(A...)(IStr text, A args...) { + import std.format; + return format(text, args); +} + +bool isYes(IStr arg) { + return (arg.length == 1 && (arg[0] == 'Y' || arg[0] == 'y')); +} + +bool isNo(IStr arg) { + return (arg.length == 1 && (arg[0] == 'N' || arg[0] == 'n')); +} + +bool isYesOrNo(IStr arg) { + return arg.isYes || arg.isNo; +} + +void clear(IStr path = ".", IStr ext = "") { + foreach (file; ls(path)) { + if (file.endsWith(ext)) rm(file); + } +} + +void paste(IStr path, IStr content, bool isOnlyMaking = false) { + import std.file; + if (isOnlyMaking) { + if (!path.isX) write(path, content); + } else { + write(path, content); + } +} + +void clone(IStr path) { + if (path.isX) cp(path, path ~ cloneExt); +} + +void restore(IStr path, bool isOnlyRemoving = false) { + auto clonePath = path ~ cloneExt; + if (clonePath.isX) { + if (!isOnlyRemoving) paste(path, cat(clonePath)); + rm(clonePath); + } +} + +void log(Level level, IStr text) { + if (minLogLevel == 0 || minLogLevel > level) return; + with (Level) final switch (level) { + case info: echo("[INFO] ", text); break; + case warning: echo("[WARNING] ", text); break; + case error: echo("[ERROR] ", text); break; + case none: break; + } +} + +void logi(IStr text) { + log(Level.info, text); +} + +void logw(IStr text) { + log(Level.warning, text); +} + +void loge(IStr text) { + log(Level.error, text); +} + +void logf(A...)(Level level, IStr text, A args) { + log(level, text.fmt(args)); +} + +int cmd(IStr[] args...) { + import std.process; + if (!isCmdLineHidden) echo("[CMD] ", args); + try { + return spawnProcess(args).wait(); + } catch (Exception e) { + return 1; + } +} + +// The following code is copied from Joka: https://github.com/Kapendev/joka/blob/main/source/joka/ascii.d + +alias Sz = size_t; /// The result of sizeof, ... + +alias Str = char[]; /// A string slice of chars. +alias Str16 = wchar[]; /// A string slice of wchars. +alias Str32 = dchar[]; /// A string slice of dchars. +alias IStr = const(char)[]; /// A string slice of constant chars. +alias IStr16 = const(wchar)[]; /// A string slice of constant wchars. +alias IStr32 = const(dchar)[]; /// A string slice of constant dchars. + +alias CStr = char*; /// A C string of chars. +alias CStr16 = wchar*; /// A C string of wchars. +alias CStr32 = dchar*; /// A C string of dchars. +alias ICStr = const(char)*; /// A C string of constant chars. +alias ICStr16 = const(wchar)*; /// A C string of constant wchars. +alias ICStr32 = const(dchar)*; /// A C string of constant dchars. + +/// A type representing error values. +enum Fault : ubyte { + none, /// Not an error. + some, /// A generic error. + bug, /// An implementation error. + invalid, /// An invalid data error. + overflow, /// An overflow error. + assertion, /// An assertion error. + cantParse, /// A parse error. + cantFind, /// A wrong path error. + cantOpen, /// An open permissions error. + cantClose, /// A close permissions error. + cantRead, /// A read permissions error. + cantWrite, /// A write permissions error. +} + +enum digitChars = "0123456789"; /// The set of digits. +enum upperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /// The set of uppercase letters. +enum lowerChars = "abcdefghijklmnopqrstuvwxyz"; /// The set of lowercase letters. +enum alphaChars = upperChars ~ lowerChars; /// The set of letters. +enum spaceChars = " \t\v\r\n\f"; /// The set of whitespace characters. +enum symbolChars = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; /// The set of symbol characters. + +version (Windows) { + enum pathSep = '\\'; + enum pathSepStr = "\\"; + enum pathSepOther = '/'; + enum pathSepOtherStr = "/"; +} else { + enum pathSep = '/'; /// The primary OS path separator as a character. + enum pathSepStr = "/"; /// The primary OS path separator as a string. + enum pathSepOther = '\\'; /// The complementary OS path separator as a character. + enum pathSepOtherStr = "\\"; /// The complementary OS path separator as a string. +} + +/// Returns true if the character is a symbol (!, ", ...). +pragma(inline, true); +bool isSymbol(char c) { + return (c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~'); +} + +/// Returns true if the character is a digit (0-9). +pragma(inline, true); +bool isDigit(char c) { + return c >= '0' && c <= '9'; +} + +/// Returns true if the character is an uppercase letter (A-Z). +pragma(inline, true); +bool isUpper(char c) { + return c >= 'A' && c <= 'Z'; +} + +/// Returns true the character is a lowercase letter (a-z). +pragma(inline, true); +bool isLower(char c) { + return c >= 'a' && c <= 'z'; +} + +/// Returns true if the character is an alphabetic letter (A-Z or a-z). +pragma(inline, true); +bool isAlpha(char c) { + return isLower(c) || isUpper(c); +} + +/// Returns true if the character is a whitespace character (space, tab, ...). +pragma(inline, true); +bool isSpace(char c) { + return (c >= '\t' && c <= '\r') || (c == ' '); +} + +/// Returns true if the string represents a C string. +pragma(inline, true); +bool isCStr(IStr str) { + return str.length != 0 && str[$ - 1] == '\0'; +} + +/// Converts the character to uppercase if it is a lowercase letter. +char toUpper(char c) { + return isLower(c) ? cast(char) (c - 32) : c; +} + +/// Converts all lowercase letters in the string to uppercase. +void toUpper(Str str) { + foreach (ref c; str) c = toUpper(c); +} + +/// Converts the character to lowercase if it is an uppercase letter. +char toLower(char c) { + return isUpper(c) ? cast(char) (c + 32) : c; +} + +/// Converts all uppercase letters in the string to lowercase. +void toLower(Str str) { + foreach (ref c; str) c = toLower(c); +} + +/// Returns the length of the C string. +@trusted +Sz cStrLength(ICStr str) { + Sz result = 0; + while (str[result] != '\0') result += 1; + return result; +} + +/// Returns true if the two strings are equal, ignoring case. +bool equalsNoCase(IStr str, IStr other) { + if (str.length != other.length) return false; + foreach (i; 0 .. str.length) if (toUpper(str[i]) != toUpper(other[i])) return false; + return true; +} + +/// Returns true if the string is equal to the specified character, ignoring case. +bool equalsNoCase(IStr str, char other) { + return equalsNoCase(str, charToStr(other)); +} + +/// Returns true if the string starts with the specified substring. +bool startsWith(IStr str, IStr start) { + if (str.length < start.length) return false; + return str[0 .. start.length] == start; +} + +/// Returns true if the string starts with the specified character. +bool startsWith(IStr str, char start) { + return startsWith(str, charToStr(start)); +} + +/// Returns true if the string ends with the specified substring. +bool endsWith(IStr str, IStr end) { + if (str.length < end.length) return false; + return str[$ - end.length .. $] == end; +} + +/// Returns true if the string ends with the specified character. +bool endsWith(IStr str, char end) { + return endsWith(str, charToStr(end)); +} + +/// Counts the number of occurrences of the specified substring in the string. +int countItem(IStr str, IStr item) { + int result = 0; + if (str.length < item.length || item.length == 0) return result; + foreach (i; 0 .. str.length - item.length) { + if (str[i .. i + item.length] == item) { + result += 1; + i += item.length - 1; + } + } + return result; +} + +/// Counts the number of occurrences of the specified character in the string. +int countItem(IStr str, char item) { + return countItem(str, charToStr(item)); +} + +/// Finds the starting index of the first occurrence of the specified substring in the string, or returns -1 if not found. +int findStart(IStr str, IStr item) { + if (str.length < item.length || item.length == 0) return -1; + foreach (i; 0 .. str.length - item.length + 1) { + if (str[i .. i + item.length] == item) return cast(int) i; + } + return -1; +} + +/// Finds the starting index of the first occurrence of the specified character in the string, or returns -1 if not found. +int findStart(IStr str, char item) { + return findStart(str, charToStr(item)); +} + +/// Finds the ending index of the first occurrence of the specified substring in the string, or returns -1 if not found. +int findEnd(IStr str, IStr item) { + if (str.length < item.length || item.length == 0) return -1; + foreach_reverse (i; 0 .. str.length - item.length + 1) { + if (str[i .. i + item.length] == item) return cast(int) i; + } + return -1; +} + +/// Finds the ending index of the first occurrence of the specified character in the string, or returns -1 if not found. +int findEnd(IStr str, char item) { + return findEnd(str, charToStr(item)); +} + +/// Finds the first occurrence of the specified item in the slice, or returns -1 if not found. +int findItem(IStr[] items, IStr item) { + foreach (i, it; items) if (it == item) return cast(int) i; + return -1; +} + +/// Finds the first occurrence of the specified start in the slice, or returns -1 if not found. +int findItemThatStartsWith(IStr[] items, IStr start) { + foreach (i, it; items) if (it.startsWith(start)) return cast(int) i; + return -1; +} + +/// Finds the first occurrence of the specified end in the slice, or returns -1 if not found. +int findItemThatEndsWith(IStr[] items, IStr end) { + foreach (i, it; items) if (it.endsWith(end)) return cast(int) i; + return -1; +} + +/// Removes whitespace characters from the beginning of the string. +IStr trimStart(IStr str) { + IStr result = str; + while (result.length > 0) { + if (isSpace(result[0])) result = result[1 .. $]; + else break; + } + return result; +} + +/// Removes whitespace characters from the end of the string. +IStr trimEnd(IStr str) { + IStr result = str; + while (result.length > 0) { + if (isSpace(result[$ - 1])) result = result[0 .. $ - 1]; + else break; + } + return result; +} + +/// Removes whitespace characters from both the beginning and end of the string. +IStr trim(IStr str) { + return str.trimStart().trimEnd(); +} + +/// Removes the specified prefix from the beginning of the string if it exists. +IStr removePrefix(IStr str, IStr prefix) { + if (str.startsWith(prefix)) return str[prefix.length .. $]; + else return str; +} + +/// Removes the specified suffix from the end of the string if it exists. +IStr removeSuffix(IStr str, IStr suffix) { + if (str.endsWith(suffix)) return str[0 .. $ - suffix.length]; + else return str; +} + +/// Advances the string by the specified number of characters. +IStr advanceStr(IStr str, Sz amount) { + if (str.length < amount) return str[$ .. $]; + else return str[amount .. $]; +} + +/// Copies characters from the source string to the destination string starting at the specified index. +@trusted +Fault copyChars(Str str, IStr source, Sz startIndex = 0) { + if (str.length < source.length + startIndex) return Fault.overflow; + foreach (i, c; source) str[startIndex + i] = c; + return Fault.none; +} + +/// Copies characters from the source string to the destination string starting at the specified index and adjusts the length of the destination string. +Fault copyStr(ref Str str, IStr source, Sz startIndex = 0) { + auto fault = copyChars(str, source, startIndex); + if (fault) return fault; + str = str[0 .. startIndex + source.length]; + return Fault.none; +} + +/// Concatenates the strings. +/// Writes into the buffer and returns the result. +IStr concatIntoBuffer(Str buffer, IStr[] args...) { + if (args.length == 0) return "."; + auto result = buffer; + auto length = 0; + foreach (i, arg; args) { + result.copyChars(arg, length); + length += arg.length; + } + result = result[0 .. length]; + return result; +} + +/// Concatenates the strings using a static buffer and returns the result. +IStr concat(IStr[] args...) { + static char[512][4] buffers = void; + static byte bufferIndex = 0; + + if (args.length == 0) return "."; + bufferIndex = (bufferIndex + 1) % buffers.length; + return concatIntoBuffer(buffers[bufferIndex][], args); +} + +/// Returns the directory of the path, or "." if there is no directory. +IStr pathDirName(IStr path) { + auto end = findEnd(path, pathSepStr); + if (end == -1) return "."; + else return path[0 .. end]; +} + +/// Returns the extension of the path. +IStr pathExtName(IStr path) { + auto end = findEnd(path, "."); + if (end == -1) return ""; + else return path[end .. $]; +} + +/// Returns the base name of the path. +IStr pathBaseName(IStr path) { + auto end = findEnd(path, pathSepStr); + if (end == -1) return path; + else return path[end + 1 .. $]; +} + +/// Returns the base name of the path without the extension. +IStr pathBaseNameNoExt(IStr path) { + return path.pathBaseName[0 .. $ - path.pathExtName.length]; +} + +/// Removes path separators from the beginning of the path. +IStr pathTrimStart(IStr path) { + IStr result = path; + while (result.length > 0) { + if (result[0] == pathSep || result[0] == pathSepOther) result = result[1 .. $]; + else break; + } + return result; + +} + +/// Removes path separators from the end of the path. +IStr pathTrimEnd(IStr path) { + IStr result = path; + while (result.length > 0) { + if (result[$ - 1] == pathSep || result[$ - 1] == pathSepOther) result = result[0 .. $ - 1]; + else break; + } + return result; +} + +/// Removes path separators from the beginning and end of the path. +IStr pathTrim(IStr path) { + return path.pathTrimStart().pathTrimEnd(); +} + +/// Formats the path to a standard form, normalizing separators. +IStr pathFormat(IStr path) { + static char[512][4] buffers = void; + static byte bufferIndex = 0; + + if (path.length == 0) return "."; + bufferIndex = (bufferIndex + 1) % buffers.length; + auto result = buffers[bufferIndex][]; + foreach (i, c; path) { + if (c == pathSepOther) { + result[i] = pathSep; + } else { + result[i] = c; + } + } + result = result[0 .. path.length]; + return result; +} + +/// Concatenates the paths, ensuring proper path separators between them. +IStr pathConcat(IStr[] args...) { + static char[512][4] buffers = void; + static byte bufferIndex = 0; + + if (args.length == 0) return "."; + bufferIndex = (bufferIndex + 1) % buffers.length; + auto result = buffers[bufferIndex][]; + auto length = 0; + auto isFirst = true; + foreach (i, arg; args) { + if (arg.length == 0) continue; + auto cleanArg = arg; + if (cleanArg[0] == pathSep || cleanArg[0] == pathSepOther) { + cleanArg = cleanArg.pathTrimStart(); + if (isFirst) { + result[length] = pathSep; + length += 1; + } + } + cleanArg = cleanArg.pathTrimEnd(); + result.copyChars(cleanArg, length); + length += cleanArg.length; + if (i != args.length - 1) { + result[length] = pathSep; + length += 1; + } + isFirst = false; + } + if (length == 0) return "."; + result = result[0 .. length]; + return result; +} + +/// Skips over the next occurrence of the specified separator in the string, returning the substring before the separator and updating the input string to start after the separator. +IStr skipValue(ref inout(char)[] str, IStr sep) { + if (str.length < sep.length || sep.length == 0) { + str = str[$ .. $]; + return ""; + } + foreach (i; 0 .. str.length - sep.length) { + if (str[i .. i + sep.length] == sep) { + auto line = str[0 .. i]; + str = str[i + sep.length .. $]; + return line; + } + } + auto line = str[0 .. $]; + if (str[$ - sep.length .. $] == sep) { + line = str[0 .. $ - 1]; + } + str = str[$ .. $]; + return line; +} + +/// Skips over the next occurrence of the specified separator in the string, returning the substring before the separator and updating the input string to start after the separator. +IStr skipValue(ref inout(char)[] str, char sep) { + return skipValue(str, charToStr(sep)); +} + +/// Skips over the next line in the string, returning the substring before the line break and updating the input string to start after the line break. +IStr skipLine(ref inout(char)[] str) { + return skipValue(str, '\n'); +} + +/// Converts the boolean value to its string representation. +IStr boolToStr(bool value) { + return value ? "true" : "false"; +} + +/// Converts the character to its string representation. +IStr charToStr(char value) { + static char[1] buffer = void; + + auto result = buffer[]; + result[0] = value; + result = result[0 .. 1]; + return result; +} + +/// Converts the unsigned long value to its string representation. +IStr unsignedToStr(ulong value) { + static char[64] buffer = void; + + auto result = buffer[]; + if (value == 0) { + result[0] = '0'; + result = result[0 .. 1]; + } else { + auto digitCount = 0; + for (auto temp = value; temp != 0; temp /= 10) { + result[$ - 1 - digitCount] = (temp % 10) + '0'; + digitCount += 1; + } + result = result[$ - digitCount .. $]; + } + return result; +} + +/// Converts the signed long value to its string representation. +IStr signedToStr(long value) { + static char[64] buffer = void; + + auto result = buffer[]; + if (value < 0) { + auto temp = unsignedToStr(-value); + result[0] = '-'; + result.copyStr(temp, 1); + } else { + auto temp = unsignedToStr(value); + result.copyStr(temp, 0); + } + return result; +} + +/// Converts the double value to its string representation with the specified precision. +IStr doubleToStr(double value, ulong precision = 2) { + static char[64] buffer = void; + + if (precision == 0) { + return signedToStr(cast(long) value); + } + + auto result = buffer[]; + auto cleanNumber = value; + auto rightDigitCount = 0; + while (cleanNumber != cast(double) (cast(long) cleanNumber)) { + rightDigitCount += 1; + cleanNumber *= 10; + } + + // Add extra zeros at the end if needed. + // I do this because it makes it easier to remove the zeros later. + if (precision > rightDigitCount) { + foreach (j; 0 .. precision - rightDigitCount) { + rightDigitCount += 1; + cleanNumber *= 10; + } + } + + // Digits go in the buffer from right to left. + auto cleanNumberStr = signedToStr(cast(long) cleanNumber); + auto i = result.length; + // Check two cases: 0.NN, N.NN + if (cast(long) value == 0) { + if (value < 0.0) { + cleanNumberStr = cleanNumberStr[1 .. $]; + } + i -= cleanNumberStr.length; + result.copyChars(cleanNumberStr, i); + foreach (j; 0 .. rightDigitCount - cleanNumberStr.length) { + i -= 1; + result[i] = '0'; + } + i -= 2; + result.copyChars("0.", i); + if (value < 0.0) { + i -= 1; + result[i] = '-'; + } + } else { + i -= rightDigitCount; + result.copyChars(cleanNumberStr[$ - rightDigitCount .. $], i); + i -= 1; + result[i] = '.'; + i -= cleanNumberStr.length - rightDigitCount; + result.copyChars(cleanNumberStr[0 .. $ - rightDigitCount], i); + } + // Remove extra zeros at the end if needed. + if (precision < rightDigitCount) { + result = result[0 .. cast(Sz) ($ - rightDigitCount + precision)]; + } + return result[i .. $]; +} + +/// Converts the C string to a string. +@trusted +IStr cStrToStr(ICStr value) { + return value[0 .. value.cStrLength]; +} + +/// Converts the enum value to its string representation. +IStr enumToStr(T)(T value) { + switch (value) { + static foreach (m; __traits(allMembers, T)) { + mixin("case T.", m, ": return m;"); + } + default: assert(0, "WTF!"); + } +} + +/// Converts the string value to its enum representation. +// NOTE: This function is adapted from Joka and modified for Noby. +T toEnum(T)(IStr str) { + switch (str) { + static foreach (m; __traits(allMembers, T)) { + mixin("case m: return T.", m, ";"); + } + default: return T.init; + } +} diff --git a/scripts/header.d b/scripts/header.d index 0cd57ef..4a3ac13 100755 --- a/scripts/header.d +++ b/scripts/header.d @@ -10,7 +10,7 @@ enum header = ` // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- `[1 .. $ - 1]; diff --git a/source/parin/engine.d b/source/parin/engine.d index e690854..edfaecf 100644 --- a/source/parin/engine.d +++ b/source/parin/engine.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- /// The `engine` module functions as a lightweight 2D game engine. @@ -19,7 +19,8 @@ public import joka.types; @trusted @nogc nothrow: -extern(C) __gshared EngineState* engineState; +extern(C) +__gshared EngineState* engineState; alias EngineUpdateFunc = bool function(float dt); alias EngineReadyFinishFunc = void function(); diff --git a/source/parin/map.d b/source/parin/map.d index f07cb36..01c95a3 100644 --- a/source/parin/map.d +++ b/source/parin/map.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- // TODO: Think about gaps in an atlas texture. diff --git a/source/parin/package.d b/source/parin/package.d index 2048e1b..2843c79 100644 --- a/source/parin/package.d +++ b/source/parin/package.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- module parin; diff --git a/source/parin/platformer.d b/source/parin/platformer.d index a62d0da..0b8358c 100644 --- a/source/parin/platformer.d +++ b/source/parin/platformer.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- // TODO: Update all the doc comments here. diff --git a/source/parin/rl/package.d b/source/parin/rl/package.d index 0ed919d..1160b85 100644 --- a/source/parin/rl/package.d +++ b/source/parin/rl/package.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- /// The `rl` module provides access to the raylib library. diff --git a/source/parin/rl/raylib.d b/source/parin/rl/raylib.d index 057232b..bbd3dd8 100644 --- a/source/parin/rl/raylib.d +++ b/source/parin/rl/raylib.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- /// The `rayib` module provides access to the raylib.h functions. diff --git a/source/parin/rl/rlgl.d b/source/parin/rl/rlgl.d index b2c8498..1a16874 100644 --- a/source/parin/rl/rlgl.d +++ b/source/parin/rl/rlgl.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- /// The `rlgl` module provides access to the rlgl.h functions. diff --git a/source/parin/sprite.d b/source/parin/sprite.d index c1e5912..5795557 100644 --- a/source/parin/sprite.d +++ b/source/parin/sprite.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- // TODO: Think about gaps in an atlas texture. diff --git a/source/parin/story.d b/source/parin/story.d index d001dc7..1246126 100644 --- a/source/parin/story.d +++ b/source/parin/story.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- // TODO: Update all the doc comments here. diff --git a/source/parin/timer.d b/source/parin/timer.d index 87c2ac9..735ab3d 100644 --- a/source/parin/timer.d +++ b/source/parin/timer.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- // TODO: Update all the doc comments here. diff --git a/source/parin/ui.d b/source/parin/ui.d index fe0b573..23aa18c 100644 --- a/source/parin/ui.d +++ b/source/parin/ui.d @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT // Email: alexandroskapretsos@gmail.com // Project: https://github.com/Kapendev/parin -// Version: v0.0.41 +// Version: v0.0.42 // --- /// The `ui` module functions as a immediate mode UI library.