Skip to content

Instantly share code, notes, and snippets.

@jweinst1
Created July 18, 2026 08:33
Show Gist options
  • Select an option

  • Save jweinst1/7053a0d2ec323b170ebad90007c54585 to your computer and use it in GitHub Desktop.

Select an option

Save jweinst1/7053a0d2ec323b170ebad90007c54585 to your computer and use it in GitHub Desktop.
rotating Cube in SDL3 with trig and C++
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <cmath>
struct Vec3 {
float x, y, z;
};
typedef struct {
Vec3 position;
SDL_FColor color;
} LocalVertex3D;
// === FULL 6-FACED CUBE BLUEPRINT (36 Vertices) ===
// Vertices are ordered intentionally so that front-facing triangles
// wind Counter-Clockwise on screen.
static constexpr LocalVertex3D BLUEPRINT[] = {
// === FRONT FACE (Bright Red) ===
{ { -100.f, -100.f, -100.f }, {1.0f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, 100.f, -100.f }, {1.0f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, -100.f, -100.f }, {1.0f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, -100.f, -100.f }, {1.0f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, 100.f, -100.f }, {1.0f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, 100.f, -100.f }, {1.0f, 0.0f, 0.0f, 1.0f} },
// === BACK FACE (Muted Dark Red) ===
{ { 100.f, -100.f, 100.f }, {0.4f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, 100.f, 100.f }, {0.4f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, -100.f, 100.f }, {0.4f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, -100.f, 100.f }, {0.4f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, 100.f, 100.f }, {0.4f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, 100.f, 100.f }, {0.4f, 0.0f, 0.0f, 1.0f} },
// === TOP FACE (Medium Red) ===
{ { -100.f, -100.f, 100.f }, {0.83f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, -100.f, -100.f }, {0.83f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, -100.f, 100.f }, {0.83f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, -100.f, 100.f }, {0.83f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, -100.f, -100.f }, {0.83f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, -100.f, -100.f }, {0.83f, 0.0f, 0.0f, 1.0f} },
// === BOTTOM FACE (Very Dark Red) ===
{ { -100.f, 100.f, -100.f }, {0.3f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, 100.f, 100.f }, {0.3f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, 100.f, -100.f }, {0.3f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, 100.f, -100.f }, {0.3f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, 100.f, 100.f }, {0.3f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, 100.f, 100.f }, {0.3f, 0.0f, 0.0f, 1.0f} },
// === RIGHT FACE (Shaded Red) ===
{ { 100.f, -100.f, -100.f }, {0.7f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, 100.f, -100.f }, {0.7f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, -100.f, 100.f }, {0.7f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, -100.f, 100.f }, {0.7f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, 100.f, -100.f }, {0.7f, 0.0f, 0.0f, 1.0f} },
{ { 100.f, 100.f, 100.f }, {0.7f, 0.0f, 0.0f, 1.0f} },
// === LEFT FACE (Light Red) ===
{ { -100.f, -100.f, 100.f }, {0.9f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, 100.f, 100.f }, {0.9f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, -100.f, -100.f }, {0.9f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, -100.f, -100.f }, {0.9f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, 100.f, 100.f }, {0.9f, 0.0f, 0.0f, 1.0f} },
{ { -100.f, 100.f, -100.f }, {0.9f, 0.0f, 0.0f, 1.0f} }
};
static constexpr size_t vertLen = sizeof(BLUEPRINT) / sizeof(BLUEPRINT[0]);
Vec3 RotatePointY(const Vec3& point, float angle_radians) {
float cosAng = cosf(angle_radians);
float sinAng = sinf(angle_radians);
Vec3 rotated;
rotated.x = (point.x * cosAng) - (point.z * sinAng);
rotated.y = point.y;
rotated.z = (point.x * sinAng) + (point.z * cosAng);
return rotated;
}
void UpdateGeometry3D(SDL_Vertex* target, const LocalVertex3D* source, int count,
float objX, float objY, float objZ,
float rotationAngle,
float screenWidth, float screenHeight)
{
float centerX = screenWidth / 2.0f;
float centerY = screenHeight / 2.0f;
float focalLength = screenWidth * 0.8f;
for (int i = 0; i < count; i++) {
Vec3 localPos = source[i].position;
Vec3 rotatedPos = RotatePointY(localPos, rotationAngle);
float worldX = rotatedPos.x + objX;
float worldY = rotatedPos.y + objY;
float worldZ = rotatedPos.z + objZ;
if (worldZ < 10.0f) worldZ = 10.0f;
target[i].position.x = (worldX / worldZ) * focalLength + centerX;
target[i].position.y = (worldY / worldZ) * focalLength + centerY;
target[i].color = source[i].color;
}
}
int main(int argc, char *argv[])
{
bool quit = false;
SDL_Window *window = SDL_CreateWindow("Backface Culling Cube", 800, 600, 0);
SDL_Renderer *renderer = SDL_CreateRenderer(window, NULL);
float cubeX = 0.0f;
float cubeY = 0.0f;
float cubeZ = 900.0f;
float cubeRotation = 0.0f;
while (!quit) {
SDL_Event ev;
while (SDL_PollEvent(&ev) != 0) {
if (ev.type == SDL_EVENT_QUIT) {
quit = true;
}
}
SDL_Vertex verts[vertLen];
SDL_SetRenderDrawColor(renderer, 20, 20, 30, 255);
SDL_RenderClear(renderer);
// 1. Process all 3D coordinates into 2D screen positions
UpdateGeometry3D(verts, BLUEPRINT, vertLen, cubeX, cubeY, cubeZ, cubeRotation, 800.0f, 600.0f);
// 2. Loop through triangles (3 vertices at a time) and cull backfaces
for (size_t i = 0; i < vertLen; i += 3) {
SDL_Vertex& a = verts[i];
SDL_Vertex& b = verts[i + 1];
SDL_Vertex& c = verts[i + 2];
// 2D Cross Product calculation
float crossProduct = (b.position.x - a.position.x) * (c.position.y - a.position.y) -
(b.position.y - a.position.y) * (c.position.x - a.position.x);
// In our screen coordinate space, if the cross product is greater than 0,
// the triangle is winding counter-clockwise (facing forward)
if (crossProduct > 0.0f) {
// Render just this single validated triangle
SDL_RenderGeometry(renderer, NULL, &verts[i], 3, NULL, 0);
}
}
cubeRotation += 0.02f;
SDL_RenderPresent(renderer);
SDL_Delay(16);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment