respect raylib style-guide

This commit is contained in:
Alexey Karnachev 2023-12-30 16:35:55 +04:00
parent 64eb5b1a7a
commit 4901d375ac
2 changed files with 396 additions and 307 deletions

View File

@ -1,3 +1,18 @@
/*******************************************************************************************
*
* raylib [gizmo] example - Gizmo gadget for an interactive object 3D transformations
*
* Example originally created with raylib 5.0, last time updated with raylib 5.0
*
* Example contributed by Alexey Karnachev (@alexeykarnachev) 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) 2023-2024 Alexey Karnachev (@alexeykarnachev)
*
********************************************************************************************/
#include "raylib.h"
#include "rcamera.h"
@ -5,39 +20,46 @@
#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;
#define CAMERA_ROT_SPEED 0.003f
#define CAMERA_MOVE_SPEED 0.01f
#define CAMERA_ZOOM_SPEED 1.0f
bool is_middle = IsMouseButtonDown(2);
bool is_shift = IsKeyDown(KEY_LEFT_SHIFT);
Vector2 mouse_delta = GetMouseDelta();
// Updates the camera in the orbital-style, i.e camera rotates around the look-at point by the orbit
static void updateCamera(Camera3D* camera) {
bool isMMBDown = IsMouseButtonDown(2);
bool isShiftDown = IsKeyDown(KEY_LEFT_SHIFT);
Vector2 mouseDelta = GetMouseDelta();
if (is_middle && is_shift) {
CameraMoveRight(camera, -move_speed * mouse_delta.x, true);
// Shift + MMB + mouse move -> change the camera position in the right-direction plane
if (isMMBDown && isShiftDown) {
CameraMoveRight(camera, -CAMERA_MOVE_SPEED * mouseDelta.x, true);
Vector3 right = GetCameraRight(camera);
Vector3 up = Vector3CrossProduct(
Vector3Subtract(camera->position, camera->target), right
);
up = Vector3Scale(Vector3Normalize(up), move_speed * mouse_delta.y);
up = Vector3Scale(Vector3Normalize(up), CAMERA_MOVE_SPEED * mouseDelta.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);
// Rotate the camera around the look-at point
} else if (isMMBDown) {
CameraYaw(camera, -CAMERA_ROT_SPEED * mouseDelta.x, true);
CameraPitch(camera, CAMERA_ROT_SPEED * mouseDelta.y, true, true, false);
}
CameraMoveToTarget(camera, -GetMouseWheelMove() * zoom_speed);
// Bring camera closer (or move away), to the look-at point
CameraMoveToTarget(camera, -GetMouseWheelMove() * CAMERA_ZOOM_SPEED);
}
int main(void) {
const int screen_width = 800;
const int screen_height = 450;
InitWindow(screen_width, screen_height, "Gizmo");
SetTargetFPS(60);
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [gizmo] example - gizmo gadget");
// Define 3D perspective camera
Camera3D camera;
camera.fovy = 45.0f;
camera.target = (Vector3){0.0f, 0.0f, 0.0f};
@ -45,20 +67,25 @@ int main(void) {
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));
Model model = LoadModelFromMesh(GenMeshTorus(0.3, 1.5, 16.0, 16.0)); // Create simple torus model
loadGizmo(); // Load gizmo
LoadGizmo();
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
while (!WindowShouldClose()) {
while (!WindowShouldClose())
{
// Update
//----------------------------------------------------------------------------------
updateCamera(&camera);
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
{
ClearBackground(DARKGRAY);
rlEnableDepthTest();
BeginMode3D(camera);
{
// Draw main model
DrawModel(model, (Vector3){0.0, 0.0, 0.0}, 1.0, PURPLE);
@ -83,13 +110,12 @@ int main(void) {
(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);
Matrix transform = updateAndDrawGizmo(camera, position);
// Apply gizmo-produced transformation to the model
model.transform = MatrixMultiply(model.transform, transform);
@ -100,13 +126,16 @@ int main(void) {
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();
// De-Initialization
//--------------------------------------------------------------------------------------
unloadGizmo(); // Unload gizmo
UnloadModel(model); // Unload model
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

View File

@ -1,17 +1,60 @@
#include <raylib.h>
#include <stdlib.h>
/*******************************************************************************************
Alexey Karnachev License
---------------------------------------------------------------------------------
MIT License
void LoadGizmo();
void UnloadGizmo();
Matrix UpdateGizmo(Camera3D camera, Vector3 position);
Copyright (c) 2023 Alexey Karnachev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---------------------------------------------------------------------------------
Copyright (c) 2015-2023 Ramon Santamaria (@raysan5)
This software is provided "as-is", without any express or implied warranty. In no event
will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you
wrote the original software. If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented
as being the original software.
3. This notice may not be removed or altered from any source distribution.
**********************************************************************************************/
#include <raylib.h>
void loadGizmo();
void unloadGizmo();
Matrix updateAndDrawGizmo(Camera3D camera, Vector3 position);
#ifdef RAYGIZMO_IMPLEMENTATION
#include "raymath.h"
#include <math.h>
#include <rlgl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rlgl.h>
#include "raymath.h"
// This will be multiplied by the distance from the camera to the gizmo,
// Which keeps the screen-space gizmo size constant.
@ -22,23 +65,24 @@ Matrix UpdateGizmo(Camera3D camera, Vector3 position);
#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 GIZMO_AXIS_HANDLE_LENGTH 1.2f;
#define GIZMO_AXIS_HANDLE_TIP_LENGTH 0.3f;
#define GIZMO_AXIS_HANDLE_TIP_RADIUS 0.1f;
#define GIZMO_PLANE_HANDLE_OFFSET 0.4f;
#define GIZMO_PLANE_HANDLE_SIZE 0.2f;
#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 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
// Size of the additional buffer to pre-render the gizmo into.
// Used for the mouse picking.
#define MASK_FRAMEBUFFER_WIDTH 500
#define MASK_FRAMEBUFFER_HEIGHT 500
#define swap(x, y) \
#define ID_TO_RED_COLOR(id) (Color){ id, 0, 0, 0 }
#define SWAP(x, y) \
do { \
unsigned char \
swap_temp[sizeof(x) == sizeof(y) ? (signed)sizeof(x) : -1]; \
@ -47,9 +91,8 @@ Matrix UpdateGizmo(Camera3D camera, Vector3 position);
memcpy(&x, swap_temp, sizeof(x)); \
} while (0)
#define id_to_red_color(id) \
(Color) { id, 0, 0, 0 }
#if defined(PLATFORM_DESKTOP) // Shaders for PLATFORM_DESKTOP
static const char* SHADER_COLOR_VERT = "\
#version 330\n\
in vec3 vertexPosition; \
@ -57,21 +100,23 @@ in vec4 vertexColor; \
out vec4 fragColor; \
out vec3 fragPosition; \
uniform mat4 mvp; \
void main() { \
void main() \
{ \
fragColor = vertexColor; \
fragPosition = vertexPosition; \
gl_Position = mvp * vec4(vertexPosition, 1.0); \
} \
";
static const char* SHADER_ROT_HANDLE_COLOR_FRAG = "\
static const char* shaderRotHandleColor_FRAG = "\
#version 330\n\
in vec4 fragColor; \
in vec3 fragPosition; \
uniform vec3 cameraPosition; \
uniform vec3 gizmoPosition; \
out vec4 finalColor; \
void main() { \
void main() \
{ \
vec3 r = normalize(fragPosition - gizmoPosition); \
vec3 c = normalize(fragPosition - cameraPosition); \
if (dot(r, c) > 0.1) discard; \
@ -79,15 +124,48 @@ void main() { \
} \
";
static Shader SHADER_ROT_HANDLE_COLOR;
static int SHADER_ROT_HANDLE_CAMERA_POS_LOC;
static int SHADER_ROT_HANDLE_GIZMO_POS_LOC;
#else // Shaders for PLATFORM_ANDROID, PLATFORM_WEB
static unsigned int MASK_FRAMEBUFFER;
static unsigned int MASK_TEXTURE;
static const char* SHADER_COLOR_VERT = "\
#version 100\n\
attribute vec3 vertexPosition; \
attribute vec4 vertexColor; \
varying vec4 fragColor; \
varying vec3 fragPosition; \
uniform mat4 mvp; \
void main() \
{ \
fragColor = vertexColor; \
fragPosition = vertexPosition; \
gl_Position = mvp * vec4(vertexPosition, 1.0); \
} \
";
static bool IS_GIZMO_LOADED;
static Vector3 GIZMO_CURRENT_AXIS;
static const char* shaderRotHandleColor_FRAG = "\
#version 100\n\
precision mediump float; \
varying vec4 fragColor; \
varying vec3 fragPosition; \
uniform vec3 cameraPosition; \
uniform vec3 gizmoPosition; \
void main() { \
vec3 r = normalize(fragPosition - gizmoPosition); \
vec3 c = normalize(fragPosition - cameraPosition); \
if (dot(r, c) > 0.1) discard; \
gl_FragColor = fragColor; \
} \
";
#endif
static Shader shaderRotHandleColor;
static int ShaderRotHandleCameraPosLoc;
static int ShaderRotHandleGizmoPosLoc;
static unsigned int maskFramebuffer;
static unsigned int maskTexture;
static bool isGizmoLoaded;
static Vector3 gizmoCurrentAxis;
typedef enum HandleId {
HANDLE_X,
@ -129,7 +207,7 @@ typedef struct Handle {
Vector3 position;
Vector3 axis;
Color color;
float dist_to_cam;
float distToCamera;
} Handle;
typedef struct HandleColors {
@ -142,17 +220,17 @@ typedef struct Handles {
Handle arr[3];
} Handles;
static GizmoState GIZMO_STATE;
static GizmoState gizmoState;
bool check_if_mouse_moved() {
Vector2 mouse_delta = GetMouseDelta();
return (fabs(mouse_delta.x) + fabs(mouse_delta.y)) > EPSILON;
static bool checkIfMouseMoved() {
Vector2 mouseDelta = GetMouseDelta();
return (fabs(mouseDelta.x) + fabs(mouseDelta.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);
static float getAngleBetweenTwoVector2(Vector2 v1, Vector2 v2) {
Vector2 v1Normal = Vector2Normalize(v1);
Vector2 v2Normal = Vector2Normalize(v2);
float dot = Vector2DotProduct(v1Normal, v2Normal);
if (1.0 - fabs(dot) < EPSILON) return 0.0;
float angle = acos(dot);
@ -163,71 +241,63 @@ static float vector2_get_angle(Vector2 v1, Vector2 v2) {
else return -angle;
}
static int isect_line_plane(
Vector3* out_p,
Vector3 line_p0,
Vector3 line_p1,
Vector3 plane_p,
Vector3 plane_normal
static int intersectLinePlane(
Vector3* outPoint,
Vector3 linePoint0,
Vector3 linePoint1,
Vector3 planePoint,
Vector3 planeNormal
) {
Vector3 u = Vector3Subtract(line_p1, line_p0);
float dot = Vector3DotProduct(plane_normal, u);
if (fabs(dot) <= EPSILON) {
return 0;
}
Vector3 u = Vector3Subtract(linePoint1, linePoint0);
float dot = Vector3DotProduct(planeNormal, u);
if (fabs(dot) <= EPSILON) return 0;
Vector3 w = Vector3Subtract(line_p0, plane_p);
float k = -Vector3DotProduct(plane_normal, w) / dot;
Vector3 w = Vector3Subtract(linePoint0, planePoint);
float k = -Vector3DotProduct(planeNormal, w) / dot;
u = Vector3Scale(u, k);
*out_p = Vector3Add(line_p0, u);
*outPoint = Vector3Add(linePoint0, 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
static int getTwoLinesNearestPoint(
Vector3* outPoint,
Vector3 line0Point0,
Vector3 line0Point1,
Vector3 line1Point0,
Vector3 line1Point1
) {
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);
Vector3 vec0 = Vector3Subtract(line0Point1, line0Point0);
Vector3 vec1 = Vector3Subtract(line1Point1, line1Point0);
Vector3 planeVec = Vector3Normalize(Vector3CrossProduct(vec0, vec1));
Vector3 planeNormal = Vector3Normalize(Vector3CrossProduct(vec0, planeVec));
int is_isect = isect_line_plane(
vec0_out_nearest_point, vec1_p0, vec1_p1, vec0_p0, plane_normal
int isIntersected = intersectLinePlane(
outPoint, line1Point0, line1Point1, line0Point0, planeNormal
);
return is_isect;
return isIntersected;
}
static RayCollision get_ray_plane_collision(
Ray ray, Vector3 plane_point, Vector3 plane_normal
static RayCollision getRayPlaneCollision(
Ray ray, Vector3 planePoint, Vector3 planeNormal
) {
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;
float denominator = ray.direction.x * planeNormal.x
+ ray.direction.y * planeNormal.y
+ ray.direction.z * planeNormal.z;
if (denominator == 0) {
// Ray is parallel to the plane, no collision
return collision;
}
// Ray is parallel to the plane, no collision
if (denominator == 0) 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)
float t = ((planePoint.x - ray.position.x) * planeNormal.x
+ (planePoint.y - ray.position.y) * planeNormal.y
+ (planePoint.z - ray.position.z) * planeNormal.z)
/ denominator;
if (t < 0) {
// Intersection point is behind the ray's starting point, no collision
return collision;
}
// Intersection point is behind the ray's starting point, no collision
if (t < 0) return collision;
// Calculate the collision point
collision.point.x = ray.position.x + t * ray.direction.x;
@ -238,188 +308,180 @@ static RayCollision get_ray_plane_collision(
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);
static Handles getSortedHandled(Handle h0, Handle h1, Handle h2) {
if (h0.distToCamera < h1.distToCamera) SWAP(h0, h1);
if (h1.distToCamera < h2.distToCamera) SWAP(h1, h2);
if (h0.distToCamera < h1.distToCamera) 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;
static HandleColors getHandleColors(GizmoState hotState) {
bool isHot = gizmoState == hotState || gizmoState == hotState + 4;
Color x = isHot && gizmoCurrentAxis.x == 1.0f ? WHITE : RED;
Color y = isHot && gizmoCurrentAxis.y == 1.0f ? WHITE : GREEN;
Color z = isHot && gizmoCurrentAxis.z == 1.0f ? WHITE : BLUE;
HandleColors colors = {x, y, z};
return colors;
}
static void draw_axis_handles(
static void drawAxisHandles(
Camera3D camera,
Vector3 position,
float gizmo_radius,
Color color_x,
Color color_y,
Color color_z
float gizmoRadius,
Color colorX,
Color colorY,
Color colorZ
) {
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;
float length = gizmoRadius * GIZMO_AXIS_HANDLE_LENGTH;
float tipLength = gizmoRadius * GIZMO_AXIS_HANDLE_TIP_LENGTH;
float tipRadius = gizmoRadius * 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)};
Handle hx = {px, X_AXIS, colorX, Vector3DistanceSqr(px, camera.position)};
Handle hy = {py, Y_AXIS, colorY, Vector3DistanceSqr(py, camera.position)};
Handle hz = {pz, Z_AXIS, colorZ, Vector3DistanceSqr(pz, camera.position)};
Handles handles = get_sorted_handles(hx, hy, hz);
Handles handles = getSortedHandled(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)
Vector3 tipEnd = Vector3Add(
h->position, Vector3Scale(h->axis, tipLength)
);
DrawLine3D(position, h->position, h->color);
DrawCylinderEx(h->position, tip_end, tip_radius, 0.0, 16, h->color);
DrawCylinderEx(h->position, tipEnd, tipRadius, 0.0f, 16, h->color);
}
}
static void draw_plane_handles(
static void drawPlaneHandles(
Camera3D camera,
Vector3 position,
float gizmo_radius,
Color color_x,
Color color_y,
Color color_z
float gizmoRadius,
Color colorX,
Color colorY,
Color colorZ
) {
float offset = gizmo_radius * GIZMO_PLANE_HANDLE_OFFSET;
float size = gizmo_radius * GIZMO_PLANE_HANDLE_SIZE;
float offset = gizmoRadius * GIZMO_PLANE_HANDLE_OFFSET;
float size = gizmoRadius * 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});
Vector3 px = Vector3Add(position, (Vector3){0.0f, offset, offset});
Vector3 py = Vector3Add(position, (Vector3){offset, 0.0f, offset});
Vector3 pz = Vector3Add(position, (Vector3){offset, offset, 0.0f});
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)};
Handle hx = {px, Z_AXIS, colorX, Vector3DistanceSqr(px, camera.position)};
Handle hy = {py, Y_AXIS, colorY, Vector3DistanceSqr(py, camera.position)};
Handle hz = {pz, X_AXIS, colorZ, Vector3DistanceSqr(pz, camera.position)};
Handles handles = get_sorted_handles(hx, hy, hz);
Handles handles = getSortedHandled(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);
rlRotatef(90.0f, h->axis.x, h->axis.y, h->axis.z);
DrawPlane(
Vector3Zero(), Vector2Scale(Vector2One(), size), h->color
);
}
rlPopMatrix();
}
}
static void draw_rot_handles(
static void drawRotHandles(
Camera3D camera,
Vector3 position,
float gizmo_radius,
Color color_x,
Color color_y,
Color color_z
float gizmoRadius,
Color colorX,
Color colorY,
Color colorZ
) {
BeginShaderMode(SHADER_ROT_HANDLE_COLOR);
{
BeginShaderMode(shaderRotHandleColor);
SetShaderValue(
SHADER_ROT_HANDLE_COLOR,
SHADER_ROT_HANDLE_CAMERA_POS_LOC,
shaderRotHandleColor,
ShaderRotHandleCameraPosLoc,
&camera.position,
SHADER_UNIFORM_VEC3
);
SetShaderValue(
SHADER_ROT_HANDLE_COLOR,
SHADER_ROT_HANDLE_GIZMO_POS_LOC,
shaderRotHandleColor,
ShaderRotHandleGizmoPosLoc,
&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);
}
DrawCircle3D(position, gizmoRadius, Y_AXIS, 90.0f, colorX);
DrawCircle3D(position, gizmoRadius, X_AXIS, 90.0f, colorY);
DrawCircle3D(position, gizmoRadius, X_AXIS, 0.0f, colorZ);
EndShaderMode();
}
static void draw_gizmo(
static void drawGizmo(
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
Color rotHandleColorX,
Color rotHandleColorY,
Color rotHandleColorZ,
Color axisHandleColorX,
Color axisHandleColorY,
Color axisHandleColorZ,
Color planeHandleColorX,
Color planeHandleColorY,
Color planeHandleColorZ
) {
float radius = GIZMO_SIZE * Vector3Distance(camera.position, position);
// Draw gizmo's handle elements
BeginMode3D(camera);
{
rlSetLineWidth(GIZMO_HANDLE_DRAW_THICKNESS);
rlDisableDepthTest();
draw_plane_handles(
drawPlaneHandles(
camera,
position,
radius,
plane_handle_color_x,
plane_handle_color_y,
plane_handle_color_z
planeHandleColorX,
planeHandleColorY,
planeHandleColorZ
);
draw_rot_handles(
drawRotHandles(
camera,
position,
radius,
rot_handle_color_x,
rot_handle_color_y,
rot_handle_color_z
rotHandleColorX,
rotHandleColorY,
rotHandleColorZ
);
draw_axis_handles(
drawAxisHandles(
camera,
position,
radius,
axis_handle_color_x,
axis_handle_color_y,
axis_handle_color_z
axisHandleColorX,
axisHandleColorY,
axisHandleColorZ
);
}
EndMode3D();
// Draw long white line which represents current active axis
if (GIZMO_STATE == GIZMO_ACTIVE_ROT || GIZMO_STATE == GIZMO_ACTIVE_AXIS) {
if (gizmoState == GIZMO_ACTIVE_ROT || gizmoState == GIZMO_ACTIVE_AXIS) {
BeginMode3D(camera);
{
rlSetLineWidth(GIZMO_ACTIVE_AXIS_DRAW_THICKNESS);
Vector3 half_axis_line = Vector3Scale(GIZMO_CURRENT_AXIS, 1000.0);
Vector3 halfAxisLine = Vector3Scale(gizmoCurrentAxis, 1000.0f);
DrawLine3D(
Vector3Subtract(position, half_axis_line),
Vector3Add(position, half_axis_line),
Vector3Subtract(position, halfAxisLine),
Vector3Add(position, halfAxisLine),
WHITE
);
}
EndMode3D();
}
// Draw white line from the gizmo's center to the mouse cursor when rotating
if (GIZMO_STATE == GIZMO_ACTIVE_ROT) {
if (gizmoState == GIZMO_ACTIVE_ROT) {
rlSetLineWidth(GIZMO_ACTIVE_AXIS_DRAW_THICKNESS);
DrawLineV(
GetWorldToScreen(position, camera), GetMousePosition(), WHITE
@ -427,26 +489,26 @@ static void draw_gizmo(
}
}
static unsigned char get_gizmo_mask_pixel(Camera3D camera, Vector3 position) {
static unsigned char getGizmoMaskPixel(Camera3D camera, Vector3 position) {
// -------------------------------------------------------------------
// Draw gizmo into a separate framebuffer for the mouse pixel-picking
rlEnableFramebuffer(MASK_FRAMEBUFFER);
rlEnableFramebuffer(maskFramebuffer);
rlViewport(0, 0, MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT);
rlClearScreenBuffers();
rlDisableColorBlend();
draw_gizmo(
drawGizmo(
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)
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();
@ -455,38 +517,38 @@ static unsigned char get_gizmo_mask_pixel(Camera3D camera, Vector3 position) {
// -------------------------------------------------------------------
// Pick the pixel under the mouse cursor
Vector2 mouse_position = GetMousePosition();
Vector2 mousePosition = GetMousePosition();
unsigned char* pixels = (unsigned char*)rlReadTexturePixels(
MASK_TEXTURE,
maskTexture,
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
float xFract = Clamp(mousePosition.x / (float)GetScreenWidth(), 0.0, 1.0);
float yFract = Clamp(
1.0 - (mousePosition.y / (float)GetScreenHeight()), 0.0, 1.0
);
int x = (int)(MASK_FRAMEBUFFER_WIDTH * x_ratio);
int y = (int)(MASK_FRAMEBUFFER_HEIGHT * y_ratio);
int x = (int)(MASK_FRAMEBUFFER_WIDTH * xFract);
int y = (int)(MASK_FRAMEBUFFER_HEIGHT * yFract);
int idx = 4 * (y * MASK_FRAMEBUFFER_WIDTH + x);
unsigned char mask_val = pixels[idx];
unsigned char maskVal = pixels[idx];
free(pixels);
return mask_val;
return maskVal;
}
Matrix update_gizmo_rot(Camera3D camera, Vector3 position) {
if (!check_if_mouse_moved()) return MatrixIdentity();
static Matrix updateGizmoRot(Camera3D camera, Vector3 position) {
if (!checkIfMouseMoved()) return MatrixIdentity();
Vector2 rot_center = GetWorldToScreen(position, camera);
Vector2 p1 = Vector2Subtract(GetMousePosition(), rot_center);
Vector2 posOnScreen = GetWorldToScreen(position, camera);
Vector2 p1 = Vector2Subtract(GetMousePosition(), posOnScreen);
Vector2 p0 = Vector2Subtract(p1, GetMouseDelta());
float angle = vector2_get_angle(p1, p0);
float angle = getAngleBetweenTwoVector2(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)) {
// If we look at the gizmo from behind, we should flip the rotation
if (Vector3DotProduct(gizmoCurrentAxis, position)
> Vector3DotProduct(gizmoCurrentAxis, camera.position)) {
angle *= -1;
}
@ -495,7 +557,7 @@ Matrix update_gizmo_rot(Camera3D camera, Vector3 position) {
Matrix transform = MatrixMultiply(
MatrixMultiply(
MatrixTranslate(-position.x, -position.y, -position.z),
MatrixRotate(GIZMO_CURRENT_AXIS, angle)
MatrixRotate(gizmoCurrentAxis, angle)
),
MatrixTranslate(position.x, position.y, position.z)
);
@ -503,92 +565,90 @@ Matrix update_gizmo_rot(Camera3D camera, Vector3 position) {
return transform;
}
Matrix update_gizmo_axis(Camera3D camera, Vector3 position) {
if (!check_if_mouse_moved()) return MatrixIdentity();
static Matrix updateGizmoAxis(Camera3D camera, Vector3 position) {
if (!checkIfMouseMoved()) 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,
Vector3 interesctionPoint = Vector3Zero();
bool isIntersected = getTwoLinesNearestPoint(
&interesctionPoint,
camera.position,
Vector3Add(camera.position, r.direction),
position,
Vector3Add(position, GIZMO_CURRENT_AXIS)
Vector3Add(position, gizmoCurrentAxis)
);
if (!is_isect)
{
return MatrixIdentity();
}
if (!isIntersected) return MatrixIdentity();
Vector3 offset = Vector3Subtract(isect_p, position);
offset = Vector3Multiply(offset, GIZMO_CURRENT_AXIS);
Vector3 offset = Vector3Subtract(interesctionPoint, position);
offset = Vector3Multiply(offset, gizmoCurrentAxis);
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();
static Matrix updateGizmoPlane(Camera3D camera, Vector3 position) {
if (!checkIfMouseMoved()) 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);
RayCollision c = getRayPlaneCollision(r, position, gizmoCurrentAxis);
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);
static Matrix updateGizmo(Camera3D camera, Vector3 position, unsigned char maskVal) {
bool isLMBDown = IsMouseButtonDown(0);
if (!is_lmb_down) GIZMO_STATE = GIZMO_COLD;
if (!isLMBDown) gizmoState = 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 (gizmoState < GIZMO_ACTIVE) {
if (maskVal < HANDLE_Y) gizmoCurrentAxis = X_AXIS;
else if (maskVal < HANDLE_Z) gizmoCurrentAxis = Y_AXIS;
else gizmoCurrentAxis = 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;
if (maskVal % 4 == 1)
gizmoState = isLMBDown ? GIZMO_ACTIVE_ROT : GIZMO_HOT_ROT;
else if (maskVal % 4 == 2)
gizmoState = isLMBDown ? GIZMO_ACTIVE_AXIS : GIZMO_HOT_AXIS;
else if (maskVal % 4 == 3)
gizmoState = isLMBDown ? 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);
switch (gizmoState) {
case GIZMO_ACTIVE_ROT: return updateGizmoRot(camera, position);
case GIZMO_ACTIVE_AXIS: return updateGizmoAxis(camera, position);
case GIZMO_ACTIVE_PLANE: return updateGizmoPlane(camera, position);
default: return MatrixIdentity();
}
}
void LoadGizmo() {
if (IS_GIZMO_LOADED) return;
void loadGizmo() {
if (isGizmoLoaded) return;
SHADER_ROT_HANDLE_COLOR = LoadShaderFromMemory(
SHADER_COLOR_VERT, SHADER_ROT_HANDLE_COLOR_FRAG
shaderRotHandleColor = LoadShaderFromMemory(
SHADER_COLOR_VERT, shaderRotHandleColor_FRAG
);
SHADER_ROT_HANDLE_CAMERA_POS_LOC = GetShaderLocation(
SHADER_ROT_HANDLE_COLOR, "cameraPosition"
ShaderRotHandleCameraPosLoc = GetShaderLocation(
shaderRotHandleColor, "cameraPosition"
);
SHADER_ROT_HANDLE_GIZMO_POS_LOC = GetShaderLocation(
SHADER_ROT_HANDLE_COLOR, "gizmoPosition"
ShaderRotHandleGizmoPosLoc = GetShaderLocation(
shaderRotHandleColor, "gizmoPosition"
);
MASK_FRAMEBUFFER = rlLoadFramebuffer(
maskFramebuffer = rlLoadFramebuffer(
MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT
);
if (!MASK_FRAMEBUFFER) {
if (!maskFramebuffer) {
TraceLog(LOG_ERROR, "Failed to create gizmo's mask framebuffer");
exit(1);
}
rlEnableFramebuffer(MASK_FRAMEBUFFER);
rlEnableFramebuffer(maskFramebuffer);
MASK_TEXTURE = rlLoadTexture(
maskTexture = rlLoadTexture(
NULL,
MASK_FRAMEBUFFER_WIDTH,
MASK_FRAMEBUFFER_HEIGHT,
@ -597,56 +657,56 @@ void LoadGizmo() {
);
rlActiveDrawBuffers(1);
rlFramebufferAttach(
MASK_FRAMEBUFFER,
MASK_TEXTURE,
maskFramebuffer,
maskTexture,
RL_ATTACHMENT_COLOR_CHANNEL0,
RL_ATTACHMENT_TEXTURE2D,
0
);
if (!rlFramebufferComplete(MASK_FRAMEBUFFER)) {
if (!rlFramebufferComplete(maskFramebuffer)) {
TraceLog(LOG_ERROR, "Gizmo's framebuffer is not complete");
exit(1);
}
IS_GIZMO_LOADED = true;
isGizmoLoaded = true;
}
void UnloadGizmo() {
if (!IS_GIZMO_LOADED) return;
void unloadGizmo() {
if (!isGizmoLoaded) return;
UnloadShader(SHADER_ROT_HANDLE_COLOR);
rlUnloadFramebuffer(MASK_FRAMEBUFFER);
rlUnloadTexture(MASK_TEXTURE);
IS_GIZMO_LOADED = false;
UnloadShader(shaderRotHandleColor);
rlUnloadFramebuffer(maskFramebuffer);
rlUnloadTexture(maskTexture);
isGizmoLoaded = false;
}
Matrix UpdateGizmo(Camera3D camera, Vector3 position) {
if (!IS_GIZMO_LOADED) {
Matrix updateAndDrawGizmo(Camera3D camera, Vector3 position) {
if (!isGizmoLoaded) {
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);
unsigned char maskVal = getGizmoMaskPixel(camera, position);
Matrix transform = updateGizmo(camera, position, maskVal);
// -------------------------------------------------------------------
// 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);
HandleColors rotHandleColors = getHandleColors(GIZMO_HOT_ROT);
HandleColors axisHandleColors = getHandleColors(GIZMO_HOT_AXIS);
HandleColors planeHandleColors = getHandleColors(GIZMO_HOT_PLANE);
draw_gizmo(
drawGizmo(
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
rotHandleColors.x,
rotHandleColors.y,
rotHandleColors.z,
axisHandleColors.x,
axisHandleColors.y,
axisHandleColors.z,
planeHandleColors.x,
planeHandleColors.y,
planeHandleColors.z
);
return transform;