Skip to content

Conversation

@WSQS
Copy link
Owner

@WSQS WSQS commented Nov 15, 2025

Summary by CodeRabbit

  • New Features
    • Camera control via arrow keys to adjust viewing angle (UP/DOWN = pitch, LEFT/RIGHT = yaw).
    • Per-frame camera/view transforms applied to rendering for immediate, responsive viewpoint changes.
    • Scene now loads with a neutral (identity) camera for a stable default orientation.
    • Shader support updated so camera/view uniforms are uploaded each frame and view updates are consistently applied.

@coderabbitai
Copy link

coderabbitai bot commented Nov 15, 2025

Walkthrough

Adds a CameraUniform and yaw/pitch state to UserApp, computes a per-frame 4×4 view matrix and uploads it as a vertex uniform; extends GpuWrapper::create_shader to accept a uniform-buffer count and updates shader creation call sites to pass that count.

Changes

Cohort / File(s) Summary
Camera uniform & input
main.cpp
Adds struct CameraUniform { std::array<float,16> m{}; }; adds float yaw, float pitch, and CameraUniform cam to UserApp; initializes cam to identity; computes view matrix from yaw/pitch each frame and uploads it with SDL_PushGPUVertexUniformData; handles arrow keys to adjust yaw/pitch; binds uniform before draw.
GpuWrapper API
sdl_wrapper/sdl_wrapper.gpu.ixx
Changes create_shader signature to accept uint32_t p_num_uniform_buffers and assigns SDL_GPUShaderCreateInfo.num_uniform_buffers from that parameter (replacing a hardcoded zero).
Pipeline shader creation
sdl_wrapper/sdl_wrapper.pipeline.cpp
Updates shader creation call sites to the new three-parameter form, e.g. create_shader(code, SDL_GPU_SHADERSTAGE_VERTEX, 1) and create_shader(code, SDL_GPU_SHADERSTAGE_FRAGMENT, 0).

Sequence Diagram(s)

sequenceDiagram
    participant Input as Input Handler
    participant App as UserApp
    participant GPU as GPU / Shader

    Input->>App: Arrow key events (LEFT/RIGHT/UP/DOWN)
    App->>App: update yaw / pitch (clamp pitch)
    Note right of App `#DDEBF7`: compute 4×4 view matrix (cam.m)
    App->>GPU: SDL_PushGPUVertexUniformData(cam) and bind vertex uniform
    GPU->>GPU: vertex shader multiplies positions by uView (cam)
    GPU->>GPU: rasterize / draw
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Verify matrix construction order and rotation (Rx/Ry) and whether it matches coordinate conventions in shaders.
  • Confirm num_uniform_buffers values match shader uniform block declarations and the pushed uniform data layout/size.
  • Check all shader creation call sites and linked pipeline code for the updated signature and correct stage/count pairs.

Possibly related PRs

Poem

🐇
I twitch my whiskers, yaw and pitch in play,
Arrow keys nudge the view where triangles sway.
I fold a matrix neat inside a tiny span,
Push it to the GPU — watch the scene begin to man.
A rabbit renderer hops and leads the way.

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title lacks clarity and contains grammatical issues; 'add control rotate' is vague and doesn't clearly convey the main change of adding camera rotation control via keyboard input. Revise the title to be more precise and grammatically correct, such as: 'Add camera rotation control with arrow keys' or 'Implement camera view matrix with keyboard control'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch camera

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 and usage tips.

@coderabbitai
Copy link

coderabbitai bot commented Nov 15, 2025

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #31

@deepsource-io
Copy link
Contributor

deepsource-io bot commented Nov 15, 2025

Here's the code health analysis summary for commits 41f3af5..38efee3. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource C & C++ LogoC & C++❌ Failure
❗ 10 occurences introduced
🎯 94 occurences resolved
View Check ↗

💡 If you’re a repository administrator, you can configure the quality gates from the settings.

coderabbitai bot added a commit that referenced this pull request Nov 15, 2025
Docstrings generation was requested by @WSQS.

* #30 (comment)

The following files were modified:

* `main.cpp`
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 78. Check the log or trigger a new build to see more.

#include <SDL3/SDL.h>
#include <SDL3/SDL_gpu.h>
#include "SDL3/SDL_log.h"
import sdl_wrapper;

Choose a reason for hiding this comment

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

warning: module 'sdl_wrapper' not found [clang-diagnostic-error]

import sdl_wrapper;
       ^


struct CameraUniform
{
std::array<float, 16> m{};

Choose a reason for hiding this comment

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

warning: 16 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

    std::array<float, 16> m{};
                      ^

sopho::BufferWrapper vertex_buffer{gpu_wrapper->create_buffer(SDL_GPU_BUFFERUSAGE_VERTEX, sizeof(vertices))};
sopho::PipelineWrapper pipeline_wrapper{gpu_wrapper->create_pipeline()};

float yaw = 0.0f;

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float yaw = 0.0f;
float yaw = 0.0F;

sopho::PipelineWrapper pipeline_wrapper{gpu_wrapper->create_pipeline()};

float yaw = 0.0f;
float pitch = 0.0f;

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float pitch = 0.0f;
float pitch = 0.0F;


{

float cy = std::cos(yaw);

Choose a reason for hiding this comment

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

warning: variable 'cy' of type 'float' can be declared 'const' [misc-const-correctness]

Suggested change
float cy = std::cos(yaw);
float const cy = std::cos(yaw);

main.cpp Outdated
float cp = std::cos(pitch);
float sp = std::sin(pitch);

float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0F, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

main.cpp Outdated
float cp = std::cos(pitch);
float sp = std::sin(pitch);

float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0F, 0.0f, 0.0f, 0.0f, 1.0f};

main.cpp Outdated
float cp = std::cos(pitch);
float sp = std::sin(pitch);

float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0F, 0.0f, 0.0f, 1.0f};

main.cpp Outdated
float cp = std::cos(pitch);
float sp = std::sin(pitch);

float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0F, 0.0f, 1.0f};

main.cpp Outdated
float cp = std::cos(pitch);
float sp = std::sin(pitch);

float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0F, 1.0f};

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
sdl_wrapper/sdl_wrapper.pipeline.cpp (1)

128-128: Consider using named constants for uniform buffer counts.

The hardcoded values 1 and 0 passed as the third parameter to create_shader are not self-documenting. Using named constants would improve readability and maintainability.

Consider defining constants at the class or namespace level:

// At class or namespace scope
static constexpr uint32_t VERTEX_UNIFORM_BUFFER_COUNT = 1;
static constexpr uint32_t FRAGMENT_UNIFORM_BUFFER_COUNT = 0;

Then use them in the calls:

-            m_vertex_shader = m_device->create_shader(code, SDL_GPU_SHADERSTAGE_VERTEX, 1);
+            m_vertex_shader = m_device->create_shader(code, SDL_GPU_SHADERSTAGE_VERTEX, VERTEX_UNIFORM_BUFFER_COUNT);
-            m_fragment_shader = m_device->create_shader(code, SDL_GPU_SHADERSTAGE_FRAGMENT, 0);
+            m_fragment_shader = m_device->create_shader(code, SDL_GPU_SHADERSTAGE_FRAGMENT, FRAGMENT_UNIFORM_BUFFER_COUNT);

Also applies to: 157-157

main.cpp (3)

94-101: Consider simplifying identity matrix initialization.

The manual identity matrix initialization is correct but verbose. You could simplify it with standard library utilities or a helper function.

Example using std::fill:

std::fill(cam.m.begin(), cam.m.end(), 0.0F);
cam.m[0] = cam.m[5] = cam.m[10] = cam.m[15] = 1.0F;

Or create a reusable helper:

static void setIdentity(std::array<float, 16>& mat) {
    std::fill(mat.begin(), mat.end(), 0.0F);
    mat[0] = mat[5] = mat[10] = mat[15] = 1.0F;
}

262-288: Consider extracting matrix operations for reusability.

The view matrix computation is mathematically correct, but the inline lambda for matrix multiplication adds complexity to the draw function. Extracting it would improve readability and enable reuse.

Consider moving matrix operations to helper functions:

// At class or namespace scope
static void multiply4x4(const float* A, const float* B, float* result) {
    for (int col = 0; col < 4; ++col) {
        for (int row = 0; row < 4; ++row) {
            result[col * 4 + row] = 
                A[0 * 4 + row] * B[col * 4 + 0] +
                A[1 * 4 + row] * B[col * 4 + 1] +
                A[2 * 4 + row] * B[col * 4 + 2] +
                A[3 * 4 + row] * B[col * 4 + 3];
        }
    }
}

static void makeRotationY(float angle, float* matrix) {
    float c = std::cos(angle);
    float s = std::sin(angle);
    float temp[16] = {
        c, 0.0f, s, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f,
        -s, 0.0f, c, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    };
    std::copy(std::begin(temp), std::end(temp), matrix);
}

This would make the draw function more readable while keeping the matrix math testable and reusable.


337-356: Input handling looks good; consider angle normalization for long sessions.

The keyboard controls correctly update yaw and pitch angles. The implementation is straightforward and functional.

For very long sessions, unbounded angle accumulation could lead to floating-point precision loss. Consider normalizing angles to the range [0, 2π) or [-π, π):

// After updating yaw or pitch:
yaw = std::fmod(yaw, 2.0f * M_PI);
pitch = std::fmod(pitch, 2.0f * M_PI);

Or clamp pitch to prevent gimbal lock:

pitch = std::clamp(pitch, -M_PI/2.0f + 0.01f, M_PI/2.0f - 0.01f);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41f3af5 and c7c2a5f.

📒 Files selected for processing (3)
  • main.cpp (5 hunks)
  • sdl_wrapper/sdl_wrapper.gpu.ixx (2 hunks)
  • sdl_wrapper/sdl_wrapper.pipeline.cpp (2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-13T11:35:48.273Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:37-43
Timestamp: 2025-11-13T11:35:48.273Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, null pointer validation for the GpuWrapper::create_buffer method (checking m_device, SDL_CreateGPUBuffer return value, and shared_from_this() validity) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
  • sdl_wrapper/sdl_wrapper.gpu.ixx
  • sdl_wrapper/sdl_wrapper.pipeline.cpp
📚 Learning: 2025-11-14T00:45:09.377Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:73-76
Timestamp: 2025-11-14T00:45:09.377Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, validation for m_window in the GpuWrapper::get_texture_formate() method (checking if m_window is nullptr before calling SDL_GetGPUSwapchainTextureFormat) is deferred to a future window wrapper implementation and should not be flagged in reviews.

Applied to files:

  • main.cpp
  • sdl_wrapper/sdl_wrapper.gpu.ixx
  • sdl_wrapper/sdl_wrapper.pipeline.cpp
📚 Learning: 2025-11-13T11:34:32.714Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.buffer.ixx:0-0
Timestamp: 2025-11-13T11:34:32.714Z
Learning: In sdl_wrapper/sdl_wrapper.buffer.ixx, null pointer validation for the BufferWrapper constructor (checking p_gpu, p_gpu->data(), and SDL_CreateGPUBuffer return value) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
  • sdl_wrapper/sdl_wrapper.gpu.ixx
  • sdl_wrapper/sdl_wrapper.pipeline.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: build (Release, gcc)
  • GitHub Check: build (windows-latest, Release, clang)
  • GitHub Check: build (windows-latest, Release, cl)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (windows-latest, Debug, clang)
  • GitHub Check: build (windows-latest, Debug, cl)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: build (windows-latest, Debug, gcc)
  • GitHub Check: build (Release, clang)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (windows-latest, Release, cl)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: build (windows-latest, Release, clang)
  • GitHub Check: build (Release, gcc)
  • GitHub Check: build (windows-latest, Debug, gcc)
  • GitHub Check: build (windows-latest, Debug, clang)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: clang-tidy-review
  • GitHub Check: build (windows-latest, Debug, cl)
🔇 Additional comments (4)
sdl_wrapper/sdl_wrapper.gpu.ixx (1)

51-63: LGTM! Clean API extension.

The addition of the p_num_uniform_buffers parameter cleanly extends the shader creation API to support uniform buffers. The parameter naming is consistent with the codebase conventions, and it's correctly propagated to the SDL GPU shader creation info.

main.cpp (3)

23-26: LGTM! Simple and appropriate data structure.

The CameraUniform struct correctly holds a 4×4 matrix as a 16-element float array, matching the shader's mat4 uView uniform declaration.


34-35: LGTM! Appropriate camera state initialization.

The camera control state (yaw, pitch) and uniform buffer are properly initialized as member variables with sensible default values.

Also applies to: 44-44


53-60: LGTM! Shader uniform integration is correct.

The Camera uniform block declaration and view matrix transformation are properly implemented. The matrix multiplication order (uView * vec4(a_position, 1.0f)) follows the correct column-major convention for Vulkan/OpenGL.

WSQS and others added 2 commits November 16, 2025 09:50
* 📝 Add docstrings to `camera`

Docstrings generation was requested by @WSQS.

* #30 (comment)

The following files were modified:

* `main.cpp`

* style: format code with ClangFormat

This commit fixes the style issues introduced in 10bd2e2 according to the output
from ClangFormat.

Details: #31

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 79. Check the log or trigger a new build to see more.

{
float x, y, z; // vec3 position
float r, g, b, a; // vec4 color
float r, g, b, a; /**

Choose a reason for hiding this comment

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

warning: member variable 'a' has public visibility [misc-non-private-member-variables-in-classes]

    float r, g, b, a; // vec4 color
                   ^

{
float x, y, z; // vec3 position
float r, g, b, a; // vec4 color
float r, g, b, a; /**

Choose a reason for hiding this comment

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

warning: member variable 'b' has public visibility [misc-non-private-member-variables-in-classes]

    float r, g, b, a; // vec4 color
                ^

{
float x, y, z; // vec3 position
float r, g, b, a; // vec4 color
float r, g, b, a; /**

Choose a reason for hiding this comment

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

warning: member variable 'g' has public visibility [misc-non-private-member-variables-in-classes]

    float r, g, b, a; // vec4 color
             ^

{
float x, y, z; // vec3 position
float r, g, b, a; // vec4 color
float r, g, b, a; /**

Choose a reason for hiding this comment

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

warning: member variable 'r' has public visibility [misc-non-private-member-variables-in-classes]

    float r, g, b, a; // vec4 color
          ^

auto position() { return &x; }
};

struct CameraUniform

Choose a reason for hiding this comment

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

warning: destructor of 'UserApp' is public and non-virtual [cppcoreguidelines-virtual-class-destructor]

class UserApp : public sopho::App
      ^
Additional context

main.cpp:27: make it public and virtual

class UserApp : public sopho::App
      ^


float cy = std::cos(yaw);
float sy = std::sin(yaw);
float cp = std::cos(pitch);

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float cp = std::cos(pitch);
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0F, 0.0f, 0.0f, 0.0f, 1.0f};


float cy = std::cos(yaw);
float sy = std::sin(yaw);
float cp = std::cos(pitch);

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float cp = std::cos(pitch);
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0F, 0.0f, 0.0f, 1.0f};


float cy = std::cos(yaw);
float sy = std::sin(yaw);
float cp = std::cos(pitch);

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float cp = std::cos(pitch);
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0F, 0.0f, 1.0f};


float cy = std::cos(yaw);
float sy = std::sin(yaw);
float cp = std::cos(pitch);

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float cp = std::cos(pitch);
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0F, 1.0f};


float cy = std::cos(yaw);
float sy = std::sin(yaw);
float cp = std::cos(pitch);

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float cp = std::cos(pitch);
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0F};

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
main.cpp (2)

94-101: Consider a more maintainable identity matrix initialization.

The manual element-by-element initialization is correct but verbose and error-prone.

Apply this diff to use a clearer approach:

-        {
-            // identity
-            cam.m[0] = cam.m[5] = cam.m[10] = cam.m[15] = 1.0F;
-            cam.m[1] = cam.m[2] = cam.m[3] = 0.0F;
-            cam.m[4] = cam.m[6] = cam.m[7] = 0.0F;
-            cam.m[8] = cam.m[9] = cam.m[11] = 0.0F;
-            cam.m[12] = cam.m[13] = cam.m[14] = 0.0F;
-        }
+        // Initialize camera to identity matrix
+        std::fill(cam.m.begin(), cam.m.end(), 0.0F);
+        cam.m[0] = cam.m[5] = cam.m[10] = cam.m[15] = 1.0F;

262-288: Optimize view matrix computation.

The mulMat4 lambda is defined every frame, adding unnecessary overhead. Additionally, the view matrix is recomputed every frame even when yaw and pitch haven't changed.

Consider these improvements:

  1. Move the lambda to class scope or use a static helper function:

Add to the class:

static void mulMat4(const float* A, const float* B, float* C)
{
    for (int col = 0; col < 4; ++col)
    {
        for (int row = 0; row < 4; ++row)
        {
            C[col * 4 + row] = A[0 * 4 + row] * B[col * 4 + 0] + A[1 * 4 + row] * B[col * 4 + 1] +
                A[2 * 4 + row] * B[col * 4 + 2] + A[3 * 4 + row] * B[col * 4 + 3];
        }
    }
}
  1. Track if camera changed and only recompute when needed:

Add a member: bool camera_dirty = true;

In event(): Set camera_dirty = true; after modifying yaw or pitch.

In draw(): Only recompute if camera_dirty, then set it to false.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c7c2a5f and a3e8d2d.

📒 Files selected for processing (1)
  • main.cpp (5 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-11-13T02:58:26.859Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:0-0
Timestamp: 2025-11-13T02:58:26.859Z
Learning: The sdl_wrapper library (in the repository WSQS/sdl_test) does not allow throwing exceptions. Error handling must use return codes, validity checks, or other non-exception mechanisms.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-13T11:35:48.273Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:37-43
Timestamp: 2025-11-13T11:35:48.273Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, null pointer validation for the GpuWrapper::create_buffer method (checking m_device, SDL_CreateGPUBuffer return value, and shared_from_this() validity) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-13T11:34:32.714Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.buffer.ixx:0-0
Timestamp: 2025-11-13T11:34:32.714Z
Learning: In sdl_wrapper/sdl_wrapper.buffer.ixx, null pointer validation for the BufferWrapper constructor (checking p_gpu, p_gpu->data(), and SDL_CreateGPUBuffer return value) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-14T00:45:09.377Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:73-76
Timestamp: 2025-11-14T00:45:09.377Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, validation for m_window in the GpuWrapper::get_texture_formate() method (checking if m_window is nullptr before calling SDL_GetGPUSwapchainTextureFormat) is deferred to a future window wrapper implementation and should not be flagged in reviews.

Applied to files:

  • main.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: build (windows-latest, Release, clang)
  • GitHub Check: build (Release, clang)
  • GitHub Check: build (Release, gcc)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (windows-latest, Debug, clang)
  • GitHub Check: build (windows-latest, Debug, cl)
  • GitHub Check: build (windows-latest, Debug, gcc)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: clang-tidy-review
  • GitHub Check: build (windows-latest, Debug, clang)
  • GitHub Check: build (windows-latest, Release, clang)
  • GitHub Check: build (windows-latest, Release, cl)
  • GitHub Check: build (windows-latest, Debug, cl)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (windows-latest, Debug, gcc)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: build (Release, clang)
  • GitHub Check: build (Release, gcc)
🔇 Additional comments (5)
main.cpp (5)

2-2: LGTM!

The <cmath> include is necessary for the trigonometric functions and std::clamp used in the camera rotation logic.


23-26: LGTM!

The CameraUniform struct correctly wraps a 4×4 matrix. The magic number warning for 16 is already flagged by static analysis.


34-35: LGTM!

Camera state members are properly initialized. Style issues (lowercase f suffixes) are already flagged by static analysis.

Also applies to: 44-44


337-358: LGTM!

The arrow key handling correctly updates camera orientation with proper pitch clamping to prevent gimbal lock. The increment values provide reasonable rotation speed.


53-60: Uniform slot mapping is correct—no action needed.

The shader correctly uses set = 1, binding = 0 for vertex uniform buffers, which aligns with SDL GPU's fixed resource set architecture where vertex uniforms are assigned to set 1. The SDL_PushGPUVertexUniformData slot parameter (0) refers to which of the 4 available uniform slots to write to, separate from the shader's set/binding designations. The mapping is valid.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 58. Check the log or trigger a new build to see more.

{
float x, y, z; // vec3 position
float r, g, b, a; // vec4 color
float r, g, b, a; /**

Choose a reason for hiding this comment

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

warning: member variable 'a' has public visibility [misc-non-private-member-variables-in-classes]

    float r, g, b, a; /**
                   ^

{
float x, y, z; // vec3 position
float r, g, b, a; // vec4 color
float r, g, b, a; /**

Choose a reason for hiding this comment

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

warning: member variable 'b' has public visibility [misc-non-private-member-variables-in-classes]

    float r, g, b, a; /**
                ^

{
float x, y, z; // vec3 position
float r, g, b, a; // vec4 color
float r, g, b, a; /**

Choose a reason for hiding this comment

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

warning: member variable 'g' has public visibility [misc-non-private-member-variables-in-classes]

    float r, g, b, a; /**
             ^

{
float x, y, z; // vec3 position
float r, g, b, a; // vec4 color
float r, g, b, a; /**

Choose a reason for hiding this comment

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

warning: member variable 'r' has public visibility [misc-non-private-member-variables-in-classes]

    float r, g, b, a; /**
          ^

main.cpp Outdated
float cp = std::cos(pitch);
float sp = std::sin(pitch);

float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0F};

main.cpp Outdated

float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

float Rx[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, cp, sp, 0.0f, 0.0f, -sp, cp, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

Choose a reason for hiding this comment

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

warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix]

Suggested change
float Rx[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, cp, sp, 0.0f, 0.0f, -sp, cp, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
float Rx[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, cp, sp, 0.0f, 0.0f, -sp, cp, 0.0f, 0.0f, 0.0f, 0.0f, 1.0F};

main.cpp Outdated

float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

float Rx[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, cp, sp, 0.0f, 0.0f, -sp, cp, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

Choose a reason for hiding this comment

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

warning: variable 'Rx' of type 'float[16]' can be declared 'const' [misc-const-correctness]

Suggested change
float Rx[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, cp, sp, 0.0f, 0.0f, -sp, cp, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
float const Rx[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, cp, sp, 0.0f, 0.0f, -sp, cp, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

main.cpp Outdated

float Ry[16] = {cy, 0.0f, sy, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -sy, 0.0f, cy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

float Rx[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, cp, sp, 0.0f, 0.0f, -sp, cp, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

Choose a reason for hiding this comment

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

warning: variable name 'Rx' is too short, expected at least 3 characters [readability-identifier-length]

            float Rx[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, cp, sp, 0.0f, 0.0f, -sp, cp, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
                  ^


float Rx[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, cp, sp, 0.0f, 0.0f, -sp, cp, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

auto mulMat4 = [](const float* A, const float* B, float* C)

Choose a reason for hiding this comment

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

warning: parameter name 'A' is too short, expected at least 3 characters [readability-identifier-length]

            auto mulMat4 = [](const float* A, const float* B, float* C)
                                           ^


float Rx[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, cp, sp, 0.0f, 0.0f, -sp, cp, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

auto mulMat4 = [](const float* A, const float* B, float* C)

Choose a reason for hiding this comment

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

warning: parameter name 'B' is too short, expected at least 3 characters [readability-identifier-length]

            auto mulMat4 = [](const float* A, const float* B, float* C)
                                                           ^

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
main.cpp (2)

265-291: Verify rotation matrix correctness and consider extraction.

The rotation matrices and multiplication logic should be verified to ensure correct camera behavior:

  1. Confirm that the matrix element ordering and signs produce the intended rotation (yaw around Y, pitch around X).
  2. Verify that the multiplication order Rx * Ry achieves the desired pitch-then-yaw transformation.
  3. Consider whether a view matrix should also include translation (camera position), or if rotation-only is intentional.

Consider extracting the matrix multiplication lambda and rotation matrix construction into named helper functions to improve readability and reusability:

+    auto createRotationY = [](float angle) -> std::array<float, 16> {
+        const float c = std::cos(angle);
+        const float s = std::sin(angle);
+        return {c, 0.0F, -s, 0.0F,
+                0.0F, 1.0F, 0.0F, 0.0F,
+                s, 0.0F, c, 0.0F,
+                0.0F, 0.0F, 0.0F, 1.0F};
+    };
+
+    auto createRotationX = [](float angle) -> std::array<float, 16> {
+        const float c = std::cos(angle);
+        const float s = std::sin(angle);
+        return {1.0F, 0.0F, 0.0F, 0.0F,
+                0.0F, c, s, 0.0F,
+                0.0F, -s, c, 0.0F,
+                0.0F, 0.0F, 0.0F, 1.0F};
+    };
+
+    auto multiplyMat4 = [](const std::array<float, 16>& A, const std::array<float, 16>& B) -> std::array<float, 16> {
+        std::array<float, 16> C{};
+        for (int col = 0; col < 4; ++col) {
+            for (int row = 0; row < 4; ++row) {
+                C[col * 4 + row] = A[0 * 4 + row] * B[col * 4 + 0] + 
+                                   A[1 * 4 + row] * B[col * 4 + 1] +
+                                   A[2 * 4 + row] * B[col * 4 + 2] + 
+                                   A[3 * 4 + row] * B[col * 4 + 3];
+            }
+        }
+        return C;
+    };

345-356: Consider using named constants for rotation increments.

The magic number 0.1f is used for rotation speed. While functional, consider extracting this to a named constant for clarity and easier tuning.

+    static constexpr float ROTATION_SPEED = 0.1F;
+
     if (event->type == SDL_EVENT_KEY_DOWN)
     {
         switch (event->key.key)
         {
         case SDLK_UP:
-            pitch += 0.1f;
+            pitch += ROTATION_SPEED;
             pitch = std::clamp<float>(pitch, -M_PI_2, M_PI_2);
             break;
         case SDLK_DOWN:
-            pitch -= 0.1f;
+            pitch -= ROTATION_SPEED;
             pitch = std::clamp<float>(pitch, -M_PI_2, M_PI_2);
             break;
         case SDLK_LEFT:
-            yaw += 0.1f;
+            yaw += ROTATION_SPEED;
             break;
         case SDLK_RIGHT:
-            yaw -= 0.1f;
+            yaw -= ROTATION_SPEED;
             break;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3e8d2d and b97f81b.

📒 Files selected for processing (1)
  • main.cpp (7 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-11-13T02:58:26.859Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:0-0
Timestamp: 2025-11-13T02:58:26.859Z
Learning: The sdl_wrapper library (in the repository WSQS/sdl_test) does not allow throwing exceptions. Error handling must use return codes, validity checks, or other non-exception mechanisms.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-13T11:35:48.273Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:37-43
Timestamp: 2025-11-13T11:35:48.273Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, null pointer validation for the GpuWrapper::create_buffer method (checking m_device, SDL_CreateGPUBuffer return value, and shared_from_this() validity) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-13T11:34:32.714Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.buffer.ixx:0-0
Timestamp: 2025-11-13T11:34:32.714Z
Learning: In sdl_wrapper/sdl_wrapper.buffer.ixx, null pointer validation for the BufferWrapper constructor (checking p_gpu, p_gpu->data(), and SDL_CreateGPUBuffer return value) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-14T00:45:09.377Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:73-76
Timestamp: 2025-11-14T00:45:09.377Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, validation for m_window in the GpuWrapper::get_texture_formate() method (checking if m_window is nullptr before calling SDL_GetGPUSwapchainTextureFormat) is deferred to a future window wrapper implementation and should not be flagged in reviews.

Applied to files:

  • main.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: build (windows-latest, Release, clang)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (Release, gcc)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: clang-tidy-review
  • GitHub Check: build (Debug, gcc)
🔇 Additional comments (2)
main.cpp (2)

98-105: Camera initialization is correct.

The explicit identity matrix initialization is clear and correct.


58-65: Assign num_uniform_buffers to shader create info—currently the parameter is passed but never used.

In sdl_wrapper/sdl_wrapper.gpu.ixx lines 51-63, the create_shader function receives p_num_uniform_buffers but never assigns it to the SDL_GPUShaderCreateInfo structure. This causes SDL to incorrectly configure the shader descriptor layout, preventing the uniform buffer at set 1 from being bound.

auto create_shader(const std::vector<uint8_t>& p_shader, SDL_GPUShaderStage p_stage, uint32_t p_num_uniform_buffers)
{
    SDL_GPUShaderCreateInfo vertexInfo{};
    vertexInfo.code = p_shader.data();
    vertexInfo.code_size = p_shader.size();
    
    vertexInfo.format = SDL_GPU_SHADERFORMAT_SPIRV;
    vertexInfo.stage = p_stage;
    vertexInfo.num_uniform_buffers = p_num_uniform_buffers;  // ← Missing assignment
    
    return SDL_CreateGPUShader(m_device, &vertexInfo);
}

Without this assignment, the shader will fail at runtime when SDL_PushGPUVertexUniformData attempts to push data to a descriptor set that SDL was never configured to expect.

⛔ Skipped due to learnings
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.buffer.ixx:0-0
Timestamp: 2025-11-13T11:34:32.714Z
Learning: In sdl_wrapper/sdl_wrapper.buffer.ixx, null pointer validation for the BufferWrapper constructor (checking p_gpu, p_gpu->data(), and SDL_CreateGPUBuffer return value) is deferred to a future issue and should not be flagged in reviews.
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:37-43
Timestamp: 2025-11-13T11:35:48.273Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, null pointer validation for the GpuWrapper::create_buffer method (checking m_device, SDL_CreateGPUBuffer return value, and shared_from_this() validity) is deferred to a future issue and should not be flagged in reviews.
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:73-76
Timestamp: 2025-11-14T00:45:09.377Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, validation for m_window in the GpuWrapper::get_texture_formate() method (checking if m_window is nullptr before calling SDL_GetGPUSwapchainTextureFormat) is deferred to a future window wrapper implementation and should not be flagged in reviews.

WSQS and others added 3 commits November 16, 2025 10:00
This commit fixes the style issues introduced in c433140 according to the output
from ClangFormat.

Details: #30
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 48. Check the log or trigger a new build to see more.

{
for (int col = 0; col < 4; ++col)
{
for (int row = 0; row < 4; ++row)

Choose a reason for hiding this comment

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

warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]

Suggested change
for (int row = 0; row < 4; ++row)
C[col * 4 + row] = A[(0 * 4) + row] * B[col * 4 + 0] + A[1 * 4 + row] * B[col * 4 + 1] +

{
for (int col = 0; col < 4; ++col)
{
for (int row = 0; row < 4; ++row)

Choose a reason for hiding this comment

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

warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]

Suggested change
for (int row = 0; row < 4; ++row)
C[col * 4 + row] = A[0 * 4 + row] * B[(col * 4) + 0] + A[1 * 4 + row] * B[col * 4 + 1] +

{
for (int col = 0; col < 4; ++col)
{
for (int row = 0; row < 4; ++row)

Choose a reason for hiding this comment

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

warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]

Suggested change
for (int row = 0; row < 4; ++row)
C[col * 4 + row] = A[0 * 4 + row] * B[col * 4 + 0] + A[(1 * 4) + row] * B[col * 4 + 1] +

{
for (int col = 0; col < 4; ++col)
{
for (int row = 0; row < 4; ++row)

Choose a reason for hiding this comment

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

warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses]

Suggested change
for (int row = 0; row < 4; ++row)
C[col * 4 + row] = A[0 * 4 + row] * B[col * 4 + 0] + A[1 * 4 + row] * B[(col * 4) + 1] +

{
for (int col = 0; col < 4; ++col)
{
for (int row = 0; row < 4; ++row)

Choose a reason for hiding this comment

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

warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]

                        C[col * 4 + row] = A[0 * 4 + row] * B[col * 4 + 0] + A[1 * 4 + row] * B[col * 4 + 1] +
                                                                                              ^

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
main.cpp (2)

100-107: Consider a more concise identity matrix initialization.

The manual element-by-element initialization is correct but verbose and harder to verify. A loop-based approach would be clearer and less error-prone.

-        {
-            // identity
-            cam.m[0] = cam.m[5] = cam.m[10] = cam.m[15] = 1.0F;
-            cam.m[1] = cam.m[2] = cam.m[3] = 0.0F;
-            cam.m[4] = cam.m[6] = cam.m[7] = 0.0F;
-            cam.m[8] = cam.m[9] = cam.m[11] = 0.0F;
-            cam.m[12] = cam.m[13] = cam.m[14] = 0.0F;
-        }
+        // Initialize camera to identity matrix
+        std::fill(cam.m.begin(), cam.m.end(), 0.0F);
+        cam.m[0] = cam.m[5] = cam.m[10] = cam.m[15] = 1.0F;

267-293: Consider extracting view matrix computation to a helper method.

The per-frame view matrix computation (rotation from yaw/pitch) is self-contained logic that could be extracted to improve readability and testability.

Example refactor:

// Add as a private method in UserApp
void update_view_matrix()
{
    const float cy = std::cos(yaw);
    const float sy = std::sin(yaw);
    const float cp = std::cos(pitch);
    const float sp = std::sin(pitch);

    const std::array Ry = {cy, 0.0F, sy, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, -sy, 0.0F, cy, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F};
    const std::array Rx = {1.0F, 0.0F, 0.0F, 0.0F, 0.0F, cp, sp, 0.0F, 0.0F, -sp, cp, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F};

    auto mulMat4 = [](const float* A, const float* B, float* C) {
        for (int col = 0; col < 4; ++col) {
            for (int row = 0; row < 4; ++row) {
                C[col * 4 + row] = A[0 * 4 + row] * B[col * 4 + 0] + 
                                   A[1 * 4 + row] * B[col * 4 + 1] +
                                   A[2 * 4 + row] * B[col * 4 + 2] + 
                                   A[3 * 4 + row] * B[col * 4 + 3];
            }
        }
    };

    mulMat4(Rx.data(), Ry.data(), cam.m.data());
}

Then in draw():

update_view_matrix();
SDL_PushGPUVertexUniformData(commandBuffer, 0, cam.m.data(), sizeof(cam.m));
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b02e1e and f3eca94.

📒 Files selected for processing (1)
  • main.cpp (6 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-11-13T02:58:26.859Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:0-0
Timestamp: 2025-11-13T02:58:26.859Z
Learning: The sdl_wrapper library (in the repository WSQS/sdl_test) does not allow throwing exceptions. Error handling must use return codes, validity checks, or other non-exception mechanisms.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-13T11:35:48.273Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:37-43
Timestamp: 2025-11-13T11:35:48.273Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, null pointer validation for the GpuWrapper::create_buffer method (checking m_device, SDL_CreateGPUBuffer return value, and shared_from_this() validity) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-13T11:34:32.714Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.buffer.ixx:0-0
Timestamp: 2025-11-13T11:34:32.714Z
Learning: In sdl_wrapper/sdl_wrapper.buffer.ixx, null pointer validation for the BufferWrapper constructor (checking p_gpu, p_gpu->data(), and SDL_CreateGPUBuffer return value) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-14T00:45:09.377Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:73-76
Timestamp: 2025-11-14T00:45:09.377Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, validation for m_window in the GpuWrapper::get_texture_formate() method (checking if m_window is nullptr before calling SDL_GetGPUSwapchainTextureFormat) is deferred to a future window wrapper implementation and should not be flagged in reviews.

Applied to files:

  • main.cpp
🔇 Additional comments (3)
main.cpp (3)

30-33: LGTM - CameraUniform structure is well-designed.

The structure appropriately encapsulates the 4×4 view matrix as a contiguous array, suitable for uploading to GPU uniforms.


342-363: LGTM - Camera input handling is correct.

The arrow key controls appropriately modify yaw and pitch, with pitch correctly clamped to prevent gimbal lock. The fixed increment is reasonable for interactive camera control.


267-293: ****

The code is correct. In vertex shaders, the set 1 is used for uniforms, and the shader declaration layout(std140, set = 1, binding = 0) uniform Camera aligns with SDL3's predefined descriptor set for vertex uniforms. The SDL_PushGPUVertexUniformData(commandBuffer, 0, ...) call correctly targets the first uniform slot within that set; you could write your vertex shaders to read a camera matrix from uniform binding slot 0, push the camera matrix at the start of the command buffer, and that data will be used for every subsequent draw call. The uniform slot indexing maps properly to the shader binding through SDL3's API abstraction.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 32. Check the log or trigger a new build to see more.

#include <algorithm>
#include <array>
#include <cmath>
#include <iostream>

Choose a reason for hiding this comment

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

warning: included header iostream is not used directly [misc-include-cleaner]

Suggested change
#include <iostream>
#include <algorithm>

#include <SDL3/SDL_gpu.h>
#include "SDL3/SDL_log.h"
#include "SDL3/SDL.h"
#include "SDL3/SDL_gpu.h"

Choose a reason for hiding this comment

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

warning: included header SDL.h is not used directly [misc-include-cleaner]

Suggested change
#include "SDL3/SDL_gpu.h"
#include "SDL3/SDL_gpu.h"

float cp = std::cos(pitch);
float sp = std::sin(pitch);

std::array Ry = {cy, 0.0F, sy, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, -sy, 0.0F, cy, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F};

Choose a reason for hiding this comment

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

warning: variable name 'Ry' is too short, expected at least 3 characters [readability-identifier-length]

            std::array Ry = {cy, 0.0F, sy, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, -sy, 0.0F, cy, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F};
                       ^


std::array Ry = {cy, 0.0F, sy, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, -sy, 0.0F, cy, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F};

std::array Rx = {1.0F, 0.0F, 0.0F, 0.0F, 0.0F, cp, sp, 0.0F, 0.0F, -sp, cp, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F};

Choose a reason for hiding this comment

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

warning: variable name 'Rx' is too short, expected at least 3 characters [readability-identifier-length]

            std::array Rx = {1.0F, 0.0F, 0.0F, 0.0F, 0.0F, cp, sp, 0.0F, 0.0F, -sp, cp, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F};
                       ^


std::array Rx = {1.0F, 0.0F, 0.0F, 0.0F, 0.0F, cp, sp, 0.0F, 0.0F, -sp, cp, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F};

auto mulMat4 = [](const float* A, const float* B, float* C)

Choose a reason for hiding this comment

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

warning: parameter name 'C' is too short, expected at least 3 characters [readability-identifier-length]

            auto mulMat4 = [](const float* A, const float* B, float* C)
                                                                     ^

for (int row = 0; row < 4; ++row)
{
C[col * 4 + row] = A[0 * 4 + row] * B[col * 4 + 0] + A[1 * 4 + row] * B[col * 4 + 1] +
A[2 * 4 + row] * B[col * 4 + 2] + A[3 * 4 + row] * B[col * 4 + 3];

Choose a reason for hiding this comment

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

warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]

                            A[2 * 4 + row] * B[col * 4 + 2] + A[3 * 4 + row] * B[col * 4 + 3];
                                                              ^

for (int row = 0; row < 4; ++row)
{
C[col * 4 + row] = A[0 * 4 + row] * B[col * 4 + 0] + A[1 * 4 + row] * B[col * 4 + 1] +
A[2 * 4 + row] * B[col * 4 + 2] + A[3 * 4 + row] * B[col * 4 + 3];

Choose a reason for hiding this comment

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

warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]

                            A[2 * 4 + row] * B[col * 4 + 2] + A[3 * 4 + row] * B[col * 4 + 3];
                                             ^

for (int row = 0; row < 4; ++row)
{
C[col * 4 + row] = A[0 * 4 + row] * B[col * 4 + 0] + A[1 * 4 + row] * B[col * 4 + 1] +
A[2 * 4 + row] * B[col * 4 + 2] + A[3 * 4 + row] * B[col * 4 + 3];

Choose a reason for hiding this comment

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

warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]

                            A[2 * 4 + row] * B[col * 4 + 2] + A[3 * 4 + row] * B[col * 4 + 3];
                            ^

virtual SDL_AppResult event(SDL_Event* event) override
{
ImGui_ImplSDL3_ProcessEvent(event);
if (event->type == SDL_EVENT_KEY_DOWN)

Choose a reason for hiding this comment

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

warning: no header providing "SDL_EVENT_KEY_DOWN" is directly included [misc-include-cleaner]

main.cpp:5:

- #include "shaderc/shaderc.hpp"
+ #include "SDL3/SDL_events.h"
+ #include "shaderc/shaderc.hpp"

{
switch (event->key.key)
{
case SDLK_UP:

Choose a reason for hiding this comment

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

warning: no header providing "SDLK_UP" is directly included [misc-include-cleaner]

main.cpp:5:

- #include "shaderc/shaderc.hpp"
+ #include "SDL3/SDL_keycode.h"
+ #include "shaderc/shaderc.hpp"

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

switch (event->key.key)
{
case SDLK_UP:
pitch += 0.1F;

Choose a reason for hiding this comment

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

warning: 0.1F is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

                pitch += 0.1F;
                         ^

pitch += 0.1F;
pitch = std::clamp<float>(pitch, -std::numbers::pi / 2, std::numbers::pi / 2);
break;
case SDLK_DOWN:

Choose a reason for hiding this comment

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

warning: no header providing "SDLK_DOWN" is directly included [misc-include-cleaner]

            case SDLK_DOWN:
                 ^

pitch = std::clamp<float>(pitch, -std::numbers::pi / 2, std::numbers::pi / 2);
break;
case SDLK_DOWN:
pitch -= 0.1F;

Choose a reason for hiding this comment

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

warning: 0.1F is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

                pitch -= 0.1F;
                         ^

pitch -= 0.1F;
pitch = std::clamp<float>(pitch, -std::numbers::pi / 2, std::numbers::pi / 2);
break;
case SDLK_LEFT:

Choose a reason for hiding this comment

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

warning: no header providing "SDLK_LEFT" is directly included [misc-include-cleaner]

            case SDLK_LEFT:
                 ^

pitch = std::clamp<float>(pitch, -std::numbers::pi / 2, std::numbers::pi / 2);
break;
case SDLK_LEFT:
yaw += 0.1F;

Choose a reason for hiding this comment

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

warning: 0.1F is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

                yaw += 0.1F;
                       ^

case SDLK_LEFT:
yaw += 0.1F;
break;
case SDLK_RIGHT:

Choose a reason for hiding this comment

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

warning: no header providing "SDLK_RIGHT" is directly included [misc-include-cleaner]

            case SDLK_RIGHT:
                 ^

yaw += 0.1F;
break;
case SDLK_RIGHT:
yaw -= 0.1F;

Choose a reason for hiding this comment

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

warning: 0.1F is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

                yaw -= 0.1F;
                       ^

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
main.cpp (4)

22-28: Vertex::position() helper and doc look consistent with ImGui usage.

Returning &x matches the contiguous (x, y, z) layout expected by ImGui::DragFloat3, and the new comment accurately documents that contract. If you ever need const access, a const overload (returning const float*) would be a minor readability win.


83-87: Identity initialization of cam.m is correct but could be simplified.

The manual assignments produce a proper 4×4 identity matrix and are only done once in init(), so performance isn’t a concern. If you want a slightly clearer expression, you could replace the block with a single aggregate:

cam.m = {1.0F, 0.0F, 0.0F, 0.0F,
         0.0F, 1.0F, 0.0F, 0.0F,
         0.0F, 0.0F, 1.0F, 0.0F,
         0.0F, 0.0F, 0.0F, 1.0F};

but the current code is functionally fine.

Also applies to: 101-108


221-225: View matrix computation is mathematically consistent with GLSL expectations.

  • cy/sy/cp/sp are used to build Ry (yaw about Y) and Rx (pitch about X) as column‑major matrices that match GLSL’s mat4 layout.
  • mulMat4 computes C = A * B in column‑major form, so uView = Rx * Ry is applied in the vertex shader as uView * vec4(a_position, 1.0f) as expected.
  • Pushing cam.m via SDL_PushGPUVertexUniformData(commandBuffer, 0, cam.m.data(), sizeof(cam.m)); correctly targets vertex uniform slot 0 using std140 layout.

This is a solid minimal camera implementation. If you later want to clean it up, consider factoring mulMat4 into a small math helper (or a tiny mat4 wrapper) to avoid raw pointer arithmetic in the render path.

Also applies to: 268-294


343-364: Arrow‑key camera controls work; tighten the numeric types for pitch clamp.

The SDL key handling integrates cleanly with ImGui and updates yaw/pitch as expected. Two small numeric nits:

  • You’re calling std::clamp<float>(pitch, -std::numbers::pi / 2, std::numbers::pi / 2); where std::numbers::pi is double. This relies on implicit narrowing to float.
  • For stricter type hygiene and to avoid surprises under warnings like -Wdouble-promotion, you could use the float specialisation:
pitch = std::clamp(
    pitch,
    -std::numbers::pi_v<float> / 2.0F,
    std::numbers::pi_v<float> / 2.0F);

Behavior stays the same, and everything remains C++20/23‑conformant.

Please confirm your C++ standard is at least C++20 so std::numbers::pi_v<float> is available; otherwise, a constexpr float kHalfPi = 1.57079632679F; constant would be a portable fallback.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3eca94 and 38efee3.

📒 Files selected for processing (1)
  • main.cpp (6 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-11-13T02:58:26.859Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:0-0
Timestamp: 2025-11-13T02:58:26.859Z
Learning: The sdl_wrapper library (in the repository WSQS/sdl_test) does not allow throwing exceptions. Error handling must use return codes, validity checks, or other non-exception mechanisms.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-13T11:35:48.273Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:37-43
Timestamp: 2025-11-13T11:35:48.273Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, null pointer validation for the GpuWrapper::create_buffer method (checking m_device, SDL_CreateGPUBuffer return value, and shared_from_this() validity) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-13T11:34:32.714Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.buffer.ixx:0-0
Timestamp: 2025-11-13T11:34:32.714Z
Learning: In sdl_wrapper/sdl_wrapper.buffer.ixx, null pointer validation for the BufferWrapper constructor (checking p_gpu, p_gpu->data(), and SDL_CreateGPUBuffer return value) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
📚 Learning: 2025-11-14T00:45:09.377Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:73-76
Timestamp: 2025-11-14T00:45:09.377Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, validation for m_window in the GpuWrapper::get_texture_formate() method (checking if m_window is nullptr before calling SDL_GetGPUSwapchainTextureFormat) is deferred to a future window wrapper implementation and should not be flagged in reviews.

Applied to files:

  • main.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: clang-tidy-review
  • GitHub Check: build (Debug, gcc)
🔇 Additional comments (3)
main.cpp (3)

1-5: Includes now cover new usage; consider adding <string> directly.

The added <algorithm>, <cmath>, <numbers>, and SDL3 headers line up with new uses of std::clamp, trig, and key/event symbols. The file still relies on transitive inclusion for std::string, though; adding #include <string> here would make the TU self‑contained.
[ suggest_optional_refactor ]

Also applies to: 13-15


31-34: CameraUniform + yaw/pitch state are straightforward and well‑scoped.

The CameraUniform wrapper and cam instance give a clear place to hang the 4×4 view matrix, and keeping yaw/pitch as members makes the camera behavior frame‑to‑frame predictable. This is a clean way to introduce camera state without touching the vertex format or buffer.

Also applies to: 42-43, 52-53


61-64: Uniform block layout matches SDL GPU expectations for vertex uniforms.

layout(std140, set = 1, binding = 0) uniform Camera { mat4 uView; }; combined with gl_Position = uView * vec4(a_position, 1.0f); is aligned with SDL’s convention that vertex uniform buffers live in set 1 and are addressed by binding index, while SDL_PushGPUVertexUniformData(..., 0, ...) targets “slot 0” (binding 0) for the vertex stage. (wiki.libsdl.org)

As long as your vertex shader is created with num_uniform_buffers = 1 (which the PR description says it is), this will bind correctly.

If you want to double‑check, ensure the generated SPIR‑V really has the uniform at set 1, binding 0 and that your create_shader call for the vertex stage passes p_num_uniform_buffers = 1.

Also applies to: 68-68

@WSQS WSQS merged commit 6ec542c into dev Nov 16, 2025
23 of 24 checks passed
@WSQS WSQS deleted the camera branch November 16, 2025 02:49
@coderabbitai coderabbitai bot mentioned this pull request Nov 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants