IndicatorShape IndicatorShape::Sphere(const Vec3f &Pos, float Radius, RGBColor Color)
{
return IndicatorShape(IndicatorShapeSphere, Pos, Vec3f::Origin, Radius, Color);
}
IndicatorShape IndicatorShape::Cylinder(const Vec3f &P0, const Vec3f &P1, float Radius, RGBColor Color)
{
return IndicatorShape(IndicatorShapeCylinder, P0, P1, Radius, Color);
}
Matrix4 IndicatorShape::TransformMatrix() const
{
switch(Type)
{
case IndicatorShapeSphere:
{
Matrix4 Scale = Matrix4::Scaling(Radius);
Matrix4 Translate = Matrix4::Translation(Pos[0]);
return Scale * Translate;
}
case IndicatorShapeCylinder:
{
Vec3f Diff = Pos[1] - Pos[0];
float Height = Diff.Length();
Matrix4 Scale = Matrix4::Scaling(Vec3f(Radius, Radius, Height));
Matrix4 Face = Matrix4::Face(Vec3f::eZ, Diff);
Matrix4 Translate = Matrix4::Translation(Pos[0]);
return Scale * Face * Translate;
}
default:
SignalError("Invalid shape type");
return Matrix4::Identity();
}
}
void Indicator::Init(GraphicsDevice &GD, int SphereRefinement, int Stacks, int Slices)
{
_Sphere.SetGD(GD);
_Cylinder.SetGD(GD);
_ArrowHead.SetGD(GD);
_Box.SetGD(GD);
if(SphereRefinement == -1)
{
_Sphere.CreateBox(2.0f, 2.0f, 2.0f);
}
else
{
_Sphere.CreateSphere(1.0f, SphereRefinement);
}
_Cylinder.CreateCylinder(1.0f, 1.0f, Slices, Stacks); _ArrowHead.CreateCylinder(1.0f, 1.0f, Slices, Stacks);
for(UINT VertexIndex = 0; VertexIndex < _ArrowHead.VertexCount(); VertexIndex++)
{
Vec3f &Pos = _ArrowHead.Vertices()[VertexIndex].Pos;
float Radius = 1.0f - Pos.z;
Pos.x *= Radius;
Pos.y *= Radius;
}
_CylinderColor = RGBColor::White;
_Box.CreateBox(1.0f, 1.0f, 1.0f);
_Box.ApplyMatrix(Matrix4::Translation(Vec3f(0.5f, 0.5f, 0.5f)));
}
void Indicator::RenderArrow(GraphicsDevice &GD, MatrixController &MC, const Vec3f &P1, const Vec3f &P2, const RGBColor &Color, bool ColorNormals)
{
Vec3f Diff = P2 - P1;
Vec3f Dir = Vec3f::Normalize(Diff);
float TotalHeight = Diff.Length();
float CylinderRadius = TotalHeight * 0.1f;
float ArrowRadius = CylinderRadius * 2.0f;
float ArrowHeight = ArrowRadius;
float CylinderHeight = TotalHeight - ArrowHeight;
RenderCylinder(GD, MC, CylinderRadius, P1, P1 + Dir * CylinderHeight, Color, false, ColorNormals);
RenderCylinder(GD, MC, ArrowRadius, P1 + Dir * CylinderHeight, P2, Color, true, ColorNormals);
}
void Indicator::RenderBox(GraphicsDevice &GD, MatrixController &MC, float Radius, const Rectangle3f &Rect, RGBColor Color)
{
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Min.x, Rect.Min.y, Rect.Min.z), Vec3f(Rect.Max.x, Rect.Min.y, Rect.Min.z), Color);
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Max.x, Rect.Min.y, Rect.Min.z), Vec3f(Rect.Max.x, Rect.Max.y, Rect.Min.z), Color);
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Max.x, Rect.Max.y, Rect.Min.z), Vec3f(Rect.Min.x, Rect.Max.y, Rect.Min.z), Color);
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Min.x, Rect.Max.y, Rect.Min.z), Vec3f(Rect.Min.x, Rect.Min.y, Rect.Min.z), Color);
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Min.x, Rect.Min.y, Rect.Min.z), Vec3f(Rect.Min.x, Rect.Min.y, Rect.Max.z), Color);
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Max.x, Rect.Min.y, Rect.Min.z), Vec3f(Rect.Max.x, Rect.Min.y, Rect.Max.z), Color);
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Max.x, Rect.Max.y, Rect.Min.z), Vec3f(Rect.Max.x, Rect.Max.y, Rect.Max.z), Color);
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Min.x, Rect.Max.y, Rect.Min.z), Vec3f(Rect.Min.x, Rect.Max.y, Rect.Max.z), Color);
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Min.x, Rect.Min.y, Rect.Max.z), Vec3f(Rect.Max.x, Rect.Min.y, Rect.Max.z), Color);
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Max.x, Rect.Min.y, Rect.Max.z), Vec3f(Rect.Max.x, Rect.Max.y, Rect.Max.z), Color);
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Max.x, Rect.Max.y, Rect.Max.z), Vec3f(Rect.Min.x, Rect.Max.y, Rect.Max.z), Color);
RenderCylinder(GD, MC, Radius, Vec3f(Rect.Min.x, Rect.Max.y, Rect.Max.z), Vec3f(Rect.Min.x, Rect.Min.y, Rect.Max.z), Color);
Matrix4 Scale = Matrix4::Scaling(Rect.Dimensions());
Matrix4 Translate = Matrix4::Translation(Rect.Min);
MC.World = Scale * Translate;
LPDIRECT3DDEVICE9 Device = GD.CastD3D9().GetDevice();
D3DCOLOR D3DColor = RGBColor(90, 90, 90);
Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_BLENDFACTOR);
Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVBLENDFACTOR);
Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
Device->SetRenderState(D3DRS_BLENDFACTOR, D3DColor);
_Box.SetColor(Color);
_Box.Render();
Device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
void Indicator::RenderCylinder(GraphicsDevice &GD, MatrixController &MC, float Radius, const Vec3f &P1, const Vec3f &P2, const RGBColor &Color, bool RenderArrow, bool ColorNormals)
{
Vec3f Diff = P2 - P1;
float Height = Diff.Length();
Matrix4 Scale = Matrix4::Scaling(Vec3f(Radius, Radius, Height)); Matrix4 Face = Matrix4::Face(Vec3f::eZ, Diff); Matrix4 Translate = Matrix4::Translation(P1);
MC.World = Scale * Face * Translate;
if(RenderArrow)
{
_ArrowHead.SetColor(Color);
if(ColorNormals)
{
_ArrowHead.ColorNormalsGrayScale(Color);
}
_ArrowHead.Render();
}
else
{
if(Color != _CylinderColor)
{
_Cylinder.SetColor(Color);
_CylinderColor = Color;
}
if(ColorNormals)
{
_Cylinder.ColorNormalsGrayScale(Color);
}
_Cylinder.Render();
}
}
void Indicator::RenderSphere(GraphicsDevice &GD, MatrixController &MC, float Radius, const Vec3f &P1, const RGBColor &Color)
{
Matrix4 Scale = Matrix4::Scaling(Vec3f(Radius,Radius,Radius));
Matrix4 Translate = Matrix4::Translation(P1);
MC.World = Scale * Translate;
_Sphere.SetColor(Color);
_Sphere.Render();
}
void Indicator::GetCameraLine(const Matrix4 &Perspective, const Camera &C, float x, float y, Vec3f &P1Out, Vec3f &P2Out)
{
Matrix4 Total = (C.Matrix() * Perspective).Inverse(); Vec3f P1(x * 2.0f - 1.0f, y * 2.0f - 1.0f, 0.0f), P2;
P2 = Vec3f(P1.x, P1.y, 1.0f);
P1Out = Total.TransformPoint(P1);
P2Out = Total.TransformPoint(P2);
}
void Indicator::DrawCameraLine(GraphicsDevice &GD, MatrixController &MC, const Matrix4 &Perspective, float Radius, const RGBColor &Color, const Camera &C, float x, float y)
{
Vec3f P1Out, P2Out;
GetCameraLine(Perspective, C, x, y, P1Out, P2Out); RenderCylinder(GD, MC, Radius, P1Out, P2Out, Color); }
void Indicator::DrawCamera(GraphicsDevice &GD, MatrixController &MC, const Matrix4 &Perspective, float Radius, float Length, const Camera &C)
{
Vec3f Frustrum[8], Target;
GetCameraLine(Perspective, C, 0.0f, 0.0f, Frustrum[0], Frustrum[4]);
GetCameraLine(Perspective, C, 1.0f, 0.0f, Frustrum[1], Frustrum[5]);
GetCameraLine(Perspective, C, 1.0f, 1.0f, Frustrum[2], Frustrum[6]);
GetCameraLine(Perspective, C, 0.0f, 1.0f, Frustrum[3], Frustrum[7]);
RenderCylinder(GD, MC, Radius, Frustrum[0], Frustrum[1], RGBColor::White);
RenderCylinder(GD, MC, Radius, Frustrum[1], Frustrum[2], RGBColor::White);
RenderCylinder(GD, MC, Radius, Frustrum[2], Frustrum[3], RGBColor::White);
RenderCylinder(GD, MC, Radius, Frustrum[3], Frustrum[0], RGBColor::White);
RenderCylinder(GD, MC, Radius, Frustrum[0], Frustrum[4], RGBColor::White);
RenderCylinder(GD, MC, Radius, Frustrum[1], Frustrum[5], RGBColor::White);
RenderCylinder(GD, MC, Radius, Frustrum[2], Frustrum[6], RGBColor::White);
RenderCylinder(GD, MC, Radius, Frustrum[3], Frustrum[7], RGBColor::White);
RenderCylinder(GD, MC, Radius, Frustrum[4], Frustrum[5], RGBColor::White);
RenderCylinder(GD, MC, Radius, Frustrum[5], Frustrum[6], RGBColor::White);
RenderCylinder(GD, MC, Radius, Frustrum[6], Frustrum[7], RGBColor::White);
RenderCylinder(GD, MC, Radius, Frustrum[7], Frustrum[4], RGBColor::White);
RenderSphere(GD, MC, Radius * 2.0f, C.VecEye(), RGBColor::Blue);
Target = C.VecEye() - C.VecLookDir() * Length;
RenderCylinder(GD, MC, Radius, C.VecEye(), Target, RGBColor::Red);
Target = C.VecEye() + C.VecUp() * Length;
RenderCylinder(GD, MC, Radius, C.VecEye(), Target, RGBColor::Green);
Target = C.VecEye() + C.VecRight() * Length;
RenderCylinder(GD, MC, Radius, C.VecEye(), Target, RGBColor::Yellow); }
void Indicator::CreateMesh(const Vector<IndicatorShape> &Shapes, BaseMesh &MOut) const
{
Vector<BaseMesh*> AllMeshes(Shapes.Length());
for(UINT ShapeIndex = 0; ShapeIndex < Shapes.Length(); ShapeIndex++)
{
const IndicatorShape &CurShape = Shapes[ShapeIndex];
Mesh *NewMesh = NULL;
switch(CurShape.Type)
{
case IndicatorShapeSphere:
{
NewMesh = new Mesh(_Sphere);
}
break;
case IndicatorShapeCylinder:
{
NewMesh = new Mesh(_Cylinder);
}
break;
default:
SignalError("Invalid shape type");
return;
}
NewMesh->ApplyMatrix(CurShape.TransformMatrix());
NewMesh->SetColor(CurShape.Color);
AllMeshes[ShapeIndex] = NewMesh;
}
MOut.SetGD(_Sphere.GetGD());
MOut.LoadMeshList(AllMeshes);
for(UINT ShapeIndex = 0; ShapeIndex < Shapes.Length(); ShapeIndex++)
{
delete AllMeshes[ShapeIndex];
}
}