mirror of
https://github.com/raysan5/raygui.git
synced 2026-02-03 20:59:18 -05:00
REVIEWED: Code formating
This commit is contained in:
@ -37,7 +37,7 @@
|
|||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Helper function
|
// Helper function
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
void LoadCurveDefaults(GuiCurveEditState curves[]);
|
void LoadCurveDefaults(GuiCurveEditorState curves[]);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Program main entry point
|
// Program main entry point
|
||||||
@ -80,7 +80,7 @@ int main()
|
|||||||
// 2 -> Ball Width
|
// 2 -> Ball Width
|
||||||
// 3 -> Ball Height
|
// 3 -> Ball Height
|
||||||
// 4 -> Ball rotation
|
// 4 -> Ball rotation
|
||||||
GuiCurveEditState curves[5] = { 0 };
|
GuiCurveEditorState curves[5] = { 0 };
|
||||||
LoadCurveDefaults(curves);
|
LoadCurveDefaults(curves);
|
||||||
|
|
||||||
// Animation time
|
// Animation time
|
||||||
@ -102,9 +102,9 @@ int main()
|
|||||||
|
|
||||||
// Ball animation
|
// Ball animation
|
||||||
const float t = time/animationTime;
|
const float t = time/animationTime;
|
||||||
Vector2 ballPos = (Vector2){ EvalGuiCurve(&curves[0], t), EvalGuiCurve(&curves[1], t) };
|
Vector2 ballPos = (Vector2){ GuiCurveEval(&curves[0], t), GuiCurveEval(&curves[1], t) };
|
||||||
Vector2 ballSize = (Vector2){ EvalGuiCurve(&curves[2], t), EvalGuiCurve(&curves[3], t) };
|
Vector2 ballSize = (Vector2){ GuiCurveEval(&curves[2], t), GuiCurveEval(&curves[3], t) };
|
||||||
float ballRotation = EvalGuiCurve(&curves[4], t);
|
float ballRotation = GuiCurveEval(&curves[4], t);
|
||||||
|
|
||||||
// Update style
|
// Update style
|
||||||
if (visualStyleActive != prevVisualStyleActive)
|
if (visualStyleActive != prevVisualStyleActive)
|
||||||
@ -170,7 +170,7 @@ int main()
|
|||||||
|
|
||||||
// GUI
|
// GUI
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
if (showHelp)
|
if (showHelp)
|
||||||
{
|
{
|
||||||
if (GuiWindowBox((Rectangle) {margin, margin, settingsRect.x-2*margin, curves[1].end-2*margin}, "help")) showHelp = false;
|
if (GuiWindowBox((Rectangle) {margin, margin, settingsRect.x-2*margin, curves[1].end-2*margin}, "help")) showHelp = false;
|
||||||
|
|
||||||
@ -239,7 +239,7 @@ int main()
|
|||||||
|
|
||||||
// Curves can leaks from control boundary... scissor it !
|
// Curves can leaks from control boundary... scissor it !
|
||||||
BeginScissorMode(curveRect.x, curveRect.y, curveRect.width, curveRect.height);
|
BeginScissorMode(curveRect.x, curveRect.y, curveRect.width, curveRect.height);
|
||||||
GuiCurveEdit(&curves[i],curveRect);
|
GuiCurveEditor(&curves[i],curveRect);
|
||||||
EndScissorMode();
|
EndScissorMode();
|
||||||
|
|
||||||
// Resume clipping from setting rect
|
// Resume clipping from setting rect
|
||||||
@ -247,7 +247,7 @@ int main()
|
|||||||
contentRect.height += fontSize*12 + margin;
|
contentRect.height += fontSize*12 + margin;
|
||||||
|
|
||||||
// Draw selected point controls
|
// Draw selected point controls
|
||||||
GuiCurveEditPoint *p = &(curves[i].points[curves[i].selectedIndex]);
|
GuiCurveEditorPoint *p = &(curves[i].points[curves[i].selectedIndex]);
|
||||||
GuiCheckBox((Rectangle){ contentRect.x, contentRect.y + contentRect.height + scrollOffset.y, 1.5f*fontSize, 1.5f*fontSize }, "Left Linear", &p->leftLinear);
|
GuiCheckBox((Rectangle){ contentRect.x, contentRect.y + contentRect.height + scrollOffset.y, 1.5f*fontSize, 1.5f*fontSize }, "Left Linear", &p->leftLinear);
|
||||||
GuiCheckBox((Rectangle){ contentRect.x+contentRect.width/2, contentRect.y + contentRect.height + scrollOffset.y, 1.5f*fontSize, 1.5f*fontSize }, "Right Linear", &p->rightLinear);
|
GuiCheckBox((Rectangle){ contentRect.x+contentRect.width/2, contentRect.y + contentRect.height + scrollOffset.y, 1.5f*fontSize, 1.5f*fontSize }, "Right Linear", &p->rightLinear);
|
||||||
contentRect.height += 1.5f*fontSize + margin;
|
contentRect.height += 1.5f*fontSize + margin;
|
||||||
@ -381,7 +381,7 @@ int main()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadCurveDefaults(GuiCurveEditState curves[])
|
void LoadCurveDefaults(GuiCurveEditorState curves[])
|
||||||
{
|
{
|
||||||
// X pos
|
// X pos
|
||||||
curves[0].start = 28;
|
curves[0].start = 28;
|
||||||
|
|||||||
@ -59,27 +59,30 @@
|
|||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Vector2 position; // In normalized space [0.f, 1.f]
|
Vector2 position; // In normalized space [0.0f, 1.0f]
|
||||||
Vector2 tangents; // The derivatives (left/right) of the 1D curve
|
Vector2 tangents; // The derivatives (left/right) of the 1D curve
|
||||||
|
|
||||||
// Let the curve editor calculate tangents to linearize part of the curve
|
// Let the curve editor calculate tangents to linearize part of the curve
|
||||||
bool leftLinear;
|
bool leftLinear;
|
||||||
bool rightLinear;
|
bool rightLinear;
|
||||||
} GuiCurveEditPoint;
|
} GuiCurveEditorPoint;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float start; // Value at y = 0
|
float start; // Value at y = 0
|
||||||
float end; // Value at y = 1
|
float end; // Value at y = 1
|
||||||
|
|
||||||
// Always valid (unless you manualy change state's point array). Make sure to set it to -1 before init
|
// Always valid (unless you manualy change state's point array). Make sure to set it to -1 before init
|
||||||
int selectedIndex;
|
int selectedIndex;
|
||||||
|
|
||||||
// Unsorted array with at least one point (constant curve)
|
// Unsorted array with at least one point (constant curve)
|
||||||
GuiCurveEditPoint points[GUI_CURVE_EDIT_MAX_POINTS];
|
GuiCurveEditorPoint points[GUI_CURVE_EDIT_MAX_POINTS];
|
||||||
int numPoints;
|
int numPoints;
|
||||||
|
|
||||||
// private part
|
// Private variables
|
||||||
bool editLeftTangent;
|
bool editLeftTangent;
|
||||||
bool editRightTangent;
|
bool editRightTangent;
|
||||||
Vector2 mouseOffset;
|
Vector2 mouseOffset;
|
||||||
} GuiCurveEditState;
|
} GuiCurveEditorState;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -90,15 +93,14 @@ extern "C" { // Prevents name mangling of functions
|
|||||||
// Module Functions Declaration
|
// Module Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Initialize state
|
|
||||||
GuiCurveEditState InitGuiCurveEdit();
|
GuiCurveEditorState GuiInitCurveEditor(); // Initialize curve editor state
|
||||||
// Draw and update curve control
|
void GuiCurveEditor(GuiCurveEditorState *state, Rectangle bounds); // Draw and update curve control
|
||||||
void GuiCurveEdit(GuiCurveEditState *state, Rectangle bounds);
|
|
||||||
|
|
||||||
// 1D Interpolation
|
// 1D Interpolation
|
||||||
// Returns the y value (in [start, end]) of the curve at x = t
|
// Returns the y value (in [start, end]) of the curve at x = t
|
||||||
// t must be normalized [0.f, 1.f]
|
// t must be normalized [0.f, 1.f]
|
||||||
float EvalGuiCurve(GuiCurveEditState *state, float t);
|
float GuiCurveEval(GuiCurveEditorState *state, float t);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@ -121,177 +123,186 @@ float EvalGuiCurve(GuiCurveEditState *state, float t);
|
|||||||
// Module Functions Definition
|
// Module Functions Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
GuiCurveEditState InitGuiCurveEdit()
|
GuiCurveEditorState GuiInitCurveEditor()
|
||||||
{
|
{
|
||||||
GuiCurveEditState state;
|
GuiCurveEditorState state = { 0 };
|
||||||
|
|
||||||
state.start = 0;
|
state.start = 0;
|
||||||
state.end = 1;
|
state.end = 1;
|
||||||
state.selectedIndex = 0;
|
state.selectedIndex = 0;
|
||||||
state.editLeftTangent = false;
|
state.editLeftTangent = false;
|
||||||
state.editRightTangent = false;
|
state.editRightTangent = false;
|
||||||
state.mouseOffset = (Vector2) {0.f,0.f};
|
state.mouseOffset = (Vector2){ 0.0f, 0.0f };
|
||||||
|
|
||||||
// At least one point (AVG by default)
|
// At least one point (AVG by default)
|
||||||
state.numPoints = 1;
|
state.numPoints = 1;
|
||||||
state.points[0].position = (Vector2) {0.5f,0.5f};
|
state.points[0].position = (Vector2){ 0.5f, 0.5f };
|
||||||
state.points[0].tangents = (Vector2) {0.f,0.f};
|
state.points[0].tangents = (Vector2){ 0.0f, 0.0f };
|
||||||
state.points[0].leftLinear = false;
|
state.points[0].leftLinear = false;
|
||||||
state.points[0].rightLinear = false;
|
state.points[0].rightLinear = false;
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CompareGuiCurveEditPointPtr (const void * a, const void * b)
|
static int CompareGuiCurveEditPointPtr(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
float fa = (*(GuiCurveEditPoint**)a)->position.x;
|
float fa = (*(GuiCurveEditorPoint**)a)->position.x;
|
||||||
float fb = (*(GuiCurveEditPoint**)b)->position.x;
|
float fb = (*(GuiCurveEditorPoint**)b)->position.x;
|
||||||
return (fa > fb) - (fa < fb);
|
|
||||||
|
return ((fa > fb) - (fa < fb));
|
||||||
}
|
}
|
||||||
|
|
||||||
float EvalGuiCurve(GuiCurveEditState *state, float t){
|
float GuiCurveEval(GuiCurveEditorState *state, float t)
|
||||||
|
{
|
||||||
// Sort points
|
// Sort points
|
||||||
GuiCurveEditPoint* sortedPoints[GUI_CURVE_EDIT_MAX_POINTS];
|
GuiCurveEditorPoint* sortedPoints[GUI_CURVE_EDIT_MAX_POINTS];
|
||||||
for(int i=0; i < state->numPoints; i++){
|
|
||||||
sortedPoints[i] = &state->points[i];
|
|
||||||
}
|
|
||||||
qsort(sortedPoints, state->numPoints, sizeof(GuiCurveEditPoint*), CompareGuiCurveEditPointPtr);
|
|
||||||
|
|
||||||
if(state->numPoints == 0)
|
for (int i=0; i < state->numPoints; i++) sortedPoints[i] = &state->points[i];
|
||||||
return state->start;
|
|
||||||
|
qsort(sortedPoints, state->numPoints, sizeof(GuiCurveEditorPoint*), CompareGuiCurveEditPointPtr);
|
||||||
|
|
||||||
|
if (state->numPoints == 0) return state->start;
|
||||||
|
|
||||||
// Constants part on edges
|
// Constants part on edges
|
||||||
if(t <= sortedPoints[0]->position.x)
|
if (t <= sortedPoints[0]->position.x) return state->start + (state->end-state->start)*sortedPoints[0]->position.y;
|
||||||
return state->start + (state->end-state->start) * sortedPoints[0]->position.y;
|
if (t >= sortedPoints[state->numPoints-1]->position.x) return state->start + (state->end-state->start)*sortedPoints[state->numPoints-1]->position.y;
|
||||||
if(t >= sortedPoints[state->numPoints-1]->position.x)
|
|
||||||
return state->start + (state->end-state->start) * sortedPoints[state->numPoints-1]->position.y;
|
|
||||||
|
|
||||||
// Find curve portion
|
// Find curve portion
|
||||||
for(int i=0; i < state->numPoints-1; i++){
|
for (int i=0; i < state->numPoints-1; i++)
|
||||||
const GuiCurveEditPoint* p1 = sortedPoints[i];
|
{
|
||||||
const GuiCurveEditPoint* p2 = sortedPoints[i+1];
|
const GuiCurveEditorPoint *p1 = sortedPoints[i];
|
||||||
|
const GuiCurveEditorPoint *p2 = sortedPoints[i+1];
|
||||||
|
|
||||||
// Skip this range
|
// Skip this range
|
||||||
if(!(t >= p1->position.x && t < p2->position.x) || p1->position.x == p2->position.x)
|
if (!((t >= p1->position.x) && (t < p2->position.x)) || (p1->position.x == p2->position.x)) continue;
|
||||||
continue;
|
|
||||||
float scale = (p2->position.x-p1->position.x);
|
float scale = (p2->position.x-p1->position.x);
|
||||||
float T = (t-p1->position.x)/scale;
|
float T = (t-p1->position.x)/scale;
|
||||||
float startTangent = scale * p1->tangents.y;
|
float startTangent = scale*p1->tangents.y;
|
||||||
float endTangent = scale * p2->tangents.x;
|
float endTangent = scale*p2->tangents.x;
|
||||||
float T2 = T*T;
|
float T2 = T*T;
|
||||||
float T3 = T*T*T;
|
float T3 = T*T*T;
|
||||||
return state->start + (state->end-state->start) * ((2*T3-3*T2+1)*p1->position.y+(T3-2*T2+T)*startTangent+(3*T2-2*T3)*p2->position.y+(T3-T2)*endTangent);
|
|
||||||
|
return (state->start + (state->end-state->start)*((2*T3 - 3*T2 + 1)*p1->position.y + (T3 - 2*T2 + T)*startTangent + (3*T2 - 2*T3)*p2->position.y + (T3 - T2)*endTangent));
|
||||||
}
|
}
|
||||||
|
|
||||||
return state->start;
|
return state->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiCurveEdit(GuiCurveEditState *state, Rectangle bounds){
|
void GuiCurveEditor(GuiCurveEditorState *state, Rectangle bounds)
|
||||||
|
{
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
// CONST
|
// CONST
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
const float pointSize = 10;
|
const float pointSize = 10.0f;
|
||||||
const float fontSize = GuiGetStyle(DEFAULT, TEXT_SIZE);
|
const float fontSize = GuiGetStyle(DEFAULT, TEXT_SIZE);
|
||||||
const float handleLength = pointSize*2.5;
|
const float handleLength = pointSize*2.5f;
|
||||||
const float handleSize = pointSize/1.5f;
|
const float handleSize = pointSize/1.5f;
|
||||||
|
|
||||||
const Rectangle innerBounds = (Rectangle){bounds.x+fontSize, bounds.y+fontSize, bounds.width-2*fontSize, bounds.height-2*fontSize};
|
const Rectangle innerBounds = (Rectangle){ bounds.x + fontSize, bounds.y + fontSize, bounds.width - 2*fontSize, bounds.height - 2*fontSize };
|
||||||
const Vector2 mouse = GetMousePosition();
|
const Vector2 mouse = GetMousePosition();
|
||||||
const Vector2 mouseLocal = (Vector2) {(mouse.x-innerBounds.x)/innerBounds.width, (innerBounds.y+innerBounds.height-mouse.y)/innerBounds.height};
|
const Vector2 mouseLocal = (Vector2){ (mouse.x - innerBounds.x)/innerBounds.width, (innerBounds.y + innerBounds.height-mouse.y)/innerBounds.height};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// UPDATE STATE
|
// UPDATE STATE
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Find first point under mouse (-1 if not found)
|
// Find first point under mouse (-1 if not found)
|
||||||
int hoveredPointIndex = -1;
|
int hoveredPointIndex = -1;
|
||||||
for(int i=0; i < state->numPoints; i++){
|
for (int i = 0; i < state->numPoints; i++)
|
||||||
const GuiCurveEditPoint* p = &state->points[i];
|
{
|
||||||
const Vector2 screenPos = (Vector2){p->position.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-p->position.y*innerBounds.height};
|
const GuiCurveEditorPoint *p = &state->points[i];
|
||||||
const Rectangle pointRect = (Rectangle) {screenPos.x-pointSize/2.f, screenPos.y-pointSize/2.f, pointSize, pointSize};
|
const Vector2 screenPos = (Vector2){ p->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height-p->position.y*innerBounds.height };
|
||||||
if(CheckCollisionPointRec(mouse, pointRect)){
|
const Rectangle pointRect = (Rectangle){ screenPos.x - pointSize/2.0f, screenPos.y - pointSize/2.0f, pointSize, pointSize };
|
||||||
|
|
||||||
|
if (CheckCollisionPointRec(mouse, pointRect))
|
||||||
|
{
|
||||||
hoveredPointIndex = i;
|
hoveredPointIndex = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unselect tangents
|
// Unselect tangents
|
||||||
if(IsMouseButtonReleased(MOUSE_BUTTON_LEFT)){
|
if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT))
|
||||||
|
{
|
||||||
state->editLeftTangent = false;
|
state->editLeftTangent = false;
|
||||||
state->editRightTangent = false;
|
state->editRightTangent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select a tangent if possible
|
// Select a tangent if possible
|
||||||
if(IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && state->selectedIndex != -1 && CheckCollisionPointRec(mouse, bounds)){
|
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (state->selectedIndex != -1) && CheckCollisionPointRec(mouse, bounds))
|
||||||
const GuiCurveEditPoint* p = &state->points[state->selectedIndex];
|
{
|
||||||
const Vector2 screenPos = (Vector2){p->position.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-p->position.y*innerBounds.height};
|
const GuiCurveEditorPoint* p = &state->points[state->selectedIndex];
|
||||||
|
const Vector2 screenPos = (Vector2){ p->position.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-p->position.y*innerBounds.height };
|
||||||
|
|
||||||
// Left control
|
// Left control
|
||||||
Vector2 target = (Vector2) {(p->position.x-1)*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-(p->position.y-p->tangents.x)*innerBounds.height};
|
Vector2 target = (Vector2){ (p->position.x-1)*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - (p->position.y-p->tangents.x)*innerBounds.height };
|
||||||
Vector2 dir = (Vector2) {target.x-screenPos.x, target.y-screenPos.y};
|
Vector2 dir = (Vector2){ target.x-screenPos.x, target.y-screenPos.y };
|
||||||
float d = sqrt(dir.x*dir.x+dir.y*dir.y);
|
float d = sqrt(dir.x*dir.x + dir.y*dir.y);
|
||||||
Vector2 control = (Vector2) {screenPos.x+dir.x/d*handleLength, screenPos.y+dir.y/d*handleLength};
|
Vector2 control = (Vector2){ screenPos.x + dir.x/d*handleLength, screenPos.y + dir.y/d*handleLength };
|
||||||
Rectangle controlRect = (Rectangle) {control.x-handleSize/2.f, control.y-handleSize/2.f, handleSize, handleSize};
|
Rectangle controlRect = (Rectangle){ control.x - handleSize/2.0f, control.y - handleSize/2.0f, handleSize, handleSize };
|
||||||
|
|
||||||
// Edit left tangent
|
// Edit left tangent
|
||||||
if(CheckCollisionPointRec(mouse, controlRect)){
|
if (CheckCollisionPointRec(mouse, controlRect)) state->editLeftTangent = true;
|
||||||
state->editLeftTangent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right control
|
// Right control
|
||||||
target = (Vector2) {(p->position.x+1)*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-(p->position.y+p->tangents.y)*innerBounds.height};
|
target = (Vector2){ (p->position.x + 1)*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - (p->position.y + p->tangents.y)*innerBounds.height };
|
||||||
dir = (Vector2) {target.x-screenPos.x, target.y-screenPos.y};
|
dir = (Vector2){ target.x-screenPos.x, target.y-screenPos.y };
|
||||||
d = sqrt(dir.x*dir.x+dir.y*dir.y);
|
d = sqrt(dir.x*dir.x + dir.y*dir.y);
|
||||||
control = (Vector2) {screenPos.x+dir.x/d*handleLength, screenPos.y+dir.y/d*handleLength};
|
control = (Vector2){ screenPos.x + dir.x/d*handleLength, screenPos.y + dir.y/d*handleLength };
|
||||||
controlRect = (Rectangle) {control.x-handleSize/2.f, control.y-handleSize/2.f, handleSize, handleSize};
|
controlRect = (Rectangle){ control.x - handleSize/2.0f, control.y - handleSize/2.0f, handleSize, handleSize };
|
||||||
|
|
||||||
// Edit right tangent
|
// Edit right tangent
|
||||||
if(CheckCollisionPointRec(mouse, controlRect)){
|
if (CheckCollisionPointRec(mouse, controlRect)) state->editRightTangent = true;
|
||||||
state->editRightTangent = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Move tangents
|
// Move tangents
|
||||||
if(IsMouseButtonDown(MOUSE_BUTTON_LEFT) && state->editRightTangent){
|
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && state->editRightTangent)
|
||||||
|
{
|
||||||
// editRightTangent == true implies selectedIndex != -1
|
// editRightTangent == true implies selectedIndex != -1
|
||||||
GuiCurveEditPoint* p = &state->points[state->selectedIndex];
|
GuiCurveEditorPoint *p = &state->points[state->selectedIndex];
|
||||||
const Vector2 screenPos = (Vector2){p->position.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-p->position.y*innerBounds.height};
|
const Vector2 screenPos = (Vector2){ p->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height-p->position.y*innerBounds.height };
|
||||||
const Vector2 dir = (Vector2){mouseLocal.x-p->position.x, mouseLocal.y-p->position.y};
|
const Vector2 dir = (Vector2){ mouseLocal.x - p->position.x, mouseLocal.y - p->position.y};
|
||||||
|
|
||||||
// Calculate right tangent slope
|
// Calculate right tangent slope
|
||||||
p->tangents.y = dir.x < 0.001f ? dir.y/0.001f : dir.y/dir.x;
|
p->tangents.y = (dir.x < 0.001f)? dir.y/0.001f : dir.y/dir.x;
|
||||||
p->rightLinear = false; // Stop right linearization update
|
p->rightLinear = false; // Stop right linearization update
|
||||||
|
|
||||||
// Tangents are symetric by default unless SHIFT is pressed
|
// Tangents are symetric by default unless SHIFT is pressed
|
||||||
if(!(IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT))){
|
if (!(IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT)))
|
||||||
|
{
|
||||||
p->tangents.x = p->tangents.y;
|
p->tangents.x = p->tangents.y;
|
||||||
p->leftLinear = false; // Stop left linearization update
|
p->leftLinear = false; // Stop left linearization update
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(IsMouseButtonDown(MOUSE_BUTTON_LEFT) && state->editLeftTangent){
|
}
|
||||||
|
else if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && state->editLeftTangent)
|
||||||
|
{
|
||||||
// editLeftTangent == true implies selectedIndex != -1
|
// editLeftTangent == true implies selectedIndex != -1
|
||||||
GuiCurveEditPoint* p = &state->points[state->selectedIndex];
|
GuiCurveEditorPoint *p = &state->points[state->selectedIndex];
|
||||||
const Vector2 screenPos = (Vector2){p->position.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-p->position.y*innerBounds.height};
|
const Vector2 screenPos = (Vector2){ p->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height-p->position.y*innerBounds.height };
|
||||||
const Vector2 dir = (Vector2){mouseLocal.x-p->position.x, mouseLocal.y-p->position.y};
|
const Vector2 dir = (Vector2){ mouseLocal.x - p->position.x, mouseLocal.y - p->position.y };
|
||||||
|
|
||||||
// Calculate left tangent slope
|
// Calculate left tangent slope
|
||||||
p->tangents.x = dir.x > -0.001f ? dir.y/(-0.001f) : dir.y/dir.x;
|
p->tangents.x = (dir.x > -0.001f)? dir.y/(-0.001f) : dir.y/dir.x;
|
||||||
p->leftLinear = false; // Stop left linearization update
|
p->leftLinear = false; // Stop left linearization update
|
||||||
|
|
||||||
// Tangents are symetric by default unless SHIFT is pressed
|
// Tangents are symetric by default unless SHIFT is pressed
|
||||||
if(!(IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT))){
|
if (!(IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT)))
|
||||||
|
{
|
||||||
p->tangents.y = p->tangents.x;
|
p->tangents.y = p->tangents.x;
|
||||||
p->rightLinear = false; // Stop right linearization update
|
p->rightLinear = false; // Stop right linearization update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Select a point
|
// Select a point
|
||||||
else if(IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && hoveredPointIndex != -1 && CheckCollisionPointRec(mouse, bounds)){
|
else if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (hoveredPointIndex != -1) && CheckCollisionPointRec(mouse, bounds))
|
||||||
|
{
|
||||||
state->selectedIndex = hoveredPointIndex;
|
state->selectedIndex = hoveredPointIndex;
|
||||||
const GuiCurveEditPoint* p = &state->points[state->selectedIndex];
|
const GuiCurveEditorPoint *p = &state->points[state->selectedIndex];
|
||||||
const Vector2 screenPos = (Vector2){p->position.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-p->position.y*innerBounds.height};
|
const Vector2 screenPos = (Vector2){ p->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - p->position.y*innerBounds.height };
|
||||||
state->mouseOffset = (Vector2) {p->position.x - mouseLocal.x, p->position.y - mouseLocal.y};
|
state->mouseOffset = (Vector2){ p->position.x - mouseLocal.x, p->position.y - mouseLocal.y };
|
||||||
}
|
}
|
||||||
// Remove a point (check against bounds)
|
// Remove a point (check against bounds)
|
||||||
else if(IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) && hoveredPointIndex != -1 && CheckCollisionPointRec(mouse, bounds) && state->numPoints > 1){
|
else if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) && (hoveredPointIndex != -1) && CheckCollisionPointRec(mouse, bounds) && (state->numPoints > 1))
|
||||||
|
{
|
||||||
// Deselect everything
|
// Deselect everything
|
||||||
state->selectedIndex = 0; // select first point by default
|
state->selectedIndex = 0; // select first point by default
|
||||||
state->editLeftTangent = false;
|
state->editLeftTangent = false;
|
||||||
@ -299,70 +310,72 @@ void GuiCurveEdit(GuiCurveEditState *state, Rectangle bounds){
|
|||||||
|
|
||||||
// Remove point
|
// Remove point
|
||||||
state->numPoints -= 1;
|
state->numPoints -= 1;
|
||||||
for(int i=hoveredPointIndex; i < state->numPoints; i++ ){
|
for (int i = hoveredPointIndex; i < state->numPoints; i++) state->points[i] = state->points[i+1];
|
||||||
state->points[i] = state->points[i+1];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Add a point (check against innerBounds)
|
// Add a point (check against innerBounds)
|
||||||
} else if(IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && CheckCollisionPointRec(mouse, innerBounds) && state->numPoints < GUI_CURVE_EDIT_MAX_POINTS){
|
else if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && CheckCollisionPointRec(mouse, innerBounds) && (state->numPoints < GUI_CURVE_EDIT_MAX_POINTS))
|
||||||
|
{
|
||||||
state->editLeftTangent = false;
|
state->editLeftTangent = false;
|
||||||
state->editRightTangent = false;
|
state->editRightTangent = false;
|
||||||
|
|
||||||
// Create new point
|
// Create new point
|
||||||
GuiCurveEditPoint p;
|
GuiCurveEditorPoint p;
|
||||||
p.tangents = (Vector2) {0.f, 0.f};
|
p.tangents = (Vector2){ 0.0f, 0.0f };
|
||||||
p.position = mouseLocal;
|
p.position = mouseLocal;
|
||||||
p.leftLinear = false;
|
p.leftLinear = false;
|
||||||
p.rightLinear = false;
|
p.rightLinear = false;
|
||||||
|
|
||||||
// Append point
|
// Append point
|
||||||
state->points[state->numPoints] = p;
|
state->points[state->numPoints] = p;
|
||||||
state->selectedIndex = state->numPoints; // select new point
|
state->selectedIndex = state->numPoints; // select new point
|
||||||
state->numPoints += 1;
|
state->numPoints += 1;
|
||||||
// Point is add on mouse pos
|
|
||||||
state->mouseOffset = (Vector2) {0,0};
|
|
||||||
|
|
||||||
|
// Point is add on mouse pos
|
||||||
|
state->mouseOffset = (Vector2){ 0, 0 };
|
||||||
|
}
|
||||||
// Move selected point
|
// Move selected point
|
||||||
} else if(state->selectedIndex != -1 && IsMouseButtonDown(MOUSE_BUTTON_LEFT) && CheckCollisionPointRec(mouse, bounds) ){
|
else if ((state->selectedIndex != -1) && IsMouseButtonDown(MOUSE_BUTTON_LEFT) && CheckCollisionPointRec(mouse, bounds))
|
||||||
GuiCurveEditPoint* p = &state->points[state->selectedIndex];
|
{
|
||||||
|
GuiCurveEditorPoint *p = &state->points[state->selectedIndex];
|
||||||
|
|
||||||
// use mouse offset on click to prevent point teleporting to mouse
|
// use mouse offset on click to prevent point teleporting to mouse
|
||||||
const Vector2 newLocalPos = (Vector2){mouseLocal.x + state->mouseOffset.x, mouseLocal.y + state->mouseOffset.y};
|
const Vector2 newLocalPos = (Vector2){ mouseLocal.x + state->mouseOffset.x, mouseLocal.y + state->mouseOffset.y };
|
||||||
|
|
||||||
// Clamp to innerbounds
|
// Clamp to innerbounds
|
||||||
p->position.x = newLocalPos.x < 0 ? 0 : newLocalPos.x > 1 ? 1 : newLocalPos.x;
|
p->position.x = (newLocalPos.x < 0)? 0 : ((newLocalPos.x > 1)? 1 : newLocalPos.x);
|
||||||
p->position.y = newLocalPos.y < 0 ? 0 : newLocalPos.y > 1 ? 1 : newLocalPos.y;
|
p->position.y = (newLocalPos.y < 0)? 0 : ((newLocalPos.y > 1)? 1 : newLocalPos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort points
|
// Sort points
|
||||||
GuiCurveEditPoint* sortedPoints[GUI_CURVE_EDIT_MAX_POINTS];
|
GuiCurveEditorPoint *sortedPoints[GUI_CURVE_EDIT_MAX_POINTS] = { 0 };
|
||||||
for(int i=0; i < state->numPoints; i++){
|
for (int i = 0; i < state->numPoints; i++) sortedPoints[i] = &state->points[i];
|
||||||
sortedPoints[i] = &state->points[i];
|
qsort(sortedPoints, state->numPoints, sizeof(GuiCurveEditorPoint*), CompareGuiCurveEditPointPtr);
|
||||||
}
|
|
||||||
qsort(sortedPoints, state->numPoints, sizeof(GuiCurveEditPoint*), CompareGuiCurveEditPointPtr);
|
|
||||||
|
|
||||||
|
|
||||||
// Update linear tangents
|
// Update linear tangents
|
||||||
for(int i=0; i < state->numPoints; i++){
|
for (int i = 0; i < state->numPoints; i++)
|
||||||
GuiCurveEditPoint* p = sortedPoints[i];
|
{
|
||||||
|
GuiCurveEditorPoint *p = sortedPoints[i];
|
||||||
|
|
||||||
// Left tangent
|
// Left tangent
|
||||||
if(i > 0 && p->leftLinear){
|
if ((i > 0) && p->leftLinear)
|
||||||
const GuiCurveEditPoint* p2 = sortedPoints[i-1];
|
{
|
||||||
Vector2 dir = (Vector2) {p2->position.x-p->position.x, p2->position.y-p->position.y};
|
const GuiCurveEditorPoint *p2 = sortedPoints[i - 1];
|
||||||
p->tangents.x = dir.x == 0 ? 0 : dir.y/dir.x;
|
Vector2 dir = (Vector2){ p2->position.x - p->position.x, p2->position.y - p->position.y };
|
||||||
|
p->tangents.x = (dir.x == 0)? 0 : dir.y/dir.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right tangent
|
// Right tangent
|
||||||
if(i < state->numPoints-1 && p->rightLinear){
|
if ((i < state->numPoints - 1) && p->rightLinear)
|
||||||
const GuiCurveEditPoint* p2 = sortedPoints[i+1];
|
{
|
||||||
Vector2 dir = (Vector2) {p2->position.x-p->position.x, p2->position.y-p->position.y};
|
const GuiCurveEditorPoint *p2 = sortedPoints[i + 1];
|
||||||
p->tangents.y = dir.x == 0 ? 0 : dir.y/dir.x;
|
Vector2 dir = (Vector2){ p2->position.x - p->position.x, p2->position.y - p->position.y };
|
||||||
|
p->tangents.y = (dir.x == 0)? 0 : dir.y/dir.x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// DRAWING
|
// DRAWING
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Draw bg
|
|
||||||
DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
|
DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
|
||||||
|
|
||||||
// Draw grid
|
// Draw grid
|
||||||
@ -374,88 +387,103 @@ void GuiCurveEdit(GuiCurveEditState *state, Rectangle bounds){
|
|||||||
|
|
||||||
// V lines
|
// V lines
|
||||||
DrawLine(innerBounds.x, bounds.y, innerBounds.x, bounds.y+bounds.height, lineColor); // 0
|
DrawLine(innerBounds.x, bounds.y, innerBounds.x, bounds.y+bounds.height, lineColor); // 0
|
||||||
DrawLine(innerBounds.x+innerBounds.width/4, bounds.y, innerBounds.x+innerBounds.width/4, bounds.y+bounds.height, lineColor); // 0.25
|
DrawLine(innerBounds.x + innerBounds.width/4, bounds.y, innerBounds.x + innerBounds.width/4, bounds.y + bounds.height, lineColor); // 0.25
|
||||||
DrawLine(innerBounds.x+innerBounds.width/2, bounds.y, innerBounds.x+innerBounds.width/2, bounds.y+bounds.height, lineColor); // 0.5
|
DrawLine(innerBounds.x + innerBounds.width/2, bounds.y, innerBounds.x + innerBounds.width/2, bounds.y + bounds.height, lineColor); // 0.5
|
||||||
DrawLine(innerBounds.x+3*innerBounds.width/4, bounds.y, innerBounds.x+3*innerBounds.width/4, bounds.y+bounds.height, lineColor); // 0.75
|
DrawLine(innerBounds.x + 3*innerBounds.width/4, bounds.y, innerBounds.x + 3*innerBounds.width/4, bounds.y + bounds.height, lineColor); // 0.75
|
||||||
DrawLine(innerBounds.x+innerBounds.width, bounds.y, innerBounds.x+innerBounds.width, bounds.y+bounds.height, lineColor); // 1
|
DrawLine(innerBounds.x + innerBounds.width, bounds.y, innerBounds.x + innerBounds.width, bounds.y + bounds.height, lineColor); // 1
|
||||||
|
|
||||||
Font font = GuiGetFont();
|
Font font = GuiGetFont();
|
||||||
// V labels
|
// V labels
|
||||||
DrawTextEx(font, "0", (Vector2) {innerBounds.x, bounds.y+bounds.height-fontSize}, fontSize,GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
DrawTextEx(font, "0", (Vector2){ innerBounds.x, bounds.y + bounds.height-fontSize}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
||||||
DrawTextEx(font, "0.25", (Vector2) {innerBounds.x+innerBounds.width/4.f, bounds.y+bounds.height-fontSize}, fontSize,GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
DrawTextEx(font, "0.25", (Vector2){ innerBounds.x + innerBounds.width/4.0f, bounds.y + bounds.height - fontSize}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
||||||
DrawTextEx(font, "0.5", (Vector2) {innerBounds.x+innerBounds.width/2.f, bounds.y+bounds.height-fontSize}, fontSize,GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
DrawTextEx(font, "0.5", (Vector2){ innerBounds.x + innerBounds.width/2.0f, bounds.y + bounds.height - fontSize}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
||||||
DrawTextEx(font, "0.75", (Vector2) {innerBounds.x+3.f*innerBounds.width/4.f, bounds.y+bounds.height-fontSize}, fontSize,GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
DrawTextEx(font, "0.75", (Vector2){ innerBounds.x + 3.0f*innerBounds.width/4.0f, bounds.y + bounds.height-fontSize}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
||||||
DrawTextEx(font, "1", (Vector2) {innerBounds.x+innerBounds.width, bounds.y+bounds.height-fontSize}, fontSize,GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
DrawTextEx(font, "1", (Vector2){ innerBounds.x + innerBounds.width, bounds.y+bounds.height - fontSize}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
||||||
|
|
||||||
// H labels
|
// H labels
|
||||||
DrawTextEx(font, TextFormat("%.2f", state->start), (Vector2) {innerBounds.x, innerBounds.y-fontSize+innerBounds.height}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
DrawTextEx(font, TextFormat("%.2f", state->start), (Vector2){ innerBounds.x, innerBounds.y - fontSize+innerBounds.height }, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
||||||
DrawTextEx(font, TextFormat("%.2f", state->start + (state->end-state->start)/2.f), (Vector2) {innerBounds.x, innerBounds.y-fontSize+innerBounds.height/2.f}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
DrawTextEx(font, TextFormat("%.2f", state->start + (state->end-state->start)/2.f), (Vector2){ innerBounds.x, innerBounds.y - fontSize + innerBounds.height/2.0f }, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
||||||
DrawTextEx(font, TextFormat("%.2f", state->end), (Vector2) {innerBounds.x, innerBounds.y}, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
DrawTextEx(font, TextFormat("%.2f", state->end), (Vector2){ innerBounds.x, innerBounds.y }, fontSize, GuiGetStyle(DEFAULT, TEXT_SPACING), lineColor);
|
||||||
|
|
||||||
// Draw contours
|
// Draw contours
|
||||||
if(CheckCollisionPointRec(mouse, bounds))
|
if (CheckCollisionPointRec(mouse, bounds)) DrawRectangleLines(bounds.x, bounds.y, bounds.width, bounds.height, GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_FOCUSED)));
|
||||||
DrawRectangleLines(bounds.x, bounds.y, bounds.width, bounds.height, GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_FOCUSED)));
|
else DrawRectangleLines(bounds.x, bounds.y, bounds.width, bounds.height, GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL)));
|
||||||
else
|
|
||||||
DrawRectangleLines(bounds.x, bounds.y, bounds.width, bounds.height, GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL)));
|
|
||||||
|
|
||||||
// Draw points
|
// Draw points
|
||||||
for(int i=0; i < state->numPoints; i++){
|
for (int i = 0; i < state->numPoints; i++)
|
||||||
|
{
|
||||||
|
const GuiCurveEditorPoint *p = sortedPoints[i];
|
||||||
|
|
||||||
const GuiCurveEditPoint* p = sortedPoints[i];
|
const Vector2 screenPos = (Vector2){ p->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - p->position.y*innerBounds.height };
|
||||||
|
const Rectangle pointRect = (Rectangle){ screenPos.x - pointSize/2.0f, screenPos.y - pointSize/2.0f, pointSize, pointSize };
|
||||||
|
|
||||||
const Vector2 screenPos = (Vector2){p->position.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-p->position.y*innerBounds.height};
|
Color pointColor = { 0 };
|
||||||
const Rectangle pointRect = (Rectangle) {screenPos.x-pointSize/2.f, screenPos.y-pointSize/2.f, pointSize, pointSize};
|
Color pointBorderColor = { 0 };
|
||||||
|
|
||||||
Color pointColor;
|
|
||||||
Color pointBorderColor;
|
|
||||||
|
|
||||||
// Draw point
|
// Draw point
|
||||||
if(&state->points[state->selectedIndex] == p){
|
if (&state->points[state->selectedIndex] == p)
|
||||||
|
{
|
||||||
// Draw left handle
|
// Draw left handle
|
||||||
if(i > 0){
|
if (i > 0)
|
||||||
const Vector2 target = (Vector2) {(p->position.x-1)*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-(p->position.y-p->tangents.x)*innerBounds.height};
|
{
|
||||||
const Vector2 dir = (Vector2) {target.x-screenPos.x, target.y-screenPos.y};
|
const Vector2 target = (Vector2){ (p->position.x - 1)*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - (p->position.y - p->tangents.x)*innerBounds.height };
|
||||||
const float d = sqrt(dir.x*dir.x+dir.y*dir.y);
|
const Vector2 dir = (Vector2){ target.x - screenPos.x, target.y - screenPos.y };
|
||||||
const Vector2 control = (Vector2) {screenPos.x+dir.x/d*handleLength, screenPos.y+dir.y/d*handleLength};
|
const float d = sqrt(dir.x*dir.x + dir.y*dir.y);
|
||||||
const Rectangle controlRect = (Rectangle) {control.x-handleSize/2.f, control.y-handleSize/2.f, handleSize, handleSize};
|
const Vector2 control = (Vector2){ screenPos.x + dir.x/d*handleLength, screenPos.y + dir.y/d*handleLength };
|
||||||
|
const Rectangle controlRect = (Rectangle){ control.x - handleSize/2.0f, control.y - handleSize/2.0f, handleSize, handleSize };
|
||||||
|
|
||||||
Color controlColor;
|
Color controlColor = { 0 };
|
||||||
Color controlBorderColor;
|
Color controlBorderColor = { 0 };
|
||||||
if(state->editLeftTangent){
|
|
||||||
|
if (state->editLeftTangent)
|
||||||
|
{
|
||||||
controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_PRESSED));
|
controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_PRESSED));
|
||||||
controlBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
controlBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
||||||
} else if(CheckCollisionPointRec(mouse, controlRect)){
|
}
|
||||||
|
else if (CheckCollisionPointRec(mouse, controlRect))
|
||||||
|
{
|
||||||
controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_FOCUSED));
|
controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_FOCUSED));
|
||||||
controlBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
controlBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
controlColor = GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL));
|
controlColor = GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL));
|
||||||
controlBorderColor = GetColor(GuiGetStyle(BUTTON, BORDER_COLOR_NORMAL));
|
controlBorderColor = GetColor(GuiGetStyle(BUTTON, BORDER_COLOR_NORMAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawLine(screenPos.x,screenPos.y, control.x, control.y, controlColor);
|
DrawLine(screenPos.x,screenPos.y, control.x, control.y, controlColor);
|
||||||
DrawRectangle(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
|
DrawRectangle(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
|
||||||
DrawRectangleLines(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
|
DrawRectangleLines(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
|
||||||
}
|
}
|
||||||
// Draw right handle
|
|
||||||
if(i < state->numPoints-1){
|
|
||||||
const Vector2 target = (Vector2) {(p->position.x+1)*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-(p->position.y+p->tangents.y)*innerBounds.height};
|
|
||||||
const Vector2 dir = (Vector2) {target.x-screenPos.x, target.y-screenPos.y};
|
|
||||||
const float d = sqrt(dir.x*dir.x+dir.y*dir.y);
|
|
||||||
const Vector2 control = (Vector2) {screenPos.x+dir.x/d*handleLength, screenPos.y+dir.y/d*handleLength};
|
|
||||||
const Rectangle controlRect = (Rectangle) {control.x-handleSize/2.f, control.y-handleSize/2.f, handleSize, handleSize};
|
|
||||||
|
|
||||||
Color controlColor;
|
// Draw right handle
|
||||||
Color controlBorderColor;
|
if (i < state->numPoints - 1)
|
||||||
if(state->editRightTangent){
|
{
|
||||||
|
const Vector2 target = (Vector2){ (p->position.x + 1)*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - (p->position.y + p->tangents.y)*innerBounds.height };
|
||||||
|
const Vector2 dir = (Vector2){ target.x - screenPos.x, target.y - screenPos.y };
|
||||||
|
const float d = sqrt(dir.x*dir.x + dir.y*dir.y);
|
||||||
|
const Vector2 control = (Vector2){ screenPos.x + dir.x/d*handleLength, screenPos.y + dir.y/d*handleLength };
|
||||||
|
const Rectangle controlRect = (Rectangle){ control.x - handleSize/2.0f, control.y - handleSize/2.0f, handleSize, handleSize };
|
||||||
|
|
||||||
|
Color controlColor = { 0 };
|
||||||
|
Color controlBorderColor = { 0 };
|
||||||
|
|
||||||
|
if (state->editRightTangent)
|
||||||
|
{
|
||||||
controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_PRESSED));
|
controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_PRESSED));
|
||||||
controlBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
controlBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
||||||
} else if(CheckCollisionPointRec(mouse, controlRect)){
|
}
|
||||||
|
else if (CheckCollisionPointRec(mouse, controlRect))
|
||||||
|
{
|
||||||
controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_FOCUSED));
|
controlColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_FOCUSED));
|
||||||
controlBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
controlBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
controlColor = GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL));
|
controlColor = GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL));
|
||||||
controlBorderColor = GetColor(GuiGetStyle(BUTTON, BORDER_COLOR_NORMAL));
|
controlBorderColor = GetColor(GuiGetStyle(BUTTON, BORDER_COLOR_NORMAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawLine(screenPos.x,screenPos.y, control.x, control.y, controlColor);
|
DrawLine(screenPos.x,screenPos.y, control.x, control.y, controlColor);
|
||||||
DrawRectangle(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
|
DrawRectangle(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
|
||||||
DrawRectangleLines(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
|
DrawRectangleLines(controlRect.x, controlRect.y, controlRect.width, controlRect.height, controlColor);
|
||||||
@ -464,49 +492,61 @@ void GuiCurveEdit(GuiCurveEditState *state, Rectangle bounds){
|
|||||||
pointColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_PRESSED));
|
pointColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_PRESSED));
|
||||||
pointBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
pointBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
||||||
|
|
||||||
} else if(&state->points[hoveredPointIndex] == p) {
|
}
|
||||||
|
else if (&state->points[hoveredPointIndex] == p)
|
||||||
|
{
|
||||||
pointColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_FOCUSED));
|
pointColor = GetColor(GuiGetStyle(DEFAULT, BASE_COLOR_FOCUSED));
|
||||||
pointBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
pointBorderColor = GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_NORMAL));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
pointColor = GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL));
|
pointColor = GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL));
|
||||||
pointBorderColor = GetColor(GuiGetStyle(BUTTON, BORDER_COLOR_NORMAL));
|
pointBorderColor = GetColor(GuiGetStyle(BUTTON, BORDER_COLOR_NORMAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawRectangle(pointRect.x, pointRect.y, pointRect.width, pointRect.height, pointColor);
|
DrawRectangle(pointRect.x, pointRect.y, pointRect.width, pointRect.height, pointColor);
|
||||||
DrawRectangleLines(pointRect.x, pointRect.y, pointRect.width, pointRect.height, pointBorderColor);
|
DrawRectangleLines(pointRect.x, pointRect.y, pointRect.width, pointRect.height, pointBorderColor);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw curve
|
// Draw curve
|
||||||
Color curveColor = GetColor(GuiGetStyle(LABEL, TEXT_COLOR_FOCUSED));
|
Color curveColor = GetColor(GuiGetStyle(LABEL, TEXT_COLOR_FOCUSED));
|
||||||
if(state->numPoints == 1){
|
|
||||||
const GuiCurveEditPoint* p = sortedPoints[0];
|
if (state->numPoints == 1)
|
||||||
const Vector2 screenPos = (Vector2){p->position.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-p->position.y*innerBounds.height};
|
{
|
||||||
|
const GuiCurveEditorPoint *p = sortedPoints[0];
|
||||||
|
const Vector2 screenPos = (Vector2){ p->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - p->position.y*innerBounds.height };
|
||||||
DrawLine(innerBounds.x, screenPos.y, innerBounds.x+innerBounds.width, screenPos.y, curveColor);
|
DrawLine(innerBounds.x, screenPos.y, innerBounds.x+innerBounds.width, screenPos.y, curveColor);
|
||||||
}else {
|
}
|
||||||
for(int i=0; i < state->numPoints-1; i++){
|
else
|
||||||
const GuiCurveEditPoint* p1 = sortedPoints[i];
|
{
|
||||||
const GuiCurveEditPoint* p2 = sortedPoints[i+1];
|
for (int i = 0; i < state->numPoints - 1; i++)
|
||||||
const Vector2 screenPos1 = (Vector2){p1->position.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-p1->position.y*innerBounds.height};
|
{
|
||||||
const Vector2 screenPos2 = (Vector2){p2->position.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-p2->position.y*innerBounds.height};
|
const GuiCurveEditorPoint *p1 = sortedPoints[i];
|
||||||
|
const GuiCurveEditorPoint *p2 = sortedPoints[i + 1];
|
||||||
|
const Vector2 screenPos1 = (Vector2){ p1->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - p1->position.y*innerBounds.height };
|
||||||
|
const Vector2 screenPos2 = (Vector2){ p2->position.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - p2->position.y*innerBounds.height };
|
||||||
|
|
||||||
// Constant on edge
|
// Constant on edge
|
||||||
if(screenPos1.x > innerBounds.x && i == 0){
|
if ((screenPos1.x > innerBounds.x) && (i == 0))
|
||||||
|
{
|
||||||
DrawLine(innerBounds.x, screenPos1.y, screenPos1.x, screenPos1.y, curveColor);
|
DrawLine(innerBounds.x, screenPos1.y, screenPos1.x, screenPos1.y, curveColor);
|
||||||
}
|
}
|
||||||
if(screenPos2.x < innerBounds.x+innerBounds.width && i == (state->numPoints-2)){
|
if ((screenPos2.x < innerBounds.x + innerBounds.width) && (i == (state->numPoints - 2)))
|
||||||
|
{
|
||||||
DrawLine(screenPos2.x, screenPos2.y, innerBounds.x+innerBounds.width, screenPos2.y, curveColor);
|
DrawLine(screenPos2.x, screenPos2.y, innerBounds.x+innerBounds.width, screenPos2.y, curveColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw cubic Hermite curve
|
// Draw cubic Hermite curve
|
||||||
const float scale = (p2->position.x-p1->position.x)/3.f;
|
const float scale = (p2->position.x - p1->position.x)/3.0f;
|
||||||
const Vector2 offset1 = (Vector2) {scale, scale*p1->tangents.y};
|
const Vector2 offset1 = (Vector2){ scale, scale*p1->tangents.y };
|
||||||
// negative endTangent => top part => need to invert value to calculate offset
|
// negative endTangent => top part => need to invert value to calculate offset
|
||||||
const Vector2 offset2 = (Vector2) {-scale, -scale*p2->tangents.x};
|
const Vector2 offset2 = (Vector2){ -scale, -scale*p2->tangents.x };
|
||||||
|
|
||||||
const Vector2 c1 = (Vector2) {p1->position.x+offset1.x, p1->position.y+offset1.y};
|
const Vector2 c1 = (Vector2){ p1->position.x + offset1.x, p1->position.y + offset1.y };
|
||||||
const Vector2 c2 = (Vector2) {p2->position.x+offset2.x, p2->position.y+offset2.y};
|
const Vector2 c2 = (Vector2){ p2->position.x + offset2.x, p2->position.y + offset2.y };
|
||||||
|
|
||||||
const Vector2 screenC1 = (Vector2) {c1.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-c1.y*innerBounds.height};
|
const Vector2 screenC1 = (Vector2){ c1.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - c1.y*innerBounds.height };
|
||||||
const Vector2 screenC2 = (Vector2) {c2.x*innerBounds.width+innerBounds.x, innerBounds.y+innerBounds.height-c2.y*innerBounds.height};
|
const Vector2 screenC2 = (Vector2){ c2.x*innerBounds.width + innerBounds.x, innerBounds.y + innerBounds.height - c2.y*innerBounds.height };
|
||||||
|
|
||||||
DrawLineBezierCubic(screenPos1, screenPos2, screenC1, screenC2, 1, curveColor);
|
DrawLineBezierCubic(screenPos1, screenPos2, screenC1, screenC2, 1, curveColor);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user