THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 09/09/2006 at 14:48, xxxxxxxx wrote:
Eureka!!!!!!!!!! ;D
For posterity and for the benefit of others to relieve their suffering in purgatory, I present code which ACTUALLY works in all projections, all views, all cameras for displaying Tool controls (similar to Cinema 4D's) using BaseDraw:
First off, implement these. ScreenToWorld is useful for drawing, but WorldToScreen may prove useful for picking.
// IPPTool.WorldToScreen (see BaseView.GetViewParameter)
//*---------------------------------------------------------------------------*
Vector IPPTool::WorldToScreen(const Vector& pp, BaseDraw* bd, LONG projection)
//*---------------------------------------------------------------------------*
{
Vector p = pp*bd->GetMi();
Vector off, scale, scalez;
bd->GetViewParameter(&off;, &scale;, &scalez;);
if (projection == Pperspective)
{
Real nz = (p.z <= 0.0) ? 20.0 : 1.0/(p.z + 0.05);
p.x = p.x*scale.x*nz+off.x;
p.y = p.y*scale.y*nz+off.y;
return p;
}
p.x = (p.x*scale.x)+off.x;
p.y = (p.y*scale.y)+off.y;
switch (projection)
{
case Pmilitary: case Pfrog: case Pbird: case Pgentleman:
p.x += p.z*scale.x*scalez.x;
p.y -= p.z*scale.y*scalez.y;
break;
}
return p;
}
// IPPTool.ScreenToWorld (see BaseView.GetViewParameter)
//*---------------------------------------------------------------------------*
Vector IPPTool::ScreenToWorld(const Vector& pp, BaseDraw* bd, LONG projection)
//*---------------------------------------------------------------------------*
{
Vector p = pp;
Vector off, scale, scalez;
bd->GetViewParameter(&off;, &scale;, &scalez;);
switch (projection)
{
case Pmilitary: case Pfrog: case Pbird: case Pgentleman:
p.x -= p.z*scale.x*scalez.x;
p.y += p.z*scale.y*scalez.y;
break;
}
p.x = (p.x-off.x)/scale.x;
p.y = (p.y-off.y)/scale.y;
if (projection==Pperspective)
{
Real nz = p.z + 0.05;
p.x *= nz;
p.y *= nz;
}
return p*bd->GetMg();
}
Then do your controls like so:
// IPPTool.DrawRotateControl
//*---------------------------------------------------------------------------*
void IPPTool::DrawRotateControl(BaseDraw* bd, BaseDrawHelp* bh)
//*---------------------------------------------------------------------------*
{
Matrix m = selectedBP->GetMg();
Vector ctr = bd->WS(m.off);
LONG left, top, right, bottom, width, height;
bd->GetFrame(&left;, ⊤, &right;, ⊥);
width = right - left + 1;
height = bottom - top + 1;
Real rad = (Real)((width > height)?(height>>2) :(width>>2));
// Scale for PolygonObject
LONG proj = bd->GetProjection();
Vector a = ScreenToWorld(ctr, bd, proj);
Vector b = ScreenToWorld(Vector(ctr.x+rad*0.5, ctr.y, ctr.z), bd, proj);
Real rad2 = 2.0 * Len(b-a);
if (proj == Pfrog)
{
m.v1 = !m.v1 * rad2;
m.v2 = !m.v2 * rad2 * 0.333;
m.v3 = !m.v3 * rad2;
}
else
{
m.v1 = !m.v1 * rad2;
m.v2 = !m.v2 * rad2;
m.v3 = !m.v3 * rad2;
}
#ifdef C4D_R9
bd->LineZOffset(32);
#endif
bd->SetTransparency(0);
// 'Sphere'
bd->SetPen(GetWorldContainer().GetVector(WPREF_SELECT_AXIS_COL));
bd->Circle2D(ctr.x, ctr.y, rad);
// 'Rings'
// X-Axis
ocp.color = GetWorldContainer().GetVector(WPREF_XAXIS_COL);
rotatObj->SetColorProperties(&ocp;);
rotatObj->SetMg(m*zrotMat);
#ifdef C4D_R9
bd->DrawPolygonObject(bh, rotatObj, 0L);
#else
bd->PolygonObject(bh, rotatObj, 0L);
#endif
// Y-Axis
ocp.color = GetWorldContainer().GetVector(WPREF_YAXIS_COL);
rotatObj->SetColorProperties(&ocp;);
rotatObj->SetMg(m);
#ifdef C4D_R9
bd->DrawPolygonObject(bh, rotatObj, 0L);
#else
bd->PolygonObject(bh, rotatObj, 0L);
#endif
// Z-Axis
ocp.color = GetWorldContainer().GetVector(WPREF_ZAXIS_COL);
rotatObj->SetColorProperties(&ocp;);
rotatObj->SetMg(m*xrotMat);
#ifdef C4D_R9
bd->DrawPolygonObject(bh, rotatObj, 0L);
bd->LineZOffset(0);
#else
bd->PolygonObject(bh, rotatObj, 0L);
#endif
}
For non-radial controls (translate/scale), rad2 = Len(b-a). This considers projection, camera, view, focus, zoom - so simple and you wonder why NOONE (especially the developers) can provide this for .... sake!!
Thank you, thank me...