📄 worldeditor.cc
字号:
// scale it
pnt.convolve(scale);
mat.mulP(pnt, &projPnts[i]);
}
glDisable(GL_CULL_FACE);
glColor4ub(col.red, col.green, col.blue, col.alpha);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
//
glBegin(GL_QUADS);
for(U32 k = 0; k < 4; k++)
glVertex3f(projPnts[k].x, projPnts[k].y, projPnts[k].z);
glEnd();
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
}
//------------------------------------------------------------------------------
void WorldEditor::renderPlane(const Point3F & origin)
{
if(!(mRenderPlane || mRenderPlaneHashes))
return;
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4ub(mGridColor.red, mGridColor.green, mGridColor.blue, mGridColor.alpha);
Point2F start(origin.x - mPlaneDim / 2, origin.y - mPlaneDim / 2);
//
if(mRenderPlane)
{
// draw the plane
glBegin(GL_QUADS);
glVertex3f(start.x, start.y, origin.z);
glVertex3f(start.x, start.y + mPlaneDim, origin.z);
glVertex3f(start.x + mPlaneDim, start.y + mPlaneDim, origin.z);
glVertex3f(start.x + mPlaneDim, start.y, origin.z);
glEnd();
}
//
if(mRenderPlaneHashes)
{
if(mGridSize.x > 0)
{
U32 xSteps = (U32)(mPlaneDim / mGridSize.x);
F32 hashStart = mCeil(start.x / mGridSize.x) * mGridSize.x;
for(U32 i = 0; i < xSteps; i++)
{
glBegin(GL_LINE_LOOP);
glVertex3f(hashStart + mGridSize.x * i, start.y, origin.z + 0.001f);
glVertex3f(hashStart + mGridSize.x * i, start.y + mPlaneDim, origin.z + 0.001f);
glEnd();
}
}
if(mGridSize.y > 0)
{
U32 ySteps = (U32)(mPlaneDim / mGridSize.y);
F32 hashStart = mCeil(start.y / mGridSize.y) * mGridSize.y;
for(U32 i = 0; i < ySteps; i++)
{
glBegin(GL_LINE_LOOP);
glVertex3f(start.x, hashStart + mGridSize.y * i, origin.z + 0.001f);
glVertex3f(start.x + mPlaneDim, hashStart + mGridSize.y * i, origin.z + 0.001f);
glEnd();
}
}
}
glDisable(GL_BLEND);
}
//------------------------------------------------------------------------------
void WorldEditor::renderMousePopupInfo()
{
Point2I pos(mLastMouseEvent.mousePoint.x,
mLastMouseEvent.mousePoint.y + mCurrentCursor->getExtent().y - mCurrentCursor->getHotSpot().y);
if(mCurrentMode == mDefaultMode && !mMouseDragged)
return;
char buf[256];
switch(mCurrentMode)
{
case Move:
{
if(!mSelected.size())
return;
Point3F pos = mObjectsUseBoxCenter ? mSelected.getBoxCentroid() : mSelected.getCentroid();
dSprintf(buf, sizeof(buf), "x: %0.3f, y: %0.3f, z: %0.3f", pos.x, pos.y, pos.z);
break;
}
case Rotate: {
if(!bool(mHitObject) || (mSelected.size() != 1))
return;
// print out the angle-axis 'fo
AngAxisF aa(mHitObject->getTransform());
dSprintf(buf, sizeof(buf), "x: %0.3f, y: %0.3f, z: %0.3f, a: %0.3f",
aa.axis.x, aa.axis.y, aa.axis.z, mRadToDeg(aa.angle));
break;
}
case Scale: {
if(!bool(mHitObject) || (mSelected.size() != 1))
return;
VectorF scale = mHitObject->getScale();
Box3F box = mHitObject->getObjBox();
box.min.convolve(scale);
box.max.convolve(scale);
box.max -= box.min;
dSprintf(buf, sizeof(buf), "w: %0.3f, h: %0.3f, d: %0.3f", box.max.x, box.max.y, box.max.z);
break;
}
default:
return;
}
U32 width = mProfile->mFont->getStrWidth(buf);
if(mRenderPopupBackground)
{
Point2I min(pos.x - width / 2 - 2, pos.y - 1);
Point2I max(pos.x + width / 2 + 2, pos.y + mProfile->mFont->getHeight() + 1);
dglDrawRectFill(min, max, mPopupBackgroundColor);
}
dglSetBitmapModulation(mPopupTextColor);
dglDrawText(mProfile->mFont, Point2I(pos.x - width / 2, pos.y), buf);
}
//------------------------------------------------------------------------------
void WorldEditor::renderPaths(SimObject *obj)
{
if (obj == NULL)
return;
bool selected = false;
// Loop through subsets
if (SimSet *set = dynamic_cast<SimSet*>(obj))
for(SimSetIterator itr(set); *itr; ++itr) {
renderPaths(*itr);
if ((*itr)->isSelected())
selected = true;
}
// Render the path if it, or any of it's immediate sub-objects, is selected.
if (Path *path = dynamic_cast<Path*>(obj))
if (selected || path->isSelected())
renderSplinePath(path);
}
void WorldEditor::renderSplinePath(Path *path)
{
// at the time of writing the path properties are not part of the path object
// so we don't know to render it looping, splined, linear etc.
// for now we render all paths splined+looping
Vector<Point3F> positions;
Vector<QuatF> rotations;
path->sortMarkers();
CameraSpline spline;
for(SimSetIterator itr(path); *itr; ++itr)
{
Marker *pathmarker = dynamic_cast<Marker*>(*itr);
if (!pathmarker)
continue;
Point3F pos;
pathmarker->getTransform().getColumn(3, &pos);
QuatF rot;
rot.set(pathmarker->getTransform());
CameraSpline::Knot::Type type;
switch (pathmarker->mKnotType)
{
case Marker::KnotTypePositionOnly: type = CameraSpline::Knot::POSITION_ONLY; break;
case Marker::KnotTypeKink: type = CameraSpline::Knot::KINK; break;
case Marker::KnotTypeNormal:
default: type = CameraSpline::Knot::NORMAL; break;
}
CameraSpline::Knot::Path path;
switch (pathmarker->mSmoothingType)
{
case Marker::SmoothingTypeLinear: path = CameraSpline::Knot::LINEAR; break;
case Marker::SmoothingTypeSpline:
default: path = CameraSpline::Knot::SPLINE; break;
}
spline.push_back(new CameraSpline::Knot(pos, rot, 1.0f, type, path));
}
F32 t = 0.0f;
S32 size = spline.size();
if (size <= 1)
return;
// DEBUG
//spline.renderTimeMap();
if (path->isLooping())
{
CameraSpline::Knot *front = new CameraSpline::Knot(*spline.front());
CameraSpline::Knot *back = new CameraSpline::Knot(*spline.back());
spline.push_back(front);
spline.push_front(back);
t = 1.0f;
size += 2;
}
while (t < size - 1)
{
CameraSpline::Knot k;
spline.value(t, &k);
t = spline.advanceDist(t, 2.0f);
VectorF a(-0.15f, -0.25f, 0.0f);
VectorF b( 0.0f, 0.25f, 0.0f);
VectorF c( 0.15f, -0.25f, 0.0f);
VectorF t1, t2, t3;
k.mRotation.mulP(a, &t1); t1 += k.mPosition;
k.mRotation.mulP(b, &t2); t2 += k.mPosition;
k.mRotation.mulP(c, &t3); t3 += k.mPosition;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// OUTLINE
glColor4f(0, 1, 0, 1);
glLineWidth(1);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_TRIANGLES);
glVertex3f(t1.x, t1.y, t1.z);
glVertex3f(t2.x, t2.y, t2.z);
glVertex3f(t3.x, t3.y, t3.z);
glEnd();
// FILL
glColor4f(0, 2, 0, 0.2);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_TRIANGLES);
glVertex3f(t1.x, t1.y, t1.z);
glVertex3f(t2.x, t2.y, t2.z);
glVertex3f(t3.x, t3.y, t3.z);
glEnd();
glDisable(GL_BLEND);
}
}
//------------------------------------------------------------------------------
// render the handle/text/...
void WorldEditor::renderScreenObj(SceneObject * obj, Point2I sPos)
{
// do not render control object stuff
if(obj == getControlObject() || obj->isHidden())
return;
ClassInfo::Entry * entry = getClassEntry(obj);
if(!entry)
entry = &mDefaultClassEntry;
TextureObject * bitmap;
if(mRenderObjHandle)
{
// offset
if(obj->isLocked())
bitmap = entry->mLockedHandle ? entry->mLockedHandle : mDefaultClassEntry.mLockedHandle;
else
{
if(mSelected.objInSet(obj))
bitmap = entry->mSelectHandle ? entry->mSelectHandle : mDefaultClassEntry.mSelectHandle;
else
bitmap = entry->mDefaultHandle ? entry->mDefaultHandle : mDefaultClassEntry.mDefaultHandle;
}
sPos.x -= (bitmap->bitmapWidth / 2);
sPos.y -= (bitmap->bitmapHeight / 2);
dglClearBitmapModulation();
dglDrawBitmap(bitmap, sPos);
}
//
if(mRenderObjText)
{
const char * str = parseObjectFormat(obj, mObjTextFormat);
Point2I extent(mProfile->mFont->getStrWidth(str), mProfile->mFont->getHeight());
Point2I pos(sPos);
if(mRenderObjHandle)
{
pos.x += (bitmap->bitmapWidth / 2) - (extent.x / 2);
pos.y += (bitmap->bitmapHeight / 2) + 3;
}
dglSetBitmapModulation(mObjectTextColor);
dglDrawText(mProfile->mFont, pos, str);
}
}
//------------------------------------------------------------------------------
// axis gizmo stuff
void WorldEditor::calcAxisInfo()
{
if(!mSelected.size())
return;
// get the centroid..
mSelected.invalidateCentroid();
Point3F centroid = mObjectsUseBoxCenter ? mSelected.getBoxCentroid() : mSelected.getCentroid();
mAxisGizmoCenter = centroid;
VectorF axisVector[3] = {
VectorF(1,0,0),
VectorF(0,1,0),
VectorF(0,0,1)
};
// adjust to object space if just one object...
if((mSelected.size() == 1) && !((mLastMouseEvent.modifier & SI_SHIFT) && (mCurrentMode == Move)))
{
const MatrixF & mat = mSelected[0]->getTransform();
for(U32 i = 0; i < 3; i++)
{
VectorF tmp;
mat.mulV(axisVector[i], &tmp);
mAxisGizmoVector[i] = tmp;
mAxisGizmoVector[i].normalizeSafe();
}
}
else
for(U32 i = 0; i < 3; i++)
mAxisGizmoVector[i] = axisVector[i];
// get the projected size...
SceneObject * obj = getControlObject();
if(!obj)
return;
//
Point3F camPos;
obj->getTransform().getColumn(3, &camPos);
// assumes a 90deg FOV
Point3F dir = mAxisGizmoCenter - camPos;
mAxisGizmoProjLen = (F32(mAxisGizmoMaxScreenLen) / F32(getExtent().x)) * dir.magnitudeSafe() * mTan(mDegToRad(45.0));
}
bool WorldEditor::collideAxisGizmo(const Gui3DMouseEvent & event)
{
if(!mAxisGizmoActive || !mSelected.size())
return(false);
// get the projected size...
SceneObject * obj = getControlObject();
if(!obj)
return(false);
//
Point3F camPos;
obj->getRenderTransform().getColumn(3, &camPos);
// assumes a 90deg FOV
Point3F dir = mAxisGizmoCenter - camPos;
mAxisGizmoProjLen = (F32(mAxisGizmoMaxScreenLen) / F32(getExtent().x)) * dir.magnitudeSafe() * mTan(mDegToRad(45.0));
dir.normalizeSafe();
mAxisGizmoSelAxis = -1;
// find axis to use...
for(U32 i = 0; i < 3; i++)
{
VectorF up, normal;
mCross(dir, mAxisGizmoVector[i], &up);
mCross(up, mAxisGizmoVector[i], &normal);
if(normal.isZero())
break;
PlaneF plane(mAxisGizmoCenter, normal);
// width of the axis poly is 1/10 the run
Point3F a = up * mAxisGizmoProjLen / 10;
Point3F b = mAxisGizmoVector[i] * mAxisGizmoProjLen;
Point3F poly [] = {
Point3F(mAxisGizmoCenter + a),
Point3F(mAxisGizmoCenter + a + b),
Point3F(mAxisGizmoCenter - a + b),
Point3F(mAxisGizmoCenter - a)
};
Point3F end = camPos + event.vec * mProjectDistance;
F32 t = plane.intersect(camPos, end);
if(t >= 0 && t <= 1)
{
Point3F pos;
pos.interpolate(camPos, end, t);
// check if inside our 'poly' of this axis vector...
bool inside = true;
for(U32 j = 0; inside && (j < 4); j++)
{
U32 k = (j+1) % 4;
VectorF vec1 = poly[k] - poly[j];
VectorF vec2 = pos - poly[k];
if(mDot(vec1, vec2) > 0.f)
inside = false;
}
//
if(inside)
{
mAxisGizmoSelAxis = i;
return(true);
}
}
}
return(false);
}
//------------------------------------------------------------------------------
void WorldEditor::renderAxisGizmo()
{
calcAxisInfo();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -