Created
July 18, 2026 08:33
-
-
Save jweinst1/7053a0d2ec323b170ebad90007c54585 to your computer and use it in GitHub Desktop.
rotating Cube in SDL3 with trig and C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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