From 82c041d06a20d9e244e05e528f7d3060be9ea033 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 18 Oct 2015 22:52:20 -0700 Subject: [PATCH 1/2] Adding git attributes file --- .gitattributes | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..5a6cc5e815 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,25 @@ +*.cpp text +*.c text +*.h text +*.qml text +*.js text +*.json text +*.slv text +*.slf text +*.slh text +*.vert text +*.frag text +*.fst text +*.ini text +*.html text +*.ts text +*.txt text + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.wav binary +*.fbx text +*.dds text +*.svg text +*.ttf text From 282cdadf6381eb1d21f14072e3b269883c3e4170 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 18 Oct 2015 22:55:14 -0700 Subject: [PATCH 2/2] Fixing line endings --- .../src/DeferredLightingEffect.cpp | 1788 +++++++-------- .../render-utils/src/RenderDeferredTask.cpp | 6 +- libraries/render-utils/src/Skinning.slh | 138 +- .../directional_ambient_light_shadow_map.slf | 2 +- .../src/directional_light_shadow_map.slf | 2 +- .../directional_skybox_light_shadow_map.slf | 2 +- .../render-utils/src/model_normal_map.slv | 88 +- libraries/render-utils/src/model_shadow.slv | 52 +- libraries/render-utils/src/skin_model.slv | 96 +- .../src/skin_model_normal_map.slv | 112 +- .../render-utils/src/skin_model_shadow.slv | 58 +- libraries/render/src/render/DrawStatus.cpp | 326 +-- libraries/render/src/render/DrawStatus.h | 86 +- .../render/src/render/drawItemBounds.slv | 70 +- .../render/src/render/drawItemStatus.slv | 204 +- .../src/SceneScriptingInterface.cpp | 4 +- tools/scribe/src/TextTemplate.cpp | 1978 ++++++++--------- tools/scribe/src/TextTemplate.h | 392 ++-- 18 files changed, 2702 insertions(+), 2702 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e9d2cf4061..57e3129ef8 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -1,894 +1,894 @@ -// -// DeferredLightingEffect.cpp -// interface/src/renderer -// -// Created by Andrzej Kapolka on 9/11/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "DeferredLightingEffect.h" - -#include -#include -#include - -#include -#include -#include - -#include "AbstractViewStateInterface.h" -#include "GeometryCache.h" -#include "TextureCache.h" -#include "FramebufferCache.h" - - -#include "simple_vert.h" -#include "simple_textured_frag.h" -#include "simple_textured_emisive_frag.h" - -#include "deferred_light_vert.h" -#include "deferred_light_limited_vert.h" -#include "deferred_light_spot_vert.h" - -#include "directional_light_frag.h" -#include "directional_light_shadow_map_frag.h" -#include "directional_light_cascaded_shadow_map_frag.h" - -#include "directional_ambient_light_frag.h" -#include "directional_ambient_light_shadow_map_frag.h" -#include "directional_ambient_light_cascaded_shadow_map_frag.h" - -#include "directional_skybox_light_frag.h" -#include "directional_skybox_light_shadow_map_frag.h" -#include "directional_skybox_light_cascaded_shadow_map_frag.h" - -#include "point_light_frag.h" -#include "spot_light_frag.h" - -static const std::string glowIntensityShaderHandle = "glowIntensity"; - -struct LightLocations { - int shadowDistances; - int shadowScale; - int radius; - int ambientSphere; - int lightBufferUnit; - int atmosphereBufferUnit; - int texcoordMat; - int coneParam; - int deferredTransformBuffer; -}; - -static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); - - -gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config) { - auto it = _simplePrograms.find(config); - if (it != _simplePrograms.end()) { - return it.value(); - } - - auto state = std::make_shared(); - if (config.isCulled()) { - state->setCullMode(gpu::State::CULL_BACK); - } else { - state->setCullMode(gpu::State::CULL_NONE); - } - state->setDepthTest(true, true, gpu::LESS_EQUAL); - if (config.hasDepthBias()) { - state->setDepthBias(1.0f); - state->setDepthBiasSlopeScale(1.0f); - } - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; - gpu::PipelinePointer pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); - _simplePrograms.insert(config, pipeline); - return pipeline; -} - -void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { - auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert))); - auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_frag))); - auto PSEmissive = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_emisive_frag))); - - _simpleShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); - _emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive)); - - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); - gpu::Shader::makeProgram(*_simpleShader, slotBindings); - gpu::Shader::makeProgram(*_emissiveShader, slotBindings); - - _viewState = viewState; - _directionalLightLocations = std::make_shared(); - _directionalLightShadowMapLocations = std::make_shared(); - _directionalLightCascadedShadowMapLocations = std::make_shared(); - _directionalAmbientSphereLightLocations = std::make_shared(); - _directionalAmbientSphereLightShadowMapLocations = std::make_shared(); - _directionalAmbientSphereLightCascadedShadowMapLocations = std::make_shared(); - _directionalSkyboxLightLocations = std::make_shared(); - _directionalSkyboxLightShadowMapLocations = std::make_shared(); - _directionalSkyboxLightCascadedShadowMapLocations = std::make_shared(); - _pointLightLocations = std::make_shared(); - _spotLightLocations = std::make_shared(); - - loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations); - loadLightProgram(deferred_light_vert, directional_light_shadow_map_frag, false, _directionalLightShadowMap, - _directionalLightShadowMapLocations); - loadLightProgram(deferred_light_vert, directional_light_cascaded_shadow_map_frag, false, _directionalLightCascadedShadowMap, - _directionalLightCascadedShadowMapLocations); - - loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations); - loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_map_frag, false, _directionalAmbientSphereLightShadowMap, - _directionalAmbientSphereLightShadowMapLocations); - loadLightProgram(deferred_light_vert, directional_ambient_light_cascaded_shadow_map_frag, false, _directionalAmbientSphereLightCascadedShadowMap, - _directionalAmbientSphereLightCascadedShadowMapLocations); - - loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations); - loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_map_frag, false, _directionalSkyboxLightShadowMap, - _directionalSkyboxLightShadowMapLocations); - loadLightProgram(deferred_light_vert, directional_skybox_light_cascaded_shadow_map_frag, false, _directionalSkyboxLightCascadedShadowMap, - _directionalSkyboxLightCascadedShadowMapLocations); - - - loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations); - loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations); - - { - //auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - //auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS(); - auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); - gpu::Shader::makeProgram(*blitProgram); - auto blitState = std::make_shared(); - blitState->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - blitState->setColorWriteMask(true, true, true, false); - _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState)); - } - - // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light - _globalLights.push_back(0); - _allocatedLights.push_back(std::make_shared()); - - model::LightPointer lp = _allocatedLights[0]; - - lp->setDirection(-glm::vec3(1.0f, 1.0f, 1.0f)); - lp->setColor(glm::vec3(1.0f)); - lp->setIntensity(1.0f); - lp->setType(model::Light::SUN); - lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); -} - - - -gpu::PipelinePointer DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, - bool emmisive, bool depthBias) { - SimpleProgramKey config{textured, culled, emmisive, depthBias}; - gpu::PipelinePointer pipeline = getPipeline(config); - batch.setPipeline(pipeline); - - gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; - int glowIntensity = program->getUniforms().findLocation("glowIntensity"); - batch._glUniform1f(glowIntensity, 1.0f); - - if (!config.isTextured()) { - // If it is not textured, bind white texture and keep using textured pipeline - batch.setResourceTexture(0, DependencyManager::get()->getWhiteTexture()); - } - - batch.setResourceTexture(NORMAL_FITTING_MAP_SLOT, DependencyManager::get()->getNormalFittingTexture()); - return pipeline; -} - -uint32_t toCompactColor(const glm::vec4& color) { - uint32_t 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); - return compactColor; -} - -static const size_t INSTANCE_TRANSFORM_BUFFER = 0; -static const size_t INSTANCE_COLOR_BUFFER = 1; - -template -void renderInstances(const std::string& name, gpu::Batch& batch, const Transform& transform, const glm::vec4& color, F f) { - { - gpu::BufferPointer instanceTransformBuffer = batch.getNamedBuffer(name, INSTANCE_TRANSFORM_BUFFER); - glm::mat4 glmTransform; - instanceTransformBuffer->append(transform.getMatrix(glmTransform)); - - gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(name, INSTANCE_COLOR_BUFFER); - auto compactColor = toCompactColor(color); - instanceColorBuffer->append(compactColor); - } - - auto that = DependencyManager::get(); - batch.setupNamedCalls(name, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - auto pipeline = that->bindSimpleProgram(batch); - auto location = pipeline->getProgram()->getUniforms().findLocation("Instanced"); - - batch._glUniform1i(location, 1); - f(batch, data); - batch._glUniform1i(location, 0); - }); -} - -void DeferredLightingEffect::renderSolidSphereInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { - static const std::string INSTANCE_NAME = __FUNCTION__; - renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderShapeInstances(batch, GeometryCache::Sphere, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - }); -} - -void DeferredLightingEffect::renderWireSphereInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { - static const std::string INSTANCE_NAME = __FUNCTION__; - renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderWireShapeInstances(batch, GeometryCache::Sphere, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - }); -} - -// Enable this in a debug build to cause 'box' entities to iterate through all the -// available shape types, both solid and wireframes -//#define DEBUG_SHAPES - -void DeferredLightingEffect::renderSolidCubeInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { - static const std::string INSTANCE_NAME = __FUNCTION__; - -#ifdef DEBUG_SHAPES - static auto startTime = usecTimestampNow(); - renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - - auto usecs = usecTimestampNow(); - usecs -= startTime; - auto msecs = usecs / USECS_PER_MSEC; - float seconds = msecs; - seconds /= MSECS_PER_SECOND; - float fractionalSeconds = seconds - floor(seconds); - int shapeIndex = (int)seconds; - - // Every second we flip to the next shape. - static const int SHAPE_COUNT = 5; - GeometryCache::Shape shapes[SHAPE_COUNT] = { - GeometryCache::Cube, - GeometryCache::Tetrahedron, - GeometryCache::Sphere, - GeometryCache::Icosahedron, - GeometryCache::Line, - }; - - shapeIndex %= SHAPE_COUNT; - GeometryCache::Shape shape = shapes[shapeIndex]; - - // For the first half second for a given shape, show the wireframe, for the second half, show the solid. - if (fractionalSeconds > 0.5f) { - DependencyManager::get()->renderShapeInstances(batch, shape, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - } else { - DependencyManager::get()->renderWireShapeInstances(batch, shape, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - } - }); -#else - renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderCubeInstances(batch, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - }); -#endif -} - -void DeferredLightingEffect::renderWireCubeInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { - static const std::string INSTANCE_NAME = __FUNCTION__; - renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderWireCubeInstances(batch, data._count, - data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); - }); -} - -void DeferredLightingEffect::renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner, - const glm::vec4& color) { - bindSimpleProgram(batch); - DependencyManager::get()->renderQuad(batch, minCorner, maxCorner, color); -} - -void DeferredLightingEffect::renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, - const glm::vec4& color1, const glm::vec4& color2) { - bindSimpleProgram(batch); - DependencyManager::get()->renderLine(batch, p1, p2, color1, color2); -} - -void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color, - float intensity) { - addSpotLight(position, radius, color, intensity); -} - -void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color, - float intensity, const glm::quat& orientation, float exponent, float cutoff) { - - unsigned int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size(); - if (lightID >= _allocatedLights.size()) { - _allocatedLights.push_back(std::make_shared()); - } - model::LightPointer lp = _allocatedLights[lightID]; - - lp->setPosition(position); - lp->setMaximumRadius(radius); - lp->setColor(color); - lp->setIntensity(intensity); - //lp->setShowContour(quadraticAttenuation); - - if (exponent == 0.0f && cutoff == PI) { - lp->setType(model::Light::POINT); - _pointLights.push_back(lightID); - - } else { - lp->setOrientation(orientation); - lp->setSpotAngle(cutoff); - lp->setSpotExponent(exponent); - lp->setType(model::Light::SPOT); - _spotLights.push_back(lightID); - } -} - -void DeferredLightingEffect::prepare(RenderArgs* args) { - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - batch.enableStereo(false); - batch.setStateScissorRect(args->_viewport); - - auto primaryFbo = DependencyManager::get()->getPrimaryFramebuffer(); - - batch.setFramebuffer(primaryFbo); - // clear the normal and specular buffers - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); - const float MAX_SPECULAR_EXPONENT = 128.0f; - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR2, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f / MAX_SPECULAR_EXPONENT), true); - }); -} - -gpu::FramebufferPointer _copyFBO; - -void DeferredLightingEffect::render(RenderArgs* args) { - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - - // Allocate the parameters buffer used by all the deferred shaders - if (!_deferredTransformBuffer[0]._buffer) { - DeferredTransform parameters; - _deferredTransformBuffer[0] = gpu::BufferView(std::make_shared(sizeof(DeferredTransform), (const gpu::Byte*) ¶meters)); - _deferredTransformBuffer[1] = gpu::BufferView(std::make_shared(sizeof(DeferredTransform), (const gpu::Byte*) ¶meters)); - } - - // Framebuffer copy operations cannot function as multipass stereo operations. - batch.enableStereo(false); - - // perform deferred lighting, rendering to free fbo - auto framebufferCache = DependencyManager::get(); - - QSize framebufferSize = framebufferCache->getFrameBufferSize(); - - // binding the first framebuffer - _copyFBO = framebufferCache->getFramebuffer(); - batch.setFramebuffer(_copyFBO); - - // Clearing it - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - batch.clearColorFramebuffer(_copyFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); - - // BInd the G-Buffer surfaces - batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture()); - batch.setResourceTexture(1, framebufferCache->getPrimaryNormalTexture()); - batch.setResourceTexture(2, framebufferCache->getPrimarySpecularTexture()); - batch.setResourceTexture(3, framebufferCache->getPrimaryDepthTexture()); - - // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport) - auto monoViewport = args->_viewport; - float sMin = args->_viewport.x / (float)framebufferSize.width(); - float sWidth = args->_viewport.z / (float)framebufferSize.width(); - float tMin = args->_viewport.y / (float)framebufferSize.height(); - float tHeight = args->_viewport.w / (float)framebufferSize.height(); - - // The view frustum is the mono frustum base - auto viewFrustum = args->_viewFrustum; - - // Eval the mono projection - mat4 monoProjMat; - viewFrustum->evalProjectionMatrix(monoProjMat); - - // The mono view transform - Transform monoViewTransform; - viewFrustum->evalViewTransform(monoViewTransform); - - // THe mono view matrix coming from the mono view transform - glm::mat4 monoViewMat; - monoViewTransform.getMatrix(monoViewMat); - - // Running in stero ? - bool isStereo = args->_context->isStereo(); - int numPasses = 1; - - mat4 projMats[2]; - Transform viewTransforms[2]; - ivec4 viewports[2]; - vec4 clipQuad[2]; - vec2 screenBottomLeftCorners[2]; - vec2 screenTopRightCorners[2]; - vec4 fetchTexcoordRects[2]; - - DeferredTransform deferredTransforms[2]; - auto geometryCache = DependencyManager::get(); - - if (isStereo) { - numPasses = 2; - - mat4 eyeViews[2]; - args->_context->getStereoProjections(projMats); - args->_context->getStereoViews(eyeViews); - - float halfWidth = 0.5f * sWidth; - - for (int i = 0; i < numPasses; i++) { - // In stereo, the 2 sides are layout side by side in the mono viewport and their width is half - int sideWidth = monoViewport.z >> 1; - viewports[i] = ivec4(monoViewport.x + (i * sideWidth), monoViewport.y, sideWidth, monoViewport.w); - - deferredTransforms[i].projection = projMats[i]; - - auto sideViewMat = monoViewMat * glm::inverse(eyeViews[i]); - viewTransforms[i].evalFromRawMatrix(sideViewMat); - deferredTransforms[i].viewInverse = sideViewMat; - - deferredTransforms[i].stereoSide = (i == 0 ? -1.0f : 1.0f); - - clipQuad[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight); - screenBottomLeftCorners[i] = glm::vec2(-1.0f + i * 1.0f, -1.0f); - screenTopRightCorners[i] = glm::vec2(i * 1.0f, 1.0f); - - fetchTexcoordRects[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight); - } - } else { - - viewports[0] = monoViewport; - projMats[0] = monoProjMat; - - deferredTransforms[0].projection = monoProjMat; - - deferredTransforms[0].viewInverse = monoViewMat; - viewTransforms[0] = monoViewTransform; - - deferredTransforms[0].stereoSide = 0.0f; - - clipQuad[0] = glm::vec4(sMin, tMin, sWidth, tHeight); - screenBottomLeftCorners[0] = glm::vec2(-1.0f, -1.0f); - screenTopRightCorners[0] = glm::vec2(1.0f, 1.0f); - - fetchTexcoordRects[0] = glm::vec4(sMin, tMin, sWidth, tHeight); - } - - auto eyePoint = viewFrustum->getPosition(); - float nearRadius = glm::distance(eyePoint, viewFrustum->getNearTopLeft()); - - - for (int side = 0; side < numPasses; side++) { - // Render in this side's viewport - batch.setViewportTransform(viewports[side]); - batch.setStateScissorRect(viewports[side]); - - // Sync and Bind the correct DeferredTransform ubo - _deferredTransformBuffer[side]._buffer->setSubData(0, sizeof(DeferredTransform), (const gpu::Byte*) &deferredTransforms[side]); - batch.setUniformBuffer(_directionalLightLocations->deferredTransformBuffer, _deferredTransformBuffer[side]); - - glm::vec2 topLeft(-1.0f, -1.0f); - glm::vec2 bottomRight(1.0f, 1.0f); - glm::vec2 texCoordTopLeft(clipQuad[side].x, clipQuad[side].y); - glm::vec2 texCoordBottomRight(clipQuad[side].x + clipQuad[side].z, clipQuad[side].y + clipQuad[side].w); - - // First Global directional light and ambient pass - { - bool useSkyboxCubemap = (_skybox) && (_skybox->getCubemap()); - - auto& program = _directionalLight; - LightLocationsPtr locations = _directionalLightLocations; - - // TODO: At some point bring back the shadows... - // Setup the global directional pass pipeline - { - if (useSkyboxCubemap) { - program = _directionalSkyboxLight; - locations = _directionalSkyboxLightLocations; - } else if (_ambientLightMode > -1) { - program = _directionalAmbientSphereLight; - locations = _directionalAmbientSphereLightLocations; - } - batch.setPipeline(program); - } - - { // Setup the global lighting - auto globalLight = _allocatedLights[_globalLights.front()]; - - if (locations->ambientSphere >= 0) { - gpu::SphericalHarmonics sh = globalLight->getAmbientSphere(); - if (useSkyboxCubemap && _skybox->getCubemap()->getIrradiance()) { - sh = (*_skybox->getCubemap()->getIrradiance()); - } - for (int i =0; i ambientSphere + i, 1, (const float*) (&sh) + i * 4); - } - } - - if (useSkyboxCubemap) { - batch.setResourceTexture(5, _skybox->getCubemap()); - } - - if (locations->lightBufferUnit >= 0) { - batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer()); - } - - if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) { - batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer()); - } - } - - { - batch.setModelTransform(Transform()); - batch.setProjectionTransform(glm::mat4()); - batch.setViewTransform(Transform()); - - glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); - geometryCache->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color); - } - - if (useSkyboxCubemap) { - batch.setResourceTexture(5, nullptr); - } - } - - auto texcoordMat = glm::mat4(); - /* texcoordMat[0] = glm::vec4(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f); - texcoordMat[1] = glm::vec4(0.0f, tHeight / 2.0f, 0.0f, tMin + tHeight / 2.0f); - */ texcoordMat[0] = glm::vec4(fetchTexcoordRects[side].z / 2.0f, 0.0f, 0.0f, fetchTexcoordRects[side].x + fetchTexcoordRects[side].z / 2.0f); - texcoordMat[1] = glm::vec4(0.0f, fetchTexcoordRects[side].w / 2.0f, 0.0f, fetchTexcoordRects[side].y + fetchTexcoordRects[side].w / 2.0f); - texcoordMat[2] = glm::vec4(0.0f, 0.0f, 1.0f, 0.0f); - texcoordMat[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); - - // enlarge the scales slightly to account for tesselation - const float SCALE_EXPANSION = 0.05f; - - - batch.setProjectionTransform(projMats[side]); - batch.setViewTransform(viewTransforms[side]); - - // Splat Point lights - if (!_pointLights.empty()) { - batch.setPipeline(_pointLight); - - batch._glUniformMatrix4fv(_pointLightLocations->texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat)); - - for (auto lightID : _pointLights) { - auto& light = _allocatedLights[lightID]; - // IN DEBUG: light->setShowContour(true); - batch.setUniformBuffer(_pointLightLocations->lightBufferUnit, light->getSchemaBuffer()); - - float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); - // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, - // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... - if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) { - Transform model; - model.setTranslation(glm::vec3(0.0f, 0.0f, -1.0f)); - batch.setModelTransform(model); - batch.setViewTransform(Transform()); - batch.setProjectionTransform(glm::mat4()); - - glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); - DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color); - - batch.setProjectionTransform(projMats[side]); - batch.setViewTransform(viewTransforms[side]); - } else { - Transform model; - model.setTranslation(glm::vec3(light->getPosition().x, light->getPosition().y, light->getPosition().z)); - batch.setModelTransform(model.postScale(expandedRadius)); - batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - geometryCache->renderSphere(batch); - } - } - } - - // Splat spot lights - if (!_spotLights.empty()) { - batch.setPipeline(_spotLight); - - batch._glUniformMatrix4fv(_spotLightLocations->texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat)); - - for (auto lightID : _spotLights) { - auto light = _allocatedLights[lightID]; - // IN DEBUG: light->setShowContour(true); - batch.setUniformBuffer(_spotLightLocations->lightBufferUnit, light->getSchemaBuffer()); - - auto eyeLightPos = eyePoint - light->getPosition(); - auto eyeHalfPlaneDistance = glm::dot(eyeLightPos, light->getDirection()); - - const float TANGENT_LENGTH_SCALE = 0.666f; - glm::vec4 coneParam(light->getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tanf(0.5f * light->getSpotAngle()), 1.0f); - - float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); - // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, - // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... - if ((eyeHalfPlaneDistance > -nearRadius) && - (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius)) { - coneParam.w = 0.0f; - batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); - - Transform model; - model.setTranslation(glm::vec3(0.0f, 0.0f, -1.0f)); - batch.setModelTransform(model); - batch.setViewTransform(Transform()); - batch.setProjectionTransform(glm::mat4()); - - glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); - DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color); - - batch.setProjectionTransform( projMats[side]); - batch.setViewTransform(viewTransforms[side]); - } else { - coneParam.w = 1.0f; - batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); - - Transform model; - model.setTranslation(light->getPosition()); - model.postRotate(light->getOrientation()); - model.postScale(glm::vec3(expandedRadius, expandedRadius, expandedRadius)); - - batch.setModelTransform(model); - auto mesh = getSpotLightMesh(); - - batch.setIndexBuffer(mesh->getIndexBuffer()); - batch.setInputBuffer(0, mesh->getVertexBuffer()); - batch.setInputFormat(mesh->getVertexFormat()); - - auto& part = mesh->getPartBuffer().get(); - - batch.drawIndexed(model::Mesh::topologyToPrimitive(part._topology), part._numIndices, part._startIndex); - } - } - } - } - - // Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target - batch.setResourceTexture(0, nullptr); - batch.setResourceTexture(1, nullptr); - batch.setResourceTexture(2, nullptr); - batch.setResourceTexture(3, nullptr); - batch.setUniformBuffer(_directionalLightLocations->deferredTransformBuffer, nullptr); - }); - - // End of the Lighting pass - if (!_pointLights.empty()) { - _pointLights.clear(); - } - if (!_spotLights.empty()) { - _spotLights.clear(); - } -} - - -void DeferredLightingEffect::copyBack(RenderArgs* args) { - auto framebufferCache = DependencyManager::get(); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - batch.enableStereo(false); - QSize framebufferSize = framebufferCache->getFrameBufferSize(); - - // TODO why doesn't this blit work? It only seems to affect a small area below the rear view mirror. - // auto destFbo = framebufferCache->getPrimaryFramebuffer(); - auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor(); - // gpu::Vec4i vp = args->_viewport; - // batch.blit(_copyFBO, vp, framebufferCache->getPrimaryFramebuffer(), vp); - batch.setFramebuffer(destFbo); - batch.setViewportTransform(args->_viewport); - batch.setProjectionTransform(glm::mat4()); - batch.setViewTransform(Transform()); - { - float sMin = args->_viewport.x / (float)framebufferSize.width(); - float sWidth = args->_viewport.z / (float)framebufferSize.width(); - float tMin = args->_viewport.y / (float)framebufferSize.height(); - float tHeight = args->_viewport.w / (float)framebufferSize.height(); - Transform model; - batch.setPipeline(_blitLightBuffer); - model.setTranslation(glm::vec3(sMin, tMin, 0.0)); - model.setScale(glm::vec3(sWidth, tHeight, 1.0)); - batch.setModelTransform(model); - } - - batch.setResourceTexture(0, _copyFBO->getRenderBuffer(0)); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - args->_context->render(batch); - }); - framebufferCache->releaseFramebuffer(_copyFBO); -} - -void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferUnit) { - auto globalLight = _allocatedLights[_globalLights.front()]; - args->_batch->setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer()); -} - -static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { - auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vertSource))); - auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fragSource))); - - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); - - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1)); - slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); - slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 3)); - slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), 4)); - slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), 5)); - const int LIGHT_GPU_SLOT = 3; - slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); - const int ATMOSPHERE_GPU_SLOT = 4; - slotBindings.insert(gpu::Shader::Binding(std::string("atmosphereBufferUnit"), ATMOSPHERE_GPU_SLOT)); - - slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), DeferredLightingEffect::DEFERRED_TRANSFORM_BUFFER_SLOT)); - - gpu::Shader::makeProgram(*program, slotBindings); - - locations->shadowDistances = program->getUniforms().findLocation("shadowDistances"); - locations->shadowScale = program->getUniforms().findLocation("shadowScale"); - - locations->radius = program->getUniforms().findLocation("radius"); - locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00"); - - locations->texcoordMat = program->getUniforms().findLocation("texcoordMat"); - locations->coneParam = program->getUniforms().findLocation("coneParam"); - - locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); - locations->atmosphereBufferUnit = program->getBuffers().findLocation("atmosphereBufferUnit"); - locations->deferredTransformBuffer = program->getBuffers().findLocation("deferredTransformBuffer"); - - auto state = std::make_shared(); - if (lightVolume) { - state->setCullMode(gpu::State::CULL_BACK); - - // No need for z test since the depth buffer is not bound state->setDepthTest(true, false, gpu::LESS_EQUAL); - // TODO: We should bind the true depth buffer both as RT and texture for the depth test - // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases - state->setDepthClampEnable(true); - - // additive blending - state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - } else { - state->setCullMode(gpu::State::CULL_BACK); - } - pipeline.reset(gpu::Pipeline::create(program, state)); - -} - -void DeferredLightingEffect::setAmbientLightMode(int preset) { - if ((preset >= 0) && (preset < gpu::SphericalHarmonics::NUM_PRESET)) { - _ambientLightMode = preset; - auto light = _allocatedLights.front(); - light->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(preset % gpu::SphericalHarmonics::NUM_PRESET)); - } else { - // force to preset 0 - setAmbientLightMode(0); - } -} - -void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity) { - auto light = _allocatedLights.front(); - light->setDirection(direction); - light->setColor(diffuse); - light->setIntensity(intensity); - light->setAmbientIntensity(ambientIntensity); -} - -void DeferredLightingEffect::setGlobalSkybox(const model::SkyboxPointer& skybox) { - _skybox = skybox; -} - -model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { - if (!_spotLightMesh) { - _spotLightMesh = std::make_shared(); - - int slices = 32; - int rings = 3; - int vertices = 2 + rings * slices; - int originVertex = vertices - 2; - int capVertex = vertices - 1; - int verticesSize = vertices * 3 * sizeof(float); - int indices = 3 * slices * (1 + 1 + 2 * (rings -1)); - int ringFloatOffset = slices * 3; - - - float* vertexData = new float[verticesSize]; - float* vertexRing0 = vertexData; - float* vertexRing1 = vertexRing0 + ringFloatOffset; - float* vertexRing2 = vertexRing1 + ringFloatOffset; - - for (int i = 0; i < slices; i++) { - float theta = TWO_PI * i / slices; - auto cosin = glm::vec2(cosf(theta), sinf(theta)); - - *(vertexRing0++) = cosin.x; - *(vertexRing0++) = cosin.y; - *(vertexRing0++) = 0.0f; - - *(vertexRing1++) = cosin.x; - *(vertexRing1++) = cosin.y; - *(vertexRing1++) = 0.33f; - - *(vertexRing2++) = cosin.x; - *(vertexRing2++) = cosin.y; - *(vertexRing2++) = 0.66f; - } - - *(vertexRing2++) = 0.0f; - *(vertexRing2++) = 0.0f; - *(vertexRing2++) = -1.0f; - - *(vertexRing2++) = 0.0f; - *(vertexRing2++) = 0.0f; - *(vertexRing2++) = 1.0f; - - _spotLightMesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(verticesSize, (gpu::Byte*) vertexData), gpu::Element::VEC3F_XYZ)); - delete[] vertexData; - - gpu::uint16* indexData = new gpu::uint16[indices]; - gpu::uint16* index = indexData; - for (int i = 0; i < slices; i++) { - *(index++) = originVertex; - - int s0 = i; - int s1 = ((i + 1) % slices); - *(index++) = s0; - *(index++) = s1; - - int s2 = s0 + slices; - int s3 = s1 + slices; - *(index++) = s1; - *(index++) = s0; - *(index++) = s2; - - *(index++) = s1; - *(index++) = s2; - *(index++) = s3; - - int s4 = s2 + slices; - int s5 = s3 + slices; - *(index++) = s3; - *(index++) = s2; - *(index++) = s4; - - *(index++) = s3; - *(index++) = s4; - *(index++) = s5; - - - *(index++) = s5; - *(index++) = s4; - *(index++) = capVertex; - } - - _spotLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(unsigned short) * indices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16)); - delete[] indexData; - - model::Mesh::Part part(0, indices, 0, model::Mesh::TRIANGLES); - //DEBUG: model::Mesh::Part part(0, indices, 0, model::Mesh::LINE_STRIP); - - _spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(sizeof(part), (gpu::Byte*) &part), gpu::Element::PART_DRAWCALL)); - - _spotLightMesh->getVertexStream(); - } - return _spotLightMesh; -} - +// +// DeferredLightingEffect.cpp +// interface/src/renderer +// +// Created by Andrzej Kapolka on 9/11/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "DeferredLightingEffect.h" + +#include +#include +#include + +#include +#include +#include + +#include "AbstractViewStateInterface.h" +#include "GeometryCache.h" +#include "TextureCache.h" +#include "FramebufferCache.h" + + +#include "simple_vert.h" +#include "simple_textured_frag.h" +#include "simple_textured_emisive_frag.h" + +#include "deferred_light_vert.h" +#include "deferred_light_limited_vert.h" +#include "deferred_light_spot_vert.h" + +#include "directional_light_frag.h" +#include "directional_light_shadow_map_frag.h" +#include "directional_light_cascaded_shadow_map_frag.h" + +#include "directional_ambient_light_frag.h" +#include "directional_ambient_light_shadow_map_frag.h" +#include "directional_ambient_light_cascaded_shadow_map_frag.h" + +#include "directional_skybox_light_frag.h" +#include "directional_skybox_light_shadow_map_frag.h" +#include "directional_skybox_light_cascaded_shadow_map_frag.h" + +#include "point_light_frag.h" +#include "spot_light_frag.h" + +static const std::string glowIntensityShaderHandle = "glowIntensity"; + +struct LightLocations { + int shadowDistances; + int shadowScale; + int radius; + int ambientSphere; + int lightBufferUnit; + int atmosphereBufferUnit; + int texcoordMat; + int coneParam; + int deferredTransformBuffer; +}; + +static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); + + +gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config) { + auto it = _simplePrograms.find(config); + if (it != _simplePrograms.end()) { + return it.value(); + } + + auto state = std::make_shared(); + if (config.isCulled()) { + state->setCullMode(gpu::State::CULL_BACK); + } else { + state->setCullMode(gpu::State::CULL_NONE); + } + state->setDepthTest(true, true, gpu::LESS_EQUAL); + if (config.hasDepthBias()) { + state->setDepthBias(1.0f); + state->setDepthBiasSlopeScale(1.0f); + } + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; + gpu::PipelinePointer pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + _simplePrograms.insert(config, pipeline); + return pipeline; +} + +void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { + auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert))); + auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_frag))); + auto PSEmissive = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_emisive_frag))); + + _simpleShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); + _emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive)); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); + gpu::Shader::makeProgram(*_simpleShader, slotBindings); + gpu::Shader::makeProgram(*_emissiveShader, slotBindings); + + _viewState = viewState; + _directionalLightLocations = std::make_shared(); + _directionalLightShadowMapLocations = std::make_shared(); + _directionalLightCascadedShadowMapLocations = std::make_shared(); + _directionalAmbientSphereLightLocations = std::make_shared(); + _directionalAmbientSphereLightShadowMapLocations = std::make_shared(); + _directionalAmbientSphereLightCascadedShadowMapLocations = std::make_shared(); + _directionalSkyboxLightLocations = std::make_shared(); + _directionalSkyboxLightShadowMapLocations = std::make_shared(); + _directionalSkyboxLightCascadedShadowMapLocations = std::make_shared(); + _pointLightLocations = std::make_shared(); + _spotLightLocations = std::make_shared(); + + loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations); + loadLightProgram(deferred_light_vert, directional_light_shadow_map_frag, false, _directionalLightShadowMap, + _directionalLightShadowMapLocations); + loadLightProgram(deferred_light_vert, directional_light_cascaded_shadow_map_frag, false, _directionalLightCascadedShadowMap, + _directionalLightCascadedShadowMapLocations); + + loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations); + loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_map_frag, false, _directionalAmbientSphereLightShadowMap, + _directionalAmbientSphereLightShadowMapLocations); + loadLightProgram(deferred_light_vert, directional_ambient_light_cascaded_shadow_map_frag, false, _directionalAmbientSphereLightCascadedShadowMap, + _directionalAmbientSphereLightCascadedShadowMapLocations); + + loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations); + loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_map_frag, false, _directionalSkyboxLightShadowMap, + _directionalSkyboxLightShadowMapLocations); + loadLightProgram(deferred_light_vert, directional_skybox_light_cascaded_shadow_map_frag, false, _directionalSkyboxLightCascadedShadowMap, + _directionalSkyboxLightCascadedShadowMapLocations); + + + loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations); + loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations); + + { + //auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + //auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS(); + auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); + gpu::Shader::makeProgram(*blitProgram); + auto blitState = std::make_shared(); + blitState->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + blitState->setColorWriteMask(true, true, true, false); + _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState)); + } + + // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light + _globalLights.push_back(0); + _allocatedLights.push_back(std::make_shared()); + + model::LightPointer lp = _allocatedLights[0]; + + lp->setDirection(-glm::vec3(1.0f, 1.0f, 1.0f)); + lp->setColor(glm::vec3(1.0f)); + lp->setIntensity(1.0f); + lp->setType(model::Light::SUN); + lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); +} + + + +gpu::PipelinePointer DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, + bool emmisive, bool depthBias) { + SimpleProgramKey config{textured, culled, emmisive, depthBias}; + gpu::PipelinePointer pipeline = getPipeline(config); + batch.setPipeline(pipeline); + + gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; + int glowIntensity = program->getUniforms().findLocation("glowIntensity"); + batch._glUniform1f(glowIntensity, 1.0f); + + if (!config.isTextured()) { + // If it is not textured, bind white texture and keep using textured pipeline + batch.setResourceTexture(0, DependencyManager::get()->getWhiteTexture()); + } + + batch.setResourceTexture(NORMAL_FITTING_MAP_SLOT, DependencyManager::get()->getNormalFittingTexture()); + return pipeline; +} + +uint32_t toCompactColor(const glm::vec4& color) { + uint32_t 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); + return compactColor; +} + +static const size_t INSTANCE_TRANSFORM_BUFFER = 0; +static const size_t INSTANCE_COLOR_BUFFER = 1; + +template +void renderInstances(const std::string& name, gpu::Batch& batch, const Transform& transform, const glm::vec4& color, F f) { + { + gpu::BufferPointer instanceTransformBuffer = batch.getNamedBuffer(name, INSTANCE_TRANSFORM_BUFFER); + glm::mat4 glmTransform; + instanceTransformBuffer->append(transform.getMatrix(glmTransform)); + + gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(name, INSTANCE_COLOR_BUFFER); + auto compactColor = toCompactColor(color); + instanceColorBuffer->append(compactColor); + } + + auto that = DependencyManager::get(); + batch.setupNamedCalls(name, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + auto pipeline = that->bindSimpleProgram(batch); + auto location = pipeline->getProgram()->getUniforms().findLocation("Instanced"); + + batch._glUniform1i(location, 1); + f(batch, data); + batch._glUniform1i(location, 0); + }); +} + +void DeferredLightingEffect::renderSolidSphereInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { + static const std::string INSTANCE_NAME = __FUNCTION__; + renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + DependencyManager::get()->renderShapeInstances(batch, GeometryCache::Sphere, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + }); +} + +void DeferredLightingEffect::renderWireSphereInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { + static const std::string INSTANCE_NAME = __FUNCTION__; + renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + DependencyManager::get()->renderWireShapeInstances(batch, GeometryCache::Sphere, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + }); +} + +// Enable this in a debug build to cause 'box' entities to iterate through all the +// available shape types, both solid and wireframes +//#define DEBUG_SHAPES + +void DeferredLightingEffect::renderSolidCubeInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { + static const std::string INSTANCE_NAME = __FUNCTION__; + +#ifdef DEBUG_SHAPES + static auto startTime = usecTimestampNow(); + renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + + auto usecs = usecTimestampNow(); + usecs -= startTime; + auto msecs = usecs / USECS_PER_MSEC; + float seconds = msecs; + seconds /= MSECS_PER_SECOND; + float fractionalSeconds = seconds - floor(seconds); + int shapeIndex = (int)seconds; + + // Every second we flip to the next shape. + static const int SHAPE_COUNT = 5; + GeometryCache::Shape shapes[SHAPE_COUNT] = { + GeometryCache::Cube, + GeometryCache::Tetrahedron, + GeometryCache::Sphere, + GeometryCache::Icosahedron, + GeometryCache::Line, + }; + + shapeIndex %= SHAPE_COUNT; + GeometryCache::Shape shape = shapes[shapeIndex]; + + // For the first half second for a given shape, show the wireframe, for the second half, show the solid. + if (fractionalSeconds > 0.5f) { + DependencyManager::get()->renderShapeInstances(batch, shape, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + } else { + DependencyManager::get()->renderWireShapeInstances(batch, shape, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + } + }); +#else + renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + DependencyManager::get()->renderCubeInstances(batch, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + }); +#endif +} + +void DeferredLightingEffect::renderWireCubeInstance(gpu::Batch& batch, const Transform& transform, const glm::vec4& color) { + static const std::string INSTANCE_NAME = __FUNCTION__; + renderInstances(INSTANCE_NAME, batch, transform, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + DependencyManager::get()->renderWireCubeInstances(batch, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + }); +} + +void DeferredLightingEffect::renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner, + const glm::vec4& color) { + bindSimpleProgram(batch); + DependencyManager::get()->renderQuad(batch, minCorner, maxCorner, color); +} + +void DeferredLightingEffect::renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, + const glm::vec4& color1, const glm::vec4& color2) { + bindSimpleProgram(batch); + DependencyManager::get()->renderLine(batch, p1, p2, color1, color2); +} + +void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color, + float intensity) { + addSpotLight(position, radius, color, intensity); +} + +void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color, + float intensity, const glm::quat& orientation, float exponent, float cutoff) { + + unsigned int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size(); + if (lightID >= _allocatedLights.size()) { + _allocatedLights.push_back(std::make_shared()); + } + model::LightPointer lp = _allocatedLights[lightID]; + + lp->setPosition(position); + lp->setMaximumRadius(radius); + lp->setColor(color); + lp->setIntensity(intensity); + //lp->setShowContour(quadraticAttenuation); + + if (exponent == 0.0f && cutoff == PI) { + lp->setType(model::Light::POINT); + _pointLights.push_back(lightID); + + } else { + lp->setOrientation(orientation); + lp->setSpotAngle(cutoff); + lp->setSpotExponent(exponent); + lp->setType(model::Light::SPOT); + _spotLights.push_back(lightID); + } +} + +void DeferredLightingEffect::prepare(RenderArgs* args) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + batch.enableStereo(false); + batch.setStateScissorRect(args->_viewport); + + auto primaryFbo = DependencyManager::get()->getPrimaryFramebuffer(); + + batch.setFramebuffer(primaryFbo); + // clear the normal and specular buffers + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); + const float MAX_SPECULAR_EXPONENT = 128.0f; + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR2, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f / MAX_SPECULAR_EXPONENT), true); + }); +} + +gpu::FramebufferPointer _copyFBO; + +void DeferredLightingEffect::render(RenderArgs* args) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + + // Allocate the parameters buffer used by all the deferred shaders + if (!_deferredTransformBuffer[0]._buffer) { + DeferredTransform parameters; + _deferredTransformBuffer[0] = gpu::BufferView(std::make_shared(sizeof(DeferredTransform), (const gpu::Byte*) ¶meters)); + _deferredTransformBuffer[1] = gpu::BufferView(std::make_shared(sizeof(DeferredTransform), (const gpu::Byte*) ¶meters)); + } + + // Framebuffer copy operations cannot function as multipass stereo operations. + batch.enableStereo(false); + + // perform deferred lighting, rendering to free fbo + auto framebufferCache = DependencyManager::get(); + + QSize framebufferSize = framebufferCache->getFrameBufferSize(); + + // binding the first framebuffer + _copyFBO = framebufferCache->getFramebuffer(); + batch.setFramebuffer(_copyFBO); + + // Clearing it + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + batch.clearColorFramebuffer(_copyFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); + + // BInd the G-Buffer surfaces + batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture()); + batch.setResourceTexture(1, framebufferCache->getPrimaryNormalTexture()); + batch.setResourceTexture(2, framebufferCache->getPrimarySpecularTexture()); + batch.setResourceTexture(3, framebufferCache->getPrimaryDepthTexture()); + + // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport) + auto monoViewport = args->_viewport; + float sMin = args->_viewport.x / (float)framebufferSize.width(); + float sWidth = args->_viewport.z / (float)framebufferSize.width(); + float tMin = args->_viewport.y / (float)framebufferSize.height(); + float tHeight = args->_viewport.w / (float)framebufferSize.height(); + + // The view frustum is the mono frustum base + auto viewFrustum = args->_viewFrustum; + + // Eval the mono projection + mat4 monoProjMat; + viewFrustum->evalProjectionMatrix(monoProjMat); + + // The mono view transform + Transform monoViewTransform; + viewFrustum->evalViewTransform(monoViewTransform); + + // THe mono view matrix coming from the mono view transform + glm::mat4 monoViewMat; + monoViewTransform.getMatrix(monoViewMat); + + // Running in stero ? + bool isStereo = args->_context->isStereo(); + int numPasses = 1; + + mat4 projMats[2]; + Transform viewTransforms[2]; + ivec4 viewports[2]; + vec4 clipQuad[2]; + vec2 screenBottomLeftCorners[2]; + vec2 screenTopRightCorners[2]; + vec4 fetchTexcoordRects[2]; + + DeferredTransform deferredTransforms[2]; + auto geometryCache = DependencyManager::get(); + + if (isStereo) { + numPasses = 2; + + mat4 eyeViews[2]; + args->_context->getStereoProjections(projMats); + args->_context->getStereoViews(eyeViews); + + float halfWidth = 0.5f * sWidth; + + for (int i = 0; i < numPasses; i++) { + // In stereo, the 2 sides are layout side by side in the mono viewport and their width is half + int sideWidth = monoViewport.z >> 1; + viewports[i] = ivec4(monoViewport.x + (i * sideWidth), monoViewport.y, sideWidth, monoViewport.w); + + deferredTransforms[i].projection = projMats[i]; + + auto sideViewMat = monoViewMat * glm::inverse(eyeViews[i]); + viewTransforms[i].evalFromRawMatrix(sideViewMat); + deferredTransforms[i].viewInverse = sideViewMat; + + deferredTransforms[i].stereoSide = (i == 0 ? -1.0f : 1.0f); + + clipQuad[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight); + screenBottomLeftCorners[i] = glm::vec2(-1.0f + i * 1.0f, -1.0f); + screenTopRightCorners[i] = glm::vec2(i * 1.0f, 1.0f); + + fetchTexcoordRects[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight); + } + } else { + + viewports[0] = monoViewport; + projMats[0] = monoProjMat; + + deferredTransforms[0].projection = monoProjMat; + + deferredTransforms[0].viewInverse = monoViewMat; + viewTransforms[0] = monoViewTransform; + + deferredTransforms[0].stereoSide = 0.0f; + + clipQuad[0] = glm::vec4(sMin, tMin, sWidth, tHeight); + screenBottomLeftCorners[0] = glm::vec2(-1.0f, -1.0f); + screenTopRightCorners[0] = glm::vec2(1.0f, 1.0f); + + fetchTexcoordRects[0] = glm::vec4(sMin, tMin, sWidth, tHeight); + } + + auto eyePoint = viewFrustum->getPosition(); + float nearRadius = glm::distance(eyePoint, viewFrustum->getNearTopLeft()); + + + for (int side = 0; side < numPasses; side++) { + // Render in this side's viewport + batch.setViewportTransform(viewports[side]); + batch.setStateScissorRect(viewports[side]); + + // Sync and Bind the correct DeferredTransform ubo + _deferredTransformBuffer[side]._buffer->setSubData(0, sizeof(DeferredTransform), (const gpu::Byte*) &deferredTransforms[side]); + batch.setUniformBuffer(_directionalLightLocations->deferredTransformBuffer, _deferredTransformBuffer[side]); + + glm::vec2 topLeft(-1.0f, -1.0f); + glm::vec2 bottomRight(1.0f, 1.0f); + glm::vec2 texCoordTopLeft(clipQuad[side].x, clipQuad[side].y); + glm::vec2 texCoordBottomRight(clipQuad[side].x + clipQuad[side].z, clipQuad[side].y + clipQuad[side].w); + + // First Global directional light and ambient pass + { + bool useSkyboxCubemap = (_skybox) && (_skybox->getCubemap()); + + auto& program = _directionalLight; + LightLocationsPtr locations = _directionalLightLocations; + + // TODO: At some point bring back the shadows... + // Setup the global directional pass pipeline + { + if (useSkyboxCubemap) { + program = _directionalSkyboxLight; + locations = _directionalSkyboxLightLocations; + } else if (_ambientLightMode > -1) { + program = _directionalAmbientSphereLight; + locations = _directionalAmbientSphereLightLocations; + } + batch.setPipeline(program); + } + + { // Setup the global lighting + auto globalLight = _allocatedLights[_globalLights.front()]; + + if (locations->ambientSphere >= 0) { + gpu::SphericalHarmonics sh = globalLight->getAmbientSphere(); + if (useSkyboxCubemap && _skybox->getCubemap()->getIrradiance()) { + sh = (*_skybox->getCubemap()->getIrradiance()); + } + for (int i =0; i ambientSphere + i, 1, (const float*) (&sh) + i * 4); + } + } + + if (useSkyboxCubemap) { + batch.setResourceTexture(5, _skybox->getCubemap()); + } + + if (locations->lightBufferUnit >= 0) { + batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer()); + } + + if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) { + batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer()); + } + } + + { + batch.setModelTransform(Transform()); + batch.setProjectionTransform(glm::mat4()); + batch.setViewTransform(Transform()); + + glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); + geometryCache->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color); + } + + if (useSkyboxCubemap) { + batch.setResourceTexture(5, nullptr); + } + } + + auto texcoordMat = glm::mat4(); + /* texcoordMat[0] = glm::vec4(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f); + texcoordMat[1] = glm::vec4(0.0f, tHeight / 2.0f, 0.0f, tMin + tHeight / 2.0f); + */ texcoordMat[0] = glm::vec4(fetchTexcoordRects[side].z / 2.0f, 0.0f, 0.0f, fetchTexcoordRects[side].x + fetchTexcoordRects[side].z / 2.0f); + texcoordMat[1] = glm::vec4(0.0f, fetchTexcoordRects[side].w / 2.0f, 0.0f, fetchTexcoordRects[side].y + fetchTexcoordRects[side].w / 2.0f); + texcoordMat[2] = glm::vec4(0.0f, 0.0f, 1.0f, 0.0f); + texcoordMat[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); + + // enlarge the scales slightly to account for tesselation + const float SCALE_EXPANSION = 0.05f; + + + batch.setProjectionTransform(projMats[side]); + batch.setViewTransform(viewTransforms[side]); + + // Splat Point lights + if (!_pointLights.empty()) { + batch.setPipeline(_pointLight); + + batch._glUniformMatrix4fv(_pointLightLocations->texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat)); + + for (auto lightID : _pointLights) { + auto& light = _allocatedLights[lightID]; + // IN DEBUG: light->setShowContour(true); + batch.setUniformBuffer(_pointLightLocations->lightBufferUnit, light->getSchemaBuffer()); + + float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); + // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, + // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... + if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) { + Transform model; + model.setTranslation(glm::vec3(0.0f, 0.0f, -1.0f)); + batch.setModelTransform(model); + batch.setViewTransform(Transform()); + batch.setProjectionTransform(glm::mat4()); + + glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); + DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color); + + batch.setProjectionTransform(projMats[side]); + batch.setViewTransform(viewTransforms[side]); + } else { + Transform model; + model.setTranslation(glm::vec3(light->getPosition().x, light->getPosition().y, light->getPosition().z)); + batch.setModelTransform(model.postScale(expandedRadius)); + batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + geometryCache->renderSphere(batch); + } + } + } + + // Splat spot lights + if (!_spotLights.empty()) { + batch.setPipeline(_spotLight); + + batch._glUniformMatrix4fv(_spotLightLocations->texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat)); + + for (auto lightID : _spotLights) { + auto light = _allocatedLights[lightID]; + // IN DEBUG: light->setShowContour(true); + batch.setUniformBuffer(_spotLightLocations->lightBufferUnit, light->getSchemaBuffer()); + + auto eyeLightPos = eyePoint - light->getPosition(); + auto eyeHalfPlaneDistance = glm::dot(eyeLightPos, light->getDirection()); + + const float TANGENT_LENGTH_SCALE = 0.666f; + glm::vec4 coneParam(light->getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tanf(0.5f * light->getSpotAngle()), 1.0f); + + float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); + // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, + // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... + if ((eyeHalfPlaneDistance > -nearRadius) && + (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius)) { + coneParam.w = 0.0f; + batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); + + Transform model; + model.setTranslation(glm::vec3(0.0f, 0.0f, -1.0f)); + batch.setModelTransform(model); + batch.setViewTransform(Transform()); + batch.setProjectionTransform(glm::mat4()); + + glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); + DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color); + + batch.setProjectionTransform( projMats[side]); + batch.setViewTransform(viewTransforms[side]); + } else { + coneParam.w = 1.0f; + batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); + + Transform model; + model.setTranslation(light->getPosition()); + model.postRotate(light->getOrientation()); + model.postScale(glm::vec3(expandedRadius, expandedRadius, expandedRadius)); + + batch.setModelTransform(model); + auto mesh = getSpotLightMesh(); + + batch.setIndexBuffer(mesh->getIndexBuffer()); + batch.setInputBuffer(0, mesh->getVertexBuffer()); + batch.setInputFormat(mesh->getVertexFormat()); + + auto& part = mesh->getPartBuffer().get(); + + batch.drawIndexed(model::Mesh::topologyToPrimitive(part._topology), part._numIndices, part._startIndex); + } + } + } + } + + // Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target + batch.setResourceTexture(0, nullptr); + batch.setResourceTexture(1, nullptr); + batch.setResourceTexture(2, nullptr); + batch.setResourceTexture(3, nullptr); + batch.setUniformBuffer(_directionalLightLocations->deferredTransformBuffer, nullptr); + }); + + // End of the Lighting pass + if (!_pointLights.empty()) { + _pointLights.clear(); + } + if (!_spotLights.empty()) { + _spotLights.clear(); + } +} + + +void DeferredLightingEffect::copyBack(RenderArgs* args) { + auto framebufferCache = DependencyManager::get(); + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + batch.enableStereo(false); + QSize framebufferSize = framebufferCache->getFrameBufferSize(); + + // TODO why doesn't this blit work? It only seems to affect a small area below the rear view mirror. + // auto destFbo = framebufferCache->getPrimaryFramebuffer(); + auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor(); + // gpu::Vec4i vp = args->_viewport; + // batch.blit(_copyFBO, vp, framebufferCache->getPrimaryFramebuffer(), vp); + batch.setFramebuffer(destFbo); + batch.setViewportTransform(args->_viewport); + batch.setProjectionTransform(glm::mat4()); + batch.setViewTransform(Transform()); + { + float sMin = args->_viewport.x / (float)framebufferSize.width(); + float sWidth = args->_viewport.z / (float)framebufferSize.width(); + float tMin = args->_viewport.y / (float)framebufferSize.height(); + float tHeight = args->_viewport.w / (float)framebufferSize.height(); + Transform model; + batch.setPipeline(_blitLightBuffer); + model.setTranslation(glm::vec3(sMin, tMin, 0.0)); + model.setScale(glm::vec3(sWidth, tHeight, 1.0)); + batch.setModelTransform(model); + } + + batch.setResourceTexture(0, _copyFBO->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + args->_context->render(batch); + }); + framebufferCache->releaseFramebuffer(_copyFBO); +} + +void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferUnit) { + auto globalLight = _allocatedLights[_globalLights.front()]; + args->_batch->setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer()); +} + +static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { + auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vertSource))); + auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fragSource))); + + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); + slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 3)); + slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), 4)); + slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), 5)); + const int LIGHT_GPU_SLOT = 3; + slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); + const int ATMOSPHERE_GPU_SLOT = 4; + slotBindings.insert(gpu::Shader::Binding(std::string("atmosphereBufferUnit"), ATMOSPHERE_GPU_SLOT)); + + slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), DeferredLightingEffect::DEFERRED_TRANSFORM_BUFFER_SLOT)); + + gpu::Shader::makeProgram(*program, slotBindings); + + locations->shadowDistances = program->getUniforms().findLocation("shadowDistances"); + locations->shadowScale = program->getUniforms().findLocation("shadowScale"); + + locations->radius = program->getUniforms().findLocation("radius"); + locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00"); + + locations->texcoordMat = program->getUniforms().findLocation("texcoordMat"); + locations->coneParam = program->getUniforms().findLocation("coneParam"); + + locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); + locations->atmosphereBufferUnit = program->getBuffers().findLocation("atmosphereBufferUnit"); + locations->deferredTransformBuffer = program->getBuffers().findLocation("deferredTransformBuffer"); + + auto state = std::make_shared(); + if (lightVolume) { + state->setCullMode(gpu::State::CULL_BACK); + + // No need for z test since the depth buffer is not bound state->setDepthTest(true, false, gpu::LESS_EQUAL); + // TODO: We should bind the true depth buffer both as RT and texture for the depth test + // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases + state->setDepthClampEnable(true); + + // additive blending + state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + } else { + state->setCullMode(gpu::State::CULL_BACK); + } + pipeline.reset(gpu::Pipeline::create(program, state)); + +} + +void DeferredLightingEffect::setAmbientLightMode(int preset) { + if ((preset >= 0) && (preset < gpu::SphericalHarmonics::NUM_PRESET)) { + _ambientLightMode = preset; + auto light = _allocatedLights.front(); + light->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(preset % gpu::SphericalHarmonics::NUM_PRESET)); + } else { + // force to preset 0 + setAmbientLightMode(0); + } +} + +void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity) { + auto light = _allocatedLights.front(); + light->setDirection(direction); + light->setColor(diffuse); + light->setIntensity(intensity); + light->setAmbientIntensity(ambientIntensity); +} + +void DeferredLightingEffect::setGlobalSkybox(const model::SkyboxPointer& skybox) { + _skybox = skybox; +} + +model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { + if (!_spotLightMesh) { + _spotLightMesh = std::make_shared(); + + int slices = 32; + int rings = 3; + int vertices = 2 + rings * slices; + int originVertex = vertices - 2; + int capVertex = vertices - 1; + int verticesSize = vertices * 3 * sizeof(float); + int indices = 3 * slices * (1 + 1 + 2 * (rings -1)); + int ringFloatOffset = slices * 3; + + + float* vertexData = new float[verticesSize]; + float* vertexRing0 = vertexData; + float* vertexRing1 = vertexRing0 + ringFloatOffset; + float* vertexRing2 = vertexRing1 + ringFloatOffset; + + for (int i = 0; i < slices; i++) { + float theta = TWO_PI * i / slices; + auto cosin = glm::vec2(cosf(theta), sinf(theta)); + + *(vertexRing0++) = cosin.x; + *(vertexRing0++) = cosin.y; + *(vertexRing0++) = 0.0f; + + *(vertexRing1++) = cosin.x; + *(vertexRing1++) = cosin.y; + *(vertexRing1++) = 0.33f; + + *(vertexRing2++) = cosin.x; + *(vertexRing2++) = cosin.y; + *(vertexRing2++) = 0.66f; + } + + *(vertexRing2++) = 0.0f; + *(vertexRing2++) = 0.0f; + *(vertexRing2++) = -1.0f; + + *(vertexRing2++) = 0.0f; + *(vertexRing2++) = 0.0f; + *(vertexRing2++) = 1.0f; + + _spotLightMesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(verticesSize, (gpu::Byte*) vertexData), gpu::Element::VEC3F_XYZ)); + delete[] vertexData; + + gpu::uint16* indexData = new gpu::uint16[indices]; + gpu::uint16* index = indexData; + for (int i = 0; i < slices; i++) { + *(index++) = originVertex; + + int s0 = i; + int s1 = ((i + 1) % slices); + *(index++) = s0; + *(index++) = s1; + + int s2 = s0 + slices; + int s3 = s1 + slices; + *(index++) = s1; + *(index++) = s0; + *(index++) = s2; + + *(index++) = s1; + *(index++) = s2; + *(index++) = s3; + + int s4 = s2 + slices; + int s5 = s3 + slices; + *(index++) = s3; + *(index++) = s2; + *(index++) = s4; + + *(index++) = s3; + *(index++) = s4; + *(index++) = s5; + + + *(index++) = s5; + *(index++) = s4; + *(index++) = capVertex; + } + + _spotLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(unsigned short) * indices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16)); + delete[] indexData; + + model::Mesh::Part part(0, indices, 0, model::Mesh::TRIANGLES); + //DEBUG: model::Mesh::Part part(0, indices, 0, model::Mesh::LINE_STRIP); + + _spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(sizeof(part), (gpu::Byte*) &part), gpu::Element::PART_DRAWCALL)); + + _spotLightMesh->getVertexStream(); + } + return _spotLightMesh; +} + diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 73a487c2df..df062e3fa9 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -231,8 +231,8 @@ const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() { auto state = std::make_shared(); state->setDepthTest(false); - // additive blending - state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + // additive blending + state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); _opaquePipeline.reset(gpu::Pipeline::create(program, state)); } @@ -336,7 +336,7 @@ void DrawStencilDeferred::run(const SceneContextPointer& sceneContext, const Ren batch.setPipeline(getOpaquePipeline()); - batch.draw(gpu::TRIANGLE_STRIP, 4); + batch.draw(gpu::TRIANGLE_STRIP, 4); batch.setResourceTexture(0, nullptr); }); diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index b34ed3ed2b..63992c35ad 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -1,70 +1,70 @@ - -<@if not SKINNING_SLH@> -<@def SKINNING_SLH@> - -const int MAX_TEXCOORDS = 2; -const int MAX_CLUSTERS = 128; -const int INDICES_PER_VERTEX = 4; - -layout(std140) uniform skinClusterBuffer { - mat4 clusterMatrices[MAX_CLUSTERS]; -}; - -void skinPosition(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { - vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); - - for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; - float clusterWeight = skinClusterWeight[i]; - newPosition += clusterMatrix * inPosition * clusterWeight; - } - - skinnedPosition = newPosition; -} - -void skinPositionNormal(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, - out vec4 skinnedPosition, out vec3 skinnedNormal) { - vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); - vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); - - for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; - float clusterWeight = skinClusterWeight[i]; - newPosition += clusterMatrix * inPosition * clusterWeight; - newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; - } - - skinnedPosition = newPosition; - skinnedNormal = newNormal.xyz; -} - -void skinPositionNormalTangent(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, - out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) { - vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); - vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); - vec4 newTangent = vec4(0.0, 0.0, 0.0, 0.0); - - for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; - float clusterWeight = skinClusterWeight[i]; - newPosition += clusterMatrix * inPosition * clusterWeight; - newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; - newTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight; - } - - skinnedPosition = newPosition; - skinnedNormal = newNormal.xyz; - skinnedTangent = newTangent.xyz; -} - - + +<@if not SKINNING_SLH@> +<@def SKINNING_SLH@> + +const int MAX_TEXCOORDS = 2; +const int MAX_CLUSTERS = 128; +const int INDICES_PER_VERTEX = 4; + +layout(std140) uniform skinClusterBuffer { + mat4 clusterMatrices[MAX_CLUSTERS]; +}; + +void skinPosition(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { + vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + float clusterWeight = skinClusterWeight[i]; + newPosition += clusterMatrix * inPosition * clusterWeight; + } + + skinnedPosition = newPosition; +} + +void skinPositionNormal(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, + out vec4 skinnedPosition, out vec3 skinnedNormal) { + vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); + vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + float clusterWeight = skinClusterWeight[i]; + newPosition += clusterMatrix * inPosition * clusterWeight; + newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; + } + + skinnedPosition = newPosition; + skinnedNormal = newNormal.xyz; +} + +void skinPositionNormalTangent(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, + out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) { + vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); + vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); + vec4 newTangent = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + float clusterWeight = skinClusterWeight[i]; + newPosition += clusterMatrix * inPosition * clusterWeight; + newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; + newTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight; + } + + skinnedPosition = newPosition; + skinnedNormal = newNormal.xyz; + skinnedTangent = newTangent.xyz; +} + + <@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/directional_ambient_light_shadow_map.slf b/libraries/render-utils/src/directional_ambient_light_shadow_map.slf index 2dee8bf9b9..97d69f2e63 100755 --- a/libraries/render-utils/src/directional_ambient_light_shadow_map.slf +++ b/libraries/render-utils/src/directional_ambient_light_shadow_map.slf @@ -20,7 +20,7 @@ <$declareEvalAmbientSphereGlobalColor()$> // Everything about shadow -<@include Shadow.slh@> +<@include Shadow.slh@> in vec2 _texCoord0; out vec4 _fragColor; diff --git a/libraries/render-utils/src/directional_light_shadow_map.slf b/libraries/render-utils/src/directional_light_shadow_map.slf index b3362a2040..4249b2787c 100644 --- a/libraries/render-utils/src/directional_light_shadow_map.slf +++ b/libraries/render-utils/src/directional_light_shadow_map.slf @@ -21,7 +21,7 @@ <$declareEvalAmbientGlobalColor()$> // Everything about shadow -<@include Shadow.slh@> +<@include Shadow.slh@> in vec2 _texCoord0; out vec4 _fragColor; diff --git a/libraries/render-utils/src/directional_skybox_light_shadow_map.slf b/libraries/render-utils/src/directional_skybox_light_shadow_map.slf index 632270476b..6f709f31fa 100755 --- a/libraries/render-utils/src/directional_skybox_light_shadow_map.slf +++ b/libraries/render-utils/src/directional_skybox_light_shadow_map.slf @@ -21,7 +21,7 @@ <$declareEvalSkyboxGlobalColor()$> // Everything about shadow -<@include Shadow.slh@> +<@include Shadow.slh@> in vec2 _texCoord0; out vec4 _fragColor; diff --git a/libraries/render-utils/src/model_normal_map.slv b/libraries/render-utils/src/model_normal_map.slv index 752f367a48..e989c1c294 100755 --- a/libraries/render-utils/src/model_normal_map.slv +++ b/libraries/render-utils/src/model_normal_map.slv @@ -1,44 +1,44 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// model_normal_map.vert -// vertex shader -// -// Created by Andrzej Kapolka on 10/14/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include gpu/Inputs.slh@> - -<@include gpu/Transform.slh@> - -<$declareStandardTransform()$> - -const int MAX_TEXCOORDS = 2; - -uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; - -out vec4 _position; -out vec2 _texCoord0; -out vec3 _normal; -out vec3 _tangent; -out vec3 _color; - -void main(void) { - // pass along the diffuse color - _color = inColor.rgb; - - // and the texture coordinates - _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.xy, 0.0, 1.0)).st; - - // standard transform - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> - <$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$> - <$transformModelToEyeDir(cam, obj, inTangent.xyz, _tangent)$> -} +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_normal_map.vert +// vertex shader +// +// Created by Andrzej Kapolka on 10/14/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Inputs.slh@> + +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + +const int MAX_TEXCOORDS = 2; + +uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; + +out vec4 _position; +out vec2 _texCoord0; +out vec3 _normal; +out vec3 _tangent; +out vec3 _color; + +void main(void) { + // pass along the diffuse color + _color = inColor.rgb; + + // and the texture coordinates + _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.xy, 0.0, 1.0)).st; + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> + <$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$> + <$transformModelToEyeDir(cam, obj, inTangent.xyz, _tangent)$> +} diff --git a/libraries/render-utils/src/model_shadow.slv b/libraries/render-utils/src/model_shadow.slv index b18c123d82..c81235b392 100755 --- a/libraries/render-utils/src/model_shadow.slv +++ b/libraries/render-utils/src/model_shadow.slv @@ -1,26 +1,26 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// model_shadow.vert -// vertex shader -// -// Created by Andrzej Kapolka on 3/24/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include gpu/Inputs.slh@> - -<@include gpu/Transform.slh@> - -<$declareStandardTransform()$> - -void main(void) { - // standard transform - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> -} +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_shadow.vert +// vertex shader +// +// Created by Andrzej Kapolka on 3/24/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Inputs.slh@> + +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + +void main(void) { + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> +} diff --git a/libraries/render-utils/src/skin_model.slv b/libraries/render-utils/src/skin_model.slv index bb2058b5f8..cba419dd4d 100755 --- a/libraries/render-utils/src/skin_model.slv +++ b/libraries/render-utils/src/skin_model.slv @@ -1,48 +1,48 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// skin_model.vert -// vertex shader -// -// Created by Andrzej Kapolka on 10/14/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include gpu/Inputs.slh@> - -<@include gpu/Transform.slh@> - -<$declareStandardTransform()$> - -<@include Skinning.slh@> - -uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; - -out vec4 _position; -out vec2 _texCoord0; -out vec3 _normal; -out vec3 _color; - -void main(void) { - vec4 position = vec4(0.0, 0.0, 0.0, 0.0); - vec3 interpolatedNormal = vec3(0.0, 0.0, 0.0); - - skinPositionNormal(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, position, interpolatedNormal); - - // pass along the diffuse color - _color = inColor.rgb; - - // and the texture coordinates - _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; - - // standard transform - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$> - <$transformModelToEyeDir(cam, obj, interpolatedNormal.xyz, interpolatedNormal.xyz)$> - _normal = interpolatedNormal.xyz; -} +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// skin_model.vert +// vertex shader +// +// Created by Andrzej Kapolka on 10/14/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Inputs.slh@> + +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + +<@include Skinning.slh@> + +uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; + +out vec4 _position; +out vec2 _texCoord0; +out vec3 _normal; +out vec3 _color; + +void main(void) { + vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + vec3 interpolatedNormal = vec3(0.0, 0.0, 0.0); + + skinPositionNormal(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, position, interpolatedNormal); + + // pass along the diffuse color + _color = inColor.rgb; + + // and the texture coordinates + _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$> + <$transformModelToEyeDir(cam, obj, interpolatedNormal.xyz, interpolatedNormal.xyz)$> + _normal = interpolatedNormal.xyz; +} diff --git a/libraries/render-utils/src/skin_model_normal_map.slv b/libraries/render-utils/src/skin_model_normal_map.slv index f198cb5f77..5dfe5ba957 100755 --- a/libraries/render-utils/src/skin_model_normal_map.slv +++ b/libraries/render-utils/src/skin_model_normal_map.slv @@ -1,56 +1,56 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// skin_model_normal_map.vert -// vertex shader -// -// Created by Andrzej Kapolka on 10/29/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include gpu/Inputs.slh@> - -<@include gpu/Transform.slh@> - -<$declareStandardTransform()$> - -<@include Skinning.slh@> - -uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; - -out vec4 _position; -out vec2 _texCoord0; -out vec3 _normal; -out vec3 _tangent; -out vec3 _color; - -void main(void) { - vec4 position = vec4(0.0, 0.0, 0.0, 0.0); - vec4 interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0); - vec4 interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0); - - skinPositionNormalTangent(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, inTangent.xyz, position, interpolatedNormal.xyz, interpolatedTangent.xyz); - - // pass along the diffuse color - _color = inColor.rgb; - - // and the texture coordinates - _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; - - interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); - interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0); - - // standard transform - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$> - <$transformModelToEyeDir(cam, obj, interpolatedNormal.xyz, interpolatedNormal.xyz)$> - <$transformModelToEyeDir(cam, obj, interpolatedTangent.xyz, interpolatedTangent.xyz)$> - - _normal = interpolatedNormal.xyz; - _tangent = interpolatedTangent.xyz; -} +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// skin_model_normal_map.vert +// vertex shader +// +// Created by Andrzej Kapolka on 10/29/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Inputs.slh@> + +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + +<@include Skinning.slh@> + +uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; + +out vec4 _position; +out vec2 _texCoord0; +out vec3 _normal; +out vec3 _tangent; +out vec3 _color; + +void main(void) { + vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + vec4 interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0); + vec4 interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0); + + skinPositionNormalTangent(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, inTangent.xyz, position, interpolatedNormal.xyz, interpolatedTangent.xyz); + + // pass along the diffuse color + _color = inColor.rgb; + + // and the texture coordinates + _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; + + interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); + interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0); + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$> + <$transformModelToEyeDir(cam, obj, interpolatedNormal.xyz, interpolatedNormal.xyz)$> + <$transformModelToEyeDir(cam, obj, interpolatedTangent.xyz, interpolatedTangent.xyz)$> + + _normal = interpolatedNormal.xyz; + _tangent = interpolatedTangent.xyz; +} diff --git a/libraries/render-utils/src/skin_model_shadow.slv b/libraries/render-utils/src/skin_model_shadow.slv index 9c00f9065b..6684cfea80 100755 --- a/libraries/render-utils/src/skin_model_shadow.slv +++ b/libraries/render-utils/src/skin_model_shadow.slv @@ -1,29 +1,29 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// skin_model_shadow.vert -// vertex shader -// -// Created by Andrzej Kapolka on 3/24/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include gpu/Inputs.slh@> -<@include gpu/Transform.slh@> -<$declareStandardTransform()$> - -<@include Skinning.slh@> - -void main(void) { - vec4 position = vec4(0.0, 0.0, 0.0, 0.0); - skinPosition(inSkinClusterIndex, inSkinClusterWeight, inPosition, position); - - // standard transform - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, position, gl_Position)$> -} +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// skin_model_shadow.vert +// vertex shader +// +// Created by Andrzej Kapolka on 3/24/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Inputs.slh@> +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include Skinning.slh@> + +void main(void) { + vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + skinPosition(inSkinClusterIndex, inSkinClusterWeight, inPosition, position); + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, position, gl_Position)$> +} diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 32cd21d0bc..57e21a1511 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -1,163 +1,163 @@ -// -// DrawStatus.cpp -// render/src/render -// -// Created by Niraj Venkat on 6/29/15. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "DrawStatus.h" - -#include -#include - -#include -#include -#include - -#include - -#include "drawItemBounds_vert.h" -#include "drawItemBounds_frag.h" -#include "drawItemStatus_vert.h" -#include "drawItemStatus_frag.h" - -using namespace render; - - - -const gpu::PipelinePointer& DrawStatus::getDrawItemBoundsPipeline() { - if (!_drawItemBoundsPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemBounds_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemBounds_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); - - gpu::Shader::BindingSet slotBindings; - gpu::Shader::makeProgram(*program, slotBindings); - - _drawItemBoundPosLoc = program->getUniforms().findLocation("inBoundPos"); - _drawItemBoundDimLoc = program->getUniforms().findLocation("inBoundDim"); - - auto state = std::make_shared(); - - state->setDepthTest(true, false, gpu::LESS_EQUAL); - - // Blend on transparent - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); - - // Good to go add the brand new pipeline - _drawItemBoundsPipeline.reset(gpu::Pipeline::create(program, state)); - } - return _drawItemBoundsPipeline; -} - -const gpu::PipelinePointer& DrawStatus::getDrawItemStatusPipeline() { - if (!_drawItemStatusPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemStatus_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemStatus_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); - - gpu::Shader::BindingSet slotBindings; - gpu::Shader::makeProgram(*program, slotBindings); - - _drawItemStatusPosLoc = program->getUniforms().findLocation("inBoundPos"); - _drawItemStatusDimLoc = program->getUniforms().findLocation("inBoundDim"); - _drawItemStatusValueLoc = program->getUniforms().findLocation("inStatus"); - - auto state = std::make_shared(); - - state->setDepthTest(false, false, gpu::LESS_EQUAL); - - // Blend on transparent - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); - - // Good to go add the brand new pipeline - _drawItemStatusPipeline.reset(gpu::Pipeline::create(program, state)); - } - return _drawItemStatusPipeline; -} - -void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); - RenderArgs* args = renderContext->args; - auto& scene = sceneContext->_scene; - - // FIrst thing, we collect the bound and the status for all the items we want to render - int nbItems = 0; - { - if (!_itemBounds) { - _itemBounds = std::make_shared(); - } - if (!_itemStatus) { - _itemStatus = std::make_shared();; - } - - _itemBounds->resize((inItems.size() * sizeof(AABox))); - _itemStatus->resize((inItems.size() * sizeof(glm::vec4))); - AABox* itemAABox = reinterpret_cast (_itemBounds->editData()); - glm::ivec4* itemStatus = reinterpret_cast (_itemStatus->editData()); - for (auto& item : inItems) { - if (!item.bounds.isInvalid()) { - if (!item.bounds.isNull()) { - (*itemAABox) = item.bounds; - } else { - (*itemAABox).setBox(item.bounds.getCorner(), 0.1f); - } - auto& itemScene = scene->getItem(item.id); - (*itemStatus) = itemScene.getStatusPackedValues(); - - nbItems++; - itemAABox++; - itemStatus++; - } - } - } - - if (nbItems == 0) { - return; - } - - // Allright, something to render let's do it - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - glm::mat4 projMat; - Transform viewMat; - args->_viewFrustum->evalProjectionMatrix(projMat); - args->_viewFrustum->evalViewTransform(viewMat); - - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - batch.setModelTransform(Transform()); - - // bind the one gpu::Pipeline we need - batch.setPipeline(getDrawItemBoundsPipeline()); - - AABox* itemAABox = reinterpret_cast (_itemBounds->editData()); - glm::ivec4* itemStatus = reinterpret_cast (_itemStatus->editData()); - - const unsigned int VEC3_ADRESS_OFFSET = 3; - - for (int i = 0; i < nbItems; i++) { - batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*) (itemAABox + i)); - batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); - - batch.draw(gpu::LINES, 24, 0); - } - - batch.setPipeline(getDrawItemStatusPipeline()); - for (int i = 0; i < nbItems; i++) { - batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const float*) (itemAABox + i)); - batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); - batch._glUniform4iv(_drawItemStatusValueLoc, 1, (const int*) (itemStatus + i)); - - batch.draw(gpu::TRIANGLES, 24, 0); - } - }); -} +// +// DrawStatus.cpp +// render/src/render +// +// Created by Niraj Venkat on 6/29/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "DrawStatus.h" + +#include +#include + +#include +#include +#include + +#include + +#include "drawItemBounds_vert.h" +#include "drawItemBounds_frag.h" +#include "drawItemStatus_vert.h" +#include "drawItemStatus_frag.h" + +using namespace render; + + + +const gpu::PipelinePointer& DrawStatus::getDrawItemBoundsPipeline() { + if (!_drawItemBoundsPipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemBounds_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemBounds_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + _drawItemBoundPosLoc = program->getUniforms().findLocation("inBoundPos"); + _drawItemBoundDimLoc = program->getUniforms().findLocation("inBoundDim"); + + auto state = std::make_shared(); + + state->setDepthTest(true, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + // Good to go add the brand new pipeline + _drawItemBoundsPipeline.reset(gpu::Pipeline::create(program, state)); + } + return _drawItemBoundsPipeline; +} + +const gpu::PipelinePointer& DrawStatus::getDrawItemStatusPipeline() { + if (!_drawItemStatusPipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemStatus_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemStatus_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + _drawItemStatusPosLoc = program->getUniforms().findLocation("inBoundPos"); + _drawItemStatusDimLoc = program->getUniforms().findLocation("inBoundDim"); + _drawItemStatusValueLoc = program->getUniforms().findLocation("inStatus"); + + auto state = std::make_shared(); + + state->setDepthTest(false, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + // Good to go add the brand new pipeline + _drawItemStatusPipeline.reset(gpu::Pipeline::create(program, state)); + } + return _drawItemStatusPipeline; +} + +void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { + assert(renderContext->args); + assert(renderContext->args->_viewFrustum); + RenderArgs* args = renderContext->args; + auto& scene = sceneContext->_scene; + + // FIrst thing, we collect the bound and the status for all the items we want to render + int nbItems = 0; + { + if (!_itemBounds) { + _itemBounds = std::make_shared(); + } + if (!_itemStatus) { + _itemStatus = std::make_shared();; + } + + _itemBounds->resize((inItems.size() * sizeof(AABox))); + _itemStatus->resize((inItems.size() * sizeof(glm::vec4))); + AABox* itemAABox = reinterpret_cast (_itemBounds->editData()); + glm::ivec4* itemStatus = reinterpret_cast (_itemStatus->editData()); + for (auto& item : inItems) { + if (!item.bounds.isInvalid()) { + if (!item.bounds.isNull()) { + (*itemAABox) = item.bounds; + } else { + (*itemAABox).setBox(item.bounds.getCorner(), 0.1f); + } + auto& itemScene = scene->getItem(item.id); + (*itemStatus) = itemScene.getStatusPackedValues(); + + nbItems++; + itemAABox++; + itemStatus++; + } + } + } + + if (nbItems == 0) { + return; + } + + // Allright, something to render let's do it + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + // bind the one gpu::Pipeline we need + batch.setPipeline(getDrawItemBoundsPipeline()); + + AABox* itemAABox = reinterpret_cast (_itemBounds->editData()); + glm::ivec4* itemStatus = reinterpret_cast (_itemStatus->editData()); + + const unsigned int VEC3_ADRESS_OFFSET = 3; + + for (int i = 0; i < nbItems; i++) { + batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*) (itemAABox + i)); + batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); + + batch.draw(gpu::LINES, 24, 0); + } + + batch.setPipeline(getDrawItemStatusPipeline()); + for (int i = 0; i < nbItems; i++) { + batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const float*) (itemAABox + i)); + batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); + batch._glUniform4iv(_drawItemStatusValueLoc, 1, (const int*) (itemStatus + i)); + + batch.draw(gpu::TRIANGLES, 24, 0); + } + }); +} diff --git a/libraries/render/src/render/DrawStatus.h b/libraries/render/src/render/DrawStatus.h index ca4763d33b..a96b897f5c 100644 --- a/libraries/render/src/render/DrawStatus.h +++ b/libraries/render/src/render/DrawStatus.h @@ -1,43 +1,43 @@ -// -// DrawStatus.h -// render/src/render -// -// Created by Niraj Venkat on 6/29/15. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_render_DrawStatus_h -#define hifi_render_DrawStatus_h - -#include "DrawTask.h" -#include "gpu/Batch.h" - -namespace render { - class DrawStatus { - int _drawItemBoundPosLoc = -1; - int _drawItemBoundDimLoc = -1; - int _drawItemStatusPosLoc = -1; - int _drawItemStatusDimLoc = -1; - int _drawItemStatusValueLoc = -1; - - gpu::Stream::FormatPointer _drawItemFormat; - gpu::PipelinePointer _drawItemBoundsPipeline; - gpu::PipelinePointer _drawItemStatusPipeline; - gpu::BufferPointer _itemBounds; - gpu::BufferPointer _itemStatus; - - public: - - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); - - typedef Job::ModelI JobModel; - - const gpu::PipelinePointer& getDrawItemBoundsPipeline(); - const gpu::PipelinePointer& getDrawItemStatusPipeline(); - }; -} - -#endif // hifi_render_DrawStatus_h +// +// DrawStatus.h +// render/src/render +// +// Created by Niraj Venkat on 6/29/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_render_DrawStatus_h +#define hifi_render_DrawStatus_h + +#include "DrawTask.h" +#include "gpu/Batch.h" + +namespace render { + class DrawStatus { + int _drawItemBoundPosLoc = -1; + int _drawItemBoundDimLoc = -1; + int _drawItemStatusPosLoc = -1; + int _drawItemStatusDimLoc = -1; + int _drawItemStatusValueLoc = -1; + + gpu::Stream::FormatPointer _drawItemFormat; + gpu::PipelinePointer _drawItemBoundsPipeline; + gpu::PipelinePointer _drawItemStatusPipeline; + gpu::BufferPointer _itemBounds; + gpu::BufferPointer _itemStatus; + + public: + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); + + typedef Job::ModelI JobModel; + + const gpu::PipelinePointer& getDrawItemBoundsPipeline(); + const gpu::PipelinePointer& getDrawItemStatusPipeline(); + }; +} + +#endif // hifi_render_DrawStatus_h diff --git a/libraries/render/src/render/drawItemBounds.slv b/libraries/render/src/render/drawItemBounds.slv index 4cb9a82371..7b69370f13 100644 --- a/libraries/render/src/render/drawItemBounds.slv +++ b/libraries/render/src/render/drawItemBounds.slv @@ -19,39 +19,39 @@ uniform vec3 inBoundPos; uniform vec3 inBoundDim; -void main(void) { - const vec4 UNIT_BOX[8] = vec4[8]( - vec4(0.0, 0.0, 0.0, 1.0), - vec4(1.0, 0.0, 0.0, 1.0), - vec4(0.0, 1.0, 0.0, 1.0), - vec4(1.0, 1.0, 0.0, 1.0), - vec4(0.0, 0.0, 1.0, 1.0), - vec4(1.0, 0.0, 1.0, 1.0), - vec4(0.0, 1.0, 1.0, 1.0), - vec4(1.0, 1.0, 1.0, 1.0) - ); - const int UNIT_BOX_LINE_INDICES[24] = int[24]( - 0, 1, - 1, 3, - 3, 2, - 2, 0, - 4, 5, - 5, 7, - 7, 6, - 6, 4, - 2, 6, - 3, 7, - 0, 4, - 1, 5 - ); - vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; - - pos.xyz = inBoundPos + inBoundDim * pos.xyz; - - // standard transform - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, pos, gl_Position)$> - - // varTexcoord = (pos.xy + 1) * 0.5; +void main(void) { + const vec4 UNIT_BOX[8] = vec4[8]( + vec4(0.0, 0.0, 0.0, 1.0), + vec4(1.0, 0.0, 0.0, 1.0), + vec4(0.0, 1.0, 0.0, 1.0), + vec4(1.0, 1.0, 0.0, 1.0), + vec4(0.0, 0.0, 1.0, 1.0), + vec4(1.0, 0.0, 1.0, 1.0), + vec4(0.0, 1.0, 1.0, 1.0), + vec4(1.0, 1.0, 1.0, 1.0) + ); + const int UNIT_BOX_LINE_INDICES[24] = int[24]( + 0, 1, + 1, 3, + 3, 2, + 2, 0, + 4, 5, + 5, 7, + 7, 6, + 6, 4, + 2, 6, + 3, 7, + 0, 4, + 1, 5 + ); + vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; + + pos.xyz = inBoundPos + inBoundDim * pos.xyz; + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, pos, gl_Position)$> + + // varTexcoord = (pos.xy + 1) * 0.5; } \ No newline at end of file diff --git a/libraries/render/src/render/drawItemStatus.slv b/libraries/render/src/render/drawItemStatus.slv index b90daef76a..178293575d 100644 --- a/libraries/render/src/render/drawItemStatus.slv +++ b/libraries/render/src/render/drawItemStatus.slv @@ -1,103 +1,103 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// drawItemStatus.slv -// vertex shader -// -// Created by Sam Gateau on 6/30/2015. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include gpu/Transform.slh@> - -<$declareStandardTransform()$> - -out vec4 varColor; - -uniform vec3 inBoundPos; -uniform vec3 inBoundDim; -uniform ivec4 inStatus; - -vec3 paintRainbow(float normalizedHue) { - float v = normalizedHue * 6.f; - if (v < 0.f) { - return vec3(1.f, 0.f, 0.f); - } else if (v < 1.f) { - return vec3(1.f, v, 0.f); - } else if (v < 2.f) { - return vec3(1.f - (v-1.f), 1.f, 0.f); - } else if (v < 3.f) { - return vec3(0.f, 1.f, (v-2.f)); - } else if (v < 4.f) { - return vec3(0.f, 1.f - (v-3.f), 1.f ); - } else if (v < 5.f) { - return vec3((v-4.f), 0.f, 1.f ); - } else if (v < 6.f) { - return vec3(1.f, 0.f, 1.f - (v-5.f)); - } else { - return vec3(1.f, 0.f, 0.f); - } -} - -vec2 unpackStatus(int v) { - return vec2(clamp(float(int((v >> 0) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0), - clamp(float(int((v >> 16) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0)); -} - -void main(void) { - const vec2 ICON_PIXEL_SIZE = vec2(10, 10); - const vec2 MARGIN_PIXEL_SIZE = vec2(2, 2); - const int NUM_VERTICES = 6; - const vec4 UNIT_QUAD[NUM_VERTICES] = vec4[NUM_VERTICES]( - vec4(-1.0, -1.0, 0.0, 1.0), - vec4(1.0, -1.0, 0.0, 1.0), - vec4(-1.0, 1.0, 0.0, 1.0), - vec4(-1.0, 1.0, 0.0, 1.0), - vec4(1.0, -1.0, 0.0, 1.0), - vec4(1.0, 1.0, 0.0, 1.0) - ); - - // anchor point in clip space - vec4 anchorPoint = vec4(inBoundPos, 1.0) + vec4(inBoundDim, 0.0) * vec4(0.5, 0.5, 0.5, 0.0); - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, anchorPoint, anchorPoint)$> - - // Which icon are we dealing with ? - int iconNum = gl_VertexID / NUM_VERTICES; - - // if invalid, just kill - if (inStatus[iconNum] == 0xFFFFFFFF) { - gl_Position = anchorPoint; - varColor = vec4(1.0); - return; - } - - // unpack to get x and y satus - vec2 iconStatus = unpackStatus(inStatus[iconNum]); - - // Use the status for showing a color - varColor = vec4(paintRainbow(abs(iconStatus.y)), 1.0); - - // Also changes the size of the notification - vec2 iconScale = ICON_PIXEL_SIZE; - iconScale = max(vec2(1, 1), (iconScale * iconStatus.x)); - - //Offset icon to the right based on the iconNum - vec2 offset = vec2(iconNum * (ICON_PIXEL_SIZE.x + MARGIN_PIXEL_SIZE.x), 0); - - // Final position in pixel space - int twoTriID = gl_VertexID - iconNum * NUM_VERTICES; - vec4 pos = UNIT_QUAD[twoTriID]; - vec2 quadPixelPos = offset.xy + pos.xy * 0.5 * iconScale; - - vec4 viewport; - <$transformCameraViewport(cam, viewport)$>; - vec2 pixelToClip = vec2(2.0 / viewport.z, 2.0 / viewport.w); - gl_Position = anchorPoint + (anchorPoint.w * vec4(quadPixelPos * pixelToClip, 0.0, 0.0)); - +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// drawItemStatus.slv +// vertex shader +// +// Created by Sam Gateau on 6/30/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + +out vec4 varColor; + +uniform vec3 inBoundPos; +uniform vec3 inBoundDim; +uniform ivec4 inStatus; + +vec3 paintRainbow(float normalizedHue) { + float v = normalizedHue * 6.f; + if (v < 0.f) { + return vec3(1.f, 0.f, 0.f); + } else if (v < 1.f) { + return vec3(1.f, v, 0.f); + } else if (v < 2.f) { + return vec3(1.f - (v-1.f), 1.f, 0.f); + } else if (v < 3.f) { + return vec3(0.f, 1.f, (v-2.f)); + } else if (v < 4.f) { + return vec3(0.f, 1.f - (v-3.f), 1.f ); + } else if (v < 5.f) { + return vec3((v-4.f), 0.f, 1.f ); + } else if (v < 6.f) { + return vec3(1.f, 0.f, 1.f - (v-5.f)); + } else { + return vec3(1.f, 0.f, 0.f); + } +} + +vec2 unpackStatus(int v) { + return vec2(clamp(float(int((v >> 0) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0), + clamp(float(int((v >> 16) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0)); +} + +void main(void) { + const vec2 ICON_PIXEL_SIZE = vec2(10, 10); + const vec2 MARGIN_PIXEL_SIZE = vec2(2, 2); + const int NUM_VERTICES = 6; + const vec4 UNIT_QUAD[NUM_VERTICES] = vec4[NUM_VERTICES]( + vec4(-1.0, -1.0, 0.0, 1.0), + vec4(1.0, -1.0, 0.0, 1.0), + vec4(-1.0, 1.0, 0.0, 1.0), + vec4(-1.0, 1.0, 0.0, 1.0), + vec4(1.0, -1.0, 0.0, 1.0), + vec4(1.0, 1.0, 0.0, 1.0) + ); + + // anchor point in clip space + vec4 anchorPoint = vec4(inBoundPos, 1.0) + vec4(inBoundDim, 0.0) * vec4(0.5, 0.5, 0.5, 0.0); + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, anchorPoint, anchorPoint)$> + + // Which icon are we dealing with ? + int iconNum = gl_VertexID / NUM_VERTICES; + + // if invalid, just kill + if (inStatus[iconNum] == 0xFFFFFFFF) { + gl_Position = anchorPoint; + varColor = vec4(1.0); + return; + } + + // unpack to get x and y satus + vec2 iconStatus = unpackStatus(inStatus[iconNum]); + + // Use the status for showing a color + varColor = vec4(paintRainbow(abs(iconStatus.y)), 1.0); + + // Also changes the size of the notification + vec2 iconScale = ICON_PIXEL_SIZE; + iconScale = max(vec2(1, 1), (iconScale * iconStatus.x)); + + //Offset icon to the right based on the iconNum + vec2 offset = vec2(iconNum * (ICON_PIXEL_SIZE.x + MARGIN_PIXEL_SIZE.x), 0); + + // Final position in pixel space + int twoTriID = gl_VertexID - iconNum * NUM_VERTICES; + vec4 pos = UNIT_QUAD[twoTriID]; + vec2 quadPixelPos = offset.xy + pos.xy * 0.5 * iconScale; + + vec4 viewport; + <$transformCameraViewport(cam, viewport)$>; + vec2 pixelToClip = vec2(2.0 / viewport.z, 2.0 / viewport.w); + gl_Position = anchorPoint + (anchorPoint.w * vec4(quadPixelPos * pixelToClip, 0.0, 0.0)); + } \ No newline at end of file diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index a8d602e6aa..59d2765659 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -90,8 +90,8 @@ void SceneScriptingInterface::setStageSunModelEnable(bool isEnabled) { _skyStage->setSunModelEnable(isEnabled); } -bool SceneScriptingInterface::isStageSunModelEnabled() const { - return _skyStage->isSunModelEnabled(); +bool SceneScriptingInterface::isStageSunModelEnabled() const { + return _skyStage->isSunModelEnabled(); } void SceneScriptingInterface::setBackgroundMode(const QString& mode) { diff --git a/tools/scribe/src/TextTemplate.cpp b/tools/scribe/src/TextTemplate.cpp index e7537508bc..027a73da5d 100755 --- a/tools/scribe/src/TextTemplate.cpp +++ b/tools/scribe/src/TextTemplate.cpp @@ -1,989 +1,989 @@ -// -// TextTemplate.cpp -// tools/shaderScribe/src -// -// Created by Sam Gateau on 12/15/2014. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -#include "TextTemplate.h" - -#include -#include -#include -#include - -typedef TextTemplate::Block::Pointer BlockPointer; -typedef TextTemplate::Config::Pointer ConfigPointer; -typedef TextTemplate::Pointer TextTemplatePointer; - -//----------------------------------------------------------------------------- -TextTemplate::Config::Config() : - _includes(), - _funcs(), - _logStream(&std::cout), - _numErrors(0), - _includerCallback(TextTemplate::loadFile) { - _paths.push_back(""); -} - -const TextTemplatePointer TextTemplate::Config::addInclude(const ConfigPointer& config, const char* include) { - if (!config) { - return TextTemplatePointer(); - } - - TextTemplatePointer included = config->findInclude(include); - if (included) { - return included; - } - - // INcluded doest exist yet so let's try to create it - String includeStream; - if (config->_includerCallback(config, include, includeStream)) { - // ok, then create a new Template on the include file with this as lib - included = std::make_shared(include, config); - - std::stringstream src(includeStream); - - int nbErrors = included->parse(src); - if (nbErrors > 0) { - included->logError(included->_root, "File failed to parse, not included"); - return TextTemplatePointer(); - } - config->_includes.insert(Includes::value_type(include, included)); - return included; - } - - return TextTemplatePointer(); -} - -const TextTemplatePointer TextTemplate::Config::findInclude(const char* include) { - Includes::iterator includeIt = _includes.find(String(include)); - if (includeIt != _includes.end()) { - return (*includeIt).second; - } else { - return TextTemplatePointer(); - } -} - -void TextTemplate::Config::addIncludePath(const char* path) { - _paths.push_back(String(path)); -} - -bool TextTemplate::loadFile(const ConfigPointer& config, const char* filename, String& source) { - String sourceFile(filename); - String fullfilename; - for (unsigned int i = 0; i < config->_paths.size(); i++) { - fullfilename = config->_paths[i] + sourceFile; - std::ifstream ifs; - ifs.open(fullfilename.c_str()); - if (ifs.is_open()) { - std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); - source = str; - ifs.close(); - return (source.length() > 0); - } - } - - return false; -} - -TextTemplate::Funcs::Funcs() : - _funcs() { -} - -TextTemplate::Funcs::~Funcs() { -} - - -const BlockPointer TextTemplate::Funcs::findFunc(const char* func) { - map::iterator it = _funcs.find(String(func)); - if (it != _funcs.end()) { - return (*it).second; - } else { - return BlockPointer(); - } -} - -const BlockPointer TextTemplate::Funcs::addFunc(const char* func, const BlockPointer& funcBlock) { - BlockPointer included = findFunc(func); - if (! included) { - _funcs.insert(map::value_type(func, funcBlock)); - } - return included; -} - -void TextTemplate::Block::addNewBlock(const Pointer& parent, const Pointer& block) { - if (parent) { - parent->blocks.push_back(block); - block->parent = parent; - } -} - -const BlockPointer& TextTemplate::Block::getCurrentBlock(const Pointer& block) { - if (block && block->command.isBlockEnd()) { - return block->parent; - } else { - return block; - } -} - -void TextTemplate::logError(const Block::Pointer& block, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - - char buff[256]; - sprintf(buff, fmt, argp); - - _numErrors++; - log() << block->sourceName << " Error >>" << buff << std::endl; - - int level = 1; - displayTree(std::cerr, level); - -} - -bool TextTemplate::grabUntilBeginTag(std::istream* str, std::string& grabbed, Tag::Type& tagType) { - std::stringstream dst; - while (!str->eof()) { - - std::string datatoken; - getline((*str), datatoken, Tag::BEGIN); - dst << datatoken; - - char next = str->peek(); - if (next == Tag::VAR) { - tagType = Tag::VARIABLE; - grabbed = dst.str(); - str->get(); // skip tag char - return true; - } else if (next == Tag::COM) { - tagType = Tag::COMMAND; - grabbed = dst.str(); - str->get(); // skip tag char - return true; - } else if (next == Tag::REM) { - tagType = Tag::REMARK; - grabbed = dst.str(); - str->get(); // skip tag char - return true; - } else { - if (!str->eof()) { - // false positive, just found the Tag::BEGIN without consequence - dst << Tag::BEGIN; - // keep searching - } else { - // end of the file finishing with no tag - tagType = Tag::INVALID; - grabbed = dst.str(); - return true; - } - } - } - - return false; -} - -bool TextTemplate::grabUntilEndTag(std::istream* str, std::string& grabbed, Tag::Type& tagType) { - std::stringstream dst; - - // preEnd char depends on tag type - char preEnd = Tag::COM; - if (tagType == Tag::VARIABLE) { - preEnd = Tag::VAR; - } else if (tagType == Tag::REMARK) { - preEnd = Tag::REM; - } - - while (!str->eof() && !str->fail()) { - // looking for the end of the tag means find the next preEnd - std::string dataToken; - getline((*str), dataToken, preEnd); - char end = str->peek(); - - dst << dataToken; - - // and if the next char is Tag::END then that's it - if (end == Tag::END) { - grabbed = dst.str(); - str->get(); // eat the Tag::END - return true; - } else { - // false positive, keep on searching - dst << preEnd; - } - } - grabbed = dst.str(); - return false; -} - -bool TextTemplate::stepForward(std::istream* str, std::string& grabbed, std::string& tag, Tag::Type& tagType, - Tag::Type& nextTagType) { - if (str->eof()) { - return false; - } - - if (!_steppingStarted) { - _steppingStarted = true; - return grabUntilBeginTag(str, grabbed, nextTagType); - } - - // Read from the last opening Tag::BEGIN captured to the next Tag::END - if (grabUntilEndTag(str, tag, tagType)) { - // skip trailing space and new lines only after Command or Remark tag block - if ((tagType == Tag::COMMAND) || (tagType == Tag::REMARK)) { - while (!str->eof() && !str->fail()) { - char c = str->peek(); - if ((c == ' ') || (c == '\t') || (c == '\n')) { - str->get(); - } else { - break; - } - } - } - - grabUntilBeginTag(str, grabbed, nextTagType); - } - - return true; //hasElement; -} - -const BlockPointer TextTemplate::processStep(const BlockPointer& block, std::string& grabbed, std::string& tag, - Tag::Type& tagType) { - switch (tagType) { - case Tag::INVALID: - block->ostr << grabbed; - return block; - break; - case Tag::VARIABLE: - return processStepVar(block, grabbed, tag); - break; - case Tag::COMMAND: - return processStepCommand(block, grabbed, tag); - break; - case Tag::REMARK: - return processStepRemark(block, grabbed, tag); - break; - } - - logError(block, "Invalid tag"); - return block; -} - -bool TextTemplate::grabFirstToken(String& src, String& token, String& reminder) { - bool goOn = true; - std::string::size_type i = 0; - while (goOn && (i < src.length())) { - char c = src[i]; - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '.') || (c == '[') || (c == ']')) { - token += c; - } else { - if (!token.empty()) { - reminder = src.substr(i); - return true; - } - } - i++; - } - - return (!token.empty()); -} - -bool TextTemplate::convertExpressionToArguments(String& src, std::vector< String >& arguments) { - std::stringstream str(src); - String token; - - while (!str.eof()) { - str >> token; - if (!str.fail()) { - arguments.push_back(token); - } - } - - return true; -} - -bool TextTemplate::convertExpressionToDefArguments(String& src, std::vector< String >& arguments) { - if (src.empty()) { - return false; - } - - std::stringstream argstr(src); - std::stringstream dest; - bool inVar = false; - while (!argstr.eof()) { - // parse the value of a var, try to find a VAR, so look for the pattern BEGIN,VAR ... VAR,END - String token; - char tag; - if (!inVar) { - getline(argstr, token, Tag::BEGIN); - dest << token; - tag = argstr.peek(); - } else { - getline(argstr, token, Tag::END); - dest << token; - tag = token.back(); - } - - if (tag == Tag::VAR) { - if (!inVar) { - // real var coming: - arguments.push_back(dest.str()); - inVar = true; - } else { - // real var over - arguments.push_back(dest.str()); - inVar = false; - } - } else { - if (argstr.eof()) { - arguments.push_back(dest.str()); - } else { - // put back the tag char stolen - dest << (!inVar ? Tag::BEGIN : Tag::END); - } - } - } - - return true; -} - -bool TextTemplate::convertExpressionToFuncArguments(String& src, std::vector< String >& arguments) { - if (src.empty()) { - return false; - } - std::stringstream streamSrc(src); - String params; - getline(streamSrc, params, '('); - getline(streamSrc, params, ')'); - if (params.empty()) { - return false; - } - - std::stringstream str(params); - String token; - int nbTokens = 0; - while (!str.eof()) { - char c = str.peek(); - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '.') || (c == Tag::VAR) || (c == '[') || (c == ']')) { - token += c; - } else if (c == ',') { - if (!token.empty()) { - arguments.push_back(token); - nbTokens++; - } - token.clear(); - } - - str.get(); - } - - if (token.size()) { - arguments.push_back(token); - nbTokens++; - } - - return (nbTokens > 0); -} - -const BlockPointer TextTemplate::processStepVar(const BlockPointer& block, String& grabbed, String& tag) { - // then look at the define - String var = tag; - String varName; - String val; - - if (grabFirstToken(var, varName, val)) { - if (!varName.empty()) { - BlockPointer parent = Block::getCurrentBlock(block); - - // Add a new BLock - BlockPointer newBlock = std::make_shared(_root->sourceName); - (newBlock->ostr) << grabbed; - - newBlock->command.type = Command::VAR; - - newBlock->command.arguments.push_back(varName); - - if (!val.empty()) { - convertExpressionToFuncArguments(val, newBlock->command.arguments); - } - - Block::addNewBlock(parent, newBlock); - - // dive in the new block - return newBlock; - } - } - - return block; -} - -const BlockPointer TextTemplate::processStepCommand(const BlockPointer& block, String& grabbed, String& tag) { - // Grab the command name - String command = tag; - String commandName; - - if (grabFirstToken(command, commandName, command)) { - if (commandName.compare("def") == 0) { - return processStepDef(block, grabbed, command); - } else if (commandName.compare("if") == 0) { - return processStepCommandIf(block, grabbed, command); - } else if (commandName.compare("endif") == 0) { - return processStepCommandEndIf(block, grabbed, command); - } else if (commandName.compare("else") == 0) { - return processStepCommandElse(block, grabbed, command); - } else if (commandName.compare("elif") == 0) { - return processStepCommandElif(block, grabbed, command); - } else if (commandName.compare("include") == 0) { - return processStepInclude(block, grabbed, command); - } else if (commandName.compare("func") == 0) { - return processStepFunc(block, grabbed, command); - } else if (commandName.compare("endfunc") == 0) { - return processStepEndFunc(block, grabbed, command); - } - } - - return block; -} - -const BlockPointer TextTemplate::processStepDef(const BlockPointer& block, String& grabbed, String& def) { - // then look at the define - String varName; - String val; - - if (!grabFirstToken(def, varName, val)) { - logError(block, "Invalid Var name in a tag"); - return block; - } - - BlockPointer parent = Block::getCurrentBlock(block); - - // Add a new BLock - BlockPointer newBlock = std::make_shared(_root->sourceName); - (newBlock->ostr) << grabbed; - - newBlock->command.type = Command::DEF; - newBlock->command.arguments.push_back(varName); - if (!val.empty()) { - // loose first character which should be a white space - val = val.substr(val.find_first_not_of(' ')); - convertExpressionToDefArguments(val, newBlock->command.arguments); - } - - Block::addNewBlock(parent, newBlock); - - // dive in the new block - return newBlock; -} - - -const BlockPointer TextTemplate::processStepCommandIf(const BlockPointer& block, String& grabbed, String& expression) { - BlockPointer parent = Block::getCurrentBlock(block); - - // Add a new BLock depth - BlockPointer newIfBlock = std::make_shared(_root->sourceName); - newIfBlock->command.type = Command::IFBLOCK; - - Block::addNewBlock(parent, newIfBlock); - - BlockPointer newBlock = std::make_shared(_root->sourceName); - (newBlock->ostr) << grabbed; - - newBlock->command.type = Command::IF; - convertExpressionToArguments(expression, newBlock->command.arguments); - - Block::addNewBlock(newIfBlock, newBlock); - - // dive in the new If branch - return newBlock; -} - -const BlockPointer TextTemplate::processStepCommandEndIf(const BlockPointer& block, String& grabbed, String& expression) { - BlockPointer parent = Block::getCurrentBlock(block); - - // are we in a if block ? - if ((parent->command.type == Command::IF) - || (parent->command.type == Command::ELIF) - || (parent->command.type == Command::ELSE)) { - BlockPointer newBlock = std::make_shared(_root->sourceName); - (newBlock->ostr) << grabbed; - - newBlock->command.type = Command::ENDIF; - newBlock->command.arguments.push_back(expression); - - Block::addNewBlock(parent->parent->parent, newBlock); - - return newBlock; - } else { - logError(block, "Invalid block, not in a block"); - return block; - } - - return block; -} - -const BlockPointer TextTemplate::processStepCommandElse(const BlockPointer& block, String& grabbed, String& expression) { - BlockPointer parent = Block::getCurrentBlock(block); - - // are we in a if block ? - if ((parent->command.type == Command::IF) - || (parent->command.type == Command::ELIF)) { - // All good go back to the IfBlock - parent = parent->parent; - - // Add a new BLock depth - BlockPointer newBlock = std::make_shared(_root->sourceName); - newBlock->ostr << grabbed; - newBlock->command.type = Command::ELSE; - newBlock->command.arguments.push_back(expression); - - Block::addNewBlock(parent, newBlock); - - // dive in the new block - return newBlock; - - } else if ((block)->command.type == Command::ELSE) { - logError(block, "Invalid block, in a block but after a block"); - return block; - } else { - logError(block, "Invalid block, not in a block"); - return block; - } -} - -const BlockPointer TextTemplate::processStepCommandElif(const BlockPointer& block, String& grabbed, String& expression) { - BlockPointer parent = Block::getCurrentBlock(block); - - // are we in a if block ? - if ((parent->command.type == Command::IF) - || (parent->command.type == Command::ELIF)) { - // All good go back to the IfBlock - parent = parent->parent; - - // Add a new BLock depth - BlockPointer newBlock = std::make_shared(_root->sourceName); - (newBlock->ostr) << grabbed; - - newBlock->command.type = Command::ELIF; - convertExpressionToArguments(expression, newBlock->command.arguments); - - Block::addNewBlock(parent, newBlock); - - // dive in the new block - return newBlock; - - } else if (parent->command.type == Command::ELSE) { - logError(block, "Invalid block, in a block but after a block"); - return block; - } else { - logError(block, "Invalid block, not in a block"); - return block; - } -} - -const BlockPointer TextTemplate::processStepRemark(const BlockPointer& block, String& grabbed, String& tag) { - // nothing to do :) - - // no need to think, let's just add the grabbed text - (block->ostr) << grabbed; - - return block; -} - -const BlockPointer TextTemplate::processStepInclude(const BlockPointer& block, String& grabbed, String& include) { - BlockPointer parent = Block::getCurrentBlock(block); - - // Add a new BLock - BlockPointer newBlock = std::make_shared(_root->sourceName); - (newBlock->ostr) << grabbed; - - newBlock->command.type = Command::INCLUDE; - convertExpressionToArguments(include, newBlock->command.arguments); - - Block::addNewBlock(parent, newBlock); - - TextTemplatePointer inc = Config::addInclude(_config, newBlock->command.arguments.front().c_str()); - if (!inc) { - logError(newBlock, "Failed to include %s", newBlock->command.arguments.front().c_str()); - } - - // dive in the new block - return newBlock; -} - -const BlockPointer TextTemplate::processStepFunc(const BlockPointer& block, String& grabbed, String& func) { - // then look at the define - String varName; - String var; - - if (!grabFirstToken(func, varName, var)) { - logError(block, "Invalid func name <%s> in a block", func.c_str()); - return block; - } - - // DOes the func already exists ? - if (_config->_funcs.findFunc(varName.c_str())) { - logError(block, "Declaring a new func named <%s> already exists", func.c_str()); - return block; - } - - BlockPointer parent = Block::getCurrentBlock(block); - - // Add a new BLock - BlockPointer newBlock = std::make_shared(_root->sourceName); - (newBlock->ostr) << grabbed; - - newBlock->command.type = Command::FUNC; - newBlock->command.arguments.push_back(varName); - convertExpressionToFuncArguments(var, newBlock->command.arguments); - - _config->_funcs.addFunc(varName.c_str(), newBlock); - - Block::addNewBlock(parent, newBlock); - - // dive in the new block - return newBlock; -} - -const BlockPointer TextTemplate::processStepEndFunc(const BlockPointer& block, String& grabbed, String& tag) { - BlockPointer parent = Block::getCurrentBlock(block); - - // are we in a func block ? - if (parent->command.type == Command::FUNC) { - // Make sure the FUnc has been declared properly - BlockPointer funcBlock = _config->_funcs.findFunc(parent->command.arguments.front().c_str()); - if (funcBlock != parent) { - logError(block, "Mismatching blocks"); - return BlockPointer(); - } - - // Everything is cool , so let's unplugg the FUnc block from this tree and just put the EndFunc block - - BlockPointer newBlock = std::make_shared(_root->sourceName); - (newBlock->ostr) << grabbed; - - newBlock->command.type = Command::ENDFUNC; - convertExpressionToArguments(tag, newBlock->command.arguments); - - newBlock->parent = parent->parent; - - parent->parent->blocks.back() = newBlock; - - parent->parent = 0; - - // dive in the new block - return newBlock; - } else { - logError(block, "Invalid block, not in a block"); - return BlockPointer(); - } - - return block; -} - -TextTemplate::TextTemplate(const String& name, const ConfigPointer& externalConfig) : - _config(externalConfig), - _root(new Block(name)), - _numErrors(0), - _steppingStarted(false) { -} - -TextTemplate::~TextTemplate() { -} - -int TextTemplate::scribe(std::ostream& dst, std::istream& src, Vars& vars) { - int nbErrors = parse(src); - - if (nbErrors == 0) { - return generate(dst, vars); - } - return nbErrors; -} - -int TextTemplate::generateTree(std::ostream& dst, const BlockPointer& block, Vars& vars) { - BlockPointer newCurrentBlock; - int numPasses = evalBlockGeneration(dst, block, vars, newCurrentBlock); - for (int passNum= 0; passNum < numPasses; passNum++) { - dst << newCurrentBlock->ostr.str(); - - for (auto child : newCurrentBlock->blocks) { - generateTree(dst, child, vars); - } - } - - return _numErrors; -} - -int TextTemplate::evalBlockGeneration(std::ostream& dst, const BlockPointer& block, Vars& vars, BlockPointer& branch) { - switch (block->command.type) { - case Command::BLOCK: { - branch = block; - return 1; - } - break; - case Command::VAR: { - Vars::iterator it = vars.find(block->command.arguments.front()); - if (it != vars.end()) { - dst << (*it).second; - } else { - BlockPointer funcBlock = _config->_funcs.findFunc(block->command.arguments.front().c_str()); - if (funcBlock) { - // before diving in the func tree, let's modify the vars with the local defs: - int nbParams = std::min(block->command.arguments.size(), funcBlock->command.arguments.size()); - std::vector< String > paramCache; - paramCache.push_back(""); - String val; - for (int i = 1; i < nbParams; i++) { - val = block->command.arguments[i]; - if ((val[0] == Tag::VAR) && (val[val.length()-1] == Tag::VAR)) { - val = val.substr(1, val.length()-2); - Vars::iterator it = vars.find(val); - if (it != vars.end()) { - val = (*it).second; - } - } - - Vars::iterator it = vars.find(funcBlock->command.arguments[i]); - if (it != vars.end()) { - paramCache.push_back((*it).second); - (*it).second = val; - } else { - vars.insert(Vars::value_type(funcBlock->command.arguments[i], val)); - paramCache.push_back(""); - } - } - - generateTree(dst, funcBlock, vars); - - for (int i = 1; i < nbParams; i++) { - vars[ funcBlock->command.arguments[i] ] = paramCache[i]; - } - } - } - branch = block; - return 1; - } - break; - case Command::IFBLOCK: { - // ok, go through the branches and pick the first one that goes - for (auto child: block->blocks) { - int numPasses = evalBlockGeneration(dst, child, vars, branch); - if (numPasses > 0) { - return numPasses; - } - } - } - break; - case Command::IF: - case Command::ELIF: { - if (!block->command.arguments.empty()) { - // Just one argument means check for the var beeing defined - if (block->command.arguments.size() == 1) { - Vars::iterator it = vars.find(block->command.arguments.front()); - if (it != vars.end()) { - branch = block; - return 1; - } - } else if (block->command.arguments.size() == 2) { - if (block->command.arguments[0].compare("not") == 0) { - Vars::iterator it = vars.find(block->command.arguments[1]); - if (it == vars.end()) { - branch = block; - return 1; - } - } - } else if (block->command.arguments.size() == 3) { - if (block->command.arguments[1].compare("and") == 0) { - Vars::iterator itL = vars.find(block->command.arguments[0]); - Vars::iterator itR = vars.find(block->command.arguments[2]); - if ((itL != vars.end()) && (itR != vars.end())) { - branch = block; - return 1; - } - } else if (block->command.arguments[1].compare("or") == 0) { - Vars::iterator itL = vars.find(block->command.arguments[0]); - Vars::iterator itR = vars.find(block->command.arguments[2]); - if ((itL != vars.end()) || (itR != vars.end())) { - branch = block; - return 1; - } - } else if (block->command.arguments[1].compare("==") == 0) { - Vars::iterator itL = vars.find(block->command.arguments[0]); - if (itL != vars.end()) { - if ((*itL).second.compare(block->command.arguments[2]) == 0) { - branch = block; - return 1; - } - } - } - } - - } - return 0; - } - break; - case Command::ELSE: { - branch = block; - return 1; - } - break; - case Command::ENDIF: { - branch = block; - return 1; - } - break; - case Command::DEF: { - if (block->command.arguments.size()) { - // THe actual value of the var defined sneeds to be evaluated: - String val; - for (unsigned int t = 1; t < block->command.arguments.size(); t++) { - // detect if a param is a var - int len = block->command.arguments[t].length(); - if ((block->command.arguments[t][0] == Tag::VAR) - && (block->command.arguments[t][len - 1] == Tag::VAR)) { - String var = block->command.arguments[t].substr(1, len - 2); - Vars::iterator it = vars.find(var); - if (it != vars.end()) { - val += (*it).second; - } - } else { - val += block->command.arguments[t]; - } - } - - Vars::iterator it = vars.find(block->command.arguments.front()); - if (it == vars.end()) { - vars.insert(Vars::value_type(block->command.arguments.front(), val)); - } else { - (*it).second = val; - } - - branch = block; - return 1; - } else { - branch = block; - return 0; - } - } - break; - - case Command::INCLUDE: { - TextTemplatePointer include = _config->findInclude(block->command.arguments.front().c_str()); - if (include && !include->_root->blocks.empty()) { - if (include->_root) { - generateTree(dst, include->_root, vars); - } - } - - branch = block; - return 1; - } - break; - - case Command::FUNC: { - branch = block; - return 1; - } - break; - - case Command::ENDFUNC: { - branch = block; - return 1; - } - break; - - default: { - } - } - - return 0; -} - - -int TextTemplate::parse(std::istream& src) { - _root->command.type = Command::BLOCK; - BlockPointer currentBlock = _root; - _numErrors = 0; - - // First Parse the input file - int nbLoops = 0; - bool goOn = true; - Tag::Type tagType = Tag::INVALID; - Tag::Type nextTagType = Tag::INVALID; - while (goOn) { - std::string data; - std::string tag; - if (stepForward(&src, data, tag, tagType, nextTagType)) { - currentBlock = processStep(currentBlock, data, tag, tagType); - } else { - goOn = false; - } - - tagType = nextTagType; - nbLoops++; - } - - return _numErrors; -} - -int TextTemplate::generate(std::ostream& dst, Vars& vars) { - return generateTree(dst, _root, vars); -} - -void TextTemplate::displayTree(std::ostream& dst, int& level) const { - Block::displayTree(_root, dst, level); -} - -void TextTemplate::Block::displayTree(const BlockPointer& block, std::ostream& dst, int& level) { - String tab(level * 2, ' '); - - const String BLOCK_TYPE_NAMES[] = { - "VAR", - "BLOCK", - "FUNC", - "ENDFUNC", - "IFBLOCK", - "IF", - "ELIF", - "ELSE", - "ENDIF", - "FOR", - "ENDFOR", - "INCLUDE", - "DEF" - }; - - dst << tab << "{ " << BLOCK_TYPE_NAMES[block->command.type] << ":"; - if (!block->command.arguments.empty()) { - for (auto arg: block->command.arguments) { - dst << " " << arg; - } - } - dst << std::endl; - - level++; - for (auto sub: block->blocks) { - displayTree(sub, dst, level); - } - level--; - - dst << tab << "}" << std::endl; -} - -void TextTemplate::Config::displayTree(std::ostream& dst, int& level) const { - String tab(level * 2, ' '); - - level++; - dst << tab << "Includes:" << std::endl; - for (auto inc: _includes) { - dst << tab << tab << inc.first << std::endl; - inc.second->displayTree(dst, level); - } - dst << tab << "Funcs:" << std::endl; - for (auto func: _funcs._funcs) { - dst << tab << tab << func.first << std::endl; - TextTemplate::Block::displayTree( func.second, dst, level); - } - level--; -} +// +// TextTemplate.cpp +// tools/shaderScribe/src +// +// Created by Sam Gateau on 12/15/2014. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +#include "TextTemplate.h" + +#include +#include +#include +#include + +typedef TextTemplate::Block::Pointer BlockPointer; +typedef TextTemplate::Config::Pointer ConfigPointer; +typedef TextTemplate::Pointer TextTemplatePointer; + +//----------------------------------------------------------------------------- +TextTemplate::Config::Config() : + _includes(), + _funcs(), + _logStream(&std::cout), + _numErrors(0), + _includerCallback(TextTemplate::loadFile) { + _paths.push_back(""); +} + +const TextTemplatePointer TextTemplate::Config::addInclude(const ConfigPointer& config, const char* include) { + if (!config) { + return TextTemplatePointer(); + } + + TextTemplatePointer included = config->findInclude(include); + if (included) { + return included; + } + + // INcluded doest exist yet so let's try to create it + String includeStream; + if (config->_includerCallback(config, include, includeStream)) { + // ok, then create a new Template on the include file with this as lib + included = std::make_shared(include, config); + + std::stringstream src(includeStream); + + int nbErrors = included->parse(src); + if (nbErrors > 0) { + included->logError(included->_root, "File failed to parse, not included"); + return TextTemplatePointer(); + } + config->_includes.insert(Includes::value_type(include, included)); + return included; + } + + return TextTemplatePointer(); +} + +const TextTemplatePointer TextTemplate::Config::findInclude(const char* include) { + Includes::iterator includeIt = _includes.find(String(include)); + if (includeIt != _includes.end()) { + return (*includeIt).second; + } else { + return TextTemplatePointer(); + } +} + +void TextTemplate::Config::addIncludePath(const char* path) { + _paths.push_back(String(path)); +} + +bool TextTemplate::loadFile(const ConfigPointer& config, const char* filename, String& source) { + String sourceFile(filename); + String fullfilename; + for (unsigned int i = 0; i < config->_paths.size(); i++) { + fullfilename = config->_paths[i] + sourceFile; + std::ifstream ifs; + ifs.open(fullfilename.c_str()); + if (ifs.is_open()) { + std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); + source = str; + ifs.close(); + return (source.length() > 0); + } + } + + return false; +} + +TextTemplate::Funcs::Funcs() : + _funcs() { +} + +TextTemplate::Funcs::~Funcs() { +} + + +const BlockPointer TextTemplate::Funcs::findFunc(const char* func) { + map::iterator it = _funcs.find(String(func)); + if (it != _funcs.end()) { + return (*it).second; + } else { + return BlockPointer(); + } +} + +const BlockPointer TextTemplate::Funcs::addFunc(const char* func, const BlockPointer& funcBlock) { + BlockPointer included = findFunc(func); + if (! included) { + _funcs.insert(map::value_type(func, funcBlock)); + } + return included; +} + +void TextTemplate::Block::addNewBlock(const Pointer& parent, const Pointer& block) { + if (parent) { + parent->blocks.push_back(block); + block->parent = parent; + } +} + +const BlockPointer& TextTemplate::Block::getCurrentBlock(const Pointer& block) { + if (block && block->command.isBlockEnd()) { + return block->parent; + } else { + return block; + } +} + +void TextTemplate::logError(const Block::Pointer& block, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + + char buff[256]; + sprintf(buff, fmt, argp); + + _numErrors++; + log() << block->sourceName << " Error >>" << buff << std::endl; + + int level = 1; + displayTree(std::cerr, level); + +} + +bool TextTemplate::grabUntilBeginTag(std::istream* str, std::string& grabbed, Tag::Type& tagType) { + std::stringstream dst; + while (!str->eof()) { + + std::string datatoken; + getline((*str), datatoken, Tag::BEGIN); + dst << datatoken; + + char next = str->peek(); + if (next == Tag::VAR) { + tagType = Tag::VARIABLE; + grabbed = dst.str(); + str->get(); // skip tag char + return true; + } else if (next == Tag::COM) { + tagType = Tag::COMMAND; + grabbed = dst.str(); + str->get(); // skip tag char + return true; + } else if (next == Tag::REM) { + tagType = Tag::REMARK; + grabbed = dst.str(); + str->get(); // skip tag char + return true; + } else { + if (!str->eof()) { + // false positive, just found the Tag::BEGIN without consequence + dst << Tag::BEGIN; + // keep searching + } else { + // end of the file finishing with no tag + tagType = Tag::INVALID; + grabbed = dst.str(); + return true; + } + } + } + + return false; +} + +bool TextTemplate::grabUntilEndTag(std::istream* str, std::string& grabbed, Tag::Type& tagType) { + std::stringstream dst; + + // preEnd char depends on tag type + char preEnd = Tag::COM; + if (tagType == Tag::VARIABLE) { + preEnd = Tag::VAR; + } else if (tagType == Tag::REMARK) { + preEnd = Tag::REM; + } + + while (!str->eof() && !str->fail()) { + // looking for the end of the tag means find the next preEnd + std::string dataToken; + getline((*str), dataToken, preEnd); + char end = str->peek(); + + dst << dataToken; + + // and if the next char is Tag::END then that's it + if (end == Tag::END) { + grabbed = dst.str(); + str->get(); // eat the Tag::END + return true; + } else { + // false positive, keep on searching + dst << preEnd; + } + } + grabbed = dst.str(); + return false; +} + +bool TextTemplate::stepForward(std::istream* str, std::string& grabbed, std::string& tag, Tag::Type& tagType, + Tag::Type& nextTagType) { + if (str->eof()) { + return false; + } + + if (!_steppingStarted) { + _steppingStarted = true; + return grabUntilBeginTag(str, grabbed, nextTagType); + } + + // Read from the last opening Tag::BEGIN captured to the next Tag::END + if (grabUntilEndTag(str, tag, tagType)) { + // skip trailing space and new lines only after Command or Remark tag block + if ((tagType == Tag::COMMAND) || (tagType == Tag::REMARK)) { + while (!str->eof() && !str->fail()) { + char c = str->peek(); + if ((c == ' ') || (c == '\t') || (c == '\n')) { + str->get(); + } else { + break; + } + } + } + + grabUntilBeginTag(str, grabbed, nextTagType); + } + + return true; //hasElement; +} + +const BlockPointer TextTemplate::processStep(const BlockPointer& block, std::string& grabbed, std::string& tag, + Tag::Type& tagType) { + switch (tagType) { + case Tag::INVALID: + block->ostr << grabbed; + return block; + break; + case Tag::VARIABLE: + return processStepVar(block, grabbed, tag); + break; + case Tag::COMMAND: + return processStepCommand(block, grabbed, tag); + break; + case Tag::REMARK: + return processStepRemark(block, grabbed, tag); + break; + } + + logError(block, "Invalid tag"); + return block; +} + +bool TextTemplate::grabFirstToken(String& src, String& token, String& reminder) { + bool goOn = true; + std::string::size_type i = 0; + while (goOn && (i < src.length())) { + char c = src[i]; + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '.') || (c == '[') || (c == ']')) { + token += c; + } else { + if (!token.empty()) { + reminder = src.substr(i); + return true; + } + } + i++; + } + + return (!token.empty()); +} + +bool TextTemplate::convertExpressionToArguments(String& src, std::vector< String >& arguments) { + std::stringstream str(src); + String token; + + while (!str.eof()) { + str >> token; + if (!str.fail()) { + arguments.push_back(token); + } + } + + return true; +} + +bool TextTemplate::convertExpressionToDefArguments(String& src, std::vector< String >& arguments) { + if (src.empty()) { + return false; + } + + std::stringstream argstr(src); + std::stringstream dest; + bool inVar = false; + while (!argstr.eof()) { + // parse the value of a var, try to find a VAR, so look for the pattern BEGIN,VAR ... VAR,END + String token; + char tag; + if (!inVar) { + getline(argstr, token, Tag::BEGIN); + dest << token; + tag = argstr.peek(); + } else { + getline(argstr, token, Tag::END); + dest << token; + tag = token.back(); + } + + if (tag == Tag::VAR) { + if (!inVar) { + // real var coming: + arguments.push_back(dest.str()); + inVar = true; + } else { + // real var over + arguments.push_back(dest.str()); + inVar = false; + } + } else { + if (argstr.eof()) { + arguments.push_back(dest.str()); + } else { + // put back the tag char stolen + dest << (!inVar ? Tag::BEGIN : Tag::END); + } + } + } + + return true; +} + +bool TextTemplate::convertExpressionToFuncArguments(String& src, std::vector< String >& arguments) { + if (src.empty()) { + return false; + } + std::stringstream streamSrc(src); + String params; + getline(streamSrc, params, '('); + getline(streamSrc, params, ')'); + if (params.empty()) { + return false; + } + + std::stringstream str(params); + String token; + int nbTokens = 0; + while (!str.eof()) { + char c = str.peek(); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '.') || (c == Tag::VAR) || (c == '[') || (c == ']')) { + token += c; + } else if (c == ',') { + if (!token.empty()) { + arguments.push_back(token); + nbTokens++; + } + token.clear(); + } + + str.get(); + } + + if (token.size()) { + arguments.push_back(token); + nbTokens++; + } + + return (nbTokens > 0); +} + +const BlockPointer TextTemplate::processStepVar(const BlockPointer& block, String& grabbed, String& tag) { + // then look at the define + String var = tag; + String varName; + String val; + + if (grabFirstToken(var, varName, val)) { + if (!varName.empty()) { + BlockPointer parent = Block::getCurrentBlock(block); + + // Add a new BLock + BlockPointer newBlock = std::make_shared(_root->sourceName); + (newBlock->ostr) << grabbed; + + newBlock->command.type = Command::VAR; + + newBlock->command.arguments.push_back(varName); + + if (!val.empty()) { + convertExpressionToFuncArguments(val, newBlock->command.arguments); + } + + Block::addNewBlock(parent, newBlock); + + // dive in the new block + return newBlock; + } + } + + return block; +} + +const BlockPointer TextTemplate::processStepCommand(const BlockPointer& block, String& grabbed, String& tag) { + // Grab the command name + String command = tag; + String commandName; + + if (grabFirstToken(command, commandName, command)) { + if (commandName.compare("def") == 0) { + return processStepDef(block, grabbed, command); + } else if (commandName.compare("if") == 0) { + return processStepCommandIf(block, grabbed, command); + } else if (commandName.compare("endif") == 0) { + return processStepCommandEndIf(block, grabbed, command); + } else if (commandName.compare("else") == 0) { + return processStepCommandElse(block, grabbed, command); + } else if (commandName.compare("elif") == 0) { + return processStepCommandElif(block, grabbed, command); + } else if (commandName.compare("include") == 0) { + return processStepInclude(block, grabbed, command); + } else if (commandName.compare("func") == 0) { + return processStepFunc(block, grabbed, command); + } else if (commandName.compare("endfunc") == 0) { + return processStepEndFunc(block, grabbed, command); + } + } + + return block; +} + +const BlockPointer TextTemplate::processStepDef(const BlockPointer& block, String& grabbed, String& def) { + // then look at the define + String varName; + String val; + + if (!grabFirstToken(def, varName, val)) { + logError(block, "Invalid Var name in a tag"); + return block; + } + + BlockPointer parent = Block::getCurrentBlock(block); + + // Add a new BLock + BlockPointer newBlock = std::make_shared(_root->sourceName); + (newBlock->ostr) << grabbed; + + newBlock->command.type = Command::DEF; + newBlock->command.arguments.push_back(varName); + if (!val.empty()) { + // loose first character which should be a white space + val = val.substr(val.find_first_not_of(' ')); + convertExpressionToDefArguments(val, newBlock->command.arguments); + } + + Block::addNewBlock(parent, newBlock); + + // dive in the new block + return newBlock; +} + + +const BlockPointer TextTemplate::processStepCommandIf(const BlockPointer& block, String& grabbed, String& expression) { + BlockPointer parent = Block::getCurrentBlock(block); + + // Add a new BLock depth + BlockPointer newIfBlock = std::make_shared(_root->sourceName); + newIfBlock->command.type = Command::IFBLOCK; + + Block::addNewBlock(parent, newIfBlock); + + BlockPointer newBlock = std::make_shared(_root->sourceName); + (newBlock->ostr) << grabbed; + + newBlock->command.type = Command::IF; + convertExpressionToArguments(expression, newBlock->command.arguments); + + Block::addNewBlock(newIfBlock, newBlock); + + // dive in the new If branch + return newBlock; +} + +const BlockPointer TextTemplate::processStepCommandEndIf(const BlockPointer& block, String& grabbed, String& expression) { + BlockPointer parent = Block::getCurrentBlock(block); + + // are we in a if block ? + if ((parent->command.type == Command::IF) + || (parent->command.type == Command::ELIF) + || (parent->command.type == Command::ELSE)) { + BlockPointer newBlock = std::make_shared(_root->sourceName); + (newBlock->ostr) << grabbed; + + newBlock->command.type = Command::ENDIF; + newBlock->command.arguments.push_back(expression); + + Block::addNewBlock(parent->parent->parent, newBlock); + + return newBlock; + } else { + logError(block, "Invalid block, not in a block"); + return block; + } + + return block; +} + +const BlockPointer TextTemplate::processStepCommandElse(const BlockPointer& block, String& grabbed, String& expression) { + BlockPointer parent = Block::getCurrentBlock(block); + + // are we in a if block ? + if ((parent->command.type == Command::IF) + || (parent->command.type == Command::ELIF)) { + // All good go back to the IfBlock + parent = parent->parent; + + // Add a new BLock depth + BlockPointer newBlock = std::make_shared(_root->sourceName); + newBlock->ostr << grabbed; + newBlock->command.type = Command::ELSE; + newBlock->command.arguments.push_back(expression); + + Block::addNewBlock(parent, newBlock); + + // dive in the new block + return newBlock; + + } else if ((block)->command.type == Command::ELSE) { + logError(block, "Invalid block, in a block but after a block"); + return block; + } else { + logError(block, "Invalid block, not in a block"); + return block; + } +} + +const BlockPointer TextTemplate::processStepCommandElif(const BlockPointer& block, String& grabbed, String& expression) { + BlockPointer parent = Block::getCurrentBlock(block); + + // are we in a if block ? + if ((parent->command.type == Command::IF) + || (parent->command.type == Command::ELIF)) { + // All good go back to the IfBlock + parent = parent->parent; + + // Add a new BLock depth + BlockPointer newBlock = std::make_shared(_root->sourceName); + (newBlock->ostr) << grabbed; + + newBlock->command.type = Command::ELIF; + convertExpressionToArguments(expression, newBlock->command.arguments); + + Block::addNewBlock(parent, newBlock); + + // dive in the new block + return newBlock; + + } else if (parent->command.type == Command::ELSE) { + logError(block, "Invalid block, in a block but after a block"); + return block; + } else { + logError(block, "Invalid block, not in a block"); + return block; + } +} + +const BlockPointer TextTemplate::processStepRemark(const BlockPointer& block, String& grabbed, String& tag) { + // nothing to do :) + + // no need to think, let's just add the grabbed text + (block->ostr) << grabbed; + + return block; +} + +const BlockPointer TextTemplate::processStepInclude(const BlockPointer& block, String& grabbed, String& include) { + BlockPointer parent = Block::getCurrentBlock(block); + + // Add a new BLock + BlockPointer newBlock = std::make_shared(_root->sourceName); + (newBlock->ostr) << grabbed; + + newBlock->command.type = Command::INCLUDE; + convertExpressionToArguments(include, newBlock->command.arguments); + + Block::addNewBlock(parent, newBlock); + + TextTemplatePointer inc = Config::addInclude(_config, newBlock->command.arguments.front().c_str()); + if (!inc) { + logError(newBlock, "Failed to include %s", newBlock->command.arguments.front().c_str()); + } + + // dive in the new block + return newBlock; +} + +const BlockPointer TextTemplate::processStepFunc(const BlockPointer& block, String& grabbed, String& func) { + // then look at the define + String varName; + String var; + + if (!grabFirstToken(func, varName, var)) { + logError(block, "Invalid func name <%s> in a block", func.c_str()); + return block; + } + + // DOes the func already exists ? + if (_config->_funcs.findFunc(varName.c_str())) { + logError(block, "Declaring a new func named <%s> already exists", func.c_str()); + return block; + } + + BlockPointer parent = Block::getCurrentBlock(block); + + // Add a new BLock + BlockPointer newBlock = std::make_shared(_root->sourceName); + (newBlock->ostr) << grabbed; + + newBlock->command.type = Command::FUNC; + newBlock->command.arguments.push_back(varName); + convertExpressionToFuncArguments(var, newBlock->command.arguments); + + _config->_funcs.addFunc(varName.c_str(), newBlock); + + Block::addNewBlock(parent, newBlock); + + // dive in the new block + return newBlock; +} + +const BlockPointer TextTemplate::processStepEndFunc(const BlockPointer& block, String& grabbed, String& tag) { + BlockPointer parent = Block::getCurrentBlock(block); + + // are we in a func block ? + if (parent->command.type == Command::FUNC) { + // Make sure the FUnc has been declared properly + BlockPointer funcBlock = _config->_funcs.findFunc(parent->command.arguments.front().c_str()); + if (funcBlock != parent) { + logError(block, "Mismatching blocks"); + return BlockPointer(); + } + + // Everything is cool , so let's unplugg the FUnc block from this tree and just put the EndFunc block + + BlockPointer newBlock = std::make_shared(_root->sourceName); + (newBlock->ostr) << grabbed; + + newBlock->command.type = Command::ENDFUNC; + convertExpressionToArguments(tag, newBlock->command.arguments); + + newBlock->parent = parent->parent; + + parent->parent->blocks.back() = newBlock; + + parent->parent = 0; + + // dive in the new block + return newBlock; + } else { + logError(block, "Invalid block, not in a block"); + return BlockPointer(); + } + + return block; +} + +TextTemplate::TextTemplate(const String& name, const ConfigPointer& externalConfig) : + _config(externalConfig), + _root(new Block(name)), + _numErrors(0), + _steppingStarted(false) { +} + +TextTemplate::~TextTemplate() { +} + +int TextTemplate::scribe(std::ostream& dst, std::istream& src, Vars& vars) { + int nbErrors = parse(src); + + if (nbErrors == 0) { + return generate(dst, vars); + } + return nbErrors; +} + +int TextTemplate::generateTree(std::ostream& dst, const BlockPointer& block, Vars& vars) { + BlockPointer newCurrentBlock; + int numPasses = evalBlockGeneration(dst, block, vars, newCurrentBlock); + for (int passNum= 0; passNum < numPasses; passNum++) { + dst << newCurrentBlock->ostr.str(); + + for (auto child : newCurrentBlock->blocks) { + generateTree(dst, child, vars); + } + } + + return _numErrors; +} + +int TextTemplate::evalBlockGeneration(std::ostream& dst, const BlockPointer& block, Vars& vars, BlockPointer& branch) { + switch (block->command.type) { + case Command::BLOCK: { + branch = block; + return 1; + } + break; + case Command::VAR: { + Vars::iterator it = vars.find(block->command.arguments.front()); + if (it != vars.end()) { + dst << (*it).second; + } else { + BlockPointer funcBlock = _config->_funcs.findFunc(block->command.arguments.front().c_str()); + if (funcBlock) { + // before diving in the func tree, let's modify the vars with the local defs: + int nbParams = std::min(block->command.arguments.size(), funcBlock->command.arguments.size()); + std::vector< String > paramCache; + paramCache.push_back(""); + String val; + for (int i = 1; i < nbParams; i++) { + val = block->command.arguments[i]; + if ((val[0] == Tag::VAR) && (val[val.length()-1] == Tag::VAR)) { + val = val.substr(1, val.length()-2); + Vars::iterator it = vars.find(val); + if (it != vars.end()) { + val = (*it).second; + } + } + + Vars::iterator it = vars.find(funcBlock->command.arguments[i]); + if (it != vars.end()) { + paramCache.push_back((*it).second); + (*it).second = val; + } else { + vars.insert(Vars::value_type(funcBlock->command.arguments[i], val)); + paramCache.push_back(""); + } + } + + generateTree(dst, funcBlock, vars); + + for (int i = 1; i < nbParams; i++) { + vars[ funcBlock->command.arguments[i] ] = paramCache[i]; + } + } + } + branch = block; + return 1; + } + break; + case Command::IFBLOCK: { + // ok, go through the branches and pick the first one that goes + for (auto child: block->blocks) { + int numPasses = evalBlockGeneration(dst, child, vars, branch); + if (numPasses > 0) { + return numPasses; + } + } + } + break; + case Command::IF: + case Command::ELIF: { + if (!block->command.arguments.empty()) { + // Just one argument means check for the var beeing defined + if (block->command.arguments.size() == 1) { + Vars::iterator it = vars.find(block->command.arguments.front()); + if (it != vars.end()) { + branch = block; + return 1; + } + } else if (block->command.arguments.size() == 2) { + if (block->command.arguments[0].compare("not") == 0) { + Vars::iterator it = vars.find(block->command.arguments[1]); + if (it == vars.end()) { + branch = block; + return 1; + } + } + } else if (block->command.arguments.size() == 3) { + if (block->command.arguments[1].compare("and") == 0) { + Vars::iterator itL = vars.find(block->command.arguments[0]); + Vars::iterator itR = vars.find(block->command.arguments[2]); + if ((itL != vars.end()) && (itR != vars.end())) { + branch = block; + return 1; + } + } else if (block->command.arguments[1].compare("or") == 0) { + Vars::iterator itL = vars.find(block->command.arguments[0]); + Vars::iterator itR = vars.find(block->command.arguments[2]); + if ((itL != vars.end()) || (itR != vars.end())) { + branch = block; + return 1; + } + } else if (block->command.arguments[1].compare("==") == 0) { + Vars::iterator itL = vars.find(block->command.arguments[0]); + if (itL != vars.end()) { + if ((*itL).second.compare(block->command.arguments[2]) == 0) { + branch = block; + return 1; + } + } + } + } + + } + return 0; + } + break; + case Command::ELSE: { + branch = block; + return 1; + } + break; + case Command::ENDIF: { + branch = block; + return 1; + } + break; + case Command::DEF: { + if (block->command.arguments.size()) { + // THe actual value of the var defined sneeds to be evaluated: + String val; + for (unsigned int t = 1; t < block->command.arguments.size(); t++) { + // detect if a param is a var + int len = block->command.arguments[t].length(); + if ((block->command.arguments[t][0] == Tag::VAR) + && (block->command.arguments[t][len - 1] == Tag::VAR)) { + String var = block->command.arguments[t].substr(1, len - 2); + Vars::iterator it = vars.find(var); + if (it != vars.end()) { + val += (*it).second; + } + } else { + val += block->command.arguments[t]; + } + } + + Vars::iterator it = vars.find(block->command.arguments.front()); + if (it == vars.end()) { + vars.insert(Vars::value_type(block->command.arguments.front(), val)); + } else { + (*it).second = val; + } + + branch = block; + return 1; + } else { + branch = block; + return 0; + } + } + break; + + case Command::INCLUDE: { + TextTemplatePointer include = _config->findInclude(block->command.arguments.front().c_str()); + if (include && !include->_root->blocks.empty()) { + if (include->_root) { + generateTree(dst, include->_root, vars); + } + } + + branch = block; + return 1; + } + break; + + case Command::FUNC: { + branch = block; + return 1; + } + break; + + case Command::ENDFUNC: { + branch = block; + return 1; + } + break; + + default: { + } + } + + return 0; +} + + +int TextTemplate::parse(std::istream& src) { + _root->command.type = Command::BLOCK; + BlockPointer currentBlock = _root; + _numErrors = 0; + + // First Parse the input file + int nbLoops = 0; + bool goOn = true; + Tag::Type tagType = Tag::INVALID; + Tag::Type nextTagType = Tag::INVALID; + while (goOn) { + std::string data; + std::string tag; + if (stepForward(&src, data, tag, tagType, nextTagType)) { + currentBlock = processStep(currentBlock, data, tag, tagType); + } else { + goOn = false; + } + + tagType = nextTagType; + nbLoops++; + } + + return _numErrors; +} + +int TextTemplate::generate(std::ostream& dst, Vars& vars) { + return generateTree(dst, _root, vars); +} + +void TextTemplate::displayTree(std::ostream& dst, int& level) const { + Block::displayTree(_root, dst, level); +} + +void TextTemplate::Block::displayTree(const BlockPointer& block, std::ostream& dst, int& level) { + String tab(level * 2, ' '); + + const String BLOCK_TYPE_NAMES[] = { + "VAR", + "BLOCK", + "FUNC", + "ENDFUNC", + "IFBLOCK", + "IF", + "ELIF", + "ELSE", + "ENDIF", + "FOR", + "ENDFOR", + "INCLUDE", + "DEF" + }; + + dst << tab << "{ " << BLOCK_TYPE_NAMES[block->command.type] << ":"; + if (!block->command.arguments.empty()) { + for (auto arg: block->command.arguments) { + dst << " " << arg; + } + } + dst << std::endl; + + level++; + for (auto sub: block->blocks) { + displayTree(sub, dst, level); + } + level--; + + dst << tab << "}" << std::endl; +} + +void TextTemplate::Config::displayTree(std::ostream& dst, int& level) const { + String tab(level * 2, ' '); + + level++; + dst << tab << "Includes:" << std::endl; + for (auto inc: _includes) { + dst << tab << tab << inc.first << std::endl; + inc.second->displayTree(dst, level); + } + dst << tab << "Funcs:" << std::endl; + for (auto func: _funcs._funcs) { + dst << tab << tab << func.first << std::endl; + TextTemplate::Block::displayTree( func.second, dst, level); + } + level--; +} diff --git a/tools/scribe/src/TextTemplate.h b/tools/scribe/src/TextTemplate.h index a19d2938da..a6fd04da5c 100755 --- a/tools/scribe/src/TextTemplate.h +++ b/tools/scribe/src/TextTemplate.h @@ -1,4 +1,4 @@ - + // // TextTemplate.cpp // tools/shaderScribe/src @@ -7,198 +7,198 @@ // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -#ifndef hifi_TEXT_TEMPLATE_H -#define hifi_TEXT_TEMPLATE_H - -#include -#include -#include -#include -#include -#include -#include - -class TextTemplate { -public: - typedef std::shared_ptr< TextTemplate > Pointer; - typedef std::string String; - typedef std::vector< String > StringVector; - typedef std::map< String, String > Vars; - typedef std::map< String, TextTemplate::Pointer > Includes; - - class Tag { - public: - enum Type { - VARIABLE = 0, - COMMAND, - REMARK, - INVALID = -1, - }; - - static const char BEGIN = '<'; - static const char END = '>'; - - static const char VAR = '$'; - static const char COM = '@'; - static const char REM = '!'; - }; - - class Command { - public: - typedef std::vector< Command > vector; - - enum Type { - VAR = 0, - BLOCK, - FUNC, - ENDFUNC, - IFBLOCK, - IF, - ELIF, - ELSE, - ENDIF, - FOR, - ENDFOR, - INCLUDE, - DEF, - }; - - Type type; - std::vector< String > arguments; - - bool isBlockEnd() { - switch (type) { - case ENDFUNC: - case ENDIF: - case ENDFOR: - case INCLUDE: - case DEF: - case VAR: - return true; - default: - return false; - } - } - }; - - class Block { - public: - typedef std::shared_ptr Pointer; - typedef std::vector< Block::Pointer > Vector; - - Block::Pointer parent; - Command command; - Vector blocks; - std::stringstream ostr; - - String sourceName; - - Block(const String& sourceFilename) : - sourceName(sourceFilename) {} - - static void addNewBlock(const Block::Pointer& parent, const Block::Pointer& block); - static const Block::Pointer& getCurrentBlock(const Block::Pointer& block); - - static void displayTree(const Block::Pointer& block, std::ostream& dst, int& level); - }; - - class Funcs { - public: - typedef std::map< String, Block::Pointer > map; - - Funcs(); - ~Funcs(); - - const Block::Pointer findFunc(const char* func); - const Block::Pointer addFunc(const char* func, const Block::Pointer& root); - - map _funcs; - protected: - }; - - class Config { - public: - typedef std::shared_ptr< Config > Pointer; - typedef bool (*IncluderCallback) (const Config::Pointer& config, const char* filename, String& source); - - Includes _includes; - Funcs _funcs; - std::ostream* _logStream; - int _numErrors; - IncluderCallback _includerCallback; - StringVector _paths; - - Config(); - - static const TextTemplate::Pointer addInclude(const Config::Pointer& config, const char* include); - const TextTemplate::Pointer findInclude(const char* include); - - void addIncludePath(const char* path); - - void displayTree(std::ostream& dst, int& level) const; - }; - - static bool loadFile(const Config::Pointer& config, const char* filename, String& source); - - TextTemplate(const String& name, const Config::Pointer& config = std::make_shared()); - ~TextTemplate(); - - // Scibe does all the job of parsing an inout template stream and then gneerating theresulting stream using the vars - int scribe(std::ostream& dst, std::istream& src, Vars& vars); - - int parse(std::istream& src); - int generate(std::ostream& dst, Vars& vars); - - const Config::Pointer config() { return _config; } - - void displayTree(std::ostream& dst, int& level) const; - -protected: - Config::Pointer _config; - Block::Pointer _root; - int _numErrors; - bool _steppingStarted; - - bool grabUntilBeginTag(std::istream* str, String& grabbed, Tag::Type& tagType); - bool grabUntilEndTag(std::istream* str, String& grabbed, Tag::Type& tagType); - - bool stepForward(std::istream* str, String& grabbed, String& tag, Tag::Type& tagType, Tag::Type& nextTagType); - - bool grabFirstToken(String& src, String& token, String& reminder); - bool convertExpressionToArguments(String& src, std::vector< String >& arguments); - bool convertExpressionToDefArguments(String& src, std::vector< String >& arguments); - bool convertExpressionToFuncArguments(String& src, std::vector< String >& arguments); - - // Filter between var, command or comments - const Block::Pointer processStep(const Block::Pointer& block, String& grabbed, String& tag, Tag::Type& tagType); - const Block::Pointer processStepVar(const Block::Pointer& block, String& grabbed, String& tag); - const Block::Pointer processStepCommand(const Block::Pointer& block, String& grabbed, String& tag); - const Block::Pointer processStepRemark(const Block::Pointer& block, String& grabbed, String& tag); - - // Define command - const Block::Pointer processStepDef(const Block::Pointer& block, String& grabbed, String& tag); - - // If commands - const Block::Pointer processStepCommandIf(const Block::Pointer& block, String& grabbed, String& expression); - const Block::Pointer processStepCommandEndIf(const Block::Pointer& block, String& grabbed, String& expression); - const Block::Pointer processStepCommandElif(const Block::Pointer& block, String& grabbed, String& expression); - const Block::Pointer processStepCommandElse(const Block::Pointer& block, String& grabbed, String& expression); - - // Include command - const Block::Pointer processStepInclude(const Block::Pointer& block, String& grabbed, String& tag); - - // Function command - const Block::Pointer processStepFunc(const Block::Pointer& block, String& grabbed, String& tag); - const Block::Pointer processStepEndFunc(const Block::Pointer& block, String& grabbed, String& tag); - - // Generation - int generateTree(std::ostream& dst, const Block::Pointer& block, Vars& vars); - int evalBlockGeneration(std::ostream& dst, const Block::Pointer& block, Vars& vars, Block::Pointer& branch); - - // Errors - std::ostream& log() { return (* _config->_logStream); } - void logError(const Block::Pointer& block, const char* error, ...); -}; - -#endif +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +#ifndef hifi_TEXT_TEMPLATE_H +#define hifi_TEXT_TEMPLATE_H + +#include +#include +#include +#include +#include +#include +#include + +class TextTemplate { +public: + typedef std::shared_ptr< TextTemplate > Pointer; + typedef std::string String; + typedef std::vector< String > StringVector; + typedef std::map< String, String > Vars; + typedef std::map< String, TextTemplate::Pointer > Includes; + + class Tag { + public: + enum Type { + VARIABLE = 0, + COMMAND, + REMARK, + INVALID = -1, + }; + + static const char BEGIN = '<'; + static const char END = '>'; + + static const char VAR = '$'; + static const char COM = '@'; + static const char REM = '!'; + }; + + class Command { + public: + typedef std::vector< Command > vector; + + enum Type { + VAR = 0, + BLOCK, + FUNC, + ENDFUNC, + IFBLOCK, + IF, + ELIF, + ELSE, + ENDIF, + FOR, + ENDFOR, + INCLUDE, + DEF, + }; + + Type type; + std::vector< String > arguments; + + bool isBlockEnd() { + switch (type) { + case ENDFUNC: + case ENDIF: + case ENDFOR: + case INCLUDE: + case DEF: + case VAR: + return true; + default: + return false; + } + } + }; + + class Block { + public: + typedef std::shared_ptr Pointer; + typedef std::vector< Block::Pointer > Vector; + + Block::Pointer parent; + Command command; + Vector blocks; + std::stringstream ostr; + + String sourceName; + + Block(const String& sourceFilename) : + sourceName(sourceFilename) {} + + static void addNewBlock(const Block::Pointer& parent, const Block::Pointer& block); + static const Block::Pointer& getCurrentBlock(const Block::Pointer& block); + + static void displayTree(const Block::Pointer& block, std::ostream& dst, int& level); + }; + + class Funcs { + public: + typedef std::map< String, Block::Pointer > map; + + Funcs(); + ~Funcs(); + + const Block::Pointer findFunc(const char* func); + const Block::Pointer addFunc(const char* func, const Block::Pointer& root); + + map _funcs; + protected: + }; + + class Config { + public: + typedef std::shared_ptr< Config > Pointer; + typedef bool (*IncluderCallback) (const Config::Pointer& config, const char* filename, String& source); + + Includes _includes; + Funcs _funcs; + std::ostream* _logStream; + int _numErrors; + IncluderCallback _includerCallback; + StringVector _paths; + + Config(); + + static const TextTemplate::Pointer addInclude(const Config::Pointer& config, const char* include); + const TextTemplate::Pointer findInclude(const char* include); + + void addIncludePath(const char* path); + + void displayTree(std::ostream& dst, int& level) const; + }; + + static bool loadFile(const Config::Pointer& config, const char* filename, String& source); + + TextTemplate(const String& name, const Config::Pointer& config = std::make_shared()); + ~TextTemplate(); + + // Scibe does all the job of parsing an inout template stream and then gneerating theresulting stream using the vars + int scribe(std::ostream& dst, std::istream& src, Vars& vars); + + int parse(std::istream& src); + int generate(std::ostream& dst, Vars& vars); + + const Config::Pointer config() { return _config; } + + void displayTree(std::ostream& dst, int& level) const; + +protected: + Config::Pointer _config; + Block::Pointer _root; + int _numErrors; + bool _steppingStarted; + + bool grabUntilBeginTag(std::istream* str, String& grabbed, Tag::Type& tagType); + bool grabUntilEndTag(std::istream* str, String& grabbed, Tag::Type& tagType); + + bool stepForward(std::istream* str, String& grabbed, String& tag, Tag::Type& tagType, Tag::Type& nextTagType); + + bool grabFirstToken(String& src, String& token, String& reminder); + bool convertExpressionToArguments(String& src, std::vector< String >& arguments); + bool convertExpressionToDefArguments(String& src, std::vector< String >& arguments); + bool convertExpressionToFuncArguments(String& src, std::vector< String >& arguments); + + // Filter between var, command or comments + const Block::Pointer processStep(const Block::Pointer& block, String& grabbed, String& tag, Tag::Type& tagType); + const Block::Pointer processStepVar(const Block::Pointer& block, String& grabbed, String& tag); + const Block::Pointer processStepCommand(const Block::Pointer& block, String& grabbed, String& tag); + const Block::Pointer processStepRemark(const Block::Pointer& block, String& grabbed, String& tag); + + // Define command + const Block::Pointer processStepDef(const Block::Pointer& block, String& grabbed, String& tag); + + // If commands + const Block::Pointer processStepCommandIf(const Block::Pointer& block, String& grabbed, String& expression); + const Block::Pointer processStepCommandEndIf(const Block::Pointer& block, String& grabbed, String& expression); + const Block::Pointer processStepCommandElif(const Block::Pointer& block, String& grabbed, String& expression); + const Block::Pointer processStepCommandElse(const Block::Pointer& block, String& grabbed, String& expression); + + // Include command + const Block::Pointer processStepInclude(const Block::Pointer& block, String& grabbed, String& tag); + + // Function command + const Block::Pointer processStepFunc(const Block::Pointer& block, String& grabbed, String& tag); + const Block::Pointer processStepEndFunc(const Block::Pointer& block, String& grabbed, String& tag); + + // Generation + int generateTree(std::ostream& dst, const Block::Pointer& block, Vars& vars); + int evalBlockGeneration(std::ostream& dst, const Block::Pointer& block, Vars& vars, Block::Pointer& branch); + + // Errors + std::ostream& log() { return (* _config->_logStream); } + void logError(const Block::Pointer& block, const char* error, ...); +}; + +#endif