Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 209 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
TabWidth: 4
IndentWidth: 4
ColumnLimit: 80

UseTab: AlignWithSpaces

# Pointer and reference alignment style. Possible values: Left, Right, Middle.
PointerAlignment: Right

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vote for pointer to the left (on the side of the type)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 from me, I tend to prefer int* foo instead of int *foo


# AccessModifierOffset (int)
# The extra indent or outdent of access modifiers, e.g. public:.
AccessModifierOffset: 0

AlignArrayOfStructures: Right
AlignAfterOpenBracket: true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer AlwaysBreak. This is important to comment out parameters without having to worry if it is the first or last one.

AlignConsecutiveAssignments: Consecutive

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure how I feel about this.
On the one hand, it looks pretty, on the other, I think the resulting code might be more difficult to work with after this is applied, such as renaming variables.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When aesthetcs are at odds with ergonomics, ergonomics should win.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

AlignConsecutiveBitFields: Consecutive
AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: Consecutive
AlignConsecutiveShortCaseStatements:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignCaseColons: false


AlignEscapedNewlines: LeftWithLastLine

AlignOperands: Align

AlignTrailingComments:
Kind: Always
AlignPPAndNotPP: true

AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Always

AllowShortBlocksOnASingleLine: Always
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: false

AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLambdasOnASingleLine: Inline
AllowShortLoopsOnASingleLine: true
AllowShortNamespacesOnASingleLine: false

AlwaysBreakBeforeMultilineStrings: false

BitFieldColonSpacing: Both

# TODO Highly Opinionated will need to deliberate on this. I prefer K&R Style but some prefer Allman

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While K&R does save space, I tend to find it harder to read and review than Allman.
Allman makes it a lot easier to mentally keep track of scopes when not using an IDE because the opening and closing brace are at the same indentation level, and most of the time when I am reviewing code changes, I am doing my initial code review inside the GitHub WebUI.

Not sure if we want to have a poll for this or not. But if the C++ team is already heavily leaning towards K&R then I wont really object.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I write code in Allman, but it isn't a hill I care to die on.

BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterStruct: false
AfterExternBlock: false
BeforeCatch: true # catch on separate line, not like we'll use catch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for consistency. I'd also rather have K&R

BeforeElse: true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not having a break for if but having for else will look strange for me.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like

if(false) {
// Stuff
}
else if (true) {

}

if you set BeforeElse to false it would like

if(false) {
// Stuff
} else if (true) {

}

In my opinion that does make it a little harder to read especially if the last line before the else has a lot of values.

BeforeLambdaBody: false
BeforeWhile: true
IndentBraces: false

BreakAdjacentStringLiterals: false
BreakAfterAttributes: Leave

BreakAfterOpenBracketBracedList: false
BreakAfterOpenBracketFunction: false
BreakAfterOpenBracketIf: false
BreakAfterOpenBracketLoop: false
BreakAfterOpenBracketSwitch: false
BreakAfterReturnType: Automatic

BreakBeforeBinaryOperators: None
BreakBeforeCloseBracketBracedList: true
BreakBeforeCloseBracketFunction: true
BreakBeforeCloseBracketIf: true
BreakBeforeCloseBracketSwitch: true

Comment on lines +75 to +87

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Look for clang-format version pinning in repo docs/CI =="
rg -n -S "clang-format|llvm|clang version|PackParameters|BinPackParameters" -g '!**/build/**'

echo
echo "== Show .clang-format lines around version-sensitive settings =="
nl -ba .clang-format | sed -n '70,95p;155,170p'

Repository: Redot-Engine/DraconicEngine

Length of output: 3135


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search for clang-format pinning/version usage (CI/docs/scripts) =="
rg -n -S --hidden --glob '!.git/*' \
  "clang-format[ -]?(1[5-9]|2[0-9]|[3-9][0-9])|clang-format\\b|LLVM_VERSION|clang version|PackParameters|BinPackParameters" \
  .github .gitlab ci scripts tools docs . 2>/dev/null | head -n 200

echo
echo "== Show .clang-format lines 70-95 (with line numbers) =="
awk 'NR>=70 && NR<=95 {printf "%4d:%s\n", NR, $0}' .clang-format

echo
echo "== Show .clang-format lines 155-170 (with line numbers) =="
awk 'NR>=155 && NR<=170 {printf "%4d:%s\n", NR, $0}' .clang-format

Repository: Redot-Engine/DraconicEngine

Length of output: 3186


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== .clang-format lines 70-95 =="
awk 'NR>=70 && NR<=95 {printf "%4d:%s\n", NR, $0}' .clang-format

echo
echo "== .clang-format lines 155-170 =="
awk 'NR>=155 && NR<=170 {printf "%4d:%s\n", NR, $0}' .clang-format

Repository: Redot-Engine/DraconicEngine

Length of output: 1350


Pin and enforce a single clang-format version for this config.

This .clang-format includes a Clang 23–scoped migration note—# TODO Use after upgrading to Clang 23 and currently uses BinPackParameters (with PackParameters commented out)—so different clang-format versions can produce divergent formatting. No explicit repo CI/docs pin for a specific clang-format/Clang version was found (beyond clang-format off/on markers in third-party code). Update CI/docs to install/run the same formatter version for formatting checks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.clang-format around lines 75 - 87, Pin the repository to a single
clang-format version and update CI/docs so everyone uses the same formatter: add
a clear version marker at the top of .clang-format (near the existing "TODO Use
after upgrading to Clang 23" and the BinPackParameters/PackParameters lines) and
update the CI formatting job to install and invoke that exact clang-format
binary (use the distro/package name you choose, e.g., clang-format-XX) and fail
the build when diffs are present; also add a short note to repo docs/README
explaining which clang-format version to install and how to run it locally.
Ensure the CI job name and script call the pinned binary (so
BreakAfterReturnType, BreakBeforeBinaryOperators,
BinPackParameters/PackParameters behavior is deterministic) and keep the TODO
comment indicating upgrade plans.

BreakBeforeConceptDeclarations: Allowed
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTemplateCloser: true
BreakBeforeTernaryOperators: true

BreakConstructorInitializers: AfterColon
BreakFunctionDefinitionParameters: false

BreakInheritanceList: AfterColon

BreakStringLiterals: false

BreakTemplateDeclarations: Leave

CompactNamespaces: false

Cpp11BracedListStyle: FunctionCall

EmptyLineAfterAccessModifier: Leave
EmptyLineBeforeAccessModifier: LogicalBlock

EnumTrailingComma: Leave

FixNamespaceComments: true

IndentAccessModifiers: false

IndentCaseBlocks: false

IndentExportBlock: false
IndentExternBlock: false
IndentGotoLabels: true

IndentPPDirectives: BeforeHash
IndentRequiresClause: false
IndentWrappedFunctionNames: false

# I personally don't like unbraced things but this should be heavily discussed
# For example it's a Pain in the ass to go back and add braces when someone
# didn't include them after you need to extend it
InsertBraces: true

InsertNewlineAtEOF: true

# This one will be controversial...
IntegerLiteralSeparator:
Binary: 4
Decimal: 3
Hex: 4
Comment thread
JoltedJon marked this conversation as resolved.
BinaryMinDigitsInsert: 8
DecimalMinDigitsInsert: 6
HexMinDigitsInsert: 8

KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: false
AtStartOfFile: false

KeepFormFeed: false

# No Microslop BS \r\n
Comment thread
Arctis-Fireblight marked this conversation as resolved.
LineEnding: LF

NamespaceIndentation: None

NumericLiteralCase:
ExponentLetter: Leave
HexDigit: Lower
Prefix: Lower
Suffix: Upper

# TODO Use after upgrading to Clang 23
# PackParameters:
# BinPack: OnePerLine

BinPackParameters: OnePerLine

QualifierAlignment: Right

ReflowComments: Never

RemoveBracesLLVM: false
RemoveEmptyLinesInUnwrappedLines: false
RemoveParentheses: Leave

RemoveSemicolon: false

RequiresExpressionIndentation: OuterScope

SeparateDefinitionBlocks: Leave

SkipMacroDefinitionBody: true

SortIncludes:
Enabled: false

SortUsingDeclarations: Never

SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterOperatorKeyword: false
SpaceAfterTemplateKeyword: false
SpaceAroundPointerQualifiers: Default

SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements

SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBraces: Always

SpacesInAngles: Leave

SpacesInContainerLiterals: false
SpacesInParens: Never
SpacesInSquareBrackets: false


2 changes: 2 additions & 0 deletions .clang-format-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build/*
engine/native/thirdparty/*
28 changes: 13 additions & 15 deletions engine/native/core/definitions/definitions.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,22 @@ export module core.defs;
export import core.version;
export import core.stdtypes;

static_assert(__cplusplus >= 202207L, "Minimum of C++23 required. Consider upgrading your compiler.");
static_assert(__cplusplus >= 202'207L,
"Minimum of C++23 required. Consider upgrading your compiler.");

export namespace draco {
template<typename T>
concept arithmetic = std::is_arithmetic_v<T>;
template<typename T> concept arithmetic = std::is_arithmetic_v<T>;

template<typename T>
concept trivial = std::is_trivial_v<T>;
template<typename T> concept trivial = std::is_trivial_v<T>;

// Whether the default value of a type is just all-0 bytes.
// This can most commonly be exploited by using memset for these types instead of loop-construct.
// Must be explicitly specialized to mark a type as such.
template <typename T>
struct is_zero_constructible : std::false_type {};
// Whether the default value of a type is just all-0 bytes.
// This can most commonly be exploited by using memset for these types instead of loop-construct.
// Must be explicitly specialized to mark a type as such.
template<typename T>
struct is_zero_constructible : std::false_type { };

template <typename T>
constexpr bool is_zero_constructible_v = is_zero_constructible<T>::value;
template<typename T>
constexpr bool is_zero_constructible_v = is_zero_constructible<T>::value;

template <typename T>
concept zero_constructible = is_zero_constructible_v<T>;
}
template<typename T> concept zero_constructible = is_zero_constructible_v<T>;
} // namespace draco
12 changes: 6 additions & 6 deletions engine/native/core/definitions/stdtypes.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@ module;
export module core.stdtypes;

export namespace draco {
using i8 = int8_t;
using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;

using uint = unsigned int;
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;

using f32 = float;
using f64 = double;

using isize = int64_t;
using usize = std::size_t;

using rawptr = void *;
using rawptr = void *;
using uintptr = uintptr_t;
using ptrdiff = ptrdiff_t;

Expand Down
23 changes: 12 additions & 11 deletions engine/native/core/definitions/version.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,23 @@ import core.stdtypes;
export namespace draco {

struct Version {
u16 major;
u16 minor;
u16 patch;
u16 major;
u16 minor;
u16 patch;
};

constexpr Version VERSION{.major = 2026, .minor = 0, .patch = 0};
} // namespace draco

export namespace std {
template <> struct formatter<draco::Version> {
constexpr auto parse(std::format_parse_context &ctx) {
return ctx.begin(); // Accept any format spec (or parse custom ones)
}

auto format(const draco::Version &v, std::format_context &ctx) const {
return std::format_to(ctx.out(), "{}.{}.{}", v.major, v.minor, v.patch);
}
template<> struct formatter<draco::Version> {
constexpr auto parse(std::format_parse_context &ctx) {
return ctx.begin(); // Accept any format spec (or parse custom ones)
}

auto format(draco::Version const &v, std::format_context &ctx) const {
return std::format_to(ctx.out(), "{}.{}.{}", v.major, v.minor, v.patch);
}
};

} // namespace std
64 changes: 30 additions & 34 deletions engine/native/core/io/filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,33 @@ module core.io.filesystem;

import core.stdtypes;

namespace draco::core::io::filesystem
{
std::vector<u8> load_binary(const std::string& path)
{
// Open at the end (ate) to get size and in binary mode
std::ifstream file(path, std::ios::binary | std::ios::ate);

if (!file.is_open()) {
std::println("Error: Could not open file at: {}", path);
// Return an empty vector
return {};
}

std::streamsize size = file.tellg();
if (size < 0) {
std::println("Error: File is empty or unreadable: {}", path);
return {};
}

if (size == 0) {
return {};
}

file.seekg(0, std::ios::beg);

std::vector<u8> buffer(static_cast<std::size_t>(size));
if (file.read(reinterpret_cast<char*>(buffer.data()), size)) {
return buffer;
}

std::println("Error: Failed to read file contents: {}", path);
return {};
}
}
namespace draco::core::io::filesystem {
std::vector<u8> load_binary(std::string const &path) {
// Open at the end (ate) to get size and in binary mode
std::ifstream file(path, std::ios::binary | std::ios::ate);

if (!file.is_open()) {
std::println("Error: Could not open file at: {}", path);
// Return an empty vector
return {};
}

std::streamsize size = file.tellg();
if (size < 0) {
std::println("Error: File is empty or unreadable: {}", path);
return {};
}

if (size == 0) { return {}; }

file.seekg(0, std::ios::beg);

std::vector<u8> buffer(static_cast<std::size_t>(size));
if (file.read(reinterpret_cast<char *>(buffer.data()), size)) {
return buffer;
}

std::println("Error: Failed to read file contents: {}", path);
return {};
}
} // namespace draco::core::io::filesystem
9 changes: 4 additions & 5 deletions engine/native/core/io/filesystem.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ export module core.io.filesystem;

import core.stdtypes;

export namespace draco::core::io::filesystem
{
// Returns a buffer of the file data
std::vector<u8> load_binary(const std::string& path);
}
export namespace draco::core::io::filesystem {
// Returns a buffer of the file data
std::vector<u8> load_binary(std::string const &path);
} // namespace draco::core::io::filesystem
Loading
Loading