Created
August 15, 2019 00:31
IM3D
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "ImmediateRender.h" | |
#include "../Core/Context.h" | |
#include "../Graphics/VertexBuffer.h" | |
#include "../Graphics/Camera.h" | |
#include "../Graphics/Graphics.h" | |
#include "../Scene/Node.h" | |
#include "../Input/Input.h" | |
#include "../Graphics/View.h" | |
#include "../Graphics/Viewport.h" | |
namespace Urho3D | |
{ | |
ImmediateRenderer::ImmediateRenderer(Context* context) : | |
Component(context) | |
{ | |
vertexBuffer_ = new VertexBuffer(context); | |
} | |
/// Destruct. | |
ImmediateRenderer::~ImmediateRenderer() | |
{ | |
} | |
/// Register object factory. | |
void ImmediateRenderer::RegisterObject(Context* context) | |
{ | |
context->RegisterFactory<ImmediateRenderer>(); | |
} | |
void ImmediateRenderer::EndFrame() | |
{ | |
Im3d::EndFrame(); | |
} | |
void ImmediateRenderer::Render() | |
{ | |
Im3d::SetContext(imContext_); | |
unsigned vertCt = 0; | |
for (unsigned i = 0; i < Im3d::GetDrawListCount(); ++i) | |
{ | |
const Im3d::DrawList& drawList = Im3d::GetDrawLists()[i]; | |
vertCt += drawList.m_vertexCount; | |
} | |
if (vertexBuffer_->GetVertexCount() < vertCt) | |
{ | |
vertexBuffer_->SetSize(vertCt, { | |
VertexElement(TYPE_VECTOR4, SEM_POSITION, 0, false), | |
VertexElement(TYPE_UBYTE4_NORM, SEM_COLOR, 0, false) }); | |
} | |
auto* dest = (Im3d::VertexData*)vertexBuffer_->Lock(0, vertCt, true); | |
if (!dest) | |
return; | |
for (unsigned i = 0; i < Im3d::GetDrawListCount(); ++i) | |
{ | |
const Im3d::DrawList& drawList = Im3d::GetDrawLists()[i]; | |
unsigned cpyCt = drawList.m_vertexCount * sizeof(Im3d::VertexData); | |
memcpy(dest, drawList.m_vertexData, cpyCt); | |
dest += drawList.m_vertexCount; | |
} | |
vertexBuffer_->Unlock(); | |
auto graphics = GetSubsystem<Graphics>(); | |
ShaderVariation* vsLines = graphics->GetShader(VS, "IM3D", "LINES VERTEX_SHADER"); | |
ShaderVariation* gsLines = graphics->GetShader(GS, "IM3D", "LINES GEOMETRY_SHADER"); | |
ShaderVariation* psLines = graphics->GetShader(PS, "IM3D", "LINES PIXEL_SHADER"); | |
ShaderVariation* vsPoints = graphics->GetShader(VS, "IM3D", "POINTS VERTEX_SHADER"); | |
ShaderVariation* gsPoints = graphics->GetShader(GS, "IM3D", "POINTS GEOMETRY_SHADER"); | |
ShaderVariation* psPoints = graphics->GetShader(PS, "IM3D", "POINTS PIXEL_SHADER"); | |
ShaderVariation* vsTris = graphics->GetShader(VS, "IM3D", "TRIS VERTEX_SHADER"); | |
ShaderVariation* psTris = graphics->GetShader(PS, "IM3D", "TRIS PIXEL_SHADER"); | |
graphics->SetBlendMode(BLEND_ALPHA); | |
graphics->SetColorWrite(true); | |
graphics->SetCullMode(CULL_NONE); | |
graphics->SetDepthWrite(false); | |
graphics->SetLineAntiAlias(false); | |
graphics->SetScissorTest(false); | |
graphics->SetStencilTest(false); | |
graphics->SetVertexBuffer(vertexBuffer_); | |
graphics->SetDepthTest(CMP_ALWAYS); | |
static const auto depthTestLayer = Im3d::MakeId("DepthTest"); | |
static const auto depthLessLayer = Im3d::MakeId("DepthGreater"); | |
static const auto noDepthLayer = Im3d::MakeId("NoDepth"); | |
Im3d::Id lastID = 0; | |
unsigned vertStart = 0; | |
for (unsigned i = 0; i < Im3d::GetDrawListCount(); ++i) | |
{ | |
const Im3d::DrawList& drawList = Im3d::GetDrawLists()[i]; | |
if (drawList.m_layerId != lastID) | |
{ | |
if (drawList.m_layerId == depthTestLayer) | |
{ | |
graphics->SetDepthWrite(true); | |
graphics->SetDepthTest(CMP_LESSEQUAL); | |
} | |
else if (drawList.m_layerId == noDepthLayer || drawList.m_layerId == 0) | |
{ | |
graphics->SetDepthWrite(false); | |
graphics->SetDepthTest(CMP_ALWAYS); | |
} | |
else if (drawList.m_layerId == depthLessLayer) | |
{ | |
graphics->SetDepthWrite(false); | |
graphics->SetDepthTest(CMP_GREATER); | |
} | |
} | |
switch (drawList.m_primType) | |
{ | |
case Im3d::DrawPrimitive_Lines: | |
graphics->SetShaders(vsLines, psLines, gsLines, nullptr, nullptr); | |
break; | |
case Im3d::DrawPrimitive_Points: | |
graphics->SetShaders(vsPoints, psPoints, gsPoints, nullptr, nullptr); | |
break; | |
case Im3d::DrawPrimitive_Triangles: | |
graphics->SetShaders(vsTris, psTris, nullptr, nullptr, nullptr); | |
break; | |
} | |
graphics->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY); | |
graphics->SetShaderParameter(VSP_VIEW, view_); | |
graphics->SetShaderParameter(VSP_VIEWINV, view_.Inverse()); | |
graphics->SetShaderParameter(VSP_VIEWPROJ, gpuProjection_ * view_); | |
auto& appData = Im3d::GetAppData(); | |
static const StringHash VSP_VIEWSIZE = "Viewport"; | |
graphics->SetShaderParameter(VSP_VIEWSIZE, Vector2(appData.m_viewportSize.x, appData.m_viewportSize.y)); | |
switch (drawList.m_primType) | |
{ | |
case Im3d::DrawPrimitive_Lines: | |
graphics->Draw(LINE_LIST, vertStart, drawList.m_vertexCount); | |
break; | |
case Im3d::DrawPrimitive_Points: | |
graphics->Draw(POINT_LIST, vertStart, drawList.m_vertexCount); | |
break; | |
case Im3d::DrawPrimitive_Triangles: | |
graphics->Draw(TRIANGLE_LIST, vertStart, drawList.m_vertexCount); | |
break; | |
} | |
vertStart += drawList.m_vertexCount; | |
} | |
graphics->SetShaders(nullptr, nullptr, nullptr, nullptr, nullptr); | |
} | |
void ImmediateRenderer::BeginFrame(Viewport* viewport, Vector2 mousePos, IntRect r, float timeStep, bool grabInput) | |
{ | |
Im3d::SetContext(imContext_); | |
auto& appData = Im3d::GetAppData(); | |
auto camera = GetNode()->GetComponent<Camera>(); | |
view_ = camera->GetView(); | |
projection_ = camera->GetProjection(); | |
gpuProjection_ = camera->GetGPUProjection(); | |
auto frustum = camera->GetFrustum(); | |
for (int i = 0; i < 6; ++i) | |
appData.m_cullFrustum[i] = ToIm(Vector4(frustum.planes_[i].normal_, frustum.planes_[i].d_)); | |
appData.m_viewDirection = ToIm(GetNode()->GetWorldDirection()); | |
appData.m_viewOrigin = ToIm(GetNode()->GetWorldPosition()); | |
appData.m_deltaTime = timeStep; | |
appData.m_worldUp = ToIm(Vector3::UP); | |
appData.m_projOrtho = camera->IsOrthographic(); | |
appData.m_projScaleY = Tan(camera->GetFov()) * 3; | |
appData.m_viewportSize = ToIm(r.Size()); | |
auto input = GetSubsystem<Input>(); | |
auto mouseP = input->GetMousePosition(); | |
appData.m_cursorRayOrigin = appData.m_viewOrigin; | |
appData.m_cursorRayDirection = ToIm(camera->GetScreenRay(mousePos.x_, mousePos.y_).direction_); | |
if (!grabInput) | |
{ | |
for (int i = 0; i < Im3d::Key_Count; ++i) | |
appData.m_keyDown[i] = false; | |
} | |
else | |
{ | |
for (int i = 0; i < Im3d::Key_Count; ++i) | |
appData.m_keyDown[i] = false; | |
appData.m_keyDown[Im3d::Mouse_Left] = input->GetMouseButtonDown(MOUSEB_LEFT); | |
} | |
Im3d::NewFrame(); | |
} | |
void ImmediateRenderer::PushMatrix(const Matrix4& mat) | |
{ | |
Im3d::Mat4 newMat; | |
memcpy(&newMat, mat.Data(), sizeof(Matrix4)); | |
Im3d::PushMatrix(newMat); | |
} | |
void ImmediateRenderer::PushMatrix(const Matrix3x4& mat) | |
{ | |
Im3d::Mat4 newMat; | |
newMat.setIdentity(); | |
for (int i = 0; i < 3; ++i) | |
newMat.setRow(i, ToIm(mat.Row(i))); | |
Im3d::PushMatrix(newMat); | |
} | |
bool ImmediateRenderer::GizmoTranslation(const String& id, Vector3& translation, bool local, bool small) | |
{ | |
return Im3d::GizmoTranslation(id.CString(), const_cast<float*>(translation.Data()), local, small); | |
} | |
bool ImmediateRenderer::GizmoRotation(const String& id, Matrix3& rotation, bool local) | |
{ | |
return Im3d::GizmoRotation(id.CString(), const_cast<float*>(rotation.Data()), local); | |
} | |
bool ImmediateRenderer::GizmoScale(const String& id, Vector3& scale) | |
{ | |
return Im3d::GizmoScale(id.CString(), const_cast<float*>(scale.Data())); | |
} | |
bool ImmediateRenderer::GizmoPoint(const String& id, const Vector3& pt, Color c, float radius) | |
{ | |
return Im3d::GizmoPoint(id.CString(), ToIm(pt), ToIm(c), radius); | |
} | |
bool ImmediateRenderer::GizmoNormal(const String& id, const Vector3& origin, Vector3& normal) | |
{ | |
Quaternion q; | |
q.FromRotationTo(Vector3::FORWARD, normal); | |
DrawArrow(origin, origin + normal * 2, -1, 16); | |
auto rotMat = q.RotationMatrix(); | |
PushMatrix(Matrix3x4(origin, q, 1)); | |
bool ret = false; | |
if (GizmoRotation(id, rotMat, true)) | |
{ | |
ret = true; | |
normal = (rotMat * Vector3::FORWARD).Normalized(); | |
} | |
PopMatrix(); | |
return ret; | |
} | |
bool ImmediateRenderer::GizmoArrow(const String& id, const Vector3& oOrigin, const Vector3& dir, float& position) | |
{ | |
auto nDir = dir.Normalized(); | |
Vector3 origin = oOrigin; | |
float junk = 0.0f; | |
if (Im3d::GizmoDir(Im3d::MakeId(id.CString()), (float*)origin.Data(), ToIm(nDir), ToIm(Color::GREEN), junk)) | |
{ | |
Urho3D::Plane plane(nDir, origin); | |
position = plane.d_; | |
return true; | |
} | |
return false; | |
} | |
bool ImmediateRenderer::GizmoPlane(const String& id, const Vector3& oOrigin, Plane& plane) | |
{ | |
Vector3 origin = plane.Origin(); | |
float junk = 0.0f; | |
if (GizmoArrow(id, oOrigin, plane.normal_, plane.d_)) | |
{ | |
} | |
//if (Im3d::GizmoDir(Im3d::MakeId(id.CString()), (float*)origin.Data(), ToIm(plane.normal_), ToIm(Color::GREEN), junk)) | |
//{ | |
// plane = Urho3D::Plane(plane.normal_, origin); | |
// return true; | |
//} | |
return false; | |
} | |
void ImmediateRenderer::PointLine(const Vector3& a, const Vector3& b, float size, const Color& color, float spacing) | |
{ | |
Vertex(a, size, color); | |
Vertex(b, size, color); | |
auto d = a.DistanceToPoint(b); | |
for (float f = spacing; f < d; f += spacing) | |
Vertex(a.Lerp(b, f / d), size, color); | |
} | |
void ImmediateRenderer::PointSpline(const Spline& spline, float size, const Color& color, float spacing) | |
{ | |
float length = 0.0f; | |
Vector3 a = spline.GetKnot(0).GetVector3(); | |
for (auto i = 0; i <= 100; ++i) | |
{ | |
Vector3 b = spline.GetPoint(i / 100.f).GetVector3(); | |
length += Abs((a - b).Length()); | |
a = b; | |
} | |
Vertex(spline.GetPoint(0.0f).GetVector3(), size, color); | |
Vertex(spline.GetPoint(1.0f).GetVector3(), size, color); | |
for (float f = spacing; f < length; f += spacing) | |
Vertex(spline.GetPoint(f/length).GetVector3(), size, color); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "../Math/Color.h" | |
#include "../Math/Frustum.h" | |
#include "../Scene/Component.h" | |
#include "../Core/Spline.h" | |
#include <im3d/im3d.h> | |
// someone in the include tree of im3d.h has included the word small ... and it messes with VS | |
#undef small | |
namespace Urho3D | |
{ | |
class BoundingBox; | |
class Camera; | |
class Polyhedron; | |
class Drawable; | |
class Light; | |
class Matrix3x4; | |
class Renderer; | |
class Skeleton; | |
class Sphere; | |
class VertexBuffer; | |
class Viewport; | |
class URHO3D_API ImmediateRenderer : public Component | |
{ | |
URHO3D_OBJECT(ImmediateRenderer, Component); | |
public: | |
/// Construct. | |
explicit ImmediateRenderer(Context* context); | |
/// Destruct. | |
~ImmediateRenderer() override; | |
/// Register object factory. | |
static void RegisterObject(Context* context); | |
void BeginFrame(Viewport*, Vector2, IntRect, float timeStep, bool grabInput); | |
void EndFrame(); | |
void Render(); | |
void PushMatrix(const Matrix4&); | |
void PushMatrix(const Matrix3x4&); | |
void PopMatrix() { Im3d::PopMatrix(); } | |
void SetIdentity() { Im3d::SetIdentity(); } | |
void PushColor(const Color& in) { Im3d::PushColor(ToIm(in)); } | |
void PopColor() { Im3d::PopColor(); } | |
void PushLayer(const String& layer) { Im3d::PushLayerId(layer.CString()); } | |
void PopLayer() { Im3d::PopLayerId(); } | |
static Im3d::Vec2 ToIm(const IntVector2& in) { return Im3d::Vec2(in.x_, in.y_); } | |
static Im3d::Vec2 ToIm(const Vector2& in) { return Im3d::Vec2(in.x_, in.y_); } | |
static Im3d::Vec3 ToIm(const Vector3& in) { return Im3d::Vec3(in.x_, in.y_, in.z_); } | |
static Im3d::Vec4 ToIm(const Vector4& in) { return Im3d::Vec4(in.x_, in.y_, in.z_, in.w_); } | |
static Im3d::Color ToIm(const Color& in) { return Im3d::Color(in.r_, in.g_, in.b_, in.a_); } | |
void DrawXyzAxes() { Im3d::DrawXyzAxes(); } | |
void DrawPoint(const Vector3& p, float s, Color c) { Im3d::DrawPoint(ToIm(p), s, ToIm(c)); } | |
void DrawLine(const Vector3& a, const Vector3& b, float size, Color color) { Im3d::DrawLine(ToIm(a), ToIm(b), size, ToIm(color)); } | |
void DrawQuad(const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d) { Im3d::DrawQuad(ToIm(a), ToIm(b), ToIm(c), ToIm(d)); } | |
void DrawQuad(const Vector3& origin, const Vector3& normal, const Vector2& size) { Im3d::DrawQuad(ToIm(origin), ToIm(normal), ToIm(size)); } | |
void DrawQuadFilled(const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d) { Im3d::DrawQuadFilled(ToIm(a), ToIm(b), ToIm(c), ToIm(d)); } | |
void DrawQuadFilled(const Vector3& origin, const Vector3& normal, const Vector2& size) { Im3d::DrawQuadFilled(ToIm(origin), ToIm(normal), ToIm(size)); } | |
void DrawCircle(const Vector3& origin, const Vector3& normal, float radius, int detail = -1) { Im3d::DrawCircle(ToIm(origin), ToIm(normal), radius, detail); } | |
void DrawCircleFilled(const Vector3& origin, const Vector3& normal, float radius, int detail = -1) { Im3d::DrawCircleFilled(ToIm(origin), ToIm(normal), radius, detail); } | |
void DrawSphere(const Vector3& origin, float radius, int detail = -1) { Im3d::DrawSphere(ToIm(origin), radius, detail); } | |
void DrawSphereFilled(const Vector3& origin, float radius, int detail = -1) { Im3d::DrawSphereFilled(ToIm(origin), radius, detail); } | |
void DrawAlignedBox(const Vector3& min, const Vector3& max) { Im3d::DrawAlignedBox(ToIm(min), ToIm(max)); } | |
void DrawAlignedBoxFilled(const Vector3& min, const Vector3& max) { Im3d::DrawAlignedBoxFilled(ToIm(min), ToIm(max)); } | |
void DrawCylinder(const Vector3& start, const Vector3& end, float radius, int detail = -1) { Im3d::DrawCylinder(ToIm(start), ToIm(end), radius, detail); } | |
void DrawCapsule(const Vector3& start, const Vector3& end, float radius, int detail = -1) { Im3d::DrawCapsule(ToIm(start), ToIm(end), radius, detail); } | |
void DrawPrism(const Vector3& start, const Vector3& end, float radius, int sides) { Im3d::DrawPrism(ToIm(start), ToIm(end), radius, sides); } | |
void DrawArrow(const Vector3& start, const Vector3& end, float headLength = -1.0f, float headThickness = -1.0f) { Im3d::DrawArrow(ToIm(start), ToIm(end), headLength, headThickness); } | |
bool GizmoTranslation(const String& id, Vector3& translation, bool local, bool small); | |
bool GizmoRotation(const String& id, Matrix3& rotation, bool local = false); | |
bool GizmoScale(const String& id, Vector3& scale); // local scale only | |
bool GizmoPoint(const String& id, const Vector3& pt, Color c, float radius); | |
bool GizmoNormal(const String& id, const Vector3& origin, Vector3& normal); | |
bool GizmoArrow(const String& id, const Vector3& origin, const Vector3& dir, float& position); | |
bool GizmoPlane(const String& id, const Vector3& origin, Plane& plane); | |
void BeginTriangles() { Im3d::BeginTriangles(); } | |
void BeginPoints() { Im3d::BeginPoints(); } | |
void BeginLines() { Im3d::BeginLines(); } | |
void Vertex(const Vector3& pt) { Im3d::Vertex(ToIm(pt)); } | |
void Vertex(const Vector3& pt, float size) { Im3d::Vertex(ToIm(pt), size); } | |
void Vertex(const Vector3& pt, float size, const Color& color) { Im3d::Vertex(ToIm(pt), size, ToIm(color)); } | |
void End() { Im3d::End(); } | |
void PointLine(const Vector3& a, const Vector3& b, float size, const Color&, float spacing); | |
void PointSpline(const Spline& spline, float size, const Color&, float spacing); | |
private: | |
Im3d::Context imContext_; | |
SharedPtr<VertexBuffer> vertexBuffer_; | |
Matrix3x4 view_; | |
Matrix4 projection_; | |
Matrix4 gpuProjection_; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment