2024-05-11 17:43:38 +08:00

722 lines
19 KiB
C++

#include "Renderer.h"
#include <vlCore/VisualizationLibrary.hpp>
#include <vlCore/GlobalSettings.hpp>
#include <vlCore/Time.hpp>
#include <vlCore/Colors.hpp>
#include <vlGraphics/Geometry.hpp>
#include <vlGraphics/GeometryPrimitives.hpp>
void TrackBall::mouseDownEvent(EMouseButton btn, int x, int y)
{
if (camera() == NULL)
return;
// if already busy ignore the event
if (mode() != NoMode)
return;
// set x/y relative to the viewport
x -= camera()->viewport()->x();
y -= openglContext()->framebuffer()->height() - 1 - (camera()->viewport()->y() + camera()->viewport()->height() - 1);
unsigned char selected;
// enter new mode
if (btn == rotationButton())
{
glReadPixels(x, y, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &selected);
GLenum err = glGetError();
err = glGetError();
}
else
if (btn == translationButton())
mMode = TranslationMode;
else
if (btn == zoomButton())
mMode = ZoomMode;
VL_CHECK(openglContext()->framebuffer())
// check that the click is in the viewport
int w = camera()->viewport()->width();
int h = camera()->viewport()->height();
if (x<0 || y<0 || x >= w || y >= h)
return;
mMouseStart.x() = x;
mMouseStart.y() = y;
if (mTransform)
{
mStartMatrix = mTransform->localMatrix();
mPivot = mStartMatrix.getT();
}
else
mStartMatrix = camera()->modelingMatrix();
mStartCameraPos = camera()->modelingMatrix().getT();
mStartPivot = mPivot;
}
void TrackBall::mouseMoveEvent(int x, int y)
{
if (camera() == NULL)
return;
mCurrentX = x - camera()->viewport()->x();
mCurrentY = y - (openglContext()->framebuffer()->height() - 1 - (camera()->viewport()->y() + camera()->viewport()->height() - 1));
// ignore the event if the trackball is not in any mode
if (mode() == NoMode)
return;
VL_CHECK(openglContext()->framebuffer())
// set x/y relative to the top/left cornder of the viewport
x -= camera()->viewport()->x();
y -= openglContext()->framebuffer()->height() - 1 - (camera()->viewport()->y() + camera()->viewport()->height() - 1);
//if (mode() == RotationMode)TrackBall::
//{
// if (mTransform)
// {
// mTransform->setLocalMatrix(mat4::getTranslation(mPivot) * trackballRotation(x, y) * mat4::getTranslation(-mPivot) * mStartMatrix);
// mTransform->computeWorldMatrix();
// mStartMatrix = mTransform->localMatrix();
// }
// else
// {
// camera()->setModelingMatrix(mat4::getTranslation(mPivot) * trackballRotation(x, y) * mat4::getTranslation(-mPivot) * mStartMatrix);
// mStartMatrix = camera()->modelingMatrix();
// }
// mMouseStart.x() = x;
// mMouseStart.y() = y;
//}
//else
//{
if (mode() == ZoomMode)
{
float t = (y - mMouseStart.y()) / 200.0f;
t *= zoomSpeed();
real distance = (mStartCameraPos - mPivot).length();
vec3 camera_pos = mStartCameraPos - camera()->modelingMatrix().getZ()*t*distance;
mat4 m = camera()->modelingMatrix();
m.setT(camera_pos);
camera()->setModelingMatrix(m);
}
else if (mode() == TranslationMode)
{
vl::vec3 eye, at, up, right;
camera()->getViewMatrixAsLookAt(eye, at, up, right);
vl::vec4 focus_point_w, focus_point;
focus_point_w.x() = at.x();
focus_point_w.y() = at.y();
focus_point_w.z() = at.z();
focus_point_w.w() = 1.0;
camera()->project(focus_point_w, focus_point);
vl::vec3 vp0, vp1;
vp0.x() = mMouseStart.x();
vp0.y() = mMouseStart.y();
vp0.z() = focus_point.z();
vp1.x() = x;
vp1.y() = y;
vp1.z() = focus_point.z();
vl::vec4 v4p0, v4p1;
camera()->unproject(vp0, v4p0);
camera()->unproject(vp1, v4p1);
vec3 mv = v4p1.xyz() - v4p0.xyz();
mv.x() = -mv.x();
mat4 m = camera()->modelingMatrix();
m.setT(mStartCameraPos + mv);
camera()->setModelingMatrix(m);
mPivot = mStartPivot + mv;
}
//}
// update the view
openglContext()->update();
}
void TrackBall::mouseWheelEvent(int delta)
{
vl::vec3 eye, at, up, right;
camera()->getViewMatrixAsLookAt(eye, at, up, right);
vl::vec4 focus_point_w, focus_point;
focus_point_w.x() = at.x();
focus_point_w.y() = at.y();
//focus_point_w.z() = at.z();
focus_point_w.z() = at.z();
focus_point_w.w() = 1.0;
camera()->project(focus_point_w, focus_point);
vl::vec3 vp0;
vp0.x() = mCurrentX;
vp0.y() = mCurrentY;
vp0.z() = focus_point.z();
vl::vec4 v4p0;
camera()->unproject(vp0, v4p0);
mMode = ZoomMode;
float t = delta / 20.0f;
t *= zoomSpeed();
vec3 camera_pos = camera()->modelingMatrix().getT();
if (delta > 0)
{
camera_pos.x() += (v4p0.x() - camera_pos.x()) / 5;
camera_pos.y() -= (v4p0.y() - camera_pos.y()) / 5;
mPivot.x() += (v4p0.x() - mPivot.x()) / 5;
mPivot.y() -= (v4p0.y() - mPivot.y()) / 5;
}
else
{
camera_pos.x() -= (v4p0.x() - camera_pos.x()) / 5;
camera_pos.y() += (v4p0.y() - camera_pos.y()) / 5;
mPivot.x() -= (v4p0.x() - mPivot.x()) / 5;
mPivot.y() += (v4p0.y() - mPivot.y()) / 5;
}
real distance = (camera_pos - mPivot).length();
camera_pos = camera_pos - camera()->modelingMatrix().getZ()*t*distance;
mat4 m = camera()->modelingMatrix();
m.setT(camera_pos);
camera()->setModelingMatrix(m);
openglContext()->update();
mMode = NoMode;
}
bool VLRenderer::m_IsInit = false;
VLRenderer::VLRenderer()
:m_Width(800)
, m_Height(600)
{
if (!m_IsInit)
{
m_IsInit = true;
vl::VisualizationLibrary::init(true);
vl::globalSettings()->setCheckOpenGLStates(false);
}
mCubeTransform = new vl::Transform;
trackball = new TrackBall;
}
VLRenderer::~VLRenderer()
{
dispatchDestroyEvent();
vl::VisualizationLibrary::shutdown();
}
void VLRenderer::Init(void)
{
initGLContext(true);
mRendering = new vl::Rendering;
mSceneManager = new vl::SceneManagerActorTree;
mRendering->sceneManagers()->push_back(mSceneManager.get());
rendering()->camera()->viewport()->setClearColor(vl::darkgray);
rendering()->camera()->viewport()->setClearFlags(vl::CF_CLEAR_COLOR_DEPTH_STENCIL);
rendering()->camera()->viewport()->set(0, 0, m_Width, m_Height);
ResetCamera();
/* use a framebuffer object as render target */
mFBO = openglContext()->createFramebufferObject(m_Width, m_Height);
rendering()->renderer()->setFramebuffer(mFBO.get());
/* bind a depth buffer */
mFBODB = new vl::FBODepthBufferAttachment(vl::DBF_DEPTH_COMPONENT16);
mFBO->addDepthAttachment(mFBODB.get());
/* use texture as color buffer */
mTexture = new vl::Texture(m_Width, m_Height, vl::TF_RGBA);
vl::ref<vl::FBOTexture2DAttachment> fbo_tex_attachm = new vl::FBOTexture2DAttachment(mTexture.get(), 0, vl::T2DT_TEXTURE_2D);
mFBO->addTextureAttachment(vl::AP_COLOR_ATTACHMENT0, fbo_tex_attachm.get());
mFBO->setDrawBuffer(vl::RDB_COLOR_ATTACHMENT0);
//vl::ref<vl::TrackballManipulator> trackball = new vl::TrackballManipulator;
trackball->setCamera(rendering()->camera());
trackball->setTransform(NULL);
trackball->setPivot(vl::vec3(0, 0, 0));
//trackball->setRotationButton(100000);
trackball->setTranslationSpeed(0.5);
trackball->mVLRenderer = this;
openglContext()->addEventListener(trackball.get());
/*mvg = new vl::VectorGraphics;
vl::ref<vl::SceneManagerVectorGraphics> vgscene = new vl::SceneManagerVectorGraphics;
vgscene->vectorGraphicObjects()->push_back(mvg.get());
mRendering->sceneManagers()->push_back(vgscene.get());*/
}
void VLRenderer::Render(void)
{
// --- scene update ---
rendering()->setFrameClock(vl::Time::currentTime());
rendering()->render();
if (openglContext()->hasDoubleBuffer())
openglContext()->swapBuffers();
}
bool VLRenderer::UpdateSize(unsigned int w, unsigned int h)
{
if (w == m_Width && h == m_Height)
return false;
if (w <= 0 || h <= 0)
return false;
m_Width = w;
m_Height = h;
if (mTexture)mTexture->destroyTexture();
mTexture = nullptr;
if (mFBODB)mFBODB->deleteRenderBuffer();
mFBODB = nullptr;
if (mFBO)mFBO->deleteFBO();
mFBO = nullptr;
rendering()->camera()->viewport()->setWidth(m_Width);
rendering()->camera()->viewport()->setHeight(m_Height);
rendering()->camera()->setProjectionPerspective();
mFBO = openglContext()->createFramebufferObject(m_Width, m_Height);
rendering()->renderer()->setFramebuffer(mFBO.get());
mFBODB = new vl::FBODepthBufferAttachment(vl::DBF_DEPTH_COMPONENT16);
mFBO->addDepthAttachment(mFBODB.get());
mTexture = new vl::Texture(m_Width, m_Height, vl::TF_RGBA);
vl::ref<vl::FBOTexture2DAttachment> fbo_tex_attachm = new vl::FBOTexture2DAttachment(mTexture.get(), 0, vl::T2DT_TEXTURE_2D);
mFBO->addTextureAttachment(vl::AP_COLOR_ATTACHMENT0, fbo_tex_attachm.get());
mFBO->setDrawBuffer(vl::RDB_COLOR_ATTACHMENT0);
dispatchResizeEvent(m_Width, m_Height);
UpdateScene();
return true;
}
double VLRenderer::GetWorldDis(double *p0, double *p1)
{
vl::vec3 eye, at, up, right;
mRendering->camera()->getViewMatrixAsLookAt(eye, at, up, right);
vl::vec4 focus_point_w, focus_point;
focus_point_w.x() = at.x();
focus_point_w.y() = at.y();
focus_point_w.z() = 0.0;
focus_point_w.w() = 1.0;
mRendering->camera()->project(focus_point_w, focus_point);
vl::vec3 vp0, vp1;
vp0.x() = p0[0];
vp0.y() = p0[1];
vp0.z() = focus_point.z();
vp1.x() = p1[0];
vp1.y() = p1[1];
vp1.z() = focus_point.z();
vl::vec4 v4p0, v4p1;
mRendering->camera()->unproject(vp0, v4p0);
mRendering->camera()->unproject(vp1, v4p1);
return sqrt((v4p0.x() - v4p1.x()) * (v4p0.x() - v4p1.x()) +
(v4p0.y() - v4p1.y()) * (v4p0.y() - v4p1.y())/* +
(v4p0.z() - v4p1.z()) * (v4p0.z() - v4p1.z())*/);
}
/*void VLRenderer::UpdateCurrentLayer()
{
if (m_RenderMode != RenderMode2D)
return;
if (m_DataType == DATATYPE_BP) {
if (m_BPData == nullptr)
return;
m_PartSelected = -1;
ClearScene();
m_BPData->UpdateCurrentLayerParts();
std::vector<Part *> parts = m_BPData->GetParts();
for (unsigned int i = 0; i < parts.size(); i++)
{
if (parts[i]->GetActor().get() == nullptr)
continue;
m_actors.push_back(parts[i]->GetActor());
}
UpdateScene();
}
}*/
void VLRenderer::UpdateScene(void)
{
vl::ActorCollection actors;
mSceneManager->tree()->extractActors(actors);
for (unsigned int i = 0; i < actors.size(); i++)
mSceneManager->tree()->eraseActor(actors.at(i));
rendering()->transform()->eraseAllChildrenRecursive();
#if 0
if (m_RenderMode == RenderMode3D)
m_vtkRenderWindowInteractor->SetInteractorStyle(style3d);
else
m_vtkRenderWindowInteractor->SetInteractorStyle(style2d);
#endif
for (unsigned int i = 0; i < m_actors.size(); i++)
{
if (m_actors[i].get() != nullptr)
{
mSceneManager->tree()->addActor(m_actors[i].get());
rendering()->transform()->addChild(m_actors[i]->transform());
}
}
InitScene();
}
void VLRenderer::ClearScene(bool ClearJobs)
{
vl::ActorCollection actors;
mSceneManager->tree()->extractActors(actors);
for (unsigned int i = 0; i < actors.size(); i++)
mSceneManager->tree()->eraseActor(actors.at(i));
rendering()->transform()->eraseAllChildrenRecursive();
m_actors.clear();
if (ClearJobs && m_BPData)
{
delete m_BPData;
m_BPData = nullptr;
}
InitScene();
}
vl::ref<Geometry> VLRenderer::MakePlatform(const vec3& origin, real xside, real yside, int x, int y, bool gen_texcoords, fvec2 uv0, fvec2 uv1, bool center)
{
vl::ref<Geometry> geom = new Geometry;
geom->setObjectName("Platform");
vl::ref<ArrayFloat3> vert3 = new ArrayFloat3;
vl::ref<ArrayFloat2> text2 = new ArrayFloat2;
geom->setVertexArray(vert3.get());
VL_CHECK(x >= 2)
VL_CHECK(y >= 2)
real dx = xside / (x - 1);
real dz = yside / (y - 1);
if (center) {
xside /= 2.0f;
yside /= 2.0f;
}
vert3->resize(x * y);
if (gen_texcoords)
{
geom->setTexCoordArray(0, text2.get());
text2->resize(x * y);
}
// create vertices
int vert_idx = 0;
for (int i = 0; i<y; ++i)
for (int j = 0; j<x; ++j, ++vert_idx)
{
vert3->at(vert_idx) = (fvec3)(vec3(-xside + j*dx, -yside + i*dz, 0) + vec3(0, 0, 0));
if (gen_texcoords)
{
float tu = (float)j / (x - 1); // 0 .. 1
float tv = (float)i / (y - 1); // 0 .. 1
text2->at(vert_idx).s() = (1.0f - tu) * uv0.s() + tu * uv1.s();
text2->at(vert_idx).t() = (1.0f - tv) * uv0.t() + tv * uv1.t();
}
}
// create indices
vl::ref<DrawElementsUInt> polys = new DrawElementsUInt(PT_QUADS);
geom->drawCalls().push_back(polys.get());
int idx = 0;
polys->indexBuffer()->resize((y - 1)*(x - 1) * 4);
for (int i = 0; i<y - 1; ++i)
{
for (int j = 0; j<x - 1; ++j)
{
polys->indexBuffer()->at(idx++) = j + 0 + x*(i + 1);
polys->indexBuffer()->at(idx++) = j + 1 + x*(i + 1);
polys->indexBuffer()->at(idx++) = j + 1 + x*(i + 0);
polys->indexBuffer()->at(idx++) = j + 0 + x*(i + 0);
}
}
#if defined(VL_OPENGL_ES1) || defined(VL_OPENGL_ES2)
geom->makeGLESFriendly();
#endif
return geom;
}
vl::ref<Geometry> VLRenderer::MakePlatform(const vec3& origin, real diameter, unsigned int phi)
{
vl::ref<Geometry> geom = new Geometry;
geom->setObjectName("Platform");
vl::ref<ArrayFloat3> vert3 = new ArrayFloat3;
vert3->resize(phi + 1);
geom->setVertexArray(vert3.get());
vl::ref<DrawElementsUInt> tris = new DrawElementsUInt(PT_TRIANGLE_FAN);
tris->indexBuffer()->resize(phi + 2);
geom->drawCalls().push_back(tris.get());
int idx = 0;
diameter /= 2;
vert3->at(0) = origin;
for (int j = 0; j < phi; ++j)
{
vec3 v(diameter, 0, 0);
v = mat4::getRotation(360.0f / phi * j, 0, 0, 1) * v;
vert3->at(j + 1) = (fvec3)(v + origin);
}
// top fan
tris->indexBuffer()->at(idx++) = 0;
for (int j = 0; j < phi + 1; ++j)
tris->indexBuffer()->at(idx++) = 1 + j % phi;
#if defined(VL_OPENGL_ES1) || defined(VL_OPENGL_ES2)
geom->makeGLESFriendly();
#endif
return geom;
}
void VLRenderer::InitScene()
{
vl::ref<vl::Geometry> platform;
if (m_PlatformShape == PS_ROUND)
platform = MakePlatform(vl::vec3(0, 0, 0), m_PlatformWidth, 100);
else
platform = MakePlatform(vl::vec3(0, 0, 0), m_PlatformWidth, m_PlatformDepth, 2, 2);
vl::ref<vl::Effect> effect = new vl::Effect;
effect->shader()->enable(vl::EN_DEPTH_TEST);
effect->shader()->enable(vl::EN_BLEND);
effect->shader()->gocColor()->setValue(vl::lightgray);
/* wireframe shader */
//effect->lod(0)->push_back(new Shader);
//effect->shader(0, 1)->enable(EN_BLEND);
//effect->shader(0, 1)->enable(EN_DEPTH_TEST);
//effect->shader(0, 1)->enable(EN_POLYGON_OFFSET_LINE);
//effect->shader(0, 1)->gocPolygonOffset()->set(-0.5f, -0.5f);
//effect->shader(0, 1)->gocPolygonMode()->set(PM_LINE, PM_LINE);
//effect->shader(0, 1)->gocColor()->setValue(vl::fvec4(0, 0.05, 0.05, 0.02));
//effect->shader(0, 1)->gocBlendFunc()->set(vl::BF_SRC_ALPHA, vl::BF_ONE_MINUS_SRC_ALPHA);
mSceneManager->tree()->addActor(platform.get(), effect.get());
}
void VLRenderer::SetCurrentLayer(unsigned int layer)
{
if (m_RenderMode != RenderMode2D)
return;
if (m_DataType == DATATYPE_BP) {
if (m_BPData == nullptr)
return;
if (m_BPData->GetCurrentLayer() == layer)
return;
m_PartSelected = -1;
ClearScene();
//m_BPData->GetLayerData(layer);
std::map<int, Part*>* partMap = m_BPData->GetPartMap();
for (map<int, Part*>::iterator it = partMap->begin(); it != partMap->end(); it++) {
Part* part = it->second;
if (part->GetActor().get() == nullptr)
continue;
m_actors.push_back(part->GetActor());
}
UpdateScene();
}
}
void VLRenderer::SetPreviewLayer(unsigned int layer)
{
if (m_RenderMode != RenderMode2D)
return;
if (m_DataType == DATATYPE_BP) {
if (m_BPData == nullptr)
return;
if (m_BPData->GetCurrentLayer() == layer)
return;
m_PartSelected = -1;
ClearScene();
//m_BPData->GetPrevLayerData(layer);
std::map<int, Part*>* partMap = m_BPData->GetPartMap();
for (map<int, Part*>::iterator it = partMap->begin(); it != partMap->end(); it++) {
Part* part = it->second;
if (part->GetActor().get() == nullptr)
continue;
m_actors.push_back(part->GetActor());
}
UpdateScene();
}
}
//void VLRenderer::SetJob(FileProcessor * jfp)
//{
// if (jfp == nullptr)
// return;
//
// if (m_BPData == nullptr)
// m_BPData = new BPData;
//
// if (m_BPData->GetJobFileProcessor() != nullptr &&
// jfp->GetJobUid() == m_BPData->GetJobID())
// return;
//
// ClearScene();
//
// m_DataType = DATATYPE_BP;
// m_BPData->SetJob(jfp);
// if (m_RenderMode == RenderMode2D)
// {
// m_BPData->GetPrevLayerData(0);
// m_BPData->GetJobFileProcessor()->m_IsOpen = true;
// }
// else
// m_BPData->GetJobData();
//
// std::map<int, Part*>* partMap = m_BPData->GetPartMap();
// for (map<int, Part*>::iterator it = partMap->begin(); it != partMap->end(); it++) {
// AddActor(it->second->GetActor());
// }
// UpdateScene();
//}
//void VLRenderer::AddPart(MetaData::Part* part)
//{
// Part* tmep = m_BPData->AddPart(part);
// AddActor(tmep->GetActor());
// UpdateScene();
// //UpdateScene();
//}
//void VLRenderer::DelPart(MetaData::Part* part)
//{
// Part* temp = m_BPData->GetPart(part->id);
// for (vector<vl::ref<vl::Actor>>::iterator it = m_actors.begin(); it != m_actors.end();) {
// vl::ref<vl::Actor> act = (*it);
// if (act == temp->GetActor()) {
// it = m_actors.erase(it);
// }
// else {
// it++;
// }
// }
// m_BPData->DelPart(part);
// UpdateScene();
//}
void VLRenderer::SetRenderMode(RenderMode mode)
{
if (m_RenderMode == mode)
return;
m_RenderMode = mode;
if (mode == RenderMode2D)
SetCurrentLayer(0);
else if (mode == RenderMode3D) {
if (m_DataType == DATATYPE_BP) {
m_BPData->GetJobData();
ClearScene();
std::map<int, Part*>* partMap = m_BPData->GetPartMap();
for (map<int, Part*>::iterator it = partMap->begin(); it != partMap->end(); it++) {
AddActor(it->second->GetActor());
}
UpdateScene();
}
}
}
/*std::vector<Part *>* VLRenderer::GetParts(void)
{
if (m_DataType == DATATYPE_BP && m_BPData)
return &m_BPData->GetParts();
else
return nullptr;
}*/
std::map<int, Part*>* VLRenderer::GetPartMap()
{
if (m_DataType == DATATYPE_BP && m_BPData)
return m_BPData->GetPartMap();
else
return nullptr;
}
void VLRenderer::UpdateGlobalOffset(double offset_x, double offset_y)
{
if (offset_x == m_GlobalOffsetX && offset_y == m_GlobalOffsetY)
return;
m_GlobalOffsetX = offset_x;
m_GlobalOffsetY = offset_y;
if (m_BPData == NULL)return;
std::map<int, Part*>* partMap = m_BPData->GetPartMap();
for (map<int, Part*>::iterator it = partMap->begin(); it != partMap->end(); it++) {
it->second->UpdateGlobalOffset(offset_x, offset_y);
}
}
void VLRenderer::ResetCamera(void)
{
double high = (m_PlatformWidth / 2 + 20) / tan(0.55);
rendering()->camera()->setProjectionPerspective();
vl::mat4 m = vl::mat4::getLookAt(vl::vec3(0, 0, high), vl::vec3(0, 0, 0), vl::vec3(0, 1, 0));
rendering()->camera()->setViewMatrix(m);
trackball->setPivot(vl::vec3(0, 0, 0));
}
void VLRenderer::SetPlatfromSize(double width, double depth, double height)
{
if (width < 10.0 || depth < 10.0 || height < 10.0)
return;
m_PlatformWidth = width;
m_PlatformDepth = depth;
m_PlatformHeight = height;
UpdateScene();
ResetCamera();
}
void VLRenderer::SetPlatformShape(PlatformShape shape)
{
m_PlatformShape = shape;
}
void VLRenderer::AddActor(vl::ref<vl::Actor> actor)
{
if (!actor)
return;
m_actors.push_back(actor);
}
Part* VLRenderer::GetPart(unsigned int index)
{
if (m_BPData)
return m_BPData->GetPart(index);
else return nullptr;
}