/******************************************************************************************* * * raylib example - point rendering * * Example originally created with raylib 5.0, last time updated with raylib 5.0 * * Example contributed by Reese Gallagher (@satchelfrost) and reviewed by Ramon Santamaria (@raysan5) * * 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 Reese Gallagher (@satchelfrost) * ********************************************************************************************/ #include "raylib.h" #include // Required for: rand() #include // Required for: cos(), sin() #define MAX_POINTS 10000000 // 10 million #define MIN_POINTS 1000 // 1 thousand static float RandFloat(); //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ int main() { // Initialization //-------------------------------------------------------------------------------------- const int screenWidth = 800; const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [models] example - point rendering"); SetTargetFPS(60); Camera camera = { .position = {3.0f, 3.0f, 3.0f}, .target = {0.0f, 0.0f, 0.0f}, .up = {0.0f, 1.0f, 0.0f}, .fovy = 45.0f, .projection = CAMERA_PERSPECTIVE, }; Vector3 position = {0.0f, 0.0f, 0.0f}; bool useDrawModelPoints = true; bool numPointsChanged = false; int numPoints = 1000; Mesh mesh = GenPoints(numPoints); Model model = LoadModelFromMesh(mesh); //-------------------------------------------------------------------------------------- // Main game loop while(!WindowShouldClose()) { // Update //---------------------------------------------------------------------------------- UpdateCamera(&camera, CAMERA_ORBITAL); if (IsKeyPressed(KEY_SPACE)) useDrawModelPoints = !useDrawModelPoints; if (IsKeyPressed(KEY_UP)) { numPoints = (numPoints * 10 > MAX_POINTS) ? MAX_POINTS : numPoints * 10; numPointsChanged = true; TraceLog(LOG_INFO, "num points %d", numPoints); } if (IsKeyPressed(KEY_DOWN)) { numPoints = (numPoints / 10 < MIN_POINTS) ? MIN_POINTS : numPoints / 10; numPointsChanged = true; TraceLog(LOG_INFO, "num points %d", numPoints); } // upload a different point cloud size if (numPointsChanged) { UnloadModel(model); mesh = GenPoints(numPoints); model = LoadModelFromMesh(mesh); numPointsChanged = false; } // Draw //---------------------------------------------------------------------------------- BeginDrawing(); ClearBackground(BLACK); BeginMode3D(camera); // The new method only uploads the points once to the GPU if (useDrawModelPoints) { DrawModelPoints(model, position, 1.0f, WHITE); } // The old method must continually draw the "points" (lines) else { for (int i = 0; i < numPoints; i++) { Vector3 pos = { .x = mesh.vertices[i * 3 + 0], .y = mesh.vertices[i * 3 + 1], .z = mesh.vertices[i * 3 + 2], }; Color color = { .r = mesh.colors[i * 4 + 0], .g = mesh.colors[i * 4 + 1], .b = mesh.colors[i * 4 + 2], .a = mesh.colors[i * 4 + 3], }; DrawPoint3D(pos, color); } } // Draw a unit sphere for reference DrawSphereWires(position, 1.0f, 10, 10, YELLOW); EndMode3D(); // Text formatting Color color = WHITE; int fps = GetFPS(); if ((fps < 30) && (fps >= 15)) color = ORANGE; else if (fps < 15) color = RED; DrawText(TextFormat("%2i FPS", fps), 20, 20, 40, color); DrawText(TextFormat("Point Count: %d", numPoints), 20, screenHeight - 50, 40, WHITE); DrawText("Up - increase points", 20, 70, 20, WHITE); DrawText("Down - decrease points", 20, 100, 20, WHITE); DrawText("Space - drawing function", 20, 130, 20, WHITE); if (useDrawModelPoints) DrawText("DrawModelPoints()", 20, 160, 20, GREEN); else DrawText("DrawPoint3D()", 20, 160, 20, RED); EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- UnloadModel(model); CloseWindow(); //-------------------------------------------------------------------------------------- return 0; } // Generate a spherical point cloud Mesh GenPoints(int numPoints) { Mesh mesh = { .triangleCount = 1, .vertexCount = numPoints, .vertices = (float *)MemAlloc(numPoints * 3 * sizeof(float)), .colors = (unsigned char*)MemAlloc(numPoints * 4 * sizeof(unsigned char)), }; // https://en.wikipedia.org/wiki/Spherical_coordinate_system for (int i = 0; i < numPoints; i++) { float theta = PI * rand() / RAND_MAX; float phi = 2.0f * PI * rand() / RAND_MAX; float r = 10.0f * rand() / RAND_MAX; mesh.vertices[i * 3 + 0] = r * sin(theta) * cos(phi); mesh.vertices[i * 3 + 1] = r * sin(theta) * sin(phi); mesh.vertices[i * 3 + 2] = r * cos(theta); Color color = ColorFromHSV(r * 360.0f, 1.0f, 1.0f); mesh.colors[i * 4 + 0] = color.r; mesh.colors[i * 4 + 1] = color.g; mesh.colors[i * 4 + 2] = color.b; mesh.colors[i * 4 + 3] = color.a; } // Upload mesh data from CPU (RAM) to GPU (VRAM) memory UploadMesh(&mesh, false); return mesh; }