diff --git a/examples/Makefile b/examples/Makefile index 93b05a0c7caa..904917f7c806 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -582,6 +582,7 @@ MODELS = \ models/models_mesh_generation \ models/models_mesh_picking \ models/models_orthographic_projection \ + models/models_point_rendering \ models/models_rlgl_solar_system \ models/models_skybox \ models/models_waving_cubes \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 46a8a98ea077..7057da1c03d9 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -447,6 +447,7 @@ MODELS = \ models/models_mesh_generation \ models/models_mesh_picking \ models/models_orthographic_projection \ + models/models_point_rendering \ models/models_rlgl_solar_system \ models/models_skybox \ models/models_waving_cubes \ diff --git a/examples/README.md b/examples/README.md index 317f43c899a3..d573ff23ef54 100644 --- a/examples/README.md +++ b/examples/README.md @@ -147,11 +147,12 @@ Examples using raylib models functionality, including models loading/generation | 91 | [models_loading_vox](models/models_loading_vox.c) | models_loading_vox | ⭐️☆☆☆ | **4.0** | **4.0** | [Johann Nadalutti](https://github.com/procfxgen) | | 92 | [models_loading_m3d](models/models_loading_m3d.c) | models_loading_m3d | ⭐️☆☆☆ | **4.2** | **4.2** | [bzt](https://bztsrc.gitlab.io/model3d) | | 93 | [models_orthographic_projection](models/models_orthographic_projection.c) | models_orthographic_projection | ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) | -| 94 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | models_rlgl_solar_system | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | -| 95 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | models_yaw_pitch_roll | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) | -| 96 | [models_waving_cubes](models/models_waving_cubes.c) | models_waving_cubes | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) | -| 97 | [models_heightmap](models/models_heightmap.c) | models_heightmap | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | -| 98 | [models_skybox](models/models_skybox.c) | models_skybox | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | +| 94 | [models_point_rendering](models/models_point_rendering.c) | models_point_rendering | ⭐️⭐️☆☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) | +| 95 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | models_rlgl_solar_system | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | +| 96 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | models_yaw_pitch_roll | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) | +| 97 | [models_waving_cubes](models/models_waving_cubes.c) | models_waving_cubes | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) | +| 98 | [models_heightmap](models/models_heightmap.c) | models_heightmap | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | +| 99 | [models_skybox](models/models_skybox.c) | models_skybox | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | ### category: shaders @@ -159,26 +160,25 @@ Examples using raylib shaders functionality, including shaders loading, paramete | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 99 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | shaders_basic_lighting | ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) | -| 100 | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) | -| 101 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | -| 102 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | shaders_custom_uniform | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 103 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | shaders_postprocessing | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 104 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | shaders_palette_switch | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) | -| 105 | [shaders_raymarching](shaders/shaders_raymarching.c) | shaders_raymarching | ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) | -| 106 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | shaders_texture_drawing | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) | -| 107 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | shaders_texture_outline | ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) | -| 108 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | shaders_texture_waves | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) | -| 109 | [shaders_julia_set](shaders/shaders_julia_set.c) | shaders_julia_set | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) | -| 110 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | shaders_eratosthenes | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) | -| 111 | [shaders_fog](shaders/shaders_fog.c) | shaders_fog | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 112 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | shaders_simple_mask | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 113 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | shaders_hot_reloading | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) | -| 114 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | shaders_mesh_instancing | ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) | -| 115 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | shaders_multi_sample2d | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | -| 116 | [shaders_spotlight](shaders/shaders_spotlight.c) | shaders_spotlight | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 117 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | shaders_deferred_render | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) | -| 118 | [shaders_vertex_displacement](shaders/shaders_vertex_displacement.c) | shaders_deferred_render | ⭐️☆☆☆ | 1.5 | 1.5 | [Alex ZH](https://github.com/ZzzhHe) | +| 100 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | shaders_basic_lighting | ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) | +| 101 | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) | +| 102 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | +| 103 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | shaders_custom_uniform | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 104 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | shaders_postprocessing | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 105 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | shaders_palette_switch | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) | +| 106 | [shaders_raymarching](shaders/shaders_raymarching.c) | shaders_raymarching | ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) | +| 107 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | shaders_texture_drawing | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) | +| 108 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | shaders_texture_outline | ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) | +| 109 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | shaders_texture_waves | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) | +| 110 | [shaders_julia_set](shaders/shaders_julia_set.c) | shaders_julia_set | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) | +| 111 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | shaders_eratosthenes | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) | +| 112 | [shaders_fog](shaders/shaders_fog.c) | shaders_fog | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 113 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | shaders_simple_mask | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 114 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | shaders_hot_reloading | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) | +| 115 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | shaders_mesh_instancing | ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) | +| 116 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | shaders_multi_sample2d | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | +| 117 | [shaders_spotlight](shaders/shaders_spotlight.c) | shaders_spotlight | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 118 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | shaders_deferred_render | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) | ### category: audio diff --git a/examples/models/models_point_rendering.c b/examples/models/models_point_rendering.c new file mode 100644 index 000000000000..128a70f57ee1 --- /dev/null +++ b/examples/models/models_point_rendering.c @@ -0,0 +1,171 @@ +/******************************************************************************************* +* +* 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; +} diff --git a/examples/models/models_point_rendering.png b/examples/models/models_point_rendering.png new file mode 100644 index 000000000000..a1fc718e4dd5 Binary files /dev/null and b/examples/models/models_point_rendering.png differ diff --git a/src/raylib.h b/src/raylib.h index 0759c259f18e..f51a444e1f07 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1545,6 +1545,8 @@ RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters +RLAPI void DrawModelPoints(Model model, Vector3 position, float scale, Color tint); // Draw a model as points +RLAPI void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model as points with extended parameters RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a billboard texture RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source diff --git a/src/rmodels.c b/src/rmodels.c index 8afa3df574c5..966a8665c622 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -3631,6 +3631,30 @@ void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rlDisableWireMode(); } +// Draw a model points +void DrawModelPoints(Model model, Vector3 position, float scale, Color tint) +{ + rlEnablePointMode(); + rlDisableBackfaceCulling(); + + DrawModel(model, position, scale, tint); + + rlEnableBackfaceCulling(); + rlDisableWireMode(); +} + +// Draw a model points +void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) +{ + rlEnablePointMode(); + rlDisableBackfaceCulling(); + + DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint); + + rlEnableBackfaceCulling(); + rlDisableWireMode(); +} + // Draw a billboard void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint) {