vtk9/Rendering/ContextOpenGL2/vtkOpenGLContextDevice3D.cxx

645 lines
16 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkOpenGLContextDevice3D.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkOpenGLContextDevice3D.h"
#include "vtkBrush.h"
#include "vtkMatrix4x4.h"
#include "vtkObjectFactory.h"
#include "vtkOpenGLCamera.h"
#include "vtkOpenGLContextDevice2D.h"
#include "vtkOpenGLError.h"
#include "vtkOpenGLHelper.h"
#include "vtkOpenGLIndexBufferObject.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkOpenGLRenderer.h"
#include "vtkOpenGLShaderCache.h"
#include "vtkOpenGLState.h"
#include "vtkOpenGLVertexArrayObject.h"
#include "vtkOpenGLVertexBufferObject.h"
#include "vtkPen.h"
#include "vtkShaderProgram.h"
#include "vtkTransform.h"
class vtkOpenGLContextDevice3D::Private
{
public:
Private() = default;
~Private() = default;
void Transpose(double* in, double* transposed)
{
transposed[0] = in[0];
transposed[1] = in[4];
transposed[2] = in[8];
transposed[3] = in[12];
transposed[4] = in[1];
transposed[5] = in[5];
transposed[6] = in[9];
transposed[7] = in[13];
transposed[8] = in[2];
transposed[9] = in[6];
transposed[10] = in[10];
transposed[11] = in[14];
transposed[12] = in[3];
transposed[13] = in[7];
transposed[14] = in[11];
transposed[15] = in[15];
}
void SetLineType(int type)
{
if (type == vtkPen::SOLID_LINE || type == vtkPen::NO_PEN)
{
return;
}
vtkGenericWarningMacro(<< "Line Stipples are no longer supported");
}
vtkVector2i Dim;
vtkVector2i Offset;
};
vtkStandardNewMacro(vtkOpenGLContextDevice3D);
vtkOpenGLContextDevice3D::vtkOpenGLContextDevice3D()
: Storage(new Private)
{
this->ModelMatrix = vtkTransform::New();
this->ModelMatrix->Identity();
this->VBO = new vtkOpenGLHelper;
this->VCBO = new vtkOpenGLHelper;
this->ClippingPlaneStates.resize(6, false);
this->ClippingPlaneValues.resize(24);
}
vtkOpenGLContextDevice3D::~vtkOpenGLContextDevice3D()
{
delete this->VBO;
this->VBO = nullptr;
delete this->VCBO;
this->VCBO = nullptr;
this->ModelMatrix->Delete();
delete Storage;
}
void vtkOpenGLContextDevice3D::Initialize(vtkRenderer* ren, vtkOpenGLContextDevice2D* dev)
{
this->Device2D = dev;
this->Renderer = ren;
this->RenderWindow = vtkOpenGLRenderWindow::SafeDownCast(ren->GetVTKWindow());
}
//------------------------------------------------------------------------------
void vtkOpenGLContextDevice3D::Begin(vtkViewport* vtkNotUsed(viewport))
{
this->ModelMatrix->Identity();
for (int i = 0; i < 6; i++)
{
this->ClippingPlaneStates[i] = false;
}
}
void vtkOpenGLContextDevice3D::SetMatrices(vtkShaderProgram* prog)
{
vtkOpenGLState* ostate = this->RenderWindow->GetState();
ostate->vtkglDisable(GL_SCISSOR_TEST);
prog->SetUniformMatrix("WCDCMatrix", this->Device2D->GetProjectionMatrix());
vtkMatrix4x4* mvm = this->Device2D->GetModelMatrix();
vtkMatrix4x4* tmp = vtkMatrix4x4::New();
vtkMatrix4x4::Multiply4x4(mvm, this->ModelMatrix->GetMatrix(), tmp);
prog->SetUniformMatrix("MCWCMatrix",
// this->ModelMatrix->GetMatrix());
tmp);
tmp->Delete();
// add all the clipping planes
int numClipPlanes = 0;
float planeEquations[6][4];
for (int i = 0; i < 6; i++)
{
if (this->ClippingPlaneStates[i])
{
planeEquations[numClipPlanes][0] = this->ClippingPlaneValues[i * 4];
planeEquations[numClipPlanes][1] = this->ClippingPlaneValues[i * 4 + 1];
planeEquations[numClipPlanes][2] = this->ClippingPlaneValues[i * 4 + 2];
planeEquations[numClipPlanes][3] = this->ClippingPlaneValues[i * 4 + 3];
numClipPlanes++;
}
}
prog->SetUniformi("numClipPlanes", numClipPlanes);
prog->SetUniform4fv("clipPlanes", 6, planeEquations);
}
void vtkOpenGLContextDevice3D::BuildVBO(vtkOpenGLHelper* cellBO, const float* f, int nv,
const unsigned char* colors, int nc, float* tcoords)
{
int stride = 3;
int cOffset = 0;
int tOffset = 0;
if (colors)
{
cOffset = stride;
stride++;
}
if (tcoords)
{
tOffset = stride;
stride += 2;
}
std::vector<float> va;
va.resize(nv * stride);
vtkFourByteUnion c;
for (int i = 0; i < nv; i++)
{
va[i * stride] = f[i * 3];
va[i * stride + 1] = f[i * 3 + 1];
va[i * stride + 2] = f[i * 3 + 2];
if (colors)
{
c.c[0] = colors[nc * i];
c.c[1] = colors[nc * i + 1];
c.c[2] = colors[nc * i + 2];
if (nc == 4)
{
c.c[3] = colors[nc * i + 3];
}
else
{
c.c[3] = 255;
}
va[i * stride + cOffset] = c.f;
}
if (tcoords)
{
va[i * stride + tOffset] = tcoords[i * 2];
va[i * stride + tOffset + 1] = tcoords[i * 2 + 1];
}
}
// upload the data
cellBO->IBO->Upload(va, vtkOpenGLBufferObject::ArrayBuffer);
cellBO->VAO->Bind();
if (!cellBO->VAO->AddAttributeArray(
cellBO->Program, cellBO->IBO, "vertexMC", 0, sizeof(float) * stride, VTK_FLOAT, 3, false))
{
vtkErrorMacro(<< "Error setting vertexMC in shader VAO.");
}
if (colors)
{
if (!cellBO->VAO->AddAttributeArray(cellBO->Program, cellBO->IBO, "vertexScalar",
sizeof(float) * cOffset, sizeof(float) * stride, VTK_UNSIGNED_CHAR, 4, true))
{
vtkErrorMacro(<< "Error setting vertexScalar in shader VAO.");
}
}
if (tcoords)
{
if (!cellBO->VAO->AddAttributeArray(cellBO->Program, cellBO->IBO, "tcoordMC",
sizeof(float) * tOffset, sizeof(float) * stride, VTK_FLOAT, 2, false))
{
vtkErrorMacro(<< "Error setting tcoordMC in shader VAO.");
}
}
cellBO->VAO->Bind();
}
void vtkOpenGLContextDevice3D::ReadyVBOProgram()
{
if (!this->VBO->Program)
{
this->VBO->Program = this->RenderWindow->GetShaderCache()->ReadyShaderProgram(
// vertex shader
"//VTK::System::Dec\n"
"in vec3 vertexMC;\n"
"uniform mat4 WCDCMatrix;\n"
"uniform mat4 MCWCMatrix;\n"
"uniform int numClipPlanes;\n"
"uniform vec4 clipPlanes[6];\n"
"out float clipDistances[6];\n"
"void main() {\n"
"vec4 vertex = vec4(vertexMC.xyz, 1.0);\n"
"for (int planeNum = 0; planeNum < numClipPlanes; planeNum++)\n"
" {\n"
" clipDistances[planeNum] = dot(clipPlanes[planeNum], vertex*MCWCMatrix);\n"
" }\n"
"gl_Position = vertex*MCWCMatrix*WCDCMatrix; }\n",
// fragment shader
"//VTK::System::Dec\n"
"//VTK::Output::Dec\n"
"uniform vec4 vertexColor;\n"
"uniform int numClipPlanes;\n"
"in float clipDistances[6];\n"
"void main() { \n"
" for (int planeNum = 0; planeNum < numClipPlanes; planeNum++)\n"
" {\n"
" if (clipDistances[planeNum] < 0.0) discard;\n"
" }\n"
" gl_FragData[0] = vertexColor; }",
// geometry shader
"");
}
else
{
this->RenderWindow->GetShaderCache()->ReadyShaderProgram(this->VBO->Program);
}
}
void vtkOpenGLContextDevice3D::ReadyVCBOProgram()
{
if (!this->VCBO->Program)
{
this->VCBO->Program = this->RenderWindow->GetShaderCache()->ReadyShaderProgram(
// vertex shader
"//VTK::System::Dec\n"
"in vec3 vertexMC;\n"
"in vec4 vertexScalar;\n"
"uniform mat4 WCDCMatrix;\n"
"uniform mat4 MCWCMatrix;\n"
"out vec4 vertexColor;\n"
"uniform int numClipPlanes;\n"
"uniform vec4 clipPlanes[6];\n"
"out float clipDistances[6];\n"
"void main() {\n"
"vec4 vertex = vec4(vertexMC.xyz, 1.0);\n"
"vertexColor = vertexScalar;\n"
"for (int planeNum = 0; planeNum < numClipPlanes; planeNum++)\n"
" {\n"
" clipDistances[planeNum] = dot(clipPlanes[planeNum], vertex*MCWCMatrix);\n"
" }\n"
"gl_Position = vertex*MCWCMatrix*WCDCMatrix; }\n",
// fragment shader
"//VTK::System::Dec\n"
"//VTK::Output::Dec\n"
"in vec4 vertexColor;\n"
"uniform int numClipPlanes;\n"
"in float clipDistances[6];\n"
"void main() { \n"
" for (int planeNum = 0; planeNum < numClipPlanes; planeNum++)\n"
" {\n"
" if (clipDistances[planeNum] < 0.0) discard;\n"
" }\n"
" gl_FragData[0] = vertexColor; }",
// geometry shader
"");
}
else
{
this->RenderWindow->GetShaderCache()->ReadyShaderProgram(this->VCBO->Program);
}
}
bool vtkOpenGLContextDevice3D::HaveWideLines()
{
if (this->Pen->GetWidth() > 1.0)
{
// we have wide lines, but the OpenGL implementation may
// actually support them, check the range to see if we
// really need have to implement our own wide lines
return !(this->RenderWindow &&
this->RenderWindow->GetMaximumHardwareLineWidth() >= this->Pen->GetWidth());
}
return false;
}
void vtkOpenGLContextDevice3D::DrawPoly(
const float* verts, int n, const unsigned char* colors, int nc)
{
assert("verts must be non-null" && verts != nullptr);
assert("n must be greater than 0" && n > 0);
if (this->Pen->GetLineType() == vtkPen::NO_PEN)
{
return;
}
vtkOpenGLClearErrorMacro();
this->EnableDepthBuffer();
this->Storage->SetLineType(this->Pen->GetLineType());
vtkOpenGLHelper* cbo = nullptr;
if (colors)
{
this->ReadyVCBOProgram();
cbo = this->VCBO;
if (!cbo->Program)
{
return;
}
}
else
{
this->ReadyVBOProgram();
cbo = this->VBO;
if (!cbo->Program)
{
return;
}
if (this->HaveWideLines())
{
vtkWarningMacro(
<< "a line width has been requested that is larger than your system supports");
}
else
{
this->RenderWindow->GetState()->vtkglLineWidth(this->Pen->GetWidth());
}
cbo->Program->SetUniform4uc("vertexColor", this->Pen->GetColor());
}
this->BuildVBO(cbo, verts, n, colors, nc, nullptr);
this->SetMatrices(cbo->Program);
glDrawArrays(GL_LINE_STRIP, 0, n);
// free everything
cbo->ReleaseGraphicsResources(this->RenderWindow);
this->RenderWindow->GetState()->vtkglLineWidth(1.0);
this->DisableDepthBuffer();
vtkOpenGLCheckErrorMacro("failed after DrawPoly");
}
//------------------------------------------------------------------------------
void vtkOpenGLContextDevice3D::DrawLines(
const float* verts, int n, const unsigned char* colors, int nc)
{
assert("verts must be non-null" && verts != nullptr);
assert("n must be greater than 0" && n > 0);
if (this->Pen->GetLineType() == vtkPen::NO_PEN)
{
return;
}
vtkOpenGLClearErrorMacro();
this->EnableDepthBuffer();
this->Storage->SetLineType(this->Pen->GetLineType());
if (this->Pen->GetWidth() > 1.0)
{
vtkErrorMacro(<< "lines wider than 1.0 are not supported\n");
}
this->RenderWindow->GetState()->vtkglLineWidth(this->Pen->GetWidth());
vtkOpenGLHelper* cbo = nullptr;
if (colors)
{
this->ReadyVCBOProgram();
cbo = this->VCBO;
if (!cbo->Program)
{
return;
}
}
else
{
this->ReadyVBOProgram();
cbo = this->VBO;
if (!cbo->Program)
{
return;
}
cbo->Program->SetUniform4uc("vertexColor", this->Pen->GetColor());
}
this->BuildVBO(cbo, verts, n, colors, nc, nullptr);
this->SetMatrices(cbo->Program);
glDrawArrays(GL_LINES, 0, n);
// free everything
cbo->ReleaseGraphicsResources(this->RenderWindow);
this->RenderWindow->GetState()->vtkglLineWidth(1.0);
this->DisableDepthBuffer();
vtkOpenGLCheckErrorMacro("failed after DrawLines");
}
void vtkOpenGLContextDevice3D::DrawPoints(
const float* verts, int n, const unsigned char* colors, int nc)
{
assert("verts must be non-null" && verts != nullptr);
assert("n must be greater than 0" && n > 0);
vtkOpenGLClearErrorMacro();
this->EnableDepthBuffer();
this->RenderWindow->GetState()->vtkglPointSize(this->Pen->GetWidth());
vtkOpenGLHelper* cbo = nullptr;
if (colors)
{
this->ReadyVCBOProgram();
cbo = this->VCBO;
if (!cbo->Program)
{
return;
}
}
else
{
this->ReadyVBOProgram();
cbo = this->VBO;
if (!cbo->Program)
{
return;
}
cbo->Program->SetUniform4uc("vertexColor", this->Pen->GetColor());
}
this->BuildVBO(cbo, verts, n, colors, nc, nullptr);
this->SetMatrices(cbo->Program);
glDrawArrays(GL_POINTS, 0, n);
// free everything
cbo->ReleaseGraphicsResources(this->RenderWindow);
this->DisableDepthBuffer();
vtkOpenGLCheckErrorMacro("failed DrawPoints");
}
void vtkOpenGLContextDevice3D::DrawTriangleMesh(
const float* mesh, int n, const unsigned char* colors, int nc)
{
assert("mesh must be non-null" && mesh != nullptr);
assert("n must be greater than 0" && n > 0);
vtkOpenGLClearErrorMacro();
this->EnableDepthBuffer();
vtkOpenGLHelper* cbo = nullptr;
if (colors)
{
this->ReadyVCBOProgram();
cbo = this->VCBO;
if (!cbo->Program)
{
return;
}
}
else
{
this->ReadyVBOProgram();
cbo = this->VBO;
if (!cbo->Program)
{
return;
}
cbo->Program->SetUniform4uc("vertexColor", this->Pen->GetColor());
}
this->BuildVBO(cbo, mesh, n, colors, nc, nullptr);
this->SetMatrices(cbo->Program);
glDrawArrays(GL_TRIANGLES, 0, n);
// free everything
cbo->ReleaseGraphicsResources(this->RenderWindow);
this->DisableDepthBuffer();
vtkOpenGLCheckErrorMacro("failed after DrawTriangleMesh");
}
void vtkOpenGLContextDevice3D::ApplyPen(vtkPen* pen)
{
this->Pen->DeepCopy(pen);
}
void vtkOpenGLContextDevice3D::ApplyBrush(vtkBrush* brush)
{
this->Brush->DeepCopy(brush);
}
//------------------------------------------------------------------------------
void vtkOpenGLContextDevice3D::PushMatrix()
{
this->ModelMatrix->Push();
}
//------------------------------------------------------------------------------
void vtkOpenGLContextDevice3D::PopMatrix()
{
this->ModelMatrix->Pop();
}
void vtkOpenGLContextDevice3D::SetMatrix(vtkMatrix4x4* m)
{
this->ModelMatrix->SetMatrix(m);
}
void vtkOpenGLContextDevice3D::GetMatrix(vtkMatrix4x4* m)
{
m->DeepCopy(this->ModelMatrix->GetMatrix());
}
void vtkOpenGLContextDevice3D::MultiplyMatrix(vtkMatrix4x4* m)
{
this->ModelMatrix->Concatenate(m);
}
void vtkOpenGLContextDevice3D::SetClipping(const vtkRecti& rect)
{
// Check the bounds, and clamp if necessary
GLint vp[4] = { this->Storage->Offset.GetX(), this->Storage->Offset.GetY(),
this->Storage->Dim.GetX(), this->Storage->Dim.GetY() };
if (rect.GetX() > 0 && rect.GetX() < vp[2])
{
vp[0] += rect.GetX();
}
if (rect.GetY() > 0 && rect.GetY() < vp[3])
{
vp[1] += rect.GetY();
}
if (rect.GetWidth() > 0 && rect.GetWidth() < vp[2])
{
vp[2] = rect.GetWidth();
}
if (rect.GetHeight() > 0 && rect.GetHeight() < vp[3])
{
vp[3] = rect.GetHeight();
}
vtkOpenGLState* ostate = this->RenderWindow->GetState();
ostate->vtkglScissor(vp[0], vp[1], vp[2], vp[3]);
}
void vtkOpenGLContextDevice3D::EnableClipping(bool enable)
{
vtkOpenGLState* ostate = this->RenderWindow->GetState();
ostate->SetEnumState(GL_SCISSOR_TEST, enable);
}
void vtkOpenGLContextDevice3D::EnableClippingPlane(int i, double* planeEquation)
{
if (i >= 6)
{
vtkOpenGLCheckErrorMacro("only 6 ClippingPlane allowed");
return;
}
this->ClippingPlaneStates[i] = true;
this->ClippingPlaneValues[i * 4] = planeEquation[0];
this->ClippingPlaneValues[i * 4 + 1] = planeEquation[1];
this->ClippingPlaneValues[i * 4 + 2] = planeEquation[2];
this->ClippingPlaneValues[i * 4 + 3] = planeEquation[3];
}
void vtkOpenGLContextDevice3D::DisableClippingPlane(int i)
{
if (i >= 6)
{
vtkOpenGLCheckErrorMacro("only 6 ClippingPlane allowed");
return;
}
this->ClippingPlaneStates[i] = false;
}
void vtkOpenGLContextDevice3D::EnableDepthBuffer()
{
vtkOpenGLState* ostate = this->RenderWindow->GetState();
ostate->vtkglEnable(GL_DEPTH_TEST);
}
void vtkOpenGLContextDevice3D::DisableDepthBuffer()
{
vtkOpenGLState* ostate = this->RenderWindow->GetState();
ostate->vtkglDisable(GL_DEPTH_TEST);
}
void vtkOpenGLContextDevice3D::PrintSelf(ostream& os, vtkIndent indent)
{
Superclass::PrintSelf(os, indent);
}