mirror of
https://github.com/JulianGro/overte.git
synced 2025-05-05 10:28:03 +02:00
248 lines
8.2 KiB
C++
248 lines
8.2 KiB
C++
//
|
|
// Image3DOverlay.cpp
|
|
//
|
|
//
|
|
// Created by Clement on 7/1/14.
|
|
// Modified and renamed by Zander Otavka on 8/4/15
|
|
// 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 "Image3DOverlay.h"
|
|
|
|
#include <DependencyManager.h>
|
|
#include <GeometryCache.h>
|
|
#include <gpu/Batch.h>
|
|
#include <RegisteredMetaTypes.h>
|
|
|
|
#include "GeometryUtil.h"
|
|
|
|
#include "AbstractViewStateInterface.h"
|
|
|
|
QString const Image3DOverlay::TYPE = "image3d";
|
|
|
|
Image3DOverlay::Image3DOverlay() {
|
|
_isLoaded = false;
|
|
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
|
}
|
|
|
|
Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) :
|
|
Billboard3DOverlay(image3DOverlay),
|
|
_url(image3DOverlay->_url),
|
|
_texture(image3DOverlay->_texture),
|
|
_emissive(image3DOverlay->_emissive),
|
|
_fromImage(image3DOverlay->_fromImage)
|
|
{
|
|
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
|
}
|
|
|
|
Image3DOverlay::~Image3DOverlay() {
|
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
|
if (geometryCache) {
|
|
geometryCache->releaseID(_geometryId);
|
|
}
|
|
}
|
|
|
|
void Image3DOverlay::update(float deltatime) {
|
|
if (!_isLoaded) {
|
|
_isLoaded = true;
|
|
_texture = DependencyManager::get<TextureCache>()->getTexture(_url);
|
|
_textureIsLoaded = false;
|
|
}
|
|
#if OVERLAY_PANELS
|
|
if (usecTimestampNow() > _transformExpiry) {
|
|
Transform transform = getTransform();
|
|
applyTransformTo(transform);
|
|
setTransform(transform);
|
|
}
|
|
#endif
|
|
Parent::update(deltatime);
|
|
}
|
|
|
|
void Image3DOverlay::render(RenderArgs* args) {
|
|
if (!_visible || !getParentVisible() || !_texture || !_texture->isLoaded()) {
|
|
return;
|
|
}
|
|
|
|
// Once the texture has loaded, check if we need to update the render item because of transparency
|
|
if (!_textureIsLoaded && _texture && _texture->getGPUTexture()) {
|
|
_textureIsLoaded = true;
|
|
bool prevAlphaTexture = _alphaTexture;
|
|
_alphaTexture = _texture->getGPUTexture()->getUsage().isAlpha();
|
|
if (_alphaTexture != prevAlphaTexture) {
|
|
auto itemID = getRenderItemID();
|
|
if (render::Item::isValidID(itemID)) {
|
|
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
|
render::Transaction transaction;
|
|
transaction.updateItem(itemID);
|
|
scene->enqueueTransaction(transaction);
|
|
}
|
|
}
|
|
}
|
|
|
|
Q_ASSERT(args->_batch);
|
|
gpu::Batch* batch = args->_batch;
|
|
|
|
float imageWidth = _texture->getWidth();
|
|
float imageHeight = _texture->getHeight();
|
|
|
|
QRect fromImage;
|
|
if (_fromImage.isNull()) {
|
|
fromImage.setX(0);
|
|
fromImage.setY(0);
|
|
fromImage.setWidth(imageWidth);
|
|
fromImage.setHeight(imageHeight);
|
|
} else {
|
|
float scaleX = imageWidth / _texture->getOriginalWidth();
|
|
float scaleY = imageHeight / _texture->getOriginalHeight();
|
|
|
|
fromImage.setX(scaleX * _fromImage.x());
|
|
fromImage.setY(scaleY * _fromImage.y());
|
|
fromImage.setWidth(scaleX * _fromImage.width());
|
|
fromImage.setHeight(scaleY * _fromImage.height());
|
|
}
|
|
|
|
float maxSize = glm::max(fromImage.width(), fromImage.height());
|
|
float x = fromImage.width() / (2.0f * maxSize);
|
|
float y = -fromImage.height() / (2.0f * maxSize);
|
|
|
|
glm::vec2 topLeft(-x, -y);
|
|
glm::vec2 bottomRight(x, y);
|
|
glm::vec2 texCoordTopLeft((fromImage.x() + 0.5f) / imageWidth, (fromImage.y() + 0.5f) / imageHeight);
|
|
glm::vec2 texCoordBottomRight((fromImage.x() + fromImage.width() - 0.5f) / imageWidth,
|
|
(fromImage.y() + fromImage.height() - 0.5f) / imageHeight);
|
|
|
|
const float MAX_COLOR = 255.0f;
|
|
xColor color = getColor();
|
|
float alpha = getAlpha();
|
|
|
|
batch->setModelTransform(getRenderTransform());
|
|
batch->setResourceTexture(0, _texture->getGPUTexture());
|
|
|
|
DependencyManager::get<GeometryCache>()->renderQuad(
|
|
*batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
|
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha),
|
|
_geometryId
|
|
);
|
|
|
|
batch->setResourceTexture(0, nullptr); // restore default white color after me
|
|
}
|
|
|
|
const render::ShapeKey Image3DOverlay::getShapeKey() {
|
|
auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias();
|
|
if (_emissive) {
|
|
builder.withUnlit();
|
|
}
|
|
if (isTransparent()) {
|
|
builder.withTranslucent();
|
|
}
|
|
return builder.build();
|
|
}
|
|
|
|
void Image3DOverlay::setProperties(const QVariantMap& properties) {
|
|
Billboard3DOverlay::setProperties(properties);
|
|
|
|
auto urlValue = properties["url"];
|
|
if (urlValue.isValid()) {
|
|
QString newURL = urlValue.toString();
|
|
if (newURL != _url) {
|
|
setURL(newURL);
|
|
}
|
|
}
|
|
|
|
auto subImageBoundsVar = properties["subImage"];
|
|
if (subImageBoundsVar.isValid()) {
|
|
if (subImageBoundsVar.isNull()) {
|
|
_fromImage = QRect();
|
|
} else {
|
|
QRect oldSubImageRect = _fromImage;
|
|
QRect subImageRect = _fromImage;
|
|
auto subImageBounds = subImageBoundsVar.toMap();
|
|
if (subImageBounds["x"].isValid()) {
|
|
subImageRect.setX(subImageBounds["x"].toInt());
|
|
} else {
|
|
subImageRect.setX(oldSubImageRect.x());
|
|
}
|
|
if (subImageBounds["y"].isValid()) {
|
|
subImageRect.setY(subImageBounds["y"].toInt());
|
|
} else {
|
|
subImageRect.setY(oldSubImageRect.y());
|
|
}
|
|
if (subImageBounds["width"].isValid()) {
|
|
subImageRect.setWidth(subImageBounds["width"].toInt());
|
|
} else {
|
|
subImageRect.setWidth(oldSubImageRect.width());
|
|
}
|
|
if (subImageBounds["height"].isValid()) {
|
|
subImageRect.setHeight(subImageBounds["height"].toInt());
|
|
} else {
|
|
subImageRect.setHeight(oldSubImageRect.height());
|
|
}
|
|
setClipFromSource(subImageRect);
|
|
}
|
|
}
|
|
|
|
auto emissiveValue = properties["emissive"];
|
|
if (emissiveValue.isValid()) {
|
|
_emissive = emissiveValue.toBool();
|
|
}
|
|
}
|
|
|
|
QVariant Image3DOverlay::getProperty(const QString& property) {
|
|
if (property == "url") {
|
|
return _url;
|
|
}
|
|
if (property == "subImage") {
|
|
return _fromImage;
|
|
}
|
|
if (property == "offsetPosition") {
|
|
return vec3toVariant(getOffsetPosition());
|
|
}
|
|
if (property == "emissive") {
|
|
return _emissive;
|
|
}
|
|
|
|
return Billboard3DOverlay::getProperty(property);
|
|
}
|
|
|
|
void Image3DOverlay::setURL(const QString& url) {
|
|
_url = url;
|
|
_isLoaded = false;
|
|
}
|
|
|
|
bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
|
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
|
if (_texture && _texture->isLoaded()) {
|
|
// Make sure position and rotation is updated.
|
|
Transform transform = getTransform();
|
|
|
|
// Don't call applyTransformTo() or setTransform() here because this code runs too frequently.
|
|
|
|
// Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale.
|
|
bool isNull = _fromImage.isNull();
|
|
float width = isNull ? _texture->getWidth() : _fromImage.width();
|
|
float height = isNull ? _texture->getHeight() : _fromImage.height();
|
|
float maxSize = glm::max(width, height);
|
|
glm::vec2 dimensions = _dimensions * glm::vec2(width / maxSize, height / maxSize);
|
|
|
|
// FIXME - face and surfaceNormal not being set
|
|
return findRayRectangleIntersection(origin, direction,
|
|
transform.getRotation(),
|
|
transform.getTranslation(),
|
|
dimensions, distance);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Image3DOverlay* Image3DOverlay::createClone() const {
|
|
return new Image3DOverlay(this);
|
|
}
|
|
|
|
Transform Image3DOverlay::evalRenderTransform() {
|
|
auto transform = Parent::evalRenderTransform();
|
|
transform.postScale(glm::vec3(getDimensions(), 1.0f));
|
|
return transform;
|
|
}
|