#include "gpuCacheRasterSelect.h"
#include "gpuCacheSample.h"
#include "gpuCacheVBOProxy.h"
#include "gpuCacheDrawTraversal.h"
#include "gpuCacheGLFT.h"
#include "CacheReader.h"
#include <algorithm>
namespace {
using namespace GPUCache;
class DrawWireframeState : public DrawTraversalState
{
public:
DrawWireframeState(
const Frustum& frustrum,
const double seconds,
VBOProxy::VBOMode vboMode)
: DrawTraversalState(frustrum, seconds, kPruneNone),
fVBOMode(vboMode)
{}
VBOProxy::VBOMode vboMode() const
{ return fVBOMode; }
private:
VBOProxy::VBOMode fVBOMode;
};
class DrawWireframeTraversal
: public DrawTraversal<DrawWireframeTraversal, DrawWireframeState>
{
public:
typedef DrawTraversal<DrawWireframeTraversal, DrawWireframeState> BaseClass;
DrawWireframeTraversal(
DrawWireframeState& state,
bool isReflection,
Frustum::ClippingResult parentClippingResult)
: BaseClass(state, xform, isReflection, parentClippingResult)
{}
void draw(const std::shared_ptr<const ShapeSample>& sample)
{
if (!sample->visibility()) return;
gGLFT->glLoadMatrixd(xform().matrix[0]);
if (sample->isBoundingBoxPlaceHolder()) {
state().vboProxy().drawBoundingBox(sample);
GlobalReaderCache::theCache().hintShapeReadOrder(subNode());
return;
}
assert(sample->positions());
assert(sample->normals());
state().vboProxy().drawWireframe(sample, state().vboMode());
state().vboProxy().drawVertices(sample, state().vboMode());
}
};
class DrawShadedState : public DrawTraversalState
{
public:
DrawShadedState(
const Frustum& frustrum,
const double seconds,
VBOProxy::VBOMode vboMode)
: DrawTraversalState(frustrum, seconds, kPruneNone),
fVBOMode(vboMode)
{}
VBOProxy::VBOMode vboMode() const
{ return fVBOMode; }
private:
VBOProxy::VBOMode fVBOMode;
};
class DrawShadedTraversal
: public DrawTraversal<DrawShadedTraversal, DrawShadedState>
{
public:
typedef DrawTraversal<DrawShadedTraversal, DrawShadedState> BaseClass;
DrawShadedTraversal(
DrawShadedState& state,
bool isReflection,
Frustum::ClippingResult parentClippingResult)
: BaseClass(state, xform, isReflection, parentClippingResult)
{}
void draw(const std::shared_ptr<const ShapeSample>& sample)
{
if (!sample->visibility()) return;
gGLFT->glLoadMatrixd(xform().matrix[0]);
if (sample->isBoundingBoxPlaceHolder()) {
state().vboProxy().drawBoundingBox(sample, true);
GlobalReaderCache::theCache().hintShapeReadOrder(subNode());
return;
}
assert(sample->positions());
assert(sample->normals());
const size_t numGroups = sample->numIndexGroups();
for (size_t groupId = 0; groupId < numGroups; groupId++) {
state().vboProxy().drawTriangles(
sample, groupId, VBOProxy::kNoNormals, VBOProxy::kNoUVs,
state().vboMode());
state().vboProxy().drawVertices(sample, state().vboMode());
}
}
};
}
namespace GPUCache {
#define MAX_RASTER_SELECT_RENDER_SIZE 16
RasterSelect::RasterSelect(
)
: fSelectInfo(selectInfo),
fMinZ(std::numeric_limits<float>::max())
{
unsigned int sxl, syl, sw, sh;
fSelectInfo.selectRect(sxl, syl, sw, sh);
unsigned int vxl, vyl, vw, vh;
const unsigned int width = (MAX_RASTER_SELECT_RENDER_SIZE < sw) ?
MAX_RASTER_SELECT_RENDER_SIZE : sw;
const unsigned int height = (MAX_RASTER_SELECT_RENDER_SIZE < sh) ?
MAX_RASTER_SELECT_RENDER_SIZE : sh;
const double sx = double(width) / double(sw);
const double sy = double(height) / double(sh);
const double fx = 2.0 / double(vw);
const double fy = 2.0 / double(vh);
selectMatrix.
matrix[0][0] = sx;
selectMatrix.
matrix[1][1] = sy;
selectMatrix.
matrix[3][0] = -1.0 - sx * (fx * (sxl - vxl) - 1.0);
selectMatrix.matrix[3][1] = -1.0 - sy * (fy * (syl - vyl) - 1.0);
::glMatrixMode(GL_PROJECTION);
::glPushMatrix();
::glLoadMatrixd(selectMatrix[0]);
::glMultMatrixd(projMatrix[0]);
::glMatrixMode(GL_MODELVIEW);
::glScissor(vxl, vyl, width, height);
::glEnable(GL_SCISSOR_TEST);
::glClear(GL_DEPTH_BUFFER_BIT);
fWasDepthTestEnabled = ::glIsEnabled(GL_DEPTH_TEST);
if (!fWasDepthTestEnabled) {
::glEnable(GL_DEPTH_TEST);
}
}
RasterSelect::~RasterSelect()
{}
void RasterSelect::processEdges(
const SubNode::Ptr rootNode,
double seconds,
size_t ,
VBOProxy::VBOMode vboMode
)
{
unsigned int x, y, w, h;
double viewportX = static_cast<int>(x);
double viewportY = static_cast<int>(y);
double viewportW = w;
double viewportH = h;
fSelectInfo.selectRect(x, y, w, h);
double selectX = static_cast<int>(x);
double selectY = static_cast<int>(y);
double selectW = w;
double selectH = h;
selectAdjustMatrix[0][0] = viewportW / selectW;
selectAdjustMatrix[1][1] = viewportH / selectH;
selectAdjustMatrix[3][0] = ((viewportX + viewportW/2.0) - (selectX + selectW/2.0)) /
viewportW * 2.0 * selectAdjustMatrix[0][0];
selectAdjustMatrix[3][1] = ((viewportY + viewportH/2.0) - (selectY + selectH/2.0)) /
viewportH * 2.0 * selectAdjustMatrix[1][1];
MMatrix localToPort = modelViewMatrix * projMatrix * selectAdjustMatrix;
{
Frustum frustum(localToPort.
inverse());
DrawWireframeState state(frustum, seconds, vboMode);
DrawWireframeTraversal traveral(state, xform, false, Frustum::kUnknown);
rootNode->accept(traveral);
}
}
void RasterSelect::processTriangles(
const SubNode::Ptr rootNode,
double seconds,
size_t ,
VBOProxy::VBOMode vboMode
)
{
unsigned int x, y, w, h;
double viewportX = static_cast<int>(x);
double viewportY = static_cast<int>(y);
double viewportW = w;
double viewportH = h;
fSelectInfo.selectRect(x, y, w, h);
double selectX = static_cast<int>(x);
double selectY = static_cast<int>(y);
double selectW = w;
double selectH = h;
selectAdjustMatrix[0][0] = viewportW / selectW;
selectAdjustMatrix[1][1] = viewportH / selectH;
selectAdjustMatrix[3][0] = ((viewportX + viewportW/2.0) - (selectX + selectW/2.0)) /
viewportW * 2.0 * selectAdjustMatrix[0][0];
selectAdjustMatrix[3][1] = ((viewportY + viewportH/2.0) - (selectY + selectH/2.0)) /
viewportH * 2.0 * selectAdjustMatrix[1][1];
MMatrix localToPort = modelViewMatrix * projMatrix * selectAdjustMatrix;
{
Frustum frustum(localToPort.
inverse());
DrawShadedState state(frustum, seconds, vboMode);
DrawShadedTraversal traveral(state, xform, false, Frustum::kUnknown);
rootNode->accept(traveral);
}
}
void RasterSelect::processBoundingBox(
const SubNode::Ptr rootNode,
double seconds
)
{
assert(0);
}
void RasterSelect::end()
{
unsigned int sxl, syl, sw, sh;
fSelectInfo.selectRect(sxl, syl, sw, sh);
unsigned int vxl, vyl, vw, vh;
const unsigned int width = (MAX_RASTER_SELECT_RENDER_SIZE < sw) ?
MAX_RASTER_SELECT_RENDER_SIZE : sw;
const unsigned int height = (MAX_RASTER_SELECT_RENDER_SIZE < sh) ?
MAX_RASTER_SELECT_RENDER_SIZE : sh;
float* selDepth = new float[MAX_RASTER_SELECT_RENDER_SIZE*
MAX_RASTER_SELECT_RENDER_SIZE];
GLint buffer;
::glGetIntegerv( GL_READ_BUFFER, &buffer );
::glReadBuffer( GL_BACK );
::glReadPixels(vxl, vyl, width, height,
GL_DEPTH_COMPONENT, GL_FLOAT, (void *)selDepth);
::glReadBuffer( buffer );
for (unsigned int j=0; j<height; ++j) {
for (unsigned int i=0; i<width; ++i) {
const GLfloat depth = selDepth[j*width + i];
if (depth < 1.0f) {
fMinZ = std::min(fMinZ, depth);
}
}
}
::glMatrixMode(GL_PROJECTION);
::glPopMatrix();
::glMatrixMode(GL_MODELVIEW);
::glDisable(GL_SCISSOR_TEST);
if (!fWasDepthTestEnabled) {
::glDisable(GL_DEPTH_TEST);
}
}
bool RasterSelect::isSelected() const
{
return fMinZ != std::numeric_limits<float>::max();
}
float RasterSelect::minZ() const
{
return fMinZ;
}
}