overte-JulianGro/libraries/entities-renderer/src/RenderableImageEntityItem.cpp
2021-02-25 19:03:42 -08:00

188 lines
6.6 KiB
C++

//
// Created by Sam Gondelman on 11/29/18
// Copyright 2018 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 "RenderableImageEntityItem.h"
#include <DependencyManager.h>
#include <GeometryCache.h>
#include "RenderPipelines.h"
using namespace render;
using namespace render::entities;
ImageEntityRenderer::ImageEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
_material->setCullFaceMode(graphics::MaterialKey::CullFaceMode::CULL_NONE);
addMaterial(graphics::MaterialLayer(_material, 0), "0");
}
ImageEntityRenderer::~ImageEntityRenderer() {
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
geometryCache->releaseID(_geometryId);
}
}
bool ImageEntityRenderer::needsRenderUpdate() const {
return needsRenderUpdateFromMaterials() || Parent::needsRenderUpdate();
}
void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
withWriteLock([&] {
_renderTransform = getModelTransform();
_renderTransform.postScale(entity->getScaledDimensions());
});
});
}
void ImageEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
auto imageURL = entity->getImageURL();
if (_imageURL != imageURL) {
_imageURL = imageURL;
if (imageURL.isEmpty()) {
_texture.reset();
} else {
_texture = DependencyManager::get<TextureCache>()->getTexture(_imageURL);
}
_textureIsLoaded = false;
}
_keepAspectRatio = entity->getKeepAspectRatio();
_subImage = entity->getSubImage();
_pulseProperties = entity->getPulseProperties();
bool materialChanged = false;
glm::vec3 color = toGlm(entity->getColor());
if (_color != color) {
_color = color;
_material->setAlbedo(color);
materialChanged = true;
}
float alpha = entity->getAlpha();
if (_alpha != alpha) {
_alpha = alpha;
_material->setOpacity(alpha);
materialChanged = true;
}
auto emissive = entity->getEmissive();
if (_emissive != emissive) {
_emissive = emissive;
_material->setUnlit(_emissive);
materialChanged = true;
}
updateMaterials(materialChanged);
if (!_textureIsLoaded) {
emit requestRenderUpdate();
}
_textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
}
bool ImageEntityRenderer::isTransparent() const {
bool imageTransparent = _alpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE ||
(_textureIsLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha());
return imageTransparent || Parent::isTransparent() || materialsTransparent();
}
Item::Bound ImageEntityRenderer::getBound(RenderArgs* args) {
return Parent::getMaterialBound(args);
}
ShapeKey ImageEntityRenderer::getShapeKey() {
auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias();
updateShapeKeyBuilderFromMaterials(builder);
return builder.build();
}
void ImageEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableImageEntityItem::render");
Q_ASSERT(args->_batch);
graphics::MultiMaterial materials;
{
std::lock_guard<std::mutex> lock(_materialsLock);
materials = _materials["0"];
}
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
glm::vec4 color = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
if (!_texture || !_texture->isLoaded() || color.a == 0.0f) {
return;
}
Transform transform;
bool transparent;
withReadLock([&] {
transform = _renderTransform;
transparent = isTransparent();
});
gpu::Batch* batch = args->_batch;
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch->setModelTransform(transform);
float imageWidth = _texture->getWidth();
float imageHeight = _texture->getHeight();
QRect fromImage;
if (_subImage.width() <= 0) {
fromImage.setX(0);
fromImage.setWidth(imageWidth);
} else {
float scaleX = imageWidth / _texture->getOriginalWidth();
fromImage.setX(scaleX * _subImage.x());
fromImage.setWidth(scaleX * _subImage.width());
}
if (_subImage.height() <= 0) {
fromImage.setY(0);
fromImage.setHeight(imageHeight);
} else {
float scaleY = imageHeight / _texture->getOriginalHeight();
fromImage.setY(scaleY * _subImage.y());
fromImage.setHeight(scaleY * _subImage.height());
}
float maxSize = glm::max(fromImage.width(), fromImage.height());
float x = _keepAspectRatio ? fromImage.width() / (2.0f * maxSize) : 0.5f;
float y = _keepAspectRatio ? fromImage.height() / (2.0f * maxSize) : 0.5f;
glm::vec2 texCoordBottomLeft((fromImage.x() + 0.5f) / imageWidth, (fromImage.y() + fromImage.height() - 0.5f) / imageHeight);
glm::vec2 texCoordTopRight((fromImage.x() + fromImage.width() - 0.5f) / imageWidth, (fromImage.y() + 0.5f) / imageHeight);
Pipeline pipelineType = getPipelineType(materials);
if (pipelineType == Pipeline::PROCEDURAL) {
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials.top().material);
transparent |= procedural->isFading();
procedural->prepare(*batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(transparent));
} else if (pipelineType == Pipeline::SIMPLE) {
batch->setResourceTexture(0, _texture->getGPUTexture());
} else {
if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) {
args->_details._materialSwitches++;
}
}
DependencyManager::get<GeometryCache>()->renderQuad(
*batch, glm::vec2(-x, -y), glm::vec2(x, y), texCoordBottomLeft, texCoordTopRight,
color, _geometryId
);
batch->setResourceTexture(0, nullptr);
}