mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 23:53:52 +00:00
Merge remote-tracking branch 'aesylwinn/InstanceRotateAndScale'
This commit is contained in:
commit
2fef8948f1
5 changed files with 397 additions and 76 deletions
|
@ -188,6 +188,7 @@ void CSMPrefs::State::declare()
|
||||||
"Shift-acceleration factor during drag operations", 4.0).
|
"Shift-acceleration factor during drag operations", 4.0).
|
||||||
setTooltip ("Acceleration factor during drag operations while holding down shift").
|
setTooltip ("Acceleration factor during drag operations while holding down shift").
|
||||||
setRange (0.001, 100.0);
|
setRange (0.001, 100.0);
|
||||||
|
declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1);
|
||||||
|
|
||||||
declareCategory ("Tooltips");
|
declareCategory ("Tooltips");
|
||||||
declareBool ("scene", "Show Tooltips in 3D scenes", true);
|
declareBool ("scene", "Show Tooltips in 3D scenes", true);
|
||||||
|
|
|
@ -27,6 +27,68 @@ int CSVRender::InstanceMode::getSubModeFromId (const std::string& id) const
|
||||||
return id=="move" ? 0 : (id=="rotate" ? 1 : 2);
|
return id=="move" ? 0 : (id=="rotate" ? 1 : 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::Vec3f CSVRender::InstanceMode::quatToEuler(const osg::Quat& rot) const
|
||||||
|
{
|
||||||
|
const float Pi = 3.14159265f;
|
||||||
|
|
||||||
|
float x, y, z;
|
||||||
|
float test = 2 * (rot.w() * rot.y() + rot.x() * rot.z());
|
||||||
|
|
||||||
|
if (std::abs(test) >= 1.f)
|
||||||
|
{
|
||||||
|
x = atan2(rot.x(), rot.w());
|
||||||
|
y = (test > 0) ? (Pi / 2) : (-Pi / 2);
|
||||||
|
z = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = std::atan2(2 * (rot.w() * rot.x() - rot.y() * rot.z()), 1 - 2 * (rot.x() * rot.x() + rot.y() * rot.y()));
|
||||||
|
y = std::asin(test);
|
||||||
|
z = std::atan2(2 * (rot.w() * rot.z() - rot.x() * rot.y()), 1 - 2 * (rot.y() * rot.y() + rot.z() * rot.z()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return osg::Vec3f(-x, -y, -z);
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Quat CSVRender::InstanceMode::eulerToQuat(const osg::Vec3f& euler) const
|
||||||
|
{
|
||||||
|
osg::Quat xr = osg::Quat(-euler[0], osg::Vec3f(1,0,0));
|
||||||
|
osg::Quat yr = osg::Quat(-euler[1], osg::Vec3f(0,1,0));
|
||||||
|
osg::Quat zr = osg::Quat(-euler[2], osg::Vec3f(0,0,1));
|
||||||
|
|
||||||
|
return zr * yr * xr;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Vec3f CSVRender::InstanceMode::getSelectionCenter(const std::vector<osg::ref_ptr<TagBase> >& selection) const
|
||||||
|
{
|
||||||
|
osg::Vec3f center = osg::Vec3f(0, 0, 0);
|
||||||
|
int objectCount = 0;
|
||||||
|
|
||||||
|
for (std::vector<osg::ref_ptr<TagBase> >::const_iterator iter (selection.begin()); iter!=selection.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
|
||||||
|
{
|
||||||
|
const ESM::Position& position = objectTag->mObject->getPosition();
|
||||||
|
center += osg::Vec3f(position.pos[0], position.pos[1], position.pos[2]);
|
||||||
|
|
||||||
|
++objectCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
center /= objectCount;
|
||||||
|
|
||||||
|
return center;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Vec3f CSVRender::InstanceMode::getScreenCoords(const osg::Vec3f& pos)
|
||||||
|
{
|
||||||
|
osg::Matrix viewMatrix = getWorldspaceWidget().getCamera()->getViewMatrix();
|
||||||
|
osg::Matrix projMatrix = getWorldspaceWidget().getCamera()->getProjectionMatrix();
|
||||||
|
osg::Matrix windowMatrix = getWorldspaceWidget().getCamera()->getViewport()->computeWindowMatrix();
|
||||||
|
osg::Matrix combined = viewMatrix * projMatrix * windowMatrix;
|
||||||
|
|
||||||
|
return pos * combined;
|
||||||
|
}
|
||||||
|
|
||||||
CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
|
CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
|
||||||
: EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing",
|
: EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing",
|
||||||
parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None),
|
parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None),
|
||||||
|
@ -44,14 +106,16 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
|
||||||
"Rotate selected instances"
|
"Rotate selected instances"
|
||||||
"<ul><li>Use {scene-edit-primary} to rotate instances freely</li>"
|
"<ul><li>Use {scene-edit-primary} to rotate instances freely</li>"
|
||||||
"<li>Use {scene-edit-secondary} to rotate instances within the grid</li>"
|
"<li>Use {scene-edit-secondary} to rotate instances within the grid</li>"
|
||||||
|
"<li>The center of the view acts as the axis of rotation</li>"
|
||||||
"</ul>"
|
"</ul>"
|
||||||
"<font color=Red>Not implemented yet</font color>");
|
"<font color=Red>Grid rotate not implemented yet</font color>");
|
||||||
mSubMode->addButton (":placeholder", "scale",
|
mSubMode->addButton (":placeholder", "scale",
|
||||||
"Scale selected instances"
|
"Scale selected instances"
|
||||||
"<ul><li>Use {scene-edit-primary} to scale instances freely</li>"
|
"<ul><li>Use {scene-edit-primary} to scale instances freely</li>"
|
||||||
"<li>Use {scene-edit-secondary} to scale instances along the grid</li>"
|
"<li>Use {scene-edit-secondary} to scale instances along the grid</li>"
|
||||||
|
"<li>The scaling rate is based on how close the start of a drag is to the center of the screen</li>"
|
||||||
"</ul>"
|
"</ul>"
|
||||||
"<font color=Red>Not implemented yet</font color>");
|
"<font color=Red>Grid scale not implemented yet</font color>");
|
||||||
|
|
||||||
mSubMode->setButton (mSubModeId);
|
mSubMode->setButton (mSubModeId);
|
||||||
|
|
||||||
|
@ -152,6 +216,11 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||||
|
|
||||||
|
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Reference);
|
||||||
|
if (selection.empty())
|
||||||
|
{
|
||||||
|
// Only change selection at the start of drag if no object is already selected
|
||||||
if (hit.tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
|
if (hit.tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
|
||||||
{
|
{
|
||||||
getWorldspaceWidget().clearSelection (Mask_Reference);
|
getWorldspaceWidget().clearSelection (Mask_Reference);
|
||||||
|
@ -162,22 +231,44 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<osg::ref_ptr<TagBase> > selection =
|
selection = getWorldspaceWidget().getSelection (Mask_Reference);
|
||||||
getWorldspaceWidget().getSelection (Mask_Reference);
|
|
||||||
|
|
||||||
if (selection.empty())
|
if (selection.empty())
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
|
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
|
||||||
iter!=selection.end(); ++iter)
|
iter!=selection.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
|
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
|
||||||
|
{
|
||||||
|
if (mSubModeId == "move")
|
||||||
{
|
{
|
||||||
objectTag->mObject->setEdited (Object::Override_Position);
|
objectTag->mObject->setEdited (Object::Override_Position);
|
||||||
|
mDragMode = DragMode_Move;
|
||||||
}
|
}
|
||||||
|
else if (mSubModeId == "rotate")
|
||||||
|
{
|
||||||
|
objectTag->mObject->setEdited (Object::Override_Rotation);
|
||||||
|
mDragMode = DragMode_Rotate;
|
||||||
}
|
}
|
||||||
|
else if (mSubModeId == "scale")
|
||||||
|
{
|
||||||
|
objectTag->mObject->setEdited (Object::Override_Scale);
|
||||||
|
mDragMode = DragMode_Scale;
|
||||||
|
|
||||||
// \todo check for sub-mode
|
// Calculate scale factor
|
||||||
|
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getEdited (Mask_Reference);
|
||||||
|
osg::Vec3f center = getScreenCoords(getSelectionCenter(selection));
|
||||||
|
|
||||||
|
int widgetHeight = getWorldspaceWidget().height();
|
||||||
|
|
||||||
|
float dx = pos.x() - center.x();
|
||||||
|
float dy = (widgetHeight - pos.y()) - center.y();
|
||||||
|
|
||||||
|
mUnitScaleDist = std::sqrt(dx * dx + dy * dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (CSVRender::ObjectMarkerTag *objectTag = dynamic_cast<CSVRender::ObjectMarkerTag *> (hit.tag.get()))
|
if (CSVRender::ObjectMarkerTag *objectTag = dynamic_cast<CSVRender::ObjectMarkerTag *> (hit.tag.get()))
|
||||||
{
|
{
|
||||||
|
@ -186,8 +277,6 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos)
|
||||||
else
|
else
|
||||||
mDragAxis = -1;
|
mDragAxis = -1;
|
||||||
|
|
||||||
mDragMode = DragMode_Move;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,48 +290,160 @@ bool CSVRender::InstanceMode::secondaryEditStartDrag (const QPoint& pos)
|
||||||
|
|
||||||
void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
|
void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
|
||||||
{
|
{
|
||||||
osg::Vec3f eye;
|
osg::Vec3f offset;
|
||||||
osg::Vec3f centre;
|
osg::Quat rotation;
|
||||||
osg::Vec3f up;
|
|
||||||
|
|
||||||
|
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getEdited (Mask_Reference);
|
||||||
|
|
||||||
|
if (mDragMode == DragMode_Move)
|
||||||
|
{
|
||||||
|
osg::Vec3f eye, centre, up;
|
||||||
getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up);
|
getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up);
|
||||||
|
|
||||||
osg::Vec3f offset;
|
|
||||||
|
|
||||||
if (diffY)
|
if (diffY)
|
||||||
|
{
|
||||||
offset += up * diffY * speedFactor;
|
offset += up * diffY * speedFactor;
|
||||||
|
}
|
||||||
if (diffX)
|
if (diffX)
|
||||||
|
{
|
||||||
offset += ((centre-eye) ^ up) * diffX * speedFactor;
|
offset += ((centre-eye) ^ up) * diffX * speedFactor;
|
||||||
|
}
|
||||||
|
|
||||||
switch (mDragMode)
|
|
||||||
{
|
|
||||||
case DragMode_Move:
|
|
||||||
{
|
|
||||||
if (mDragAxis!=-1)
|
if (mDragAxis!=-1)
|
||||||
|
{
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
|
{
|
||||||
if (i!=mDragAxis)
|
if (i!=mDragAxis)
|
||||||
offset[i] = 0;
|
offset[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mDragMode == DragMode_Rotate)
|
||||||
|
{
|
||||||
|
osg::Vec3f eye, centre, up;
|
||||||
|
getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up);
|
||||||
|
|
||||||
std::vector<osg::ref_ptr<TagBase> > selection =
|
float angle;
|
||||||
getWorldspaceWidget().getEdited (Mask_Reference);
|
osg::Vec3f axis;
|
||||||
|
|
||||||
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
|
if (mDragAxis == -1)
|
||||||
iter!=selection.end(); ++iter)
|
{
|
||||||
|
// Free rotate
|
||||||
|
float rotationFactor = CSMPrefs::get()["3D Scene Input"]["rotate-factor"].toDouble() * speedFactor;
|
||||||
|
|
||||||
|
osg::Quat cameraRotation = getWorldspaceWidget().getCamera()->getInverseViewMatrix().getRotate();
|
||||||
|
|
||||||
|
osg::Vec3f camForward = centre - eye;
|
||||||
|
osg::Vec3f screenDir = cameraRotation * osg::Vec3f(diffX, diffY, 0);
|
||||||
|
screenDir.normalize();
|
||||||
|
|
||||||
|
angle = std::sqrt(diffX*diffX + diffY*diffY) * rotationFactor;
|
||||||
|
axis = screenDir ^ camForward;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Global axis rotation
|
||||||
|
osg::Vec3f camBack = eye - centre;
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
if (i == mDragAxis)
|
||||||
|
axis[i] = 1;
|
||||||
|
else
|
||||||
|
axis[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flip axis if facing opposite side
|
||||||
|
if (camBack * axis < 0)
|
||||||
|
axis *= -1;
|
||||||
|
|
||||||
|
// Convert coordinate system
|
||||||
|
osg::Vec3f screenCenter = getScreenCoords(getSelectionCenter(selection));
|
||||||
|
|
||||||
|
int widgetHeight = getWorldspaceWidget().height();
|
||||||
|
|
||||||
|
float newX = pos.x() - screenCenter.x();
|
||||||
|
float newY = (widgetHeight - pos.y()) - screenCenter.y();
|
||||||
|
|
||||||
|
float oldX = newX - diffX;
|
||||||
|
float oldY = newY - diffY; // diffY appears to already be flipped
|
||||||
|
|
||||||
|
osg::Vec3f oldVec = osg::Vec3f(oldX, oldY, 0);
|
||||||
|
oldVec.normalize();
|
||||||
|
|
||||||
|
osg::Vec3f newVec = osg::Vec3f(newX, newY, 0);
|
||||||
|
newVec.normalize();
|
||||||
|
|
||||||
|
// Find angle and axis of rotation
|
||||||
|
angle = std::acos(oldVec * newVec) * speedFactor;
|
||||||
|
if (((oldVec ^ newVec) * camBack < 0) ^ (camBack.z() < 0))
|
||||||
|
angle *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rotation = osg::Quat(angle, axis);
|
||||||
|
}
|
||||||
|
else if (mDragMode == DragMode_Scale)
|
||||||
|
{
|
||||||
|
osg::Vec3f center = getScreenCoords(getSelectionCenter(selection));
|
||||||
|
|
||||||
|
// Calculate scaling distance/rate
|
||||||
|
int widgetHeight = getWorldspaceWidget().height();
|
||||||
|
|
||||||
|
float dx = pos.x() - center.x();
|
||||||
|
float dy = (widgetHeight - pos.y()) - center.y();
|
||||||
|
|
||||||
|
float dist = std::sqrt(dx * dx + dy * dy);
|
||||||
|
float scale = dist / mUnitScaleDist;
|
||||||
|
|
||||||
|
// Only uniform scaling is currently supported
|
||||||
|
offset = osg::Vec3f(scale, scale, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply
|
||||||
|
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin()); iter!=selection.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
|
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
|
||||||
|
{
|
||||||
|
if (mDragMode == DragMode_Move)
|
||||||
{
|
{
|
||||||
ESM::Position position = objectTag->mObject->getPosition();
|
ESM::Position position = objectTag->mObject->getPosition();
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
|
{
|
||||||
position.pos[i] += offset[i];
|
position.pos[i] += offset[i];
|
||||||
objectTag->mObject->setPosition (position.pos);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
objectTag->mObject->setPosition(position.pos);
|
||||||
|
}
|
||||||
|
else if (mDragMode == DragMode_Rotate)
|
||||||
|
{
|
||||||
|
ESM::Position position = objectTag->mObject->getPosition();
|
||||||
|
|
||||||
|
osg::Quat currentRot = eulerToQuat(osg::Vec3f(position.rot[0], position.rot[1], position.rot[2]));
|
||||||
|
osg::Quat combined = currentRot * rotation;
|
||||||
|
|
||||||
|
osg::Vec3f euler = quatToEuler(combined);
|
||||||
|
// There appears to be a very rare rounding error that can cause asin to return NaN
|
||||||
|
if (!euler.isNaN())
|
||||||
|
{
|
||||||
|
position.rot[0] = euler.x();
|
||||||
|
position.rot[1] = euler.y();
|
||||||
|
position.rot[2] = euler.z();
|
||||||
}
|
}
|
||||||
|
|
||||||
case DragMode_None: break;
|
objectTag->mObject->setRotation(position.rot);
|
||||||
|
}
|
||||||
|
else if (mDragMode == DragMode_Scale)
|
||||||
|
{
|
||||||
|
// Reset scale
|
||||||
|
objectTag->mObject->setEdited(0);
|
||||||
|
objectTag->mObject->setEdited(Object::Override_Scale);
|
||||||
|
|
||||||
|
float scale = objectTag->mObject->getScale();
|
||||||
|
scale *= offset.x();
|
||||||
|
|
||||||
|
objectTag->mObject->setScale (scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,6 +459,8 @@ void CSVRender::InstanceMode::dragCompleted(const QPoint& pos)
|
||||||
switch (mDragMode)
|
switch (mDragMode)
|
||||||
{
|
{
|
||||||
case DragMode_Move: description = "Move Instances"; break;
|
case DragMode_Move: description = "Move Instances"; break;
|
||||||
|
case DragMode_Rotate: description = "Rotate Instances"; break;
|
||||||
|
case DragMode_Scale: description = "Scale Instances"; break;
|
||||||
|
|
||||||
case DragMode_None: break;
|
case DragMode_None: break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#ifndef CSV_RENDER_INSTANCEMODE_H
|
#ifndef CSV_RENDER_INSTANCEMODE_H
|
||||||
#define CSV_RENDER_INSTANCEMODE_H
|
#define CSV_RENDER_INSTANCEMODE_H
|
||||||
|
|
||||||
|
#include <osg/ref_ptr>
|
||||||
|
#include <osg/Quat>
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
#include "editmode.hpp"
|
#include "editmode.hpp"
|
||||||
|
|
||||||
namespace CSVWidget
|
namespace CSVWidget
|
||||||
|
@ -10,6 +14,7 @@ namespace CSVWidget
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
|
class TagBase;
|
||||||
class InstanceSelectionMode;
|
class InstanceSelectionMode;
|
||||||
|
|
||||||
class InstanceMode : public EditMode
|
class InstanceMode : public EditMode
|
||||||
|
@ -19,7 +24,9 @@ namespace CSVRender
|
||||||
enum DragMode
|
enum DragMode
|
||||||
{
|
{
|
||||||
DragMode_None,
|
DragMode_None,
|
||||||
DragMode_Move
|
DragMode_Move,
|
||||||
|
DragMode_Rotate,
|
||||||
|
DragMode_Scale
|
||||||
};
|
};
|
||||||
|
|
||||||
CSVWidget::SceneToolMode *mSubMode;
|
CSVWidget::SceneToolMode *mSubMode;
|
||||||
|
@ -28,9 +35,16 @@ namespace CSVRender
|
||||||
DragMode mDragMode;
|
DragMode mDragMode;
|
||||||
int mDragAxis;
|
int mDragAxis;
|
||||||
bool mLocked;
|
bool mLocked;
|
||||||
|
float mUnitScaleDist;
|
||||||
|
|
||||||
int getSubModeFromId (const std::string& id) const;
|
int getSubModeFromId (const std::string& id) const;
|
||||||
|
|
||||||
|
osg::Vec3f quatToEuler(const osg::Quat& quat) const;
|
||||||
|
osg::Quat eulerToQuat(const osg::Vec3f& euler) const;
|
||||||
|
|
||||||
|
osg::Vec3f getSelectionCenter(const std::vector<osg::ref_ptr<TagBase> >& selection) const;
|
||||||
|
osg::Vec3f getScreenCoords(const osg::Vec3f& pos);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0);
|
InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0);
|
||||||
|
|
|
@ -29,6 +29,13 @@
|
||||||
|
|
||||||
#include "mask.hpp"
|
#include "mask.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
const float CSVRender::Object::MarkerShaftWidth = 30;
|
||||||
|
const float CSVRender::Object::MarkerShaftBaseLength = 70;
|
||||||
|
const float CSVRender::Object::MarkerHeadWidth = 50;
|
||||||
|
const float CSVRender::Object::MarkerHeadLength = 50;
|
||||||
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -179,7 +186,21 @@ void CSVRender::Object::updateMarker()
|
||||||
{
|
{
|
||||||
if (mSubMode==0)
|
if (mSubMode==0)
|
||||||
{
|
{
|
||||||
mMarker[i] = makeMarker (i);
|
mMarker[i] = makeMoveOrScaleMarker (i);
|
||||||
|
mMarker[i]->setUserData(new ObjectMarkerTag (this, i));
|
||||||
|
|
||||||
|
mRootNode->addChild (mMarker[i]);
|
||||||
|
}
|
||||||
|
else if (mSubMode==1)
|
||||||
|
{
|
||||||
|
mMarker[i] = makeRotateMarker (i);
|
||||||
|
mMarker[i]->setUserData(new ObjectMarkerTag (this, i));
|
||||||
|
|
||||||
|
mRootNode->addChild (mMarker[i]);
|
||||||
|
}
|
||||||
|
else if (mSubMode==2)
|
||||||
|
{
|
||||||
|
mMarker[i] = makeMoveOrScaleMarker (i);
|
||||||
mMarker[i]->setUserData(new ObjectMarkerTag (this, i));
|
mMarker[i]->setUserData(new ObjectMarkerTag (this, i));
|
||||||
|
|
||||||
mRootNode->addChild (mMarker[i]);
|
mRootNode->addChild (mMarker[i]);
|
||||||
|
@ -188,16 +209,11 @@ void CSVRender::Object::updateMarker()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> CSVRender::Object::makeMarker (int axis)
|
osg::ref_ptr<osg::Node> CSVRender::Object::makeMoveOrScaleMarker (int axis)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
|
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
|
||||||
|
|
||||||
const float shaftWidth = 10;
|
float shaftLength = MarkerShaftBaseLength + mBaseNode->getBound().radius();
|
||||||
const float shaftBaseLength = 50;
|
|
||||||
const float headWidth = 30;
|
|
||||||
const float headLength = 30;
|
|
||||||
|
|
||||||
float shaftLength = shaftBaseLength + mBaseNode->getBound().radius();
|
|
||||||
|
|
||||||
// shaft
|
// shaft
|
||||||
osg::Vec3Array *vertices = new osg::Vec3Array;
|
osg::Vec3Array *vertices = new osg::Vec3Array;
|
||||||
|
@ -206,20 +222,20 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeMarker (int axis)
|
||||||
{
|
{
|
||||||
float length = i ? shaftLength : 0;
|
float length = i ? shaftLength : 0;
|
||||||
|
|
||||||
vertices->push_back (getMarkerPosition (-shaftWidth/2, -shaftWidth/2, length, axis));
|
vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, -MarkerShaftWidth/2, length, axis));
|
||||||
vertices->push_back (getMarkerPosition (-shaftWidth/2, shaftWidth/2, length, axis));
|
vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, MarkerShaftWidth/2, length, axis));
|
||||||
vertices->push_back (getMarkerPosition (shaftWidth/2, shaftWidth/2, length, axis));
|
vertices->push_back (getMarkerPosition (MarkerShaftWidth/2, MarkerShaftWidth/2, length, axis));
|
||||||
vertices->push_back (getMarkerPosition (shaftWidth/2, -shaftWidth/2, length, axis));
|
vertices->push_back (getMarkerPosition (MarkerShaftWidth/2, -MarkerShaftWidth/2, length, axis));
|
||||||
}
|
}
|
||||||
|
|
||||||
// head backside
|
// head backside
|
||||||
vertices->push_back (getMarkerPosition (-headWidth/2, -headWidth/2, shaftLength, axis));
|
vertices->push_back (getMarkerPosition (-MarkerHeadWidth/2, -MarkerHeadWidth/2, shaftLength, axis));
|
||||||
vertices->push_back (getMarkerPosition (-headWidth/2, headWidth/2, shaftLength, axis));
|
vertices->push_back (getMarkerPosition (-MarkerHeadWidth/2, MarkerHeadWidth/2, shaftLength, axis));
|
||||||
vertices->push_back (getMarkerPosition (headWidth/2, headWidth/2, shaftLength, axis));
|
vertices->push_back (getMarkerPosition (MarkerHeadWidth/2, MarkerHeadWidth/2, shaftLength, axis));
|
||||||
vertices->push_back (getMarkerPosition (headWidth/2, -headWidth/2, shaftLength, axis));
|
vertices->push_back (getMarkerPosition (MarkerHeadWidth/2, -MarkerHeadWidth/2, shaftLength, axis));
|
||||||
|
|
||||||
// head
|
// head
|
||||||
vertices->push_back (getMarkerPosition (0, 0, shaftLength+headLength, axis));
|
vertices->push_back (getMarkerPosition (0, 0, shaftLength+MarkerHeadLength, axis));
|
||||||
|
|
||||||
geometry->setVertexArray (vertices);
|
geometry->setVertexArray (vertices);
|
||||||
|
|
||||||
|
@ -285,6 +301,87 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeMarker (int axis)
|
||||||
return geode;
|
return geode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
|
{
|
||||||
|
const float Pi = 3.14159265f;
|
||||||
|
|
||||||
|
const float InnerRadius = mBaseNode->getBound().radius();
|
||||||
|
const float OuterRadius = InnerRadius + MarkerShaftWidth;
|
||||||
|
|
||||||
|
const float SegmentDistance = 100.f;
|
||||||
|
const size_t SegmentCount = std::min(64, std::max(8, (int)(OuterRadius * 2 * Pi / SegmentDistance)));
|
||||||
|
const size_t VerticesPerSegment = 4;
|
||||||
|
const size_t IndicesPerSegment = 24;
|
||||||
|
|
||||||
|
const size_t VertexCount = SegmentCount * VerticesPerSegment;
|
||||||
|
const size_t IndexCount = SegmentCount * IndicesPerSegment;
|
||||||
|
|
||||||
|
const float Angle = 2 * Pi / SegmentCount;
|
||||||
|
|
||||||
|
const unsigned short IndexPattern[IndicesPerSegment] =
|
||||||
|
{
|
||||||
|
0, 4, 5, 0, 5, 1,
|
||||||
|
2, 6, 4, 2, 4, 0,
|
||||||
|
3, 7, 6, 3, 6, 2,
|
||||||
|
1, 5, 7, 1, 7, 3
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array(VertexCount);
|
||||||
|
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(1);
|
||||||
|
osg::ref_ptr<osg::DrawElementsUShort> primitives = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES,
|
||||||
|
IndexCount);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < SegmentCount; ++i)
|
||||||
|
{
|
||||||
|
size_t index = i * VerticesPerSegment;
|
||||||
|
|
||||||
|
float innerX = InnerRadius * std::cos(i * Angle);
|
||||||
|
float innerY = InnerRadius * std::sin(i * Angle);
|
||||||
|
|
||||||
|
float outerX = OuterRadius * std::cos(i * Angle);
|
||||||
|
float outerY = OuterRadius * std::sin(i * Angle);
|
||||||
|
|
||||||
|
vertices->at(index++) = getMarkerPosition(innerX, innerY, MarkerShaftWidth / 2, axis);
|
||||||
|
vertices->at(index++) = getMarkerPosition(innerX, innerY, -MarkerShaftWidth / 2, axis);
|
||||||
|
vertices->at(index++) = getMarkerPosition(outerX, outerY, MarkerShaftWidth / 2, axis);
|
||||||
|
vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
colors->at(0) = osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f, axis==2 ? 1.0f : 0.2f, 1.0f);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < SegmentCount; ++i)
|
||||||
|
{
|
||||||
|
size_t indices[IndicesPerSegment];
|
||||||
|
for (size_t j = 0; j < IndicesPerSegment; ++j)
|
||||||
|
{
|
||||||
|
indices[j] = i * VerticesPerSegment + j;
|
||||||
|
|
||||||
|
if (indices[j] >= VertexCount)
|
||||||
|
indices[j] -= VertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t offset = i * IndicesPerSegment;
|
||||||
|
for (size_t j = 0; j < IndicesPerSegment; ++j)
|
||||||
|
{
|
||||||
|
primitives->setElement(offset++, indices[IndexPattern[j]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
geometry->setVertexArray(vertices);
|
||||||
|
geometry->setColorArray(colors, osg::Array::BIND_OVERALL);
|
||||||
|
geometry->addPrimitiveSet(primitives);
|
||||||
|
|
||||||
|
geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
|
||||||
|
geode->addDrawable (geometry);
|
||||||
|
|
||||||
|
return geode;
|
||||||
|
}
|
||||||
|
|
||||||
osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis)
|
osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis)
|
||||||
{
|
{
|
||||||
switch (axis)
|
switch (axis)
|
||||||
|
@ -494,7 +591,7 @@ ESM::Position CSVRender::Object::getPosition() const
|
||||||
|
|
||||||
float CSVRender::Object::getScale() const
|
float CSVRender::Object::getScale() const
|
||||||
{
|
{
|
||||||
return mOverrideFlags & Override_Scale ? mScaleOverride : getReference().mScale;
|
return (mOverrideFlags & Override_Scale) ? mScaleOverride : getReference().mScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::Object::setPosition (const float position[3])
|
void CSVRender::Object::setPosition (const float position[3])
|
||||||
|
|
|
@ -78,6 +78,11 @@ namespace CSVRender
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
static const float MarkerShaftWidth;
|
||||||
|
static const float MarkerShaftBaseLength;
|
||||||
|
static const float MarkerHeadWidth;
|
||||||
|
static const float MarkerHeadLength;
|
||||||
|
|
||||||
CSMWorld::Data& mData;
|
CSMWorld::Data& mData;
|
||||||
std::string mReferenceId;
|
std::string mReferenceId;
|
||||||
std::string mReferenceableId;
|
std::string mReferenceableId;
|
||||||
|
@ -89,7 +94,7 @@ namespace CSVRender
|
||||||
Resource::ResourceSystem* mResourceSystem;
|
Resource::ResourceSystem* mResourceSystem;
|
||||||
bool mForceBaseToZero;
|
bool mForceBaseToZero;
|
||||||
ESM::Position mPositionOverride;
|
ESM::Position mPositionOverride;
|
||||||
int mScaleOverride;
|
float mScaleOverride;
|
||||||
int mOverrideFlags;
|
int mOverrideFlags;
|
||||||
osg::ref_ptr<osg::Node> mMarker[3];
|
osg::ref_ptr<osg::Node> mMarker[3];
|
||||||
int mSubMode;
|
int mSubMode;
|
||||||
|
@ -115,7 +120,8 @@ namespace CSVRender
|
||||||
|
|
||||||
void updateMarker();
|
void updateMarker();
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> makeMarker (int axis);
|
osg::ref_ptr<osg::Node> makeMoveOrScaleMarker (int axis);
|
||||||
|
osg::ref_ptr<osg::Node> makeRotateMarker (int axis);
|
||||||
|
|
||||||
osg::Vec3f getMarkerPosition (float x, float y, float z, int axis);
|
osg::Vec3f getMarkerPosition (float x, float y, float z, int axis);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue