void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec3& topLeft, const glm::vec3& bottomLeft, const glm::vec3& bottomRight, const glm::vec3& topRight, const glm::vec2& texCoordTopLeft, const glm::vec2& texCoordBottomLeft, const glm::vec2& texCoordBottomRight, const glm::vec2& texCoordTopRight, const glm::vec4& color, int id) { #ifdef WANT_DEBUG qCDebug(renderutils) << "renderQuad() vec3 + texture VBO..."; qCDebug(renderutils) << " topLeft:" << topLeft; qCDebug(renderutils) << " bottomLeft:" << bottomLeft; qCDebug(renderutils) << " bottomRight:" << bottomRight; qCDebug(renderutils) << " topRight:" << topRight; qCDebug(renderutils) << " texCoordTopLeft:" << texCoordTopLeft; qCDebug(renderutils) << " texCoordBottomRight:" << texCoordBottomRight; qCDebug(renderutils) << " color:" << color; #endif //def WANT_DEBUG bool registered = (id != UNKNOWN_ID); Vec3PairVec4Pair key(Vec3Pair(topLeft, bottomRight), Vec4Pair(glm::vec4(texCoordTopLeft.x,texCoordTopLeft.y,texCoordBottomRight.x,texCoordBottomRight.y), color)); BatchItemDetails& details = registered ? _registeredQuad3DTextures[id] : _quad3DTextures[key]; // if this is a registered quad, and we have buffers, then check to see if the geometry changed and rebuild if needed if (registered && details.isCreated) { Vec3PairVec4Pair& lastKey = _lastRegisteredQuad3DTexture[id]; if (lastKey != key) { details.clear(); _lastRegisteredQuad3DTexture[id] = key; #ifdef WANT_DEBUG qCDebug(renderutils) << "renderQuad() 3D+texture ... RELEASING REGISTERED"; #endif // def WANT_DEBUG } #ifdef WANT_DEBUG else { qCDebug(renderutils) << "renderQuad() 3D+texture ... REUSING PREVIOUSLY REGISTERED"; } #endif // def WANT_DEBUG } const int FLOATS_PER_VERTEX = 3 + 3 + 2; // vertices + normals + tex coords const int VERTICES = 4; // 1 quad = 4 vertices const int NUM_POS_COORDS = 3; const int NUM_NORMAL_COORDS = 3; const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); const int VERTEX_TEXCOORD_OFFSET = VERTEX_NORMAL_OFFSET + NUM_NORMAL_COORDS * sizeof(float); if (!details.isCreated) { details.isCreated = true; details.vertices = VERTICES; details.vertexSize = FLOATS_PER_VERTEX; // NOTE: this isn't used for BatchItemDetails maybe we can get rid of it auto verticesBuffer = std::make_shared<gpu::Buffer>(); auto colorBuffer = std::make_shared<gpu::Buffer>(); auto streamFormat = std::make_shared<gpu::Stream::Format>(); auto stream = std::make_shared<gpu::BufferStream>(); details.verticesBuffer = verticesBuffer; details.colorBuffer = colorBuffer; details.streamFormat = streamFormat; details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); const glm::vec3 NORMAL(0.0f, 0.0f, 1.0f); float vertexBuffer[VERTICES * FLOATS_PER_VERTEX] = { bottomLeft.x, bottomLeft.y, bottomLeft.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordBottomLeft.x, texCoordBottomLeft.y, bottomRight.x, bottomRight.y, bottomRight.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordBottomRight.x, texCoordBottomRight.y, topLeft.x, topLeft.y, topLeft.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordTopLeft.x, texCoordTopLeft.y, topRight.x, topRight.y, topRight.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordTopRight.x, texCoordTopRight.y, }; const int NUM_COLOR_SCALARS_PER_QUAD = 4; int compactColor = ((int(color.x * 255.0f) & 0xFF)) | ((int(color.y * 255.0f) & 0xFF) << 8) | ((int(color.z * 255.0f) & 0xFF) << 16) | ((int(color.w * 255.0f) & 0xFF) << 24); int colors[NUM_COLOR_SCALARS_PER_QUAD] = { compactColor, compactColor, compactColor, compactColor }; details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer); details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors); } batch.setInputFormat(details.streamFormat); batch.setInputStream(0, *details.stream); batch.draw(gpu::TRIANGLE_STRIP, 4, 0);} void GeometryCache::renderDashedLine(gpu::Batch& batch, const glm::vec3& start, const glm::vec3& end, const glm::vec4& color, const float dash_length, const float gap_length, int id) { bool registered = (id != UNKNOWN_ID); Vec3PairVec2Pair key(Vec3Pair(start, end), Vec2Pair(glm::vec2(color.x, color.y), glm::vec2(color.z, color.w))); BatchItemDetails& details = registered ? _registeredDashedLines[id] : _dashedLines[key]; // if this is a registered , and we have buffers, then check to see if the geometry changed and rebuild if needed if (registered && details.isCreated) { if (_lastRegisteredDashedLines[id] != key) { details.clear(); _lastRegisteredDashedLines[id] = key; #ifdef WANT_DEBUG qCDebug(renderutils) << "renderDashedLine()... RELEASING REGISTERED"; #endif // def WANT_DEBUG } } if (!details.isCreated) { int compactColor = ((int(color.x * 255.0f) & 0xFF)) | ((int(color.y * 255.0f) & 0xFF) << 8) | ((int(color.z * 255.0f) & 0xFF) << 16) | ((int(color.w * 255.0f) & 0xFF) << 24); // draw each line segment with appropriate gaps const float SEGMENT_LENGTH = dash_length + gap_length; float length = glm::distance(start, end); float segmentCount = length / SEGMENT_LENGTH; int segmentCountFloor = (int)glm::floor(segmentCount); glm::vec3 segmentVector = (end - start) / segmentCount; glm::vec3 dashVector = segmentVector / SEGMENT_LENGTH * dash_length; glm::vec3 gapVector = segmentVector / SEGMENT_LENGTH * gap_length; const int FLOATS_PER_VERTEX = 3 + 3; // vertices + normals const int NUM_POS_COORDS = 3; const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); details.vertices = (segmentCountFloor + 1) * 2; details.vertexSize = FLOATS_PER_VERTEX; details.isCreated = true; auto verticesBuffer = std::make_shared<gpu::Buffer>(); auto colorBuffer = std::make_shared<gpu::Buffer>(); auto streamFormat = std::make_shared<gpu::Stream::Format>(); auto stream = std::make_shared<gpu::BufferStream>(); details.verticesBuffer = verticesBuffer; details.colorBuffer = colorBuffer; details.streamFormat = streamFormat; details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); int* colorData = new int[details.vertices]; int* colorDataAt = colorData; float* vertexData = new float[details.vertices * FLOATS_PER_VERTEX]; float* vertex = vertexData; const glm::vec3 NORMAL(1.0f, 0.0f, 0.0f); glm::vec3 point = start; *(vertex++) = point.x; *(vertex++) = point.y; *(vertex++) = point.z; *(vertex++) = NORMAL.x; *(vertex++) = NORMAL.y; *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; for (int i = 0; i < segmentCountFloor; i++) { point += dashVector; *(vertex++) = point.x; *(vertex++) = point.y; *(vertex++) = point.z; *(vertex++) = NORMAL.x; *(vertex++) = NORMAL.y; *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; point += gapVector; *(vertex++) = point.x; *(vertex++) = point.y; *(vertex++) = point.z; *(vertex++) = NORMAL.x; *(vertex++) = NORMAL.y; *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; } *(vertex++) = end.x; *(vertex++) = end.y; *(vertex++) = end.z; *(vertex++) = NORMAL.x; *(vertex++) = NORMAL.y; *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; details.verticesBuffer->append(sizeof(float) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData); details.colorBuffer->append(sizeof(int) * details.vertices, (gpu::Byte*) colorData); delete[] vertexData; delete[] colorData; #ifdef WANT_DEBUG if (registered) { qCDebug(renderutils) << "new registered dashed line buffer made -- _registeredVertices:" << _registeredDashedLines.size(); } else { qCDebug(renderutils) << "new dashed lines buffer made -- _dashedLines:" << _dashedLines.size(); } #endif } batch.setInputFormat(details.streamFormat); batch.setInputStream(0, *details.stream); batch.draw(gpu::LINES, details.vertices, 0);} int GeometryCache::BatchItemDetails::population = 0; GeometryCache::BatchItemDetails::BatchItemDetails() : verticesBuffer(NULL), colorBuffer(NULL), streamFormat(NULL), stream(NULL), vertices(0), vertexSize(0), isCreated(false){ population++; #ifdef WANT_DEBUG qCDebug(renderutils) << "BatchItemDetails()... population:" << population << "**********************************"; #endif} GeometryCache::BatchItemDetails::BatchItemDetails(const GeometryCache::BatchItemDetails& other) : verticesBuffer(other.verticesBuffer), colorBuffer(other.colorBuffer), streamFormat(other.streamFormat), stream(other.stream), vertices(other.vertices), vertexSize(other.vertexSize), isCreated(other.isCreated){ population++; #ifdef WANT_DEBUG qCDebug(renderutils) << "BatchItemDetails()... population:" << population << "**********************************"; #endif} GeometryCache::BatchItemDetails::~BatchItemDetails() { population--; clear(); #ifdef WANT_DEBUG qCDebug(renderutils) << "~BatchItemDetails()... population:" << population << "**********************************"; #endif} void GeometryCache::BatchItemDetails::clear() { isCreated = false; verticesBuffer.reset(); colorBuffer.reset(); streamFormat.reset(); stream.reset();} void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec4& color1, const glm::vec4& color2, int id) { bool registered = (id != UNKNOWN_ID); Vec3Pair key(p1, p2); BatchItemDetails& details = registered ? _registeredLine3DVBOs[id] : _line3DVBOs[key]; int compactColor1 = ((int(color1.x * 255.0f) & 0xFF)) | ((int(color1.y * 255.0f) & 0xFF) << 8) | ((int(color1.z * 255.0f) & 0xFF) << 16) | ((int(color1.w * 255.0f) & 0xFF) << 24); int compactColor2 = ((int(color2.x * 255.0f) & 0xFF)) | ((int(color2.y * 255.0f) & 0xFF) << 8) | ((int(color2.z * 255.0f) & 0xFF) << 16) | ((int(color2.w * 255.0f) & 0xFF) << 24); // if this is a registered quad, and we have buffers, then check to see if the geometry changed and rebuild if needed if (registered && details.isCreated) { Vec3Pair& lastKey = _lastRegisteredLine3D[id]; if (lastKey != key) { details.clear(); _lastRegisteredLine3D[id] = key; #ifdef WANT_DEBUG qCDebug(renderutils) << "renderLine() 3D ... RELEASING REGISTERED line"; #endif // def WANT_DEBUG } #ifdef WANT_DEBUG else { qCDebug(renderutils) << "renderLine() 3D ... REUSING PREVIOUSLY REGISTERED line"; } #endif // def WANT_DEBUG } const int FLOATS_PER_VERTEX = 3 + 3; // vertices + normals const int NUM_POS_COORDS = 3; const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); const int vertices = 2; if (!details.isCreated) { details.isCreated = true; details.vertices = vertices; details.vertexSize = FLOATS_PER_VERTEX; auto verticesBuffer = std::make_shared<gpu::Buffer>(); auto colorBuffer = std::make_shared<gpu::Buffer>(); auto streamFormat = std::make_shared<gpu::Stream::Format>(); auto stream = std::make_shared<gpu::BufferStream>(); details.verticesBuffer = verticesBuffer; details.colorBuffer = colorBuffer; details.streamFormat = streamFormat; details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); const glm::vec3 NORMAL(1.0f, 0.0f, 0.0f); float vertexBuffer[vertices * FLOATS_PER_VERTEX] = { p1.x, p1.y, p1.z, NORMAL.x, NORMAL.y, NORMAL.z, p2.x, p2.y, p2.z, NORMAL.x, NORMAL.y, NORMAL.z}; const int NUM_COLOR_SCALARS = 2; int colors[NUM_COLOR_SCALARS] = { compactColor1, compactColor2 }; details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer); details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors); #ifdef WANT_DEBUG if (id == UNKNOWN_ID) { qCDebug(renderutils) << "new renderLine() 3D VBO made -- _line3DVBOs.size():" << _line3DVBOs.size(); } else { qCDebug(renderutils) << "new registered renderLine() 3D VBO made -- _registeredLine3DVBOs.size():" << _registeredLine3DVBOs.size(); } #endif } // this is what it takes to render a quad batch.setInputFormat(details.streamFormat); batch.setInputStream(0, *details.stream); batch.draw(gpu::LINES, 2, 0);} void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2, const glm::vec4& color1, const glm::vec4& color2, int id) { bool registered = (id != UNKNOWN_ID); Vec2Pair key(p1, p2); BatchItemDetails& details = registered ? _registeredLine2DVBOs[id] : _line2DVBOs[key]; int compactColor1 = ((int(color1.x * 255.0f) & 0xFF)) | ((int(color1.y * 255.0f) & 0xFF) << 8) | ((int(color1.z * 255.0f) & 0xFF) << 16) | ((int(color1.w * 255.0f) & 0xFF) << 24); int compactColor2 = ((int(color2.x * 255.0f) & 0xFF)) | ((int(color2.y * 255.0f) & 0xFF) << 8) | ((int(color2.z * 255.0f) & 0xFF) << 16) | ((int(color2.w * 255.0f) & 0xFF) << 24); // if this is a registered quad, and we have buffers, then check to see if the geometry changed and rebuild if needed if (registered && details.isCreated) { Vec2Pair& lastKey = _lastRegisteredLine2D[id]; if (lastKey != key) { details.clear(); _lastRegisteredLine2D[id] = key; #ifdef WANT_DEBUG qCDebug(renderutils) << "renderLine() 2D ... RELEASING REGISTERED line"; #endif // def WANT_DEBUG } #ifdef WANT_DEBUG else { qCDebug(renderutils) << "renderLine() 2D ... REUSING PREVIOUSLY REGISTERED line"; } #endif // def WANT_DEBUG } const int FLOATS_PER_VERTEX = 2; const int vertices = 2; if (!details.isCreated) { details.isCreated = true; details.vertices = vertices; details.vertexSize = FLOATS_PER_VERTEX; auto verticesBuffer = std::make_shared<gpu::Buffer>(); auto colorBuffer = std::make_shared<gpu::Buffer>(); auto streamFormat = std::make_shared<gpu::Stream::Format>(); auto stream = std::make_shared<gpu::BufferStream>(); details.verticesBuffer = verticesBuffer; details.colorBuffer = colorBuffer; details.streamFormat = streamFormat; details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); float vertexBuffer[vertices * FLOATS_PER_VERTEX] = { p1.x, p1.y, p2.x, p2.y }; const int NUM_COLOR_SCALARS = 2; int colors[NUM_COLOR_SCALARS] = { compactColor1, compactColor2 }; details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer); details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors); #ifdef WANT_DEBUG if (id == UNKNOWN_ID) { qCDebug(renderutils) << "new renderLine() 2D VBO made -- _line3DVBOs.size():" << _line2DVBOs.size(); } else { qCDebug(renderutils) << "new registered renderLine() 2D VBO made -- _registeredLine2DVBOs.size():" << _registeredLine2DVBOs.size(); } #endif } // this is what it takes to render a quad batch.setInputFormat(details.streamFormat); batch.setInputStream(0, *details.stream); batch.draw(gpu::LINES, 2, 0);} void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { if (!_standardDrawPipeline) { auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); auto ps = gpu::Shader::createPixel(std::string(standardDrawTexture_frag)); auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); auto state = std::make_shared<gpu::State>(); // enable decal blend state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); _standardDrawPipeline = gpu::Pipeline::create(program, state); auto stateNoBlend = std::make_shared<gpu::State>(); auto noBlendPS = gpu::StandardShaderLib::getDrawTextureOpaquePS(); auto programNoBlend = gpu::Shader::createProgram(vs, noBlendPS); gpu::Shader::makeProgram((*programNoBlend)); _standardDrawPipelineNoBlend = gpu::Pipeline::create(programNoBlend, stateNoBlend); } if (noBlend) { batch.setPipeline(_standardDrawPipelineNoBlend); } else { batch.setPipeline(_standardDrawPipeline); }} void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered) { if (!_gridPipeline) { auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); auto ps = gpu::Shader::createPixel(std::string(grid_frag)); auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); _gridSlot = program->getBuffers().findLocation("gridBuffer"); auto stateLayered = std::make_shared<gpu::State>(); stateLayered->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); _gridPipelineLayered = gpu::Pipeline::create(program, stateLayered); auto state = std::make_shared<gpu::State>(stateLayered->getValues()); const float DEPTH_BIAS = 0.001f; state->setDepthBias(DEPTH_BIAS); state->setDepthTest(true, false, gpu::LESS_EQUAL); _gridPipeline = gpu::Pipeline::create(program, state); } gpu::PipelinePointer pipeline = isLayered ? _gridPipelineLayered : _gridPipeline; batch.setPipeline(pipeline); batch.setUniformBuffer(_gridSlot, gridBuffer);} class SimpleProgramKey {public: enum FlagBit { IS_TEXTURED_FLAG = 0,Lines 1001–1500 of 1698. Previous lines Load more
void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec3& topLeft, const glm::vec3& bottomLeft, const glm::vec3& bottomRight, const glm::vec3& topRight, const glm::vec2& texCoordTopLeft, const glm::vec2& texCoordBottomLeft, const glm::vec2& texCoordBottomRight, const glm::vec2& texCoordTopRight, const glm::vec4& color, int id) { #ifdef WANT_DEBUG qCDebug(renderutils) << "renderQuad() vec3 + texture VBO..."; qCDebug(renderutils) << " topLeft:" << topLeft; qCDebug(renderutils) << " bottomLeft:" << bottomLeft; qCDebug(renderutils) << " bottomRight:" << bottomRight; qCDebug(renderutils) << " topRight:" << topRight; qCDebug(renderutils) << " texCoordTopLeft:" << texCoordTopLeft; qCDebug(renderutils) << " texCoordBottomRight:" << texCoordBottomRight; qCDebug(renderutils) << " color:" << color; #endif //def WANT_DEBUG bool registered = (id != UNKNOWN_ID); Vec3PairVec4Pair key(Vec3Pair(topLeft, bottomRight), Vec4Pair(glm::vec4(texCoordTopLeft.x,texCoordTopLeft.y,texCoordBottomRight.x,texCoordBottomRight.y), color)); BatchItemDetails& details = registered ? _registeredQuad3DTextures[id] : _quad3DTextures[key]; // if this is a registered quad, and we have buffers, then check to see if the geometry changed and rebuild if needed if (registered && details.isCreated) { Vec3PairVec4Pair& lastKey = _lastRegisteredQuad3DTexture[id]; if (lastKey != key) { details.clear(); _lastRegisteredQuad3DTexture[id] = key; #ifdef WANT_DEBUG qCDebug(renderutils) << "renderQuad() 3D+texture ... RELEASING REGISTERED"; #endif // def WANT_DEBUG } #ifdef WANT_DEBUG else { qCDebug(renderutils) << "renderQuad() 3D+texture ... REUSING PREVIOUSLY REGISTERED"; } #endif // def WANT_DEBUG } const int FLOATS_PER_VERTEX = 3 + 3 + 2; // vertices + normals + tex coords const int VERTICES = 4; // 1 quad = 4 vertices const int NUM_POS_COORDS = 3; const int NUM_NORMAL_COORDS = 3; const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); const int VERTEX_TEXCOORD_OFFSET = VERTEX_NORMAL_OFFSET + NUM_NORMAL_COORDS * sizeof(float); if (!details.isCreated) { details.isCreated = true; details.vertices = VERTICES; details.vertexSize = FLOATS_PER_VERTEX; // NOTE: this isn't used for BatchItemDetails maybe we can get rid of it auto verticesBuffer = std::make_shared<gpu::Buffer>(); auto colorBuffer = std::make_shared<gpu::Buffer>(); auto streamFormat = std::make_shared<gpu::Stream::Format>(); auto stream = std::make_shared<gpu::BufferStream>(); details.verticesBuffer = verticesBuffer; details.colorBuffer = colorBuffer; details.streamFormat = streamFormat; details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); const glm::vec3 NORMAL(0.0f, 0.0f, 1.0f); float vertexBuffer[VERTICES * FLOATS_PER_VERTEX] = { bottomLeft.x, bottomLeft.y, bottomLeft.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordBottomLeft.x, texCoordBottomLeft.y, bottomRight.x, bottomRight.y, bottomRight.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordBottomRight.x, texCoordBottomRight.y, topLeft.x, topLeft.y, topLeft.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordTopLeft.x, texCoordTopLeft.y, topRight.x, topRight.y, topRight.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordTopRight.x, texCoordTopRight.y, }; const int NUM_COLOR_SCALARS_PER_QUAD = 4; int compactColor = ((int(color.x * 255.0f) & 0xFF)) | ((int(color.y * 255.0f) & 0xFF) << 8) | ((int(color.z * 255.0f) & 0xFF) << 16) | ((int(color.w * 255.0f) & 0xFF) << 24); int colors[NUM_COLOR_SCALARS_PER_QUAD] = { compactColor, compactColor, compactColor, compactColor }; details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer); details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors); } batch.setInputFormat(details.streamFormat); batch.setInputStream(0, *details.stream); batch.draw(gpu::TRIANGLE_STRIP, 4, 0); } void GeometryCache::renderDashedLine(gpu::Batch& batch, const glm::vec3& start, const glm::vec3& end, const glm::vec4& color, const float dash_length, const float gap_length, int id) { bool registered = (id != UNKNOWN_ID); Vec3PairVec2Pair key(Vec3Pair(start, end), Vec2Pair(glm::vec2(color.x, color.y), glm::vec2(color.z, color.w))); BatchItemDetails& details = registered ? _registeredDashedLines[id] : _dashedLines[key]; // if this is a registered , and we have buffers, then check to see if the geometry changed and rebuild if needed if (registered && details.isCreated) { if (_lastRegisteredDashedLines[id] != key) { details.clear(); _lastRegisteredDashedLines[id] = key; #ifdef WANT_DEBUG qCDebug(renderutils) << "renderDashedLine()... RELEASING REGISTERED"; #endif // def WANT_DEBUG } } if (!details.isCreated) { int compactColor = ((int(color.x * 255.0f) & 0xFF)) | ((int(color.y * 255.0f) & 0xFF) << 8) | ((int(color.z * 255.0f) & 0xFF) << 16) | ((int(color.w * 255.0f) & 0xFF) << 24); // draw each line segment with appropriate gaps const float SEGMENT_LENGTH = dash_length + gap_length; float length = glm::distance(start, end); float segmentCount = length / SEGMENT_LENGTH; int segmentCountFloor = (int)glm::floor(segmentCount); glm::vec3 segmentVector = (end - start) / segmentCount; glm::vec3 dashVector = segmentVector / SEGMENT_LENGTH * dash_length; glm::vec3 gapVector = segmentVector / SEGMENT_LENGTH * gap_length; const int FLOATS_PER_VERTEX = 3 + 3; // vertices + normals const int NUM_POS_COORDS = 3; const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); details.vertices = (segmentCountFloor + 1) * 2; details.vertexSize = FLOATS_PER_VERTEX; details.isCreated = true; auto verticesBuffer = std::make_shared<gpu::Buffer>(); auto colorBuffer = std::make_shared<gpu::Buffer>(); auto streamFormat = std::make_shared<gpu::Stream::Format>(); auto stream = std::make_shared<gpu::BufferStream>(); details.verticesBuffer = verticesBuffer; details.colorBuffer = colorBuffer; details.streamFormat = streamFormat; details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); int* colorData = new int[details.vertices]; int* colorDataAt = colorData; float* vertexData = new float[details.vertices * FLOATS_PER_VERTEX]; float* vertex = vertexData; const glm::vec3 NORMAL(1.0f, 0.0f, 0.0f); glm::vec3 point = start; *(vertex++) = point.x; *(vertex++) = point.y; *(vertex++) = point.z; *(vertex++) = NORMAL.x; *(vertex++) = NORMAL.y; *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; for (int i = 0; i < segmentCountFloor; i++) { point += dashVector; *(vertex++) = point.x; *(vertex++) = point.y; *(vertex++) = point.z; *(vertex++) = NORMAL.x; *(vertex++) = NORMAL.y; *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; point += gapVector; *(vertex++) = point.x; *(vertex++) = point.y; *(vertex++) = point.z; *(vertex++) = NORMAL.x; *(vertex++) = NORMAL.y; *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; } *(vertex++) = end.x; *(vertex++) = end.y; *(vertex++) = end.z; *(vertex++) = NORMAL.x; *(vertex++) = NORMAL.y; *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; details.verticesBuffer->append(sizeof(float) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData); details.colorBuffer->append(sizeof(int) * details.vertices, (gpu::Byte*) colorData); delete[] vertexData; delete[] colorData; #ifdef WANT_DEBUG if (registered) { qCDebug(renderutils) << "new registered dashed line buffer made -- _registeredVertices:" << _registeredDashedLines.size(); } else { qCDebug(renderutils) << "new dashed lines buffer made -- _dashedLines:" << _dashedLines.size(); } #endif } batch.setInputFormat(details.streamFormat); batch.setInputStream(0, *details.stream); batch.draw(gpu::LINES, details.vertices, 0); } int GeometryCache::BatchItemDetails::population = 0; GeometryCache::BatchItemDetails::BatchItemDetails() : verticesBuffer(NULL), colorBuffer(NULL), streamFormat(NULL), stream(NULL), vertices(0), vertexSize(0), isCreated(false) { population++; #ifdef WANT_DEBUG qCDebug(renderutils) << "BatchItemDetails()... population:" << population << "**********************************"; #endif } GeometryCache::BatchItemDetails::BatchItemDetails(const GeometryCache::BatchItemDetails& other) : verticesBuffer(other.verticesBuffer), colorBuffer(other.colorBuffer), streamFormat(other.streamFormat), stream(other.stream), vertices(other.vertices), vertexSize(other.vertexSize), isCreated(other.isCreated) { population++; #ifdef WANT_DEBUG qCDebug(renderutils) << "BatchItemDetails()... population:" << population << "**********************************"; #endif } GeometryCache::BatchItemDetails::~BatchItemDetails() { population--; clear(); #ifdef WANT_DEBUG qCDebug(renderutils) << "~BatchItemDetails()... population:" << population << "**********************************"; #endif } void GeometryCache::BatchItemDetails::clear() { isCreated = false; verticesBuffer.reset(); colorBuffer.reset(); streamFormat.reset(); stream.reset(); } void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec4& color1, const glm::vec4& color2, int id) { bool registered = (id != UNKNOWN_ID); Vec3Pair key(p1, p2); BatchItemDetails& details = registered ? _registeredLine3DVBOs[id] : _line3DVBOs[key]; int compactColor1 = ((int(color1.x * 255.0f) & 0xFF)) | ((int(color1.y * 255.0f) & 0xFF) << 8) | ((int(color1.z * 255.0f) & 0xFF) << 16) | ((int(color1.w * 255.0f) & 0xFF) << 24); int compactColor2 = ((int(color2.x * 255.0f) & 0xFF)) | ((int(color2.y * 255.0f) & 0xFF) << 8) | ((int(color2.z * 255.0f) & 0xFF) << 16) | ((int(color2.w * 255.0f) & 0xFF) << 24); // if this is a registered quad, and we have buffers, then check to see if the geometry changed and rebuild if needed if (registered && details.isCreated) { Vec3Pair& lastKey = _lastRegisteredLine3D[id]; if (lastKey != key) { details.clear(); _lastRegisteredLine3D[id] = key; #ifdef WANT_DEBUG qCDebug(renderutils) << "renderLine() 3D ... RELEASING REGISTERED line"; #endif // def WANT_DEBUG } #ifdef WANT_DEBUG else { qCDebug(renderutils) << "renderLine() 3D ... REUSING PREVIOUSLY REGISTERED line"; } #endif // def WANT_DEBUG } const int FLOATS_PER_VERTEX = 3 + 3; // vertices + normals const int NUM_POS_COORDS = 3; const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); const int vertices = 2; if (!details.isCreated) { details.isCreated = true; details.vertices = vertices; details.vertexSize = FLOATS_PER_VERTEX; auto verticesBuffer = std::make_shared<gpu::Buffer>(); auto colorBuffer = std::make_shared<gpu::Buffer>(); auto streamFormat = std::make_shared<gpu::Stream::Format>(); auto stream = std::make_shared<gpu::BufferStream>(); details.verticesBuffer = verticesBuffer; details.colorBuffer = colorBuffer; details.streamFormat = streamFormat; details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); const glm::vec3 NORMAL(1.0f, 0.0f, 0.0f); float vertexBuffer[vertices * FLOATS_PER_VERTEX] = { p1.x, p1.y, p1.z, NORMAL.x, NORMAL.y, NORMAL.z, p2.x, p2.y, p2.z, NORMAL.x, NORMAL.y, NORMAL.z}; const int NUM_COLOR_SCALARS = 2; int colors[NUM_COLOR_SCALARS] = { compactColor1, compactColor2 }; details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer); details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors); #ifdef WANT_DEBUG if (id == UNKNOWN_ID) { qCDebug(renderutils) << "new renderLine() 3D VBO made -- _line3DVBOs.size():" << _line3DVBOs.size(); } else { qCDebug(renderutils) << "new registered renderLine() 3D VBO made -- _registeredLine3DVBOs.size():" << _registeredLine3DVBOs.size(); } #endif } // this is what it takes to render a quad batch.setInputFormat(details.streamFormat); batch.setInputStream(0, *details.stream); batch.draw(gpu::LINES, 2, 0); } void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2, const glm::vec4& color1, const glm::vec4& color2, int id) { bool registered = (id != UNKNOWN_ID); Vec2Pair key(p1, p2); BatchItemDetails& details = registered ? _registeredLine2DVBOs[id] : _line2DVBOs[key]; int compactColor1 = ((int(color1.x * 255.0f) & 0xFF)) | ((int(color1.y * 255.0f) & 0xFF) << 8) | ((int(color1.z * 255.0f) & 0xFF) << 16) | ((int(color1.w * 255.0f) & 0xFF) << 24); int compactColor2 = ((int(color2.x * 255.0f) & 0xFF)) | ((int(color2.y * 255.0f) & 0xFF) << 8) | ((int(color2.z * 255.0f) & 0xFF) << 16) | ((int(color2.w * 255.0f) & 0xFF) << 24); // if this is a registered quad, and we have buffers, then check to see if the geometry changed and rebuild if needed if (registered && details.isCreated) { Vec2Pair& lastKey = _lastRegisteredLine2D[id]; if (lastKey != key) { details.clear(); _lastRegisteredLine2D[id] = key; #ifdef WANT_DEBUG qCDebug(renderutils) << "renderLine() 2D ... RELEASING REGISTERED line"; #endif // def WANT_DEBUG } #ifdef WANT_DEBUG else { qCDebug(renderutils) << "renderLine() 2D ... REUSING PREVIOUSLY REGISTERED line"; } #endif // def WANT_DEBUG } const int FLOATS_PER_VERTEX = 2; const int vertices = 2; if (!details.isCreated) { details.isCreated = true; details.vertices = vertices; details.vertexSize = FLOATS_PER_VERTEX; auto verticesBuffer = std::make_shared<gpu::Buffer>(); auto colorBuffer = std::make_shared<gpu::Buffer>(); auto streamFormat = std::make_shared<gpu::Stream::Format>(); auto stream = std::make_shared<gpu::BufferStream>(); details.verticesBuffer = verticesBuffer; details.colorBuffer = colorBuffer; details.streamFormat = streamFormat; details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); float vertexBuffer[vertices * FLOATS_PER_VERTEX] = { p1.x, p1.y, p2.x, p2.y }; const int NUM_COLOR_SCALARS = 2; int colors[NUM_COLOR_SCALARS] = { compactColor1, compactColor2 }; details.verticesBuffer->append(sizeof(vertexBuffer), (gpu::Byte*) vertexBuffer); details.colorBuffer->append(sizeof(colors), (gpu::Byte*) colors); #ifdef WANT_DEBUG if (id == UNKNOWN_ID) { qCDebug(renderutils) << "new renderLine() 2D VBO made -- _line3DVBOs.size():" << _line2DVBOs.size(); } else { qCDebug(renderutils) << "new registered renderLine() 2D VBO made -- _registeredLine2DVBOs.size():" << _registeredLine2DVBOs.size(); } #endif } // this is what it takes to render a quad batch.setInputFormat(details.streamFormat); batch.setInputStream(0, *details.stream); batch.draw(gpu::LINES, 2, 0); } void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { if (!_standardDrawPipeline) { auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); auto ps = gpu::Shader::createPixel(std::string(standardDrawTexture_frag)); auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); auto state = std::make_shared<gpu::State>(); // enable decal blend state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); _standardDrawPipeline = gpu::Pipeline::create(program, state); auto stateNoBlend = std::make_shared<gpu::State>(); auto noBlendPS = gpu::StandardShaderLib::getDrawTextureOpaquePS(); auto programNoBlend = gpu::Shader::createProgram(vs, noBlendPS); gpu::Shader::makeProgram((*programNoBlend)); _standardDrawPipelineNoBlend = gpu::Pipeline::create(programNoBlend, stateNoBlend); } if (noBlend) { batch.setPipeline(_standardDrawPipelineNoBlend); } else { batch.setPipeline(_standardDrawPipeline); } } void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered) { if (!_gridPipeline) { auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); auto ps = gpu::Shader::createPixel(std::string(grid_frag)); auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); _gridSlot = program->getBuffers().findLocation("gridBuffer"); auto stateLayered = std::make_shared<gpu::State>(); stateLayered->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); _gridPipelineLayered = gpu::Pipeline::create(program, stateLayered); auto state = std::make_shared<gpu::State>(stateLayered->getValues()); const float DEPTH_BIAS = 0.001f; state->setDepthBias(DEPTH_BIAS); state->setDepthTest(true, false, gpu::LESS_EQUAL); _gridPipeline = gpu::Pipeline::create(program, state); } gpu::PipelinePointer pipeline = isLayered ? _gridPipelineLayered : _gridPipeline; batch.setPipeline(pipeline); batch.setUniformBuffer(_gridSlot, gridBuffer); } class SimpleProgramKey { public: enum FlagBit { IS_TEXTURED_FLAG = 0,