Add others/gizmo example

This commit is contained in:
Alexey Karnachev 2023-12-30 15:06:54 +04:00
parent 710e811b27
commit 64eb5b1a7a
6 changed files with 777 additions and 2 deletions

View File

@ -585,7 +585,8 @@ OTHERS = \
others/raylib_opengl_interop \
others/raymath_vector_angle \
others/rlgl_compute_shader \
others/rlgl_standalone
others/rlgl_standalone \
others/gizmo
CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST))

View File

@ -491,7 +491,8 @@ OTHERS = \
others/raylib_opengl_interop \
others/raymath_vector_angle \
others/rlgl_compute_shader \
others/rlgl_standalone
others/rlgl_standalone \
others/gizmo
CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST))
@ -1099,6 +1100,9 @@ others/rlgl_compute_shader:
others/rlgl_standalone:
$(info Skipping_others_rlgl_standalone)
others/gizmo: others/gizmo.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
# Clean everything
clean:
ifeq ($(PLATFORM),PLATFORM_DESKTOP)

View File

@ -200,6 +200,7 @@ Examples showing raylib misc functionality that does not fit in other categories
| 124 | [easings_testbed](others/easings_testbed.c) | <img src="others/easings_testbed.png" alt="easings_testbed" width="80"> | ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) |
| 125 | [raylib_opengl_interop](others/raylib_opengl_interop.c) | <img src="others/raylib_opengl_interop.png" alt="raylib_opengl_interop" width="80"> | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) |
| 126 | [embedded_files_loading](others/embedded_files_loading.c) | <img src="others/embedded_files_loading.png" alt="embedded_files_loading" width="80"> | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) |
| 127 | [gizmo](others/gizmo.c) | <img src="others/gizmo.png" alt="gizmo" width="80"> | ⭐️⭐️☆☆ | 5.0 | 5.0 | [Alexey Karnachev](https://github.com/alexeykarnachev) |
As always contributions are welcome, feel free to send new examples! Here it is an [examples template](examples_template.c) to start with!

113
examples/others/gizmo.c Normal file
View File

@ -0,0 +1,113 @@
#include "raylib.h"
#include "rcamera.h"
#define RAYGIZMO_IMPLEMENTATION
#include "gizmo.h"
#undef RAYGIZMO_IMPLEMENTATION
void updateCamera(Camera3D* camera) {
float rot_speed = 0.003f;
float move_speed = 0.01f;
float zoom_speed = 1.0f;
bool is_middle = IsMouseButtonDown(2);
bool is_shift = IsKeyDown(KEY_LEFT_SHIFT);
Vector2 mouse_delta = GetMouseDelta();
if (is_middle && is_shift) {
CameraMoveRight(camera, -move_speed * mouse_delta.x, true);
Vector3 right = GetCameraRight(camera);
Vector3 up = Vector3CrossProduct(
Vector3Subtract(camera->position, camera->target), right
);
up = Vector3Scale(Vector3Normalize(up), move_speed * mouse_delta.y);
camera->position = Vector3Add(camera->position, up);
camera->target = Vector3Add(camera->target, up);
} else if (is_middle) {
CameraYaw(camera, -rot_speed * mouse_delta.x, true);
CameraPitch(camera, rot_speed * mouse_delta.y, true, true, false);
}
CameraMoveToTarget(camera, -GetMouseWheelMove() * zoom_speed);
}
int main(void) {
const int screen_width = 800;
const int screen_height = 450;
InitWindow(screen_width, screen_height, "Gizmo");
SetTargetFPS(60);
Camera3D camera;
camera.fovy = 45.0f;
camera.target = (Vector3){0.0f, 0.0f, 0.0f};
camera.position = (Vector3){5.0f, 5.0f, 5.0f};
camera.up = (Vector3){0.0f, 1.0f, 0.0f};
camera.projection = CAMERA_PERSPECTIVE;
Model model = LoadModelFromMesh(GenMeshTorus(0.3, 1.5, 16.0, 16.0));
LoadGizmo();
while (!WindowShouldClose()) {
updateCamera(&camera);
BeginDrawing();
{
ClearBackground(DARKGRAY);
rlEnableDepthTest();
BeginMode3D(camera);
{
// Draw main model
DrawModel(model, (Vector3){0.0, 0.0, 0.0}, 1.0, PURPLE);
// Draw coordinates grid
rlSetLineWidth(1.0);
DrawGrid(100.0, 1.0);
// Draw coordinate x, y and z axis
rlSetLineWidth(2.0);
DrawLine3D(
(Vector3){-50.0f, 0.0f, 0.0f},
(Vector3){50.0f, 0.0f, 0.0f},
RED
);
DrawLine3D(
(Vector3){0.0f, -50.0f, 0.0f},
(Vector3){0.0f, 50.0f, 0.0f},
GREEN
);
DrawLine3D(
(Vector3){0.0f, 0.0f, -50.0f},
(Vector3){0.0f, 0.0f, 50.0f},
DARKBLUE
);
}
EndMode3D();
// Immediately update and draw gizmo
Vector3 position = {
model.transform.m12, model.transform.m13, model.transform.m14};
Matrix transform = UpdateGizmo(camera, position);
// Apply gizmo-produced transformation to the model
model.transform = MatrixMultiply(model.transform, transform);
// Draw camera controll keys
DrawRectangle(0, 0, 280, 90, RAYWHITE);
DrawText("CAMERA:", 5, 5, 20, RED);
DrawText(" zoom: wheel", 5, 25, 20, RED);
DrawText(" rotate: mmb", 5, 45, 20, RED);
DrawText(" translate: shift + mmb", 5, 65, 20, RED);
}
EndDrawing();
}
UnloadGizmo();
UnloadModel(model);
CloseWindow();
return 0;
}

656
examples/others/gizmo.h Normal file
View File

@ -0,0 +1,656 @@
#include <raylib.h>
#include <stdlib.h>
void LoadGizmo();
void UnloadGizmo();
Matrix UpdateGizmo(Camera3D camera, Vector3 position);
#ifdef RAYGIZMO_IMPLEMENTATION
#include "raymath.h"
#include <math.h>
#include <rlgl.h>
#include <stdio.h>
#include <string.h>
// This will be multiplied by the distance from the camera to the gizmo,
// Which keeps the screen-space gizmo size constant.
#define GIZMO_SIZE 0.12f
// Line drawing thicknesses
#define GIZMO_HANDLE_DRAW_THICKNESS 5.0f
#define GIZMO_ACTIVE_AXIS_DRAW_THICKNESS 2.0f
// These sizes are relative to the gizmo radius
#define GIZMO_AXIS_HANDLE_LENGTH 1.2;
#define GIZMO_AXIS_HANDLE_TIP_LENGTH 0.3;
#define GIZMO_AXIS_HANDLE_TIP_RADIUS 0.1;
#define GIZMO_PLANE_HANDLE_OFFSET 0.4;
#define GIZMO_PLANE_HANDLE_SIZE 0.2;
#define X_AXIS \
(Vector3) { 1.0, 0.0, 0.0 }
#define Y_AXIS \
(Vector3) { 0.0, 1.0, 0.0 }
#define Z_AXIS \
(Vector3) { 0.0, 0.0, 1.0 }
#define MASK_FRAMEBUFFER_WIDTH 500.0
#define MASK_FRAMEBUFFER_HEIGHT 500.0
#define swap(x, y) \
do { \
unsigned char \
swap_temp[sizeof(x) == sizeof(y) ? (signed)sizeof(x) : -1]; \
memcpy(swap_temp, &y, sizeof(x)); \
memcpy(&y, &x, sizeof(x)); \
memcpy(&x, swap_temp, sizeof(x)); \
} while (0)
#define id_to_red_color(id) \
(Color) { id, 0, 0, 0 }
static const char* SHADER_COLOR_VERT = "\
#version 330\n\
in vec3 vertexPosition; \
in vec4 vertexColor; \
out vec4 fragColor; \
out vec3 fragPosition; \
uniform mat4 mvp; \
void main() { \
fragColor = vertexColor; \
fragPosition = vertexPosition; \
gl_Position = mvp * vec4(vertexPosition, 1.0); \
} \
";
static const char* SHADER_ROT_HANDLE_COLOR_FRAG = "\
#version 330\n\
in vec4 fragColor; \
in vec3 fragPosition; \
uniform vec3 cameraPosition; \
uniform vec3 gizmoPosition; \
out vec4 finalColor; \
void main() { \
vec3 r = normalize(fragPosition - gizmoPosition); \
vec3 c = normalize(fragPosition - cameraPosition); \
if (dot(r, c) > 0.1) discard; \
finalColor = fragColor; \
} \
";
static Shader SHADER_ROT_HANDLE_COLOR;
static int SHADER_ROT_HANDLE_CAMERA_POS_LOC;
static int SHADER_ROT_HANDLE_GIZMO_POS_LOC;
static unsigned int MASK_FRAMEBUFFER;
static unsigned int MASK_TEXTURE;
static bool IS_GIZMO_LOADED;
static Vector3 GIZMO_CURRENT_AXIS;
typedef enum HandleId {
HANDLE_X,
ROT_HANDLE_X,
AXIS_HANDLE_X,
PLANE_HANDLE_X,
HANDLE_Y,
ROT_HANDLE_Y,
AXIS_HANDLE_Y,
PLANE_HANDLE_Y,
HANDLE_Z,
ROT_HANDLE_Z,
AXIS_HANDLE_Z,
PLANE_HANDLE_Z
} HandleId;
typedef enum GizmoState {
GIZMO_COLD,
GIZMO_HOT,
GIZMO_HOT_ROT,
GIZMO_HOT_AXIS,
GIZMO_HOT_PLANE,
GIZMO_ACTIVE,
GIZMO_ACTIVE_ROT,
GIZMO_ACTIVE_AXIS,
GIZMO_ACTIVE_PLANE,
} GizmoState;
typedef struct Handle {
Vector3 position;
Vector3 axis;
Color color;
float dist_to_cam;
} Handle;
typedef struct HandleColors {
Color x;
Color y;
Color z;
} HandleColors;
typedef struct Handles {
Handle arr[3];
} Handles;
static GizmoState GIZMO_STATE;
bool check_if_mouse_moved() {
Vector2 mouse_delta = GetMouseDelta();
return (fabs(mouse_delta.x) + fabs(mouse_delta.y)) > EPSILON;
}
static float vector2_get_angle(Vector2 v1, Vector2 v2) {
Vector2 v1_norm = Vector2Normalize(v1);
Vector2 v2_norm = Vector2Normalize(v2);
float dot = Vector2DotProduct(v1_norm, v2_norm);
if (1.0 - fabs(dot) < EPSILON) return 0.0;
float angle = acos(dot);
float z = v1.x * v2.y - v1.y * v2.x;
if (fabs(z) < EPSILON) return 0.0;
else if (z > 0) return angle;
else return -angle;
}
static int isect_line_plane(
Vector3* out_p,
Vector3 line_p0,
Vector3 line_p1,
Vector3 plane_p,
Vector3 plane_normal
) {
Vector3 u = Vector3Subtract(line_p1, line_p0);
float dot = Vector3DotProduct(plane_normal, u);
if (fabs(dot) <= EPSILON) {
return 0;
}
Vector3 w = Vector3Subtract(line_p0, plane_p);
float k = -Vector3DotProduct(plane_normal, w) / dot;
u = Vector3Scale(u, k);
*out_p = Vector3Add(line_p0, u);
return 1;
}
static int get_two_vecs_nearest_point(
Vector3* vec0_out_nearest_point,
Vector3 vec0_p0,
Vector3 vec0_p1,
Vector3 vec1_p0,
Vector3 vec1_p1
) {
Vector3 vec0 = Vector3Subtract(vec0_p1, vec0_p0);
Vector3 vec1 = Vector3Subtract(vec1_p1, vec1_p0);
Vector3 plane_vec = Vector3CrossProduct(vec0, vec1);
plane_vec = Vector3Normalize(plane_vec);
Vector3 plane_normal = Vector3CrossProduct(vec0, plane_vec);
plane_normal = Vector3Normalize(plane_normal);
int is_isect = isect_line_plane(
vec0_out_nearest_point, vec1_p0, vec1_p1, vec0_p0, plane_normal
);
return is_isect;
}
static RayCollision get_ray_plane_collision(
Ray ray, Vector3 plane_point, Vector3 plane_normal
) {
RayCollision collision = {0};
// Calculate the parameter t
float denominator = ray.direction.x * plane_normal.x
+ ray.direction.y * plane_normal.y
+ ray.direction.z * plane_normal.z;
if (denominator == 0) {
// Ray is parallel to the plane, no collision
return collision;
}
float t = ((plane_point.x - ray.position.x) * plane_normal.x
+ (plane_point.y - ray.position.y) * plane_normal.y
+ (plane_point.z - ray.position.z) * plane_normal.z)
/ denominator;
if (t < 0) {
// Intersection point is behind the ray's starting point, no collision
return collision;
}
// Calculate the collision point
collision.point.x = ray.position.x + t * ray.direction.x;
collision.point.y = ray.position.y + t * ray.direction.y;
collision.point.z = ray.position.z + t * ray.direction.z;
collision.hit = true;
return collision;
}
static Handles get_sorted_handles(Handle h0, Handle h1, Handle h2) {
if (h0.dist_to_cam < h1.dist_to_cam) swap(h0, h1);
if (h1.dist_to_cam < h2.dist_to_cam) swap(h1, h2);
if (h0.dist_to_cam < h1.dist_to_cam) swap(h0, h1);
Handles handles = {.arr = {h0, h1, h2}};
return handles;
}
static HandleColors get_handle_colors(GizmoState hot_state) {
bool is_hot = GIZMO_STATE == hot_state || GIZMO_STATE == hot_state + 4;
Color x = is_hot && GIZMO_CURRENT_AXIS.x == 1.0 ? WHITE : RED;
Color y = is_hot && GIZMO_CURRENT_AXIS.y == 1.0 ? WHITE : GREEN;
Color z = is_hot && GIZMO_CURRENT_AXIS.z == 1.0 ? WHITE : BLUE;
HandleColors colors = {x, y, z};
return colors;
}
static void draw_axis_handles(
Camera3D camera,
Vector3 position,
float gizmo_radius,
Color color_x,
Color color_y,
Color color_z
) {
float length = gizmo_radius * GIZMO_AXIS_HANDLE_LENGTH;
float tip_length = gizmo_radius * GIZMO_AXIS_HANDLE_TIP_LENGTH;
float tip_radius = gizmo_radius * GIZMO_AXIS_HANDLE_TIP_RADIUS;
Vector3 px = Vector3Add(position, Vector3Scale(X_AXIS, length));
Vector3 py = Vector3Add(position, Vector3Scale(Y_AXIS, length));
Vector3 pz = Vector3Add(position, Vector3Scale(Z_AXIS, length));
Handle hx = {px, X_AXIS, color_x, Vector3DistanceSqr(px, camera.position)};
Handle hy = {py, Y_AXIS, color_y, Vector3DistanceSqr(py, camera.position)};
Handle hz = {pz, Z_AXIS, color_z, Vector3DistanceSqr(pz, camera.position)};
Handles handles = get_sorted_handles(hx, hy, hz);
for (int i = 0; i < 3; ++i) {
Handle* h = &handles.arr[i];
Vector3 tip_end = Vector3Add(
h->position, Vector3Scale(h->axis, tip_length)
);
DrawLine3D(position, h->position, h->color);
DrawCylinderEx(h->position, tip_end, tip_radius, 0.0, 16, h->color);
}
}
static void draw_plane_handles(
Camera3D camera,
Vector3 position,
float gizmo_radius,
Color color_x,
Color color_y,
Color color_z
) {
float offset = gizmo_radius * GIZMO_PLANE_HANDLE_OFFSET;
float size = gizmo_radius * GIZMO_PLANE_HANDLE_SIZE;
Vector3 px = Vector3Add(position, (Vector3){0.0, offset, offset});
Vector3 py = Vector3Add(position, (Vector3){offset, 0.0, offset});
Vector3 pz = Vector3Add(position, (Vector3){offset, offset, 0.0});
Handle hx = {px, Z_AXIS, color_x, Vector3DistanceSqr(px, camera.position)};
Handle hy = {py, Y_AXIS, color_y, Vector3DistanceSqr(py, camera.position)};
Handle hz = {pz, X_AXIS, color_z, Vector3DistanceSqr(pz, camera.position)};
Handles handles = get_sorted_handles(hx, hy, hz);
rlDisableBackfaceCulling();
for (int i = 0; i < 3; ++i) {
Handle* h = &handles.arr[i];
rlPushMatrix();
{
rlTranslatef(h->position.x, h->position.y, h->position.z);
rlRotatef(90.0, h->axis.x, h->axis.y, h->axis.z);
DrawPlane(
Vector3Zero(), Vector2Scale(Vector2One(), size), h->color
);
}
rlPopMatrix();
}
}
static void draw_rot_handles(
Camera3D camera,
Vector3 position,
float gizmo_radius,
Color color_x,
Color color_y,
Color color_z
) {
BeginShaderMode(SHADER_ROT_HANDLE_COLOR);
{
SetShaderValue(
SHADER_ROT_HANDLE_COLOR,
SHADER_ROT_HANDLE_CAMERA_POS_LOC,
&camera.position,
SHADER_UNIFORM_VEC3
);
SetShaderValue(
SHADER_ROT_HANDLE_COLOR,
SHADER_ROT_HANDLE_GIZMO_POS_LOC,
&position,
SHADER_UNIFORM_VEC3
);
DrawCircle3D(position, gizmo_radius, Y_AXIS, 90.0, color_x);
DrawCircle3D(position, gizmo_radius, X_AXIS, 90.0, color_y);
DrawCircle3D(position, gizmo_radius, X_AXIS, 0.0, color_z);
}
EndShaderMode();
}
static void draw_gizmo(
Camera3D camera,
Vector3 position,
Color rot_handle_color_x,
Color rot_handle_color_y,
Color rot_handle_color_z,
Color axis_handle_color_x,
Color axis_handle_color_y,
Color axis_handle_color_z,
Color plane_handle_color_x,
Color plane_handle_color_y,
Color plane_handle_color_z
) {
float radius = GIZMO_SIZE * Vector3Distance(camera.position, position);
// Draw gizmo's handle elements
BeginMode3D(camera);
{
rlSetLineWidth(GIZMO_HANDLE_DRAW_THICKNESS);
rlDisableDepthTest();
draw_plane_handles(
camera,
position,
radius,
plane_handle_color_x,
plane_handle_color_y,
plane_handle_color_z
);
draw_rot_handles(
camera,
position,
radius,
rot_handle_color_x,
rot_handle_color_y,
rot_handle_color_z
);
draw_axis_handles(
camera,
position,
radius,
axis_handle_color_x,
axis_handle_color_y,
axis_handle_color_z
);
}
EndMode3D();
// Draw long white line which represents current active axis
if (GIZMO_STATE == GIZMO_ACTIVE_ROT || GIZMO_STATE == GIZMO_ACTIVE_AXIS) {
BeginMode3D(camera);
{
rlSetLineWidth(GIZMO_ACTIVE_AXIS_DRAW_THICKNESS);
Vector3 half_axis_line = Vector3Scale(GIZMO_CURRENT_AXIS, 1000.0);
DrawLine3D(
Vector3Subtract(position, half_axis_line),
Vector3Add(position, half_axis_line),
WHITE
);
}
EndMode3D();
}
// Draw white line from the gizmo's center to the mouse cursor when rotating
if (GIZMO_STATE == GIZMO_ACTIVE_ROT) {
rlSetLineWidth(GIZMO_ACTIVE_AXIS_DRAW_THICKNESS);
DrawLineV(
GetWorldToScreen(position, camera), GetMousePosition(), WHITE
);
}
}
static unsigned char get_gizmo_mask_pixel(Camera3D camera, Vector3 position) {
// -------------------------------------------------------------------
// Draw gizmo into a separate framebuffer for the mouse pixel-picking
rlEnableFramebuffer(MASK_FRAMEBUFFER);
rlViewport(0, 0, MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT);
rlClearScreenBuffers();
rlDisableColorBlend();
draw_gizmo(
camera,
position,
id_to_red_color(ROT_HANDLE_X),
id_to_red_color(ROT_HANDLE_Y),
id_to_red_color(ROT_HANDLE_Z),
id_to_red_color(AXIS_HANDLE_X),
id_to_red_color(AXIS_HANDLE_Y),
id_to_red_color(AXIS_HANDLE_Z),
id_to_red_color(PLANE_HANDLE_X),
id_to_red_color(PLANE_HANDLE_Y),
id_to_red_color(PLANE_HANDLE_Z)
);
rlDisableFramebuffer();
rlEnableColorBlend();
rlViewport(0, 0, GetScreenWidth(), GetScreenHeight());
// -------------------------------------------------------------------
// Pick the pixel under the mouse cursor
Vector2 mouse_position = GetMousePosition();
unsigned char* pixels = (unsigned char*)rlReadTexturePixels(
MASK_TEXTURE,
MASK_FRAMEBUFFER_WIDTH,
MASK_FRAMEBUFFER_HEIGHT,
RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
);
float x_ratio = Clamp(mouse_position.x / (float)GetScreenWidth(), 0.0, 1.0);
float y_ratio = Clamp(
1.0 - (mouse_position.y / (float)GetScreenHeight()), 0.0, 1.0
);
int x = (int)(MASK_FRAMEBUFFER_WIDTH * x_ratio);
int y = (int)(MASK_FRAMEBUFFER_HEIGHT * y_ratio);
int idx = 4 * (y * MASK_FRAMEBUFFER_WIDTH + x);
unsigned char mask_val = pixels[idx];
free(pixels);
return mask_val;
}
Matrix update_gizmo_rot(Camera3D camera, Vector3 position) {
if (!check_if_mouse_moved()) return MatrixIdentity();
Vector2 rot_center = GetWorldToScreen(position, camera);
Vector2 p1 = Vector2Subtract(GetMousePosition(), rot_center);
Vector2 p0 = Vector2Subtract(p1, GetMouseDelta());
float angle = vector2_get_angle(p1, p0);
// If we look at gizmo from behind, we should flip the rotation
if (Vector3DotProduct(GIZMO_CURRENT_AXIS, position)
> Vector3DotProduct(GIZMO_CURRENT_AXIS, camera.position)) {
angle *= -1;
}
// We rotate gizmo relative to it's own center, so we first translate it to
// the center of world coordinates, then rotate and then translate back
Matrix transform = MatrixMultiply(
MatrixMultiply(
MatrixTranslate(-position.x, -position.y, -position.z),
MatrixRotate(GIZMO_CURRENT_AXIS, angle)
),
MatrixTranslate(position.x, position.y, position.z)
);
return transform;
}
Matrix update_gizmo_axis(Camera3D camera, Vector3 position) {
if (!check_if_mouse_moved()) return MatrixIdentity();
Vector2 p = Vector2Add(GetWorldToScreen(position, camera), GetMouseDelta());
Ray r = GetMouseRay(p, camera);
Vector3 isect_p = Vector3Zero();
bool is_isect = get_two_vecs_nearest_point(
&isect_p,
camera.position,
Vector3Add(camera.position, r.direction),
position,
Vector3Add(position, GIZMO_CURRENT_AXIS)
);
if (!is_isect)
{
return MatrixIdentity();
}
Vector3 offset = Vector3Subtract(isect_p, position);
offset = Vector3Multiply(offset, GIZMO_CURRENT_AXIS);
Matrix transform = MatrixTranslate(offset.x, offset.y, offset.z);
return transform;
}
Matrix update_gizmo_plane(Camera3D camera, Vector3 position) {
if (!check_if_mouse_moved()) return MatrixIdentity();
Vector2 p = Vector2Add(GetWorldToScreen(position, camera), GetMouseDelta());
Ray r = GetMouseRay(p, camera);
RayCollision c = get_ray_plane_collision(r, position, GIZMO_CURRENT_AXIS);
Vector3 offset = Vector3Subtract(c.point, position);
Matrix transform = MatrixTranslate(offset.x, offset.y, offset.z);
return transform;
}
Matrix update_gizmo(Camera3D camera, Vector3 position, unsigned char mask_val) {
bool is_lmb_down = IsMouseButtonDown(0);
if (!is_lmb_down) GIZMO_STATE = GIZMO_COLD;
if (GIZMO_STATE < GIZMO_ACTIVE) {
if (mask_val < HANDLE_Y) GIZMO_CURRENT_AXIS = X_AXIS;
else if (mask_val < HANDLE_Z) GIZMO_CURRENT_AXIS = Y_AXIS;
else GIZMO_CURRENT_AXIS = Z_AXIS;
if (mask_val % 4 == 1)
GIZMO_STATE = is_lmb_down ? GIZMO_ACTIVE_ROT : GIZMO_HOT_ROT;
else if (mask_val % 4 == 2)
GIZMO_STATE = is_lmb_down ? GIZMO_ACTIVE_AXIS : GIZMO_HOT_AXIS;
else if (mask_val % 4 == 3)
GIZMO_STATE = is_lmb_down ? GIZMO_ACTIVE_PLANE : GIZMO_HOT_PLANE;
}
switch (GIZMO_STATE) {
case GIZMO_ACTIVE_ROT: return update_gizmo_rot(camera, position);
case GIZMO_ACTIVE_AXIS: return update_gizmo_axis(camera, position);
case GIZMO_ACTIVE_PLANE: return update_gizmo_plane(camera, position);
default: return MatrixIdentity();
}
}
void LoadGizmo() {
if (IS_GIZMO_LOADED) return;
SHADER_ROT_HANDLE_COLOR = LoadShaderFromMemory(
SHADER_COLOR_VERT, SHADER_ROT_HANDLE_COLOR_FRAG
);
SHADER_ROT_HANDLE_CAMERA_POS_LOC = GetShaderLocation(
SHADER_ROT_HANDLE_COLOR, "cameraPosition"
);
SHADER_ROT_HANDLE_GIZMO_POS_LOC = GetShaderLocation(
SHADER_ROT_HANDLE_COLOR, "gizmoPosition"
);
MASK_FRAMEBUFFER = rlLoadFramebuffer(
MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT
);
if (!MASK_FRAMEBUFFER) {
TraceLog(LOG_ERROR, "Failed to create gizmo's mask framebuffer");
exit(1);
}
rlEnableFramebuffer(MASK_FRAMEBUFFER);
MASK_TEXTURE = rlLoadTexture(
NULL,
MASK_FRAMEBUFFER_WIDTH,
MASK_FRAMEBUFFER_HEIGHT,
RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32,
1
);
rlActiveDrawBuffers(1);
rlFramebufferAttach(
MASK_FRAMEBUFFER,
MASK_TEXTURE,
RL_ATTACHMENT_COLOR_CHANNEL0,
RL_ATTACHMENT_TEXTURE2D,
0
);
if (!rlFramebufferComplete(MASK_FRAMEBUFFER)) {
TraceLog(LOG_ERROR, "Gizmo's framebuffer is not complete");
exit(1);
}
IS_GIZMO_LOADED = true;
}
void UnloadGizmo() {
if (!IS_GIZMO_LOADED) return;
UnloadShader(SHADER_ROT_HANDLE_COLOR);
rlUnloadFramebuffer(MASK_FRAMEBUFFER);
rlUnloadTexture(MASK_TEXTURE);
IS_GIZMO_LOADED = false;
}
Matrix UpdateGizmo(Camera3D camera, Vector3 position) {
if (!IS_GIZMO_LOADED) {
TraceLog(LOG_ERROR, "Gizmo must be loaded before the update");
exit(1);
}
unsigned char mask_val = get_gizmo_mask_pixel(camera, position);
Matrix transform = update_gizmo(camera, position, mask_val);
// -------------------------------------------------------------------
// Draw gizmo
HandleColors rot_handle_colors = get_handle_colors(GIZMO_HOT_ROT);
HandleColors axis_handle_colors = get_handle_colors(GIZMO_HOT_AXIS);
HandleColors plane_handle_colors = get_handle_colors(GIZMO_HOT_PLANE);
draw_gizmo(
camera,
position,
rot_handle_colors.x,
rot_handle_colors.y,
rot_handle_colors.z,
axis_handle_colors.x,
axis_handle_colors.y,
axis_handle_colors.z,
plane_handle_colors.x,
plane_handle_colors.y,
plane_handle_colors.z
);
return transform;
}
#endif

BIN
examples/others/gizmo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB