Skip to content

constexpr math functions#1305

Open
OldDev78 wants to merge 8 commits into
Redot-Engine:masterfrom
OldDev78:constexpr-math-funcs
Open

constexpr math functions#1305
OldDev78 wants to merge 8 commits into
Redot-Engine:masterfrom
OldDev78:constexpr-math-funcs

Conversation

@OldDev78

@OldDev78 OldDev78 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Changes some math functions to templates, and a few of them constexpr as well.
Includes some changes, such as making Color constexpr and support for TinyEXR read into a std::span buffer, both of which are requirements for the terrain editor module.

Superseeds #1297

Summary by CodeRabbit

  • New Features
    • Added TinyEXR image loading from in-memory buffers.
    • Expanded the set of built-in named colors.
  • Bug Fixes
    • Improved numeric consistency for rotation/normalization checks, FOV, snapping, date/time computations, and several editor/viewport/grid rendering calculations.
    • Refined color intensity scaling used by the color picker.
  • Refactor
    • Modernized math utilities with stronger typing plus more constexpr/noexcept behavior.
    • Streamlined the Color API by removing multiple packing/HSV/utility helpers and updating related conversions.
  • Tests / Chores
    • Updated math/UI tests and ignore rules (now ignores uv.lock).

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The PR modernizes math and color APIs with C++20 templates, constexpr, and noexcept, updates numeric call sites and tolerance checks, adds named color constants, introduces span-based TinyEXR decoding, and applies related type corrections.

Changes

Math modernization and image loading

Layer / File(s) Summary
Math concepts and generic APIs
core/math/math_defs.h, core/math/math_funcs.h, core/typedefs.h
Math functions and utility templates use constrained generic forms, new constants, C++20 concepts, constexpr, and noexcept declarations.
Color constexpr API and packing
core/math/color.h, core/math/color.cpp
Color packing, conversions, arithmetic, parsing, intensity handling, and named-color constants are modernized with inline constexpr implementations and updated signatures.
Math implementations and tolerance changes
core/math/math_funcs.cpp, core/math/basis.cpp, core/math/quaternion.cpp, core/math/transform_interpolator.cpp, core/math/vector*.cpp, core/math/geometry_2d.cpp, core/math/projection.cpp, core/os/time.cpp
Random, decimal, easing, snapping, and prime helpers are revised; normalization, determinant, projection, geometry scaling, and time calculations use updated comparisons or numeric types.
Typed numeric call sites
editor/..., scene/..., modules/..., servers/rendering/..., platform/macos/...
Editor, scene, module, resource, platform, and rendering calculations explicitly select floating-point types and use updated power, interpolation, remapping, wrapping, snapping, and dispatch expressions.
Buffer-based image decoding
modules/tinyexr/image_loader_tinyexr.h, modules/tinyexr/image_loader_tinyexr.cpp
ImageLoaderTinyEXR exposes span-based decoding, while file loading reads bytes and delegates to the new buffer entry point.
Supporting repository updates
.gitignore, tests/...
uv.lock is ignored and affected tests use explicit numeric or Variant forms.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ImageLoaderTinyEXR
  participant FileAccess
  participant TinyEXRDecoder
  ImageLoaderTinyEXR->>FileAccess: read file bytes
  ImageLoaderTinyEXR->>TinyEXRDecoder: pass std::span buffer
  TinyEXRDecoder->>ImageLoaderTinyEXR: return decoded image result
Loading

Possibly related PRs

  • Redot-Engine/redot-engine#1224: Its monotonic cubic interpolation APIs directly relate to the template constraint updates in core/math/math_funcs.h.

Suggested labels: enhancement, topic:core

Suggested reviewers: arctis-fireblight

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: several math APIs were modernized with constexpr/template updates.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🧹 Nitpick comments (3)
modules/tinyexr/image_loader_tinyexr.h (1)

48-48: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Validate the new public buffer-entry precondition.

The core dispatcher validates p_image before invoking loaders, but direct callers of load_image_from_buffer() bypass that check. A null Ref<Image> will later be dereferenced by set_data(); add the same invalid-parameter guard here.

🤖 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 `@modules/tinyexr/image_loader_tinyexr.h` at line 48, Add an invalid-parameter
guard at the start of load_image_from_buffer() that rejects a null p_image
before any buffer processing or set_data() call, matching the core dispatcher’s
validation and returning the established invalid-parameter error.
core/math/math_funcs.h (2)

46-52: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Constrain sin to std::floating_point to match cos.

cos (Line 51) is constrained to std::floating_point, but sin accepts any typename T. An integer instantiation sin(int) would call std::sin(int) and truncate the double result back to int. Aligning the constraint prevents accidental integer instantiation and keeps the pair consistent.

♻️ Proposed change
-template <typename T>
-_ALWAYS_INLINE_ T sin(T p_x) {
+template <std::floating_point T>
+_ALWAYS_INLINE_ T sin(T p_x) {
 	return std::sin(p_x);
 }
🤖 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 `@core/math/math_funcs.h` around lines 46 - 52, Constrain the `sin` template in
`math_funcs.h` with `std::floating_point`, matching the existing constraint on
`cos`. Leave its implementation and return behavior unchanged while preventing
integer instantiations.

604-614: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Misleading constexpr on helpers that depend on non-constexpr functions.

linear_to_db/db_to_linear are marked constexpr but call log/exp, which forward to std::log/std::exp (not constexpr in C++20). The same applies to other constexpr helpers here that rely on floor/fmod/exp (e.g. fract, wrapf, sigmoid_affine). These can never be constant-evaluated, so the constexpr is aspirational and technically IFNDR. Consider dropping constexpr until the underlying functions are constexpr-capable, or gate the constexpr path.

Based on learnings: don't leave constexpr helpers that depend on non-constexpr functions; either avoid the misleading constexpr or add a safe alternative/gating.

🤖 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 `@core/math/math_funcs.h` around lines 604 - 614, Remove the misleading
constexpr qualifiers from linear_to_db, db_to_linear, and the nearby helpers
that call non-constexpr math functions such as log, exp, floor, or fmod,
including fract, wrapf, and sigmoid_affine. Keep their existing runtime behavior
and noexcept/template interfaces unchanged unless required by the qualifier
removal.

Source: Learnings

🤖 Prompt for all review comments with 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.

Inline comments:
In `@core/math/basis.cpp`:
- Line 128: Update the determinant comparison in is_rotation() to explicitly use
UNIT_EPSILON rather than the default Math::is_equal_approx tolerance, preserving
acceptance of slightly drifted valid rotation bases while retaining the existing
conformality check.

In `@core/math/color.h`:
- Line 608: Rename the public Colors constant PaleTorquoise to PaleTurquoise
while preserving its existing hex value and constexpr definition.

In `@core/math/math_funcs.h`:
- Around line 197-226: Update ipow() to handle negative exponents before
converting exp to unsigned long long: return the reciprocal of ipow(base, -exp),
or otherwise ensure negative values follow the correct pow() semantics. Preserve
the existing zero, one, two, three, and exponentiation-by-squaring fast paths
for non-negative exponents, while safely avoiding overflow when negating the
minimum long long value.
- Around line 386-392: Update the std::is_constant_evaluated() branch to apply
the T(0.5) factor to the entire sum of 2*p_from, a*p_weight, b*w2, and c*w3,
matching the runtime return expression while leaving the runtime path unchanged.
- Around line 103-107: Add the standard <algorithm> header to math_funcs.h so
the clamp template can directly use std::min and std::max. Keep the existing
clamp implementation and behavior unchanged.

In `@core/math/transform_interpolator.cpp`:
- Line 295: Update the determinant validation in the transform interpolation
logic around the is_equal_approx call to retain the previous explicit 0.01f
tolerance, rather than using the default CMP_EPSILON-based overload. Preserve
the existing slerp-versus-INTERP_LERP behavior while allowing the same small
determinant drift as before.

In `@core/typedefs.h`:
- Around line 402-411: Add direct standard-library includes for the concepts and
type-traits facilities used by the unsigned_integral, signed_integral, and
arithmetic concepts in core/typedefs.h. Include <concepts> for std::integral and
<type_traits> for the type-trait checks, without relying on platform_config.h or
other transitive includes.

In `@editor/scene/3d/node_3d_editor_plugin.cpp`:
- Around line 7959-7961: Update the fade-limit calculations near fade_size to
cast division_level_min and division_level_max with static_cast<real_t> before
passing them to Math::pow, matching fsteps and preserving double-precision
builds.

In `@editor/scene/canvas_item_editor_plugin.cpp`:
- Around line 486-487: Update both Math::pow calls in the grid_output.x and
grid_output.y assignments to use real_t for the base as well as the exponent,
replacing 2.f with a real_t-compatible value such as static_cast<real_t>(2).
Preserve the existing snapping calculations and offsets.

In `@modules/tinyexr/image_loader_tinyexr.cpp`:
- Around line 292-300: In ImageLoaderTinyEXR::load_image, capture the byte count
returned by f->get_buffer and reject the input with ERR_FILE_CORRUPT unless it
equals src_image_len. Perform this validation before constructing the buffer
span or invoking TinyEXR decoding, so truncated reads never expose uninitialized
Vector data.

In `@scene/resources/animation.cpp`:
- Line 4579: Update the Math::pow call in the precision calculation to cast the
base literal 0.1 to real_t, matching the existing cast of p_precision and
ensuring both arguments use the same type.

---

Nitpick comments:
In `@core/math/math_funcs.h`:
- Around line 46-52: Constrain the `sin` template in `math_funcs.h` with
`std::floating_point`, matching the existing constraint on `cos`. Leave its
implementation and return behavior unchanged while preventing integer
instantiations.
- Around line 604-614: Remove the misleading constexpr qualifiers from
linear_to_db, db_to_linear, and the nearby helpers that call non-constexpr math
functions such as log, exp, floor, or fmod, including fract, wrapf, and
sigmoid_affine. Keep their existing runtime behavior and noexcept/template
interfaces unchanged unless required by the qualifier removal.

In `@modules/tinyexr/image_loader_tinyexr.h`:
- Line 48: Add an invalid-parameter guard at the start of
load_image_from_buffer() that rejects a null p_image before any buffer
processing or set_data() call, matching the core dispatcher’s validation and
returning the established invalid-parameter error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5f925578-f9aa-4c09-b933-26f948548805

📥 Commits

Reviewing files that changed from the base of the PR and between aab4134 and 8f3de80.

📒 Files selected for processing (37)
  • .gitignore
  • core/math/basis.cpp
  • core/math/color.cpp
  • core/math/color.h
  • core/math/geometry_2d.cpp
  • core/math/math_defs.h
  • core/math/math_funcs.cpp
  • core/math/math_funcs.h
  • core/math/projection.cpp
  • core/math/quaternion.cpp
  • core/math/transform_interpolator.cpp
  • core/math/vector2.cpp
  • core/math/vector3.h
  • core/os/time.cpp
  • core/typedefs.h
  • editor/animation/animation_track_editor_plugins.cpp
  • editor/audio/editor_audio_buses.cpp
  • editor/gui/editor_toaster.cpp
  • editor/import/3d/resource_importer_scene.h
  • editor/scene/2d/tiles/tile_map_layer_editor.cpp
  • editor/scene/3d/node_3d_editor_plugin.cpp
  • editor/scene/canvas_item_editor_plugin.cpp
  • editor/settings/editor_autoload_settings.cpp
  • modules/gridmap/editor/grid_map_editor_plugin.cpp
  • modules/tinyexr/image_loader_tinyexr.cpp
  • modules/tinyexr/image_loader_tinyexr.h
  • scene/3d/spline_ik_3d.cpp
  • scene/gui/color_picker.cpp
  • scene/gui/color_picker_shape.cpp
  • scene/gui/graph_edit.cpp
  • scene/gui/range.cpp
  • scene/gui/rich_text_label.cpp
  • scene/main/canvas_item.cpp
  • scene/resources/3d/primitive_meshes.cpp
  • scene/resources/animation.cpp
  • scene/resources/packed_scene.cpp
  • servers/rendering/renderer_rd/effects/copy_effects.cpp

Comment thread core/math/basis.cpp Outdated
Comment thread core/math/color.h Outdated
Comment thread core/math/math_funcs.h
Comment thread core/math/math_funcs.h
Comment on lines +197 to 226
constexpr T ipow(T base, long long exp) noexcept {
// TODO: Should we handle negatives?
T res = T(1);
T b = base;
unsigned long long e = static_cast<unsigned long long>(exp);

if (exp == 0) {
return res;
}
if (exp == 1) {
return b;
}
if (exp == 2) {
return b * b;
}
if (exp == 3) {
return b * b * b;
}

// exponentiation by squaring.
while (e != 0) {
if (e & 1ULL) {
res *= b;
}
b *= b;
e >>= 1ULL;
}

return res;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant section of the header.
FILE="core/math/math_funcs.h"
wc -l "$FILE"
sed -n '170,260p' "$FILE"

# Find the pow overloads/usages nearby.
rg -n "constexpr .*pow|ipow\(" "$FILE"

Repository: Redot-Engine/redot-engine

Length of output: 2165


Guard the constexpr integer fast-path against negative exponents

pow() sends any integral y into ipow(), including negative values like -2.0. ipow() only handles non-negative exponents, so the cast to unsigned long long turns that into a huge power and produces the wrong constexpr result. Add a y >= 0 check here or handle negatives via 1 / ipow(x, -exp).

🤖 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 `@core/math/math_funcs.h` around lines 197 - 226, Update ipow() to handle
negative exponents before converting exp to unsigned long long: return the
reciprocal of ipow(base, -exp), or otherwise ensure negative values follow the
correct pow() semantics. Preserve the existing zero, one, two, three, and
exponentiation-by-squaring fast paths for non-negative exponents, while safely
avoiding overflow when negating the minimum long long value.

Comment thread core/math/math_funcs.h
Comment thread core/typedefs.h
Comment thread editor/scene/3d/node_3d_editor_plugin.cpp Outdated
Comment thread editor/scene/canvas_item_editor_plugin.cpp Outdated
Comment thread modules/tinyexr/image_loader_tinyexr.cpp
Comment thread scene/resources/animation.cpp Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/math/math_funcs.h (1)

48-50: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Constrain Math::sin to floating-point types.
Match the std::floating_point constraint already used by Math::cos; otherwise Math::sin(1) deduces T = int and returns 0 after truncating the std::sin result.

🤖 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 `@core/math/math_funcs.h` around lines 48 - 50, Constrain the Math::sin
template to std::floating_point types, matching the existing constraint on
Math::cos, so integral arguments such as Math::sin(1) are rejected instead of
producing a truncated result.
🤖 Prompt for all review comments with 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.

Outside diff comments:
In `@core/math/math_funcs.h`:
- Around line 48-50: Constrain the Math::sin template to std::floating_point
types, matching the existing constraint on Math::cos, so integral arguments such
as Math::sin(1) are rejected instead of producing a truncated result.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 54adeb9f-cfed-4565-b0ab-7cfa16e5f294

📥 Commits

Reviewing files that changed from the base of the PR and between 8f3de80 and 1da8121.

📒 Files selected for processing (2)
  • core/math/math_funcs.h
  • core/typedefs.h
🚧 Files skipped from review as they are similar to previous changes (1)
  • core/typedefs.h

@OldDev78 OldDev78 force-pushed the constexpr-math-funcs branch from 1da8121 to 0b59167 Compare July 13, 2026 00:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@tests/core/math/test_math_funcs.h`:
- Line 562: Update the Math::wrapi test case to use the fixed-width int64_t
template type and an LL-suffixed 300-billion input literal, preserving the
existing bounds and expected result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8c691266-d65b-48dc-9b07-6ce62ac194a0

📥 Commits

Reviewing files that changed from the base of the PR and between 1da8121 and 0b59167.

📒 Files selected for processing (7)
  • core/math/color.h
  • core/math/math_funcs.h
  • core/typedefs.h
  • platform/macos/tts_macos.mm
  • tests/core/math/test_math_funcs.h
  • tests/core/templates/test_list.h
  • tests/scene/test_code_edit.h
🚧 Files skipped from review as they are similar to previous changes (3)
  • core/typedefs.h
  • core/math/color.h
  • core/math/math_funcs.h

Comment thread tests/core/math/test_math_funcs.h Outdated
@OldDev78 OldDev78 force-pushed the constexpr-math-funcs branch from 0b59167 to b7cf6d9 Compare July 13, 2026 00:52
@Shakai-Dev Shakai-Dev added this to the Redot LTS 26.3 milestone Jul 13, 2026
@OldDev78 OldDev78 force-pushed the constexpr-math-funcs branch from ffe36a1 to e161094 Compare July 14, 2026 00:54
@OldDev78 OldDev78 requested review from a team July 14, 2026 00:54
@OldDev78 OldDev78 force-pushed the constexpr-math-funcs branch from e161094 to 807034d Compare July 14, 2026 00:58
mcdubhghlas
mcdubhghlas previously approved these changes Jul 14, 2026

@Shakai-Dev Shakai-Dev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall LGTM, only these need to be addressed

Comment thread core/math/color.cpp
Comment thread core/math/color.h
Comment thread core/math/math_funcs.cpp
Comment thread core/math/math_funcs.h
@OldDev78 OldDev78 force-pushed the constexpr-math-funcs branch from 4097d48 to b41268c Compare July 14, 2026 23:15

@Shakai-Dev Shakai-Dev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants