--User changes

-Add a palette editor.
 -Add support for reading .ugr/.gradient/.gradients palette files.
 -Allow toggling on spinners whose minimum value is not zero.
 -Allow toggling display of image, affines and grid.
 -Add new variations: cylinder2, circlesplit, tile_log, truchet_fill, waves2_radial.

--Bug fixes
 -cpow2 was wrong.
 -Palettes with rapid changes in color would produce slightly different outputs from Apo/Chaotica. This was due to a long standing bug from flam3.
 -Use exec() on Apple and show() on all other OSes for dialog boxes.
 -Trying to render a sequence with no frames would crash.
 -Selecting multiple xforms and rotating them would produce the wrong rotation.
 -Better handling when parsing flames using different encoding, such as unicode and UTF-8.
 -Switching between SP/DP didn't reselect the selected flame in the Library tab.

--Code changes
 -Make all types concerning palettes be floats, including PaletteTableWidgetItem.
 -PaletteTableWidgetItem is no longer templated because all palettes are float.
 -Include the source colors for user created gradients.
 -Change parallel_for() calls to work with very old versions of TBB which are lingering on some systems.
 -Split conditional out of accumulation loop on the CPU for better performance.
 -Vectorize summing when doing density filter for better performance.
 -Make all usage of palettes be of type float, double is pointless.
 -Allow palettes to reside in multiple folders, while ensuring only one of each name is added.
 -Refactor some palette path searching code.
 -Make ReadFile() throw and catch an exception if the file operation fails.
 -A little extra safety in foci and foci3D with a call to Zeps().
 -Cast to (real_t) in the OpenCL string for the w variation, which was having trouble compiling on Mac.
 -Fixing missing comma between paths in InitPaletteList().
 -Move Xml and PaletteList classes into cpp to shorten build times when working on them.
 -Remove default param values for IterOpenCLKernelCreator<T>::SharedDataIndexDefines in cpp file.
 -Change more NULL to nullptr.
This commit is contained in:
Person
2017-02-26 00:02:21 -08:00
parent 8a75d5d227
commit 8a4127d5d7
102 changed files with 242668 additions and 3713 deletions

View File

@ -135,8 +135,8 @@ void GLEmberController<T>::ClearWindow()
{
auto ember = m_FractoriumEmberController->CurrentEmber();
m_GL->makeCurrent();
m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GL->glClearColor(ember->m_Background.r, ember->m_Background.g, ember->m_Background.b, 1.0);
m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
/// <summary>
@ -209,7 +209,17 @@ void GLWidget::paintGL()
{
auto renderer = controller->Renderer();
m_Drawing = true;
GLController()->DrawImage();
if (m_Fractorium->DrawImage())
{
GLController()->DrawImage();
}
else
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
//Affine drawing.
bool pre = m_Fractorium->ui.PreAffineGroupBox->isChecked();
bool post = m_Fractorium->ui.PostAffineGroupBox->isChecked();
@ -249,8 +259,8 @@ void GLEmberController<T>::DrawImage()
{
auto renderer = m_FractoriumEmberController->Renderer();
auto ember = m_FractoriumEmberController->CurrentEmber();
m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GL->glClearColor(ember->m_Background.r, ember->m_Background.g, ember->m_Background.b, 1.0);
m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GL->glDisable(GL_DEPTH_TEST);
renderer->EnterFinalAccum();//Lock, may not be necessary, but just in case.
renderer->EnterResize();
@ -276,16 +286,16 @@ void GLEmberController<T>::DrawImage()
template <typename T>
void GLEmberController<T>::DrawAffines(bool pre, bool post)
{
if (!m_Fractorium->DrawXforms() || (m_DragState == eDragState::DragRotateScale))
return;
QueryVMP();//Resolves to float or double specialization function depending on T.
auto ember = m_FractoriumEmberController->CurrentEmber();
bool dragging = m_DragState == eDragState::DragDragging;
//Draw grid if control key is pressed.
if (m_GL->hasFocus() && GetControl())
{
m_GL->glLineWidth(1.0f);
m_GL->DrawGrid(m_FractoriumEmberController->AffineScaleLockedToCurrent());
}
if ((m_GL->hasFocus() && GetControl()) || m_Fractorium->DrawGrid())
DrawGrid();
//When dragging, only draw the selected xform's affine and hide all others.
if (!m_Fractorium->m_Settings->ShowAllXforms() && dragging)
@ -376,7 +386,7 @@ bool GLEmberControllerBase::KeyPress_(QKeyEvent* e)
}
/// <summary>
/// Call controller KeyPress_().
/// Call controller KeyPress().
/// </summary>
/// <param name="e">The event</param>
void GLWidget::keyPressEvent(QKeyEvent* e)
@ -466,15 +476,7 @@ void GLEmberController<T>::MousePress(QMouseEvent* e)
m_DragSrcTransforms.push_back(m_AffineType == eAffineType::AffinePre ? xform->m_Affine : xform->m_Post);
}, eXformUpdate::UPDATE_CURRENT_AND_SELECTED, false);//Don't update renderer here.
m_DragHandlePos = m_HoverHandlePos;//The location in local coordinates of the point selected on the spinner, x, y or center.
m_DragHandleOffset = m_DragHandlePos - m_MouseWorldPos;//The distance in world coordinates from the point selected to the center of the spinner.
m_DragState = eDragState::DragDragging;
//Draw large yellow dot on select or drag.
m_GL->glPointSize(6.0f);
m_GL->glBegin(GL_POINTS);
m_GL->glColor4f(1.0f, 1.0f, 0.5f, 1.0f);
m_GL->glVertex2f(m_DragHandlePos.x, m_DragHandlePos.y);
m_GL->glEnd();
m_GL->glPointSize(1.0f);//Restore point size.
m_GL->repaint();
}
else//Nothing was selected.
@ -491,13 +493,16 @@ void GLEmberController<T>::MousePress(QMouseEvent* e)
}
else if (e->button() == Qt::RightButton)//Right button does whole image rotation and scaling.
{
UpdateHover(mouseFlipped);
m_SelectedXform = m_HoverXform;
m_CenterDownX = ember->m_CenterX;//Capture these because they will change when rotating and scaling.
m_CenterDownY = ember->m_CenterY;
m_RotationDown = ember->m_Rotate;
m_ScaleDown = ember->m_PixelsPerUnit;
m_DragState = eDragState::DragRotateScale;
if (m_Fractorium->DrawImage())
{
UpdateHover(mouseFlipped);
m_SelectedXform = m_HoverXform;
m_CenterDownX = ember->m_CenterX;//Capture these because they will change when rotating and scaling.
m_CenterDownY = ember->m_CenterY;
m_RotationDown = ember->m_Rotate;
m_ScaleDown = ember->m_PixelsPerUnit;
m_DragState = eDragState::DragRotateScale;
}
}
}
}
@ -535,7 +540,7 @@ void GLEmberController<T>::MouseRelease(QMouseEvent* e)
m_DragState = eDragState::DragNone;
m_DragModifier = 0;
m_GL->repaint();//Force immediate redraw.
m_GL->update();
}
/// <summary>
@ -670,15 +675,27 @@ void GLWidget::mouseMoveEvent(QMouseEvent* e)
/// will zoom in the image in our out, while sacrificing quality.
/// If the user needs to preserve quality, they can use the zoom spinner
/// on the main window.
/// If Alt is pressed, only the scale of the affines is changed, the scale of the image remains untouched.
/// </summary>
/// <param name="e">The event</param>
template <typename T>
void GLEmberController<T>::Wheel(QWheelEvent* e)
{
auto ember = m_FractoriumEmberController->CurrentEmber();
if ((e->modifiers() & Qt::AltModifier) && m_Fractorium->DrawXforms())
{
m_FractoriumEmberController->ChangeLockedScale(e->angleDelta().x() >= 0 ? 1.0981 : 0.9);
m_GL->update();
}
else
{
if (m_Fractorium->DrawImage())
{
auto ember = m_FractoriumEmberController->CurrentEmber();
if (m_Fractorium && !(e->buttons() & Qt::MiddleButton))//Middle button does whole image translation, so ignore the mouse wheel while panning to avoid inadvertent zooming.
m_Fractorium->SetScale(ember->m_PixelsPerUnit + (e->angleDelta().y() >= 0 ? 50 : -50));
if (!(e->buttons() & Qt::MiddleButton))//Middle button does whole image translation, so ignore the mouse wheel while panning to avoid inadvertent zooming.
m_Fractorium->SetScale(ember->m_PixelsPerUnit + (e->angleDelta().y() >= 0 ? 50 : -50));
}
}
}
/// <summary>
@ -799,76 +816,6 @@ bool GLEmberController<T>::SizesMatch()
m_GL->m_TexHeight == m_GL->m_ViewHeight);
}
/// <summary>
/// Draw the grid in response to the control key being pressed.
/// The frequency of the grid lines will change depending on the zoom.
/// Calculated with the frame always centered, the renderer just moves the camera.
/// </summary>
/// <param name="scale">A value to scale by, used when locking the affine scale</param>
void GLWidget::DrawGrid(double scale)
{
auto renderer = m_Fractorium->m_Controller->Renderer();
float unitX = std::abs(renderer->UpperRightX(false) - renderer->LowerLeftX(false)) / 2.0f;
float unitY = std::abs(renderer->UpperRightY(false) - renderer->LowerLeftY(false)) / 2.0f;
float rad = std::max(unitX * scale, unitY * scale);
float xLow = floor(-unitX);
float xHigh = ceil(unitX);
float yLow = floor(-unitY);
float yHigh = ceil(unitY);
glBegin(GL_LINES);
if (rad <= 8.0f)
{
glColor4f(0.5f, 0.5f, 0.5f, 0.5f);
for (float fx = xLow; fx <= xHigh; fx += GridStep)
{
glVertex2f(fx, yLow);
glVertex2f(fx, yHigh);
}
for (float fy = yLow; fy < yHigh; fy += GridStep)
{
glVertex2f(xLow, fy);
glVertex2f(xHigh, fy);
}
}
unitX *= scale;
unitY *= scale;
if (unitX <= 64.0f)
{
glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
for (float fx = xLow; fx <= xHigh; fx += 1.0f)
{
glVertex2f(fx, yLow);
glVertex2f(fx, yHigh);
}
for (float fy = yLow; fy < yHigh; fy += 1.0f)
{
glVertex2f(xLow, fy);
glVertex2f(xHigh, fy);
}
}
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
glVertex2f(xHigh, 0.0f);
glColor4f(0.5f, 0.0f, 0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
glVertex2f(xLow, 0.0f);
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.0f, yHigh);
glColor4f(0.0f, 0.5f, 0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.0f, yLow);
glEnd();
}
/// <summary>
/// Draw the unit square.
/// </summary>
@ -894,6 +841,60 @@ void GLWidget::DrawUnitSquare()
glEnd();
}
/// <summary>
/// Draw the grid
/// The frequency of the grid lines will change depending on the zoom (ALT+WHEEL).
/// Calculated with the frame always centered, the renderer just moves the camera.
/// </summary>
template <typename T>
void GLEmberController<T>::DrawGrid()
{
auto renderer = m_Fractorium->m_Controller->Renderer();
double scale = m_FractoriumEmberController->AffineScaleCurrentToLocked();
float unitX = (std::abs(renderer->UpperRightX(false) - renderer->LowerLeftX(false)) / 2.0f) / scale;
float unitY = (std::abs(renderer->UpperRightY(false) - renderer->LowerLeftY(false)) / 2.0f) / scale;
float xLow = floor(-unitX);
float xHigh = ceil(unitX);
float yLow = floor(-unitY);
float yHigh = ceil(unitY);
float alpha = 0.25f;
Affine2D<T> temp;
m4T mat = (temp * scale).ToMat4RowMajor();
m_GL->glPushMatrix();
m_GL->glLoadIdentity();
MultMatrix(mat);
m_GL->glLineWidth(1.0f);
m_GL->glBegin(GL_LINES);
m_GL->glColor4f(0.5f, 0.5f, 0.5f, alpha);
for (float fx = xLow; fx <= xHigh; fx += GridStep)
{
m_GL->glVertex2f(fx, yLow);
m_GL->glVertex2f(fx, yHigh);
}
for (float fy = yLow; fy < yHigh; fy += GridStep)
{
m_GL->glVertex2f(xLow, fy);
m_GL->glVertex2f(xHigh, fy);
}
m_GL->glColor4f(1.0f, 0.0f, 0.0f, alpha);
m_GL->glVertex2f(0.0f, 0.0f);
m_GL->glVertex2f(xHigh, 0.0f);
m_GL->glColor4f(0.5f, 0.0f, 0.0f, alpha);
m_GL->glVertex2f(0.0f, 0.0f);
m_GL->glVertex2f(xLow, 0.0f);
m_GL->glColor4f(0.0f, 1.0f, 0.0f, alpha);
m_GL->glVertex2f(0.0f, 0.0f);
m_GL->glVertex2f(0.0f, yHigh);
m_GL->glColor4f(0.0f, 0.5f, 0.0f, alpha);
m_GL->glVertex2f(0.0f, 0.0f);
m_GL->glVertex2f(0.0f, yLow);
m_GL->glEnd();
m_GL->glPopMatrix();
}
/// <summary>
/// Draw the pre or post affine circle for the passed in xform.
/// For drawing affine transforms, multiply the identity model view matrix by the
@ -1028,42 +1029,45 @@ int GLEmberController<T>::UpdateHover(v3T& glCoords)
auto ember = m_FractoriumEmberController->CurrentEmber();
m_HoverType = eHoverType::HoverNone;
//If there's a selected/current xform, check it first so it gets precedence over the others.
if (m_SelectedXform)
if (m_Fractorium->DrawXforms())//Don't bother checking anything if the user wants to see no xforms.
{
//These checks prevent highlighting the pre/post selected xform circle, when one is set to show all, and the other
//is set to show current, and the user hovers over another xform, but doesn't select it, then moves the mouse
//back over the hidden circle for the pre/post that was set to only show current.
bool checkSelPre = preAll || (pre && m_HoverXform == m_SelectedXform);
bool checkSelPost = postAll || (post && m_HoverXform == m_SelectedXform);
if (CheckXformHover(m_SelectedXform, glCoords, bestDist, checkSelPre, checkSelPost))
//If there's a selected/current xform, check it first so it gets precedence over the others.
if (m_SelectedXform)
{
m_HoverXform = m_SelectedXform;
bestIndex = int(ember->GetTotalXformIndex(m_SelectedXform));
}
}
//These checks prevent highlighting the pre/post selected xform circle, when one is set to show all, and the other
//is set to show current, and the user hovers over another xform, but doesn't select it, then moves the mouse
//back over the hidden circle for the pre/post that was set to only show current.
bool checkSelPre = preAll || (pre && m_HoverXform == m_SelectedXform);
bool checkSelPost = postAll || (post && m_HoverXform == m_SelectedXform);
//Check all xforms.
for (int i = 0; i < int(ember->TotalXformCount()); i++)
{
auto xform = ember->GetTotalXform(i);
if (preAll || (pre && m_HoverXform == xform))//Only check pre affine if they are shown.
{
if (CheckXformHover(xform, glCoords, bestDist, true, false))
if (CheckXformHover(m_SelectedXform, glCoords, bestDist, checkSelPre, checkSelPost))
{
m_HoverXform = xform;
bestIndex = i;
m_HoverXform = m_SelectedXform;
bestIndex = int(ember->GetTotalXformIndex(m_SelectedXform));
}
}
if (postAll || (post && m_HoverXform == xform))//Only check post affine if they are shown.
//Check all xforms.
for (int i = 0; i < int(ember->TotalXformCount()); i++)
{
if (CheckXformHover(xform, glCoords, bestDist, false, true))
auto xform = ember->GetTotalXform(i);
if (preAll || (pre && m_HoverXform == xform))//Only check pre affine if they are shown.
{
m_HoverXform = xform;
bestIndex = i;
if (CheckXformHover(xform, glCoords, bestDist, true, false))
{
m_HoverXform = xform;
bestIndex = i;
}
}
if (postAll || (post && m_HoverXform == xform))//Only check post affine if they are shown.
{
if (CheckXformHover(xform, glCoords, bestDist, false, true))
{
m_HoverXform = xform;
bestIndex = i;
}
}
}
}
@ -1207,18 +1211,17 @@ template <typename T>
void GLEmberController<T>::CalcDragXAxis()
{
size_t index = 0;
auto scale = m_FractoriumEmberController->AffineScaleLockedToCurrent();
auto scaleBack = m_FractoriumEmberController->AffineScaleCurrentToLocked();
auto affineToWorldScale = m_FractoriumEmberController->AffineScaleLockedToCurrent();
auto worldToAffineScale = m_FractoriumEmberController->AffineScaleCurrentToLocked();
bool pre = m_AffineType == eAffineType::AffinePre;
bool worldPivotShiftAlt = !m_Fractorium->LocalPivot() && GetShift() && GetAlt();
auto startDiff = (v2T(m_HoverHandlePos) * affineToWorldScale) - m_DragSrcTransform.O();
T startAngle = std::atan2(startDiff.y, startDiff.x);
if (GetShift())
{
auto posOffset = m_MouseWorldPos + m_DragHandleOffset;
v3T snapped = GetControl() ? SnapToNormalizedAngle(posOffset, 24u) : posOffset;
auto startDiff = (v2T(m_MouseDownWorldPos) * scale) - m_DragSrcTransform.O();
auto endDiff = (v2T(snapped) * scale) - m_DragSrcTransform.O();
T startAngle = std::atan2(startDiff.y, startDiff.x);
v3T snapped = GetControl() ? SnapToNormalizedAngle(m_MouseWorldPos, 24u) : m_MouseWorldPos;
auto endDiff = (v2T(snapped) * affineToWorldScale) - m_DragSrcTransform.O();
T endAngle = std::atan2(endDiff.y, endDiff.x);
T angle = startAngle - endAngle;
m_FractoriumEmberController->UpdateXform([&](Xform<T>* xform)
@ -1245,32 +1248,47 @@ void GLEmberController<T>::CalcDragXAxis()
}
if (xform == m_FractoriumEmberController->CurrentXform())
m_DragHandlePos = v3T((affine.O() + affine.X()) * scaleBack, 0);
m_DragHandlePos = v3T((affine.O() + affine.X()) * worldToAffineScale, 0);
}, eXformUpdate::UPDATE_CURRENT_AND_SELECTED, false);//Calling code will update renderer.
}
else
{
v3T diff;
auto posOffset = m_MouseWorldPos + m_DragHandleOffset;
v3T diff = m_MouseWorldPos - m_MouseDownWorldPos;
auto diffscale = diff * affineToWorldScale;
auto origmag = Zeps(glm::length(m_DragSrcTransform.X()));
auto origXPlusOff = v3T(m_DragSrcTransform.X(), 0) + diffscale;
if (GetControl())
diff = SnapToGrid(posOffset) - m_MouseDownWorldPos;
else
diff = posOffset - m_MouseDownWorldPos;
{
auto o3 = v3T(m_DragSrcTransform.O(), 0);
auto o3x = origXPlusOff + o3;
origXPlusOff = SnapToGrid(o3x);
origXPlusOff -= o3;
}
auto origXPlusOff = v3T(m_DragSrcTransform.X(), 0) + (diff * scale);
auto newmag = glm::length(origXPlusOff);
auto newprc = newmag / origmag;
auto endDiff = (v2T(origXPlusOff) * affineToWorldScale);
T endAngle = std::atan2(endDiff.y, endDiff.x);
T angle = startAngle - endAngle;
m_FractoriumEmberController->UpdateXform([&](Xform<T>* xform)
{
auto& affine = pre ? xform->m_Affine : xform->m_Post;
auto axis = v3T(m_DragSrcTransforms[index++].X(), 0) + (diff * scale);
auto src = m_DragSrcTransforms[index++];
if (GetAlt())
{
affine.X(v2T(origXPlusOff));//Absolute, not ratio.
}
else
affine.RotateScaleXTo(v2T(axis));
{
src.ScaleXY(newprc);
src.Rotate(angle);
affine = src;
}
if (xform == m_FractoriumEmberController->CurrentXform())
m_DragHandlePos = v3T((affine.O() + affine.X()) * scaleBack, 0);
m_DragHandlePos = v3T((affine.O() + affine.X()) * worldToAffineScale, 0);
}, eXformUpdate::UPDATE_CURRENT_AND_SELECTED, false);
}
}
@ -1297,18 +1315,17 @@ template <typename T>
void GLEmberController<T>::CalcDragYAxis()
{
size_t index = 0;
auto scale = m_FractoriumEmberController->AffineScaleLockedToCurrent();
auto scaleBack = m_FractoriumEmberController->AffineScaleCurrentToLocked();
auto affineToWorldScale = m_FractoriumEmberController->AffineScaleLockedToCurrent();
auto worldToAffineScale = m_FractoriumEmberController->AffineScaleCurrentToLocked();
bool pre = m_AffineType == eAffineType::AffinePre;
bool worldPivotShiftAlt = !m_Fractorium->LocalPivot() && GetShift() && GetAlt();
auto startDiff = (v2T(m_HoverHandlePos) * affineToWorldScale) - m_DragSrcTransform.O();
T startAngle = std::atan2(startDiff.y, startDiff.x);
if (GetShift())
{
auto posOffset = m_MouseWorldPos + m_DragHandleOffset;
v3T snapped = GetControl() ? SnapToNormalizedAngle(posOffset, 24u) : posOffset;
auto startDiff = (v2T(m_MouseDownWorldPos) * scale) - m_DragSrcTransform.O();
auto endDiff = (v2T(snapped) * scale) - m_DragSrcTransform.O();
T startAngle = std::atan2(startDiff.y, startDiff.x);
v3T snapped = GetControl() ? SnapToNormalizedAngle(m_MouseWorldPos, 24u) : m_MouseWorldPos;
auto endDiff = (v2T(snapped) * affineToWorldScale) - m_DragSrcTransform.O();
T endAngle = std::atan2(endDiff.y, endDiff.x);
T angle = startAngle - endAngle;
m_FractoriumEmberController->UpdateXform([&](Xform<T>* xform)
@ -1335,32 +1352,47 @@ void GLEmberController<T>::CalcDragYAxis()
}
if (xform == m_FractoriumEmberController->CurrentXform())
m_DragHandlePos = v3T((affine.O() + affine.Y()) * scaleBack, 0);
m_DragHandlePos = v3T((affine.O() + affine.Y()) * worldToAffineScale, 0);
}, eXformUpdate::UPDATE_CURRENT_AND_SELECTED, false);//Calling code will update renderer.
}
else
{
v3T diff;
auto posOffset = m_MouseWorldPos + m_DragHandleOffset;
v3T diff = m_MouseWorldPos - m_MouseDownWorldPos;
auto diffscale = diff * affineToWorldScale;
auto origmag = Zeps(glm::length(m_DragSrcTransform.Y()));
auto origYPlusOff = v3T(m_DragSrcTransform.Y(), 0) + diffscale;
if (GetControl())
diff = SnapToGrid(posOffset) - m_MouseDownWorldPos;
else
diff = posOffset - m_MouseDownWorldPos;
{
auto o3 = v3T(m_DragSrcTransform.O(), 0);
auto o3y = origYPlusOff + o3;
origYPlusOff = SnapToGrid(o3y);
origYPlusOff -= o3;
}
auto origXPlusOff = v3T(m_DragSrcTransform.Y(), 0) + (diff * scale);
auto newmag = glm::length(origYPlusOff);
auto newprc = newmag / origmag;
auto endDiff = (v2T(origYPlusOff) * affineToWorldScale);
T endAngle = std::atan2(endDiff.y, endDiff.x);
T angle = startAngle - endAngle;
m_FractoriumEmberController->UpdateXform([&](Xform<T>* xform)
{
auto& affine = pre ? xform->m_Affine : xform->m_Post;
auto axis = v3T(m_DragSrcTransforms[index++].Y(), 0) + (diff * scale);
auto src = m_DragSrcTransforms[index++];
if (GetAlt())
affine.Y(v2T(origXPlusOff));//Absolute, not ratio.
{
affine.Y(v2T(origYPlusOff));//Absolute, not ratio.
}
else
affine.RotateScaleYTo(v2T(axis));
{
src.ScaleXY(newprc);
src.Rotate(angle);
affine = src;
}
if (xform == m_FractoriumEmberController->CurrentXform())
m_DragHandlePos = v3T((affine.O() + affine.Y()) * scaleBack, 0);
m_DragHandlePos = v3T((affine.O() + affine.Y()) * worldToAffineScale, 0);
}, eXformUpdate::UPDATE_CURRENT_AND_SELECTED, false);
}
}
@ -1382,8 +1414,8 @@ template <typename T>
void GLEmberController<T>::CalcDragTranslation()
{
size_t index = 0;
auto scale = m_FractoriumEmberController->AffineScaleLockedToCurrent();
auto scaleBack = m_FractoriumEmberController->AffineScaleCurrentToLocked();
auto affineToWorldScale = m_FractoriumEmberController->AffineScaleLockedToCurrent();
auto worldToAffineScale = m_FractoriumEmberController->AffineScaleCurrentToLocked();
bool worldPivotShift = !m_Fractorium->LocalPivot() && GetShift();
bool pre = m_AffineType == eAffineType::AffinePre;
@ -1409,7 +1441,7 @@ void GLEmberController<T>::CalcDragTranslation()
affine.O(srcRotated.O());
if (xform == m_FractoriumEmberController->CurrentXform())
m_DragHandlePos = v3T(srcRotated.O(), 0) * scaleBack;
m_DragHandlePos = v3T(srcRotated.O(), 0) * worldToAffineScale;
}, eXformUpdate::UPDATE_CURRENT_AND_SELECTED, false);//Calling code will update renderer.
}
else
@ -1421,20 +1453,24 @@ void GLEmberController<T>::CalcDragTranslation()
m_FractoriumEmberController->UpdateXform([&](Xform<T>* xform)
{
auto& affine = pre ? xform->m_Affine : xform->m_Post;
auto offset = m_DragSrcTransforms[index++].O() + (scale * v2T(diff));
auto offset = m_DragSrcTransforms[index++].O() + (affineToWorldScale * v2T(diff));
auto snapped = SnapToGrid(offset);
affine.O(v2T(snapped.x, snapped.y));
if (xform == m_FractoriumEmberController->CurrentXform())
m_DragHandlePos = v3T(affine.O(), 0) * worldToAffineScale;
}, eXformUpdate::UPDATE_CURRENT_AND_SELECTED, false);
m_DragHandlePos = SnapToGrid(m_MouseWorldPos);
}
else
{
m_FractoriumEmberController->UpdateXform([&](Xform<T>* xform)
{
auto& affine = pre ? xform->m_Affine : xform->m_Post;
affine.O(m_DragSrcTransforms[index++].O() + (scale * v2T(diff)));
affine.O(m_DragSrcTransforms[index++].O() + (affineToWorldScale * v2T(diff)));
if (xform == m_FractoriumEmberController->CurrentXform())
m_DragHandlePos = v3T(affine.O(), 0) * worldToAffineScale;
}, eXformUpdate::UPDATE_CURRENT_AND_SELECTED, false);
m_DragHandlePos = m_MouseWorldPos;
}
}
}
@ -1454,5 +1490,5 @@ GLEmberControllerBase* GLWidget::GLController()
template class GLEmberController<float>;
#ifdef DO_DOUBLE
template class GLEmberController<double>;
template class GLEmberController<double>;
#endif