From 4bceddd4dee834cb5aa73a8e6567d89807860058 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 12 Jan 2025 16:19:32 +0100 Subject: [PATCH] ADDED: example: `models_tesseract` --- examples/models/models_tesseract_view.c | 124 ++++++++++++++++++++++ examples/models/models_tesseract_view.png | Bin 0 -> 18900 bytes 2 files changed, 124 insertions(+) create mode 100644 examples/models/models_tesseract_view.c create mode 100644 examples/models/models_tesseract_view.png diff --git a/examples/models/models_tesseract_view.c b/examples/models/models_tesseract_view.c new file mode 100644 index 000000000..411b59497 --- /dev/null +++ b/examples/models/models_tesseract_view.c @@ -0,0 +1,124 @@ +/******************************************************************************************* +* +* raylib [models] example - Tesseract view +* +* NOTE: This example only works on platforms that support drag & drop (Windows, Linux, OSX, Html5?) +* +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2024-2025 raylib contributor (?) & Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include "raymath.h" + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - tesseract view"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 4.0f, 4.0f, 4.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 0.0f, 1.0f }; // Camera up vector (rotation towards target) + camera.fovy = 50.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera mode type + + // Find the coordinates by setting XYZW to +-1 + Vector4 tesseract[16] = { + { 1, 1, 1, 1 }, { 1, 1, 1, -1 }, + { 1, 1, -1, 1 }, { 1, 1, -1, -1 }, + { 1, -1, 1, 1 }, { 1, -1, 1, -1 }, + { 1, -1, -1, 1 }, { 1, -1, -1, -1 }, + { -1, 1, 1, 1 }, { -1, 1, 1, -1 }, + { -1, 1, -1, 1 }, { -1, 1, -1, -1 }, + { -1, -1, 1, 1 }, { -1, -1, 1, -1 }, + { -1, -1, -1, 1 }, { -1, -1, -1, -1 }, + }; + + float rotation = 0.0f; + Vector3 transformed[16] = { 0 }; + float wValues[16] = { 0 }; + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + rotation = DEG2RAD*45.0f*GetTime(); + + for (int i = 0; i < 16; i++) + { + Vector4 p = tesseract[i]; + + // Rotate the XW part of the vector + Vector2 rotXW = Vector2Rotate((Vector2){ p.x, p.w }, rotation); + p.x = rotXW.x; + p.w = rotXW.y; + + // Projection from XYZW to XYZ from perspective point (0, 0, 0, 3) + // NOTE: Trace a ray from (0, 0, 0, 3) > p and continue until W = 0 + float c = 3/(3 - p.w); + p.x = c * p.x; + p.y = c * p.y; + p.z = c * p.z; + + // Split XYZ coordinate and W values later for drawing + transformed[i] = (Vector3){ p.x, p.y, p.z }; + wValues[i] = p.w; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + for (int i = 0; i < 16; i++) + { + // Draw spheres to indicate the W value + DrawSphere(transformed[i], fabsf(wValues[i]*0.1), RED); + + for (int j = 0; j < 16; j++) + { + // Two lines are connected if they differ by 1 coordinate + // This way we dont have to keep an edge list + Vector4 v1 = tesseract[i]; + Vector4 v2 = tesseract[j]; + int diff = (int)(v1.x == v2.x) + (int)(v1.y == v2.y) + (int)(v1.z == v2.z) + (int)(v1.w == v2.w); + + // Draw only differing by 1 coordinate and the lower index only (duplicate lines) + if (diff == 3 && i < j) DrawLine3D(transformed[i], transformed[j], MAROON); + } + } + EndMode3D(); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/models/models_tesseract_view.png b/examples/models/models_tesseract_view.png new file mode 100644 index 0000000000000000000000000000000000000000..664e560b2487c0f6ef9393e4b731ffb7658b4619 GIT binary patch literal 18900 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 WlZ8x^2MZYR-}ukML-qyB(*FluimV*~ literal 0 HcmV?d00001