mirror of
https://github.com/overte-org/overte.git
synced 2025-04-12 18:42:12 +02:00
Redistributing the files to create the model-networking lib and separate that from the redner-utils
This commit is contained in:
parent
2875cb99bb
commit
d3b1bcb86d
36 changed files with 1055 additions and 748 deletions
|
@ -113,7 +113,7 @@ endif()
|
|||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
# link required hifi libraries
|
||||
link_hifi_libraries(shared octree environment gpu gpu-networking procedural model render fbx networking entities avatars
|
||||
link_hifi_libraries(shared octree environment gpu procedural model render fbx networking model-networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer ui auto-updater
|
||||
plugins display-plugins input-plugins)
|
||||
|
|
|
@ -278,6 +278,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<NodeList>(NodeType::Agent, listenPort);
|
||||
auto geometryCache = DependencyManager::set<GeometryCache>();
|
||||
auto modelCache = DependencyManager::set<ModelCache>();
|
||||
auto scriptCache = DependencyManager::set<ScriptCache>();
|
||||
auto soundCache = DependencyManager::set<SoundCache>();
|
||||
auto faceshift = DependencyManager::set<Faceshift>();
|
||||
|
@ -418,12 +419,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
// put the NodeList and datagram processing on the node thread
|
||||
nodeList->moveToThread(nodeThread);
|
||||
|
||||
// geometry background downloads need to happen on the Datagram Processor Thread. The idle loop will
|
||||
// emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background
|
||||
// Model background downloads need to happen on the Datagram Processor Thread. The idle loop will
|
||||
// emit checkBackgroundDownloads to cause the ModelCache to check it's queue for requested background
|
||||
// downloads.
|
||||
QSharedPointer<GeometryCache> geometryCacheP = DependencyManager::get<GeometryCache>();
|
||||
ResourceCache* geometryCache = geometryCacheP.data();
|
||||
connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets);
|
||||
QSharedPointer<ModelCache> modelCacheP = DependencyManager::get<ModelCache>();
|
||||
ResourceCache* modelCache = modelCacheP.data();
|
||||
connect(this, &Application::checkBackgroundDownloads, modelCache, &ResourceCache::checkAsynchronousGets);
|
||||
|
||||
// put the audio processing on a separate thread
|
||||
QThread* audioThread = new QThread();
|
||||
|
@ -892,6 +893,7 @@ Application::~Application() {
|
|||
DependencyManager::destroy<AnimationCache>();
|
||||
DependencyManager::destroy<FramebufferCache>();
|
||||
DependencyManager::destroy<TextureCache>();
|
||||
DependencyManager::destroy<ModelCache>();
|
||||
DependencyManager::destroy<GeometryCache>();
|
||||
DependencyManager::destroy<ScriptCache>();
|
||||
DependencyManager::destroy<SoundCache>();
|
||||
|
@ -2718,7 +2720,7 @@ void Application::reloadResourceCaches() {
|
|||
emptyLocalCache();
|
||||
|
||||
DependencyManager::get<AnimationCache>()->refreshAll();
|
||||
DependencyManager::get<GeometryCache>()->refreshAll();
|
||||
DependencyManager::get<ModelCache>()->refreshAll();
|
||||
DependencyManager::get<SoundCache>()->refreshAll();
|
||||
DependencyManager::get<TextureCache>()->refreshAll();
|
||||
}
|
||||
|
|
|
@ -188,8 +188,10 @@ void Stars::render(RenderArgs* renderArgs, float alpha) {
|
|||
colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element;
|
||||
});
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
auto modelCache = DependencyManager::get<ModelCache>();
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
|
||||
gpu::Batch& batch = *renderArgs->_batch;
|
||||
batch.setViewTransform(Transform());
|
||||
|
|
|
@ -56,7 +56,7 @@ CachesSizeDialog::CachesSizeDialog(QWidget* parent) :
|
|||
|
||||
void CachesSizeDialog::confirmClicked(bool checked) {
|
||||
DependencyManager::get<AnimationCache>()->setUnusedResourceCacheSize(_animations->value() * BYTES_PER_MEGABYTES);
|
||||
DependencyManager::get<GeometryCache>()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES);
|
||||
DependencyManager::get<ModelCache>()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES);
|
||||
DependencyManager::get<SoundCache>()->setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES);
|
||||
DependencyManager::get<TextureCache>()->setUnusedResourceCacheSize(_textures->value() * BYTES_PER_MEGABYTES);
|
||||
|
||||
|
@ -65,7 +65,7 @@ void CachesSizeDialog::confirmClicked(bool checked) {
|
|||
|
||||
void CachesSizeDialog::resetClicked(bool checked) {
|
||||
_animations->setValue(DependencyManager::get<AnimationCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_geometries->setValue(DependencyManager::get<GeometryCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_geometries->setValue(DependencyManager::get<ModelCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_sounds->setValue(DependencyManager::get<SoundCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_textures->setValue(DependencyManager::get<TextureCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
}
|
||||
|
|
|
@ -26,4 +26,4 @@ find_package(PolyVox REQUIRED)
|
|||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES})
|
||||
|
||||
link_hifi_libraries(shared gpu gpu-networking procedural script-engine render render-utils)
|
||||
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils)
|
||||
|
|
|
@ -71,3 +71,28 @@ bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ShaderSource
|
||||
ShaderSource::ShaderSource() {
|
||||
}
|
||||
|
||||
ShaderSource::~ShaderSource() {
|
||||
}
|
||||
|
||||
void ShaderSource::reset(const QUrl& url) {
|
||||
_shaderUrl = url;
|
||||
_gpuShader.reset();
|
||||
}
|
||||
|
||||
void ShaderSource::resetShader(gpu::Shader* shader) {
|
||||
_gpuShader.reset(shader);
|
||||
}
|
||||
|
||||
bool ShaderSource::isDefined() const {
|
||||
if (_gpuShader) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <string>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include <QUrl>
|
||||
|
||||
namespace gpu {
|
||||
|
||||
|
@ -187,6 +189,27 @@ protected:
|
|||
typedef Shader::Pointer ShaderPointer;
|
||||
typedef std::vector< ShaderPointer > Shaders;
|
||||
|
||||
// ShaderSource is the bridge between a URL or a a way to produce the final gpu::Shader that will be used to render it.
|
||||
class ShaderSource {
|
||||
public:
|
||||
ShaderSource();
|
||||
~ShaderSource();
|
||||
|
||||
const QUrl& getUrl() const { return _shaderUrl; }
|
||||
const gpu::ShaderPointer getGPUShader() const { return _gpuShader; }
|
||||
|
||||
void reset(const QUrl& url);
|
||||
|
||||
void resetShader(gpu::Shader* texture);
|
||||
|
||||
bool isDefined() const;
|
||||
|
||||
protected:
|
||||
gpu::ShaderPointer _gpuShader;
|
||||
QUrl _shaderUrl;
|
||||
};
|
||||
typedef std::shared_ptr< ShaderSource > ShaderSourcePointer;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -768,3 +768,28 @@ void SphericalHarmonics::evalFromTexture(const Texture& texture) {
|
|||
L22 = coefs[8];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TextureSource
|
||||
TextureSource::TextureSource() {
|
||||
}
|
||||
|
||||
TextureSource::~TextureSource() {
|
||||
}
|
||||
|
||||
void TextureSource::reset(const QUrl& url) {
|
||||
_imageUrl = url;
|
||||
}
|
||||
|
||||
void TextureSource::resetTexture(gpu::Texture* texture) {
|
||||
_gpuTexture.reset(texture);
|
||||
}
|
||||
|
||||
bool TextureSource::isDefined() const {
|
||||
if (_gpuTexture) {
|
||||
return _gpuTexture->isDefined();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include <algorithm> //min max and more
|
||||
|
||||
#include <QUrl>
|
||||
|
||||
namespace gpu {
|
||||
|
||||
// THe spherical harmonics is a nice tool for cubemap, so if required, the irradiance SH can be automatically generated
|
||||
|
@ -441,6 +443,28 @@ public:
|
|||
};
|
||||
typedef std::vector<TextureView> TextureViews;
|
||||
|
||||
// TextureSource is the bridge between a URL or a a way to produce an image and the final gpu::Texture that will be used to render it.
|
||||
// It provides the mechanism to create a texture using a customizable TextureLoader
|
||||
class TextureSource {
|
||||
public:
|
||||
TextureSource();
|
||||
~TextureSource();
|
||||
|
||||
const QUrl& getUrl() const { return _imageUrl; }
|
||||
const gpu::TexturePointer getGPUTexture() const { return _gpuTexture; }
|
||||
|
||||
void reset(const QUrl& url);
|
||||
|
||||
void resetTexture(gpu::Texture* texture);
|
||||
|
||||
bool isDefined() const;
|
||||
|
||||
protected:
|
||||
gpu::TexturePointer _gpuTexture;
|
||||
QUrl _imageUrl;
|
||||
};
|
||||
typedef std::shared_ptr< TextureSource > TextureSourcePointer;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
set(TARGET_NAME gpu-networking)
|
||||
set(TARGET_NAME model-networking)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
506
libraries/model-networking/src/model-networking/ModelCache.cpp
Normal file
506
libraries/model-networking/src/model-networking/ModelCache.cpp
Normal file
|
@ -0,0 +1,506 @@
|
|||
//
|
||||
// ModelCache.cpp
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Andrzej Kapolka on 6/21/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 "ModelCache.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QThreadPool>
|
||||
|
||||
#include <FSTReader.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include "TextureCache.h"
|
||||
#include "ModelNetworkingLogging.h"
|
||||
|
||||
#include "gpu/StandardShaderLib.h"
|
||||
|
||||
#include "model/TextureMap.h"
|
||||
|
||||
//#define WANT_DEBUG
|
||||
|
||||
ModelCache::ModelCache()
|
||||
{
|
||||
const qint64 GEOMETRY_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE;
|
||||
setUnusedResourceCacheSize(GEOMETRY_DEFAULT_UNUSED_MAX_SIZE);
|
||||
}
|
||||
|
||||
ModelCache::~ModelCache() {
|
||||
}
|
||||
|
||||
QSharedPointer<Resource> ModelCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
bool delayLoad, const void* extra) {
|
||||
// NetworkGeometry is no longer a subclass of Resource, but requires this method because, it is pure virtual.
|
||||
assert(false);
|
||||
return QSharedPointer<Resource>();
|
||||
}
|
||||
|
||||
|
||||
GeometryReader::GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping) :
|
||||
_url(url),
|
||||
_data(data),
|
||||
_mapping(mapping) {
|
||||
}
|
||||
|
||||
void GeometryReader::run() {
|
||||
try {
|
||||
if (_data.isEmpty()) {
|
||||
throw QString("Reply is NULL ?!");
|
||||
}
|
||||
QString urlname = _url.path().toLower();
|
||||
bool urlValid = true;
|
||||
urlValid &= !urlname.isEmpty();
|
||||
urlValid &= !_url.path().isEmpty();
|
||||
urlValid &= _url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj");
|
||||
|
||||
if (urlValid) {
|
||||
// Let's read the binaries from the network
|
||||
FBXGeometry* fbxgeo = nullptr;
|
||||
if (_url.path().toLower().endsWith(".fbx")) {
|
||||
const bool grabLightmaps = true;
|
||||
const float lightmapLevel = 1.0f;
|
||||
fbxgeo = readFBX(_data, _mapping, _url.path(), grabLightmaps, lightmapLevel);
|
||||
} else if (_url.path().toLower().endsWith(".obj")) {
|
||||
fbxgeo = OBJReader().readOBJ(_data, _mapping, _url);
|
||||
} else {
|
||||
QString errorStr("usupported format");
|
||||
emit onError(NetworkGeometry::ModelParseError, errorStr);
|
||||
}
|
||||
emit onSuccess(fbxgeo);
|
||||
} else {
|
||||
throw QString("url is invalid");
|
||||
}
|
||||
|
||||
} catch (const QString& error) {
|
||||
qCDebug(modelnetworking) << "Error reading " << _url << ": " << error;
|
||||
emit onError(NetworkGeometry::ModelParseError, error);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkGeometry::NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl) :
|
||||
_url(url),
|
||||
_mapping(mapping),
|
||||
_textureBaseUrl(textureBaseUrl.isValid() ? textureBaseUrl : url) {
|
||||
|
||||
if (delayLoad) {
|
||||
_state = DelayState;
|
||||
} else {
|
||||
attemptRequestInternal();
|
||||
}
|
||||
}
|
||||
|
||||
NetworkGeometry::~NetworkGeometry() {
|
||||
if (_resource) {
|
||||
_resource->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkGeometry::attemptRequest() {
|
||||
if (_state == DelayState) {
|
||||
attemptRequestInternal();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkGeometry::attemptRequestInternal() {
|
||||
if (_url.path().toLower().endsWith(".fst")) {
|
||||
_mappingUrl = _url;
|
||||
requestMapping(_url);
|
||||
} else {
|
||||
_modelUrl = _url;
|
||||
requestModel(_url);
|
||||
}
|
||||
}
|
||||
|
||||
bool NetworkGeometry::isLoaded() const {
|
||||
return _state == SuccessState;
|
||||
}
|
||||
|
||||
bool NetworkGeometry::isLoadedWithTextures() const {
|
||||
if (!isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_isLoadedWithTextures) {
|
||||
for (auto&& material : _materials) {
|
||||
if ((material->diffuseTexture && !material->diffuseTexture->isLoaded()) ||
|
||||
(material->normalTexture && !material->normalTexture->isLoaded()) ||
|
||||
(material->specularTexture && !material->specularTexture->isLoaded()) ||
|
||||
(material->emissiveTexture && !material->emissiveTexture->isLoaded())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_isLoadedWithTextures = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) {
|
||||
|
||||
|
||||
if (_meshes.size() > 0) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
for (auto&& material : _materials) {
|
||||
QSharedPointer<NetworkTexture> matchingTexture = QSharedPointer<NetworkTexture>();
|
||||
if (material->diffuseTextureName == name) {
|
||||
material->diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE);
|
||||
} else if (material->normalTextureName == name) {
|
||||
material->normalTexture = textureCache->getTexture(url);
|
||||
} else if (material->specularTextureName == name) {
|
||||
material->specularTexture = textureCache->getTexture(url);
|
||||
} else if (material->emissiveTextureName == name) {
|
||||
material->emissiveTexture = textureCache->getTexture(url);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCWarning(modelnetworking) << "Ignoring setTextureWirthNameToURL() geometry not ready." << name << url;
|
||||
}
|
||||
_isLoadedWithTextures = false;
|
||||
}
|
||||
|
||||
QStringList NetworkGeometry::getTextureNames() const {
|
||||
QStringList result;
|
||||
for (auto&& material : _materials) {
|
||||
if (!material->diffuseTextureName.isEmpty() && material->diffuseTexture) {
|
||||
QString textureURL = material->diffuseTexture->getURL().toString();
|
||||
result << material->diffuseTextureName + ":" + textureURL;
|
||||
}
|
||||
|
||||
if (!material->normalTextureName.isEmpty() && material->normalTexture) {
|
||||
QString textureURL = material->normalTexture->getURL().toString();
|
||||
result << material->normalTextureName + ":" + textureURL;
|
||||
}
|
||||
|
||||
if (!material->specularTextureName.isEmpty() && material->specularTexture) {
|
||||
QString textureURL = material->specularTexture->getURL().toString();
|
||||
result << material->specularTextureName + ":" + textureURL;
|
||||
}
|
||||
|
||||
if (!material->emissiveTextureName.isEmpty() && material->emissiveTexture) {
|
||||
QString textureURL = material->emissiveTexture->getURL().toString();
|
||||
result << material->emissiveTextureName + ":" + textureURL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void NetworkGeometry::requestMapping(const QUrl& url) {
|
||||
_state = RequestMappingState;
|
||||
if (_resource) {
|
||||
_resource->deleteLater();
|
||||
}
|
||||
_resource = new Resource(url, false);
|
||||
connect(_resource, &Resource::loaded, this, &NetworkGeometry::mappingRequestDone);
|
||||
connect(_resource, &Resource::failed, this, &NetworkGeometry::mappingRequestError);
|
||||
}
|
||||
|
||||
void NetworkGeometry::requestModel(const QUrl& url) {
|
||||
_state = RequestModelState;
|
||||
if (_resource) {
|
||||
_resource->deleteLater();
|
||||
}
|
||||
_modelUrl = url;
|
||||
_resource = new Resource(url, false);
|
||||
connect(_resource, &Resource::loaded, this, &NetworkGeometry::modelRequestDone);
|
||||
connect(_resource, &Resource::failed, this, &NetworkGeometry::modelRequestError);
|
||||
}
|
||||
|
||||
void NetworkGeometry::mappingRequestDone(const QByteArray& data) {
|
||||
assert(_state == RequestMappingState);
|
||||
|
||||
// parse the mapping file
|
||||
_mapping = FSTReader::readMapping(data);
|
||||
|
||||
QUrl replyUrl = _mappingUrl;
|
||||
QString modelUrlStr = _mapping.value("filename").toString();
|
||||
if (modelUrlStr.isNull()) {
|
||||
qCDebug(modelnetworking) << "Mapping file " << _url << "has no \"filename\" entry";
|
||||
emit onFailure(*this, MissingFilenameInMapping);
|
||||
} else {
|
||||
// read _textureBase from mapping file, if present
|
||||
QString texdir = _mapping.value("texdir").toString();
|
||||
if (!texdir.isNull()) {
|
||||
if (!texdir.endsWith('/')) {
|
||||
texdir += '/';
|
||||
}
|
||||
_textureBaseUrl = replyUrl.resolved(texdir);
|
||||
}
|
||||
|
||||
_modelUrl = replyUrl.resolved(modelUrlStr);
|
||||
requestModel(_modelUrl);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) {
|
||||
assert(_state == RequestMappingState);
|
||||
_state = ErrorState;
|
||||
emit onFailure(*this, MappingRequestError);
|
||||
}
|
||||
|
||||
void NetworkGeometry::modelRequestDone(const QByteArray& data) {
|
||||
assert(_state == RequestModelState);
|
||||
|
||||
_state = ParsingModelState;
|
||||
|
||||
// asynchronously parse the model file.
|
||||
GeometryReader* geometryReader = new GeometryReader(_modelUrl, data, _mapping);
|
||||
connect(geometryReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(modelParseSuccess(FBXGeometry*)));
|
||||
connect(geometryReader, SIGNAL(onError(int, QString)), SLOT(modelParseError(int, QString)));
|
||||
|
||||
QThreadPool::globalInstance()->start(geometryReader);
|
||||
}
|
||||
|
||||
void NetworkGeometry::modelRequestError(QNetworkReply::NetworkError error) {
|
||||
assert(_state == RequestModelState);
|
||||
_state = ErrorState;
|
||||
emit onFailure(*this, ModelRequestError);
|
||||
}
|
||||
|
||||
static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBaseUrl) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
NetworkMesh* networkMesh = new NetworkMesh();
|
||||
|
||||
int totalIndices = 0;
|
||||
bool checkForTexcoordLightmap = false;
|
||||
|
||||
|
||||
|
||||
// process network parts
|
||||
foreach (const FBXMeshPart& part, mesh.parts) {
|
||||
totalIndices += (part.quadIndices.size() + part.triangleIndices.size());
|
||||
}
|
||||
|
||||
// initialize index buffer
|
||||
{
|
||||
networkMesh->_indexBuffer = std::make_shared<gpu::Buffer>();
|
||||
networkMesh->_indexBuffer->resize(totalIndices * sizeof(int));
|
||||
int offset = 0;
|
||||
foreach(const FBXMeshPart& part, mesh.parts) {
|
||||
networkMesh->_indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int),
|
||||
(gpu::Byte*) part.quadIndices.constData());
|
||||
offset += part.quadIndices.size() * sizeof(int);
|
||||
networkMesh->_indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int),
|
||||
(gpu::Byte*) part.triangleIndices.constData());
|
||||
offset += part.triangleIndices.size() * sizeof(int);
|
||||
}
|
||||
}
|
||||
|
||||
// initialize vertex buffer
|
||||
{
|
||||
networkMesh->_vertexBuffer = std::make_shared<gpu::Buffer>();
|
||||
// if we don't need to do any blending, the positions/normals can be static
|
||||
if (mesh.blendshapes.isEmpty()) {
|
||||
int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
|
||||
int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);
|
||||
int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);
|
||||
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
|
||||
int texCoords1Offset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
|
||||
int clusterIndicesOffset = texCoords1Offset + mesh.texCoords1.size() * sizeof(glm::vec2);
|
||||
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
|
||||
|
||||
networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
|
||||
|
||||
networkMesh->_vertexBuffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.vertices.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(normalsOffset, mesh.normals.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.normals.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(tangentsOffset,
|
||||
mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(texCoordsOffset,
|
||||
mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(texCoords1Offset,
|
||||
mesh.texCoords1.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords1.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset,
|
||||
mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset,
|
||||
mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
|
||||
|
||||
// otherwise, at least the cluster indices/weights can be static
|
||||
networkMesh->_vertexStream = std::make_shared<gpu::BufferStream>();
|
||||
networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3));
|
||||
if (mesh.normals.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, normalsOffset, sizeof(glm::vec3));
|
||||
if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, tangentsOffset, sizeof(glm::vec3));
|
||||
if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3));
|
||||
if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
|
||||
if (mesh.texCoords1.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoords1Offset, sizeof(glm::vec2));
|
||||
if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
|
||||
if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
|
||||
|
||||
int channelNum = 0;
|
||||
networkMesh->_vertexFormat = std::make_shared<gpu::Stream::Format>();
|
||||
networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||
if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
|
||||
if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
if (mesh.texCoords1.size()) {
|
||||
networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
// } else if (checkForTexcoordLightmap && mesh.texCoords.size()) {
|
||||
} else if (mesh.texCoords.size()) {
|
||||
// need lightmap texcoord UV but doesn't have uv#1 so just reuse the same channel
|
||||
networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum - 1, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
}
|
||||
if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
|
||||
if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
|
||||
}
|
||||
else {
|
||||
int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
|
||||
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
|
||||
int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
|
||||
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
|
||||
|
||||
networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
|
||||
networkMesh->_vertexBuffer->setSubData(0, mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(texCoordsOffset,
|
||||
mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset,
|
||||
mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset,
|
||||
mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
|
||||
|
||||
networkMesh->_vertexStream = std::make_shared<gpu::BufferStream>();
|
||||
if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3));
|
||||
if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3));
|
||||
if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
|
||||
if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
|
||||
if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
|
||||
|
||||
int channelNum = 0;
|
||||
networkMesh->_vertexFormat = std::make_shared<gpu::Stream::Format>();
|
||||
networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
|
||||
if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
|
||||
if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
|
||||
}
|
||||
}
|
||||
|
||||
return networkMesh;
|
||||
}
|
||||
|
||||
static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
NetworkMaterial* networkMaterial = new NetworkMaterial();
|
||||
|
||||
int totalIndices = 0;
|
||||
bool checkForTexcoordLightmap = false;
|
||||
|
||||
networkMaterial->_material = material._material;
|
||||
|
||||
if (!material.diffuseTexture.filename.isEmpty()) {
|
||||
networkMaterial->diffuseTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.diffuseTexture.filename)), DEFAULT_TEXTURE, material.diffuseTexture.content);
|
||||
networkMaterial->diffuseTextureName = material.diffuseTexture.name;
|
||||
|
||||
auto diffuseMap = model::TextureMapPointer(new model::TextureMap());
|
||||
diffuseMap->setTextureSource(networkMaterial->diffuseTexture->_textureSource);
|
||||
diffuseMap->setTextureTransform(material.diffuseTexture.transform);
|
||||
|
||||
material._material->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap);
|
||||
}
|
||||
if (!material.normalTexture.filename.isEmpty()) {
|
||||
networkMaterial->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content);
|
||||
networkMaterial->normalTextureName = material.normalTexture.name;
|
||||
|
||||
auto normalMap = model::TextureMapPointer(new model::TextureMap());
|
||||
normalMap->setTextureSource(networkMaterial->normalTexture->_textureSource);
|
||||
|
||||
material._material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap);
|
||||
}
|
||||
if (!material.specularTexture.filename.isEmpty()) {
|
||||
networkMaterial->specularTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.specularTexture.filename)), SPECULAR_TEXTURE, material.specularTexture.content);
|
||||
networkMaterial->specularTextureName = material.specularTexture.name;
|
||||
|
||||
auto glossMap = model::TextureMapPointer(new model::TextureMap());
|
||||
glossMap->setTextureSource(networkMaterial->specularTexture->_textureSource);
|
||||
|
||||
material._material->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap);
|
||||
}
|
||||
if (!material.emissiveTexture.filename.isEmpty()) {
|
||||
networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), EMISSIVE_TEXTURE, material.emissiveTexture.content);
|
||||
networkMaterial->emissiveTextureName = material.emissiveTexture.name;
|
||||
|
||||
checkForTexcoordLightmap = true;
|
||||
|
||||
auto lightmapMap = model::TextureMapPointer(new model::TextureMap());
|
||||
lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource);
|
||||
lightmapMap->setTextureTransform(material.emissiveTexture.transform);
|
||||
lightmapMap->setLightmapOffsetScale(material.emissiveParams.x, material.emissiveParams.y);
|
||||
|
||||
material._material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap);
|
||||
}
|
||||
|
||||
return networkMaterial;
|
||||
}
|
||||
|
||||
|
||||
void NetworkGeometry::modelParseSuccess(FBXGeometry* geometry) {
|
||||
// assume owner ship of geometry pointer
|
||||
_geometry.reset(geometry);
|
||||
|
||||
|
||||
|
||||
foreach(const FBXMesh& mesh, _geometry->meshes) {
|
||||
_meshes.emplace_back(buildNetworkMesh(mesh, _textureBaseUrl));
|
||||
}
|
||||
|
||||
QHash<QString, int> fbxMatIDToMatID;
|
||||
foreach(const FBXMaterial& material, _geometry->materials) {
|
||||
fbxMatIDToMatID[material.materialID] = _materials.size();
|
||||
_materials.emplace_back(buildNetworkMaterial(material, _textureBaseUrl));
|
||||
}
|
||||
|
||||
|
||||
int meshID = 0;
|
||||
foreach(const FBXMesh& mesh, _geometry->meshes) {
|
||||
int partID = 0;
|
||||
foreach (const FBXMeshPart& part, mesh.parts) {
|
||||
NetworkShape* networkShape = new NetworkShape();
|
||||
networkShape->_meshID = meshID;
|
||||
networkShape->_partID = partID;
|
||||
networkShape->_materialID = fbxMatIDToMatID[part.materialID];
|
||||
_shapes.emplace_back(networkShape);
|
||||
partID++;
|
||||
}
|
||||
meshID++;
|
||||
}
|
||||
|
||||
_state = SuccessState;
|
||||
emit onSuccess(*this, *_geometry.get());
|
||||
|
||||
delete _resource;
|
||||
_resource = nullptr;
|
||||
}
|
||||
|
||||
void NetworkGeometry::modelParseError(int error, QString str) {
|
||||
_state = ErrorState;
|
||||
emit onFailure(*this, (NetworkGeometry::Error)error);
|
||||
|
||||
delete _resource;
|
||||
_resource = nullptr;
|
||||
}
|
||||
|
||||
|
||||
const NetworkMaterial* NetworkGeometry::getShapeMaterial(int shapeID) {
|
||||
if ((shapeID >= 0) && (shapeID < _shapes.size())) {
|
||||
int materialID = _shapes[shapeID]->_materialID;
|
||||
if ((materialID >= 0) && (materialID < _materials.size())) {
|
||||
return _materials[materialID].get();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
205
libraries/model-networking/src/model-networking/ModelCache.h
Normal file
205
libraries/model-networking/src/model-networking/ModelCache.h
Normal file
|
@ -0,0 +1,205 @@
|
|||
//
|
||||
// ModelCache.h
|
||||
// libraries/model-networking/src/model-networking
|
||||
//
|
||||
// Created by Sam Gateau on 9/21/15.
|
||||
// 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_ModelCache_h
|
||||
#define hifi_ModelCache_h
|
||||
|
||||
#include <QMap>
|
||||
#include <QRunnable>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <ResourceCache.h>
|
||||
|
||||
#include "FBXReader.h"
|
||||
#include "OBJReader.h"
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Stream.h>
|
||||
|
||||
|
||||
#include <model/Material.h>
|
||||
#include <model/Asset.h>
|
||||
|
||||
class NetworkGeometry;
|
||||
class NetworkMesh;
|
||||
class NetworkTexture;
|
||||
class NetworkMaterial;
|
||||
class NetworkShape;
|
||||
|
||||
/// Stores cached geometry.
|
||||
class ModelCache : public ResourceCache, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
bool delayLoad, const void* extra);
|
||||
|
||||
/// Loads geometry from the specified URL.
|
||||
/// \param fallback a fallback URL to load if the desired one is unavailable
|
||||
/// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested
|
||||
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
|
||||
|
||||
/// Set a batch to the simple pipeline, returning the previous pipeline
|
||||
void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false);
|
||||
|
||||
private:
|
||||
ModelCache();
|
||||
virtual ~ModelCache();
|
||||
|
||||
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
|
||||
};
|
||||
|
||||
class NetworkGeometry : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// mapping is only used if url is a .fbx or .obj file, it is essentially the content of an fst file.
|
||||
// if delayLoad is true, the url will not be immediately downloaded.
|
||||
// use the attemptRequest method to initiate the download.
|
||||
NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl = QUrl());
|
||||
~NetworkGeometry();
|
||||
|
||||
const QUrl& getURL() const { return _url; }
|
||||
|
||||
void attemptRequest();
|
||||
|
||||
// true when the geometry is loaded (but maybe not it's associated textures)
|
||||
bool isLoaded() const;
|
||||
|
||||
// true when the requested geometry and its textures are loaded.
|
||||
bool isLoadedWithTextures() const;
|
||||
|
||||
// WARNING: only valid when isLoaded returns true.
|
||||
const FBXGeometry& getFBXGeometry() const { return *_geometry; }
|
||||
const std::vector<std::unique_ptr<NetworkMesh>>& getMeshes() const { return _meshes; }
|
||||
// const model::AssetPointer getAsset() const { return _asset; }
|
||||
|
||||
// model::MeshPointer getShapeMesh(int shapeID);
|
||||
// int getShapePart(int shapeID);
|
||||
|
||||
// This would be the final verison
|
||||
// model::MaterialPointer getShapeMaterial(int shapeID);
|
||||
const NetworkMaterial* getShapeMaterial(int shapeID);
|
||||
|
||||
|
||||
void setTextureWithNameToURL(const QString& name, const QUrl& url);
|
||||
QStringList getTextureNames() const;
|
||||
|
||||
enum Error {
|
||||
MissingFilenameInMapping = 0,
|
||||
MappingRequestError,
|
||||
ModelRequestError,
|
||||
ModelParseError
|
||||
};
|
||||
|
||||
signals:
|
||||
// Fired when everything has downloaded and parsed successfully.
|
||||
void onSuccess(NetworkGeometry& networkGeometry, FBXGeometry& fbxGeometry);
|
||||
|
||||
// Fired when something went wrong.
|
||||
void onFailure(NetworkGeometry& networkGeometry, Error error);
|
||||
|
||||
protected slots:
|
||||
void mappingRequestDone(const QByteArray& data);
|
||||
void mappingRequestError(QNetworkReply::NetworkError error);
|
||||
|
||||
void modelRequestDone(const QByteArray& data);
|
||||
void modelRequestError(QNetworkReply::NetworkError error);
|
||||
|
||||
void modelParseSuccess(FBXGeometry* geometry);
|
||||
void modelParseError(int error, QString str);
|
||||
|
||||
protected:
|
||||
void attemptRequestInternal();
|
||||
void requestMapping(const QUrl& url);
|
||||
void requestModel(const QUrl& url);
|
||||
|
||||
enum State { DelayState,
|
||||
RequestMappingState,
|
||||
RequestModelState,
|
||||
ParsingModelState,
|
||||
SuccessState,
|
||||
ErrorState };
|
||||
State _state;
|
||||
|
||||
QUrl _url;
|
||||
QUrl _mappingUrl;
|
||||
QUrl _modelUrl;
|
||||
QVariantHash _mapping;
|
||||
QUrl _textureBaseUrl;
|
||||
|
||||
Resource* _resource = nullptr;
|
||||
std::unique_ptr<FBXGeometry> _geometry; // This should go away evenutally once we can put everything we need in the model::AssetPointer
|
||||
std::vector<std::unique_ptr<NetworkMesh>> _meshes;
|
||||
std::vector<std::unique_ptr<NetworkMaterial>> _materials;
|
||||
std::vector<std::unique_ptr<NetworkShape>> _shapes;
|
||||
|
||||
|
||||
// The model asset created from this NetworkGeometry
|
||||
// model::AssetPointer _asset;
|
||||
|
||||
// cache for isLoadedWithTextures()
|
||||
mutable bool _isLoadedWithTextures = false;
|
||||
};
|
||||
|
||||
/// Reads geometry in a worker thread.
|
||||
class GeometryReader : public QObject, public QRunnable {
|
||||
Q_OBJECT
|
||||
public:
|
||||
GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping);
|
||||
virtual void run();
|
||||
signals:
|
||||
void onSuccess(FBXGeometry* geometry);
|
||||
void onError(int error, QString str);
|
||||
private:
|
||||
QUrl _url;
|
||||
QByteArray _data;
|
||||
QVariantHash _mapping;
|
||||
};
|
||||
|
||||
|
||||
class NetworkShape {
|
||||
public:
|
||||
int _meshID{ -1 };
|
||||
int _partID{ -1 };
|
||||
int _materialID{ -1 };
|
||||
};
|
||||
|
||||
class NetworkMaterial {
|
||||
public:
|
||||
model::MaterialPointer _material;
|
||||
QString diffuseTextureName;
|
||||
QSharedPointer<NetworkTexture> diffuseTexture;
|
||||
QString normalTextureName;
|
||||
QSharedPointer<NetworkTexture> normalTexture;
|
||||
QString specularTextureName;
|
||||
QSharedPointer<NetworkTexture> specularTexture;
|
||||
QString emissiveTextureName;
|
||||
QSharedPointer<NetworkTexture> emissiveTexture;
|
||||
};
|
||||
|
||||
|
||||
/// The state associated with a single mesh.
|
||||
class NetworkMesh {
|
||||
public:
|
||||
gpu::BufferPointer _indexBuffer;
|
||||
gpu::BufferPointer _vertexBuffer;
|
||||
|
||||
gpu::BufferStreamPointer _vertexStream;
|
||||
|
||||
gpu::Stream::FormatPointer _vertexFormat;
|
||||
|
||||
int getTranslucentPartCount(const FBXMesh& fbxMesh) const;
|
||||
bool isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const;
|
||||
};
|
||||
|
||||
#endif // hifi_GeometryCache_h
|
|
@ -6,6 +6,6 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "GpuNetworkingLogging.h"
|
||||
#include "ModelNetworkingLogging.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(gpunetwork, "hifi.gpu-network")
|
||||
Q_LOGGING_CATEGORY(modelnetworking, "hifi.gpu-network")
|
|
@ -8,4 +8,4 @@
|
|||
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(gpunetwork)
|
||||
Q_DECLARE_LOGGING_CATEGORY(modelnetworking)
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// TextureCache.cpp
|
||||
// libraries/gpu-networking/src
|
||||
// libraries/model-networking/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 8/6/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include "GpuNetworkingLogging.h"
|
||||
#include "ModelNetworkingLogging.h"
|
||||
|
||||
TextureCache::TextureCache() {
|
||||
const qint64 TEXTURE_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE;
|
||||
|
@ -185,7 +185,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArr
|
|||
_width(0),
|
||||
_height(0) {
|
||||
|
||||
_textureSource.reset(new model::TextureSource());
|
||||
_textureSource.reset(new gpu::TextureSource());
|
||||
|
||||
if (!url.isValid()) {
|
||||
_loaded = true;
|
||||
|
@ -206,7 +206,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture
|
|||
_width(0),
|
||||
_height(0) {
|
||||
|
||||
_textureSource.reset(new model::TextureSource());
|
||||
_textureSource.reset(new gpu::TextureSource());
|
||||
|
||||
if (!url.isValid()) {
|
||||
_loaded = true;
|
||||
|
@ -223,11 +223,11 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture
|
|||
NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
|
||||
switch (_type) {
|
||||
case CUBE_TEXTURE: {
|
||||
return TextureLoaderFunc(model::TextureSource::createCubeTextureFromImage);
|
||||
return TextureLoaderFunc(model::TextureUsage::createCubeTextureFromImage);
|
||||
break;
|
||||
}
|
||||
case BUMP_TEXTURE: {
|
||||
return TextureLoaderFunc(model::TextureSource::createNormalTextureFromBumpImage);
|
||||
return TextureLoaderFunc(model::TextureUsage::createNormalTextureFromBumpImage);
|
||||
break;
|
||||
}
|
||||
case CUSTOM_TEXTURE: {
|
||||
|
@ -239,7 +239,7 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
|
|||
case SPECULAR_TEXTURE:
|
||||
case EMISSIVE_TEXTURE:
|
||||
default: {
|
||||
return TextureLoaderFunc(model::TextureSource::create2DTextureFromImage);
|
||||
return TextureLoaderFunc(model::TextureUsage::create2DTextureFromImage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ void listSupportedImageFormats() {
|
|||
foreach(const QByteArray& f, supportedFormats) {
|
||||
formats += QString(f) + ",";
|
||||
}
|
||||
qCDebug(gpunetwork) << "List of supported Image formats:" << formats;
|
||||
qCDebug(modelnetworking) << "List of supported Image formats:" << formats;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -313,9 +313,9 @@ void ImageReader::run() {
|
|||
|
||||
if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) {
|
||||
if (filenameExtension.empty()) {
|
||||
qCDebug(gpunetwork) << "QImage failed to create from content, no file extension:" << _url;
|
||||
qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url;
|
||||
} else {
|
||||
qCDebug(gpunetwork) << "QImage failed to create from content" << _url;
|
||||
qCDebug(modelnetworking) << "QImage failed to create from content" << _url;
|
||||
}
|
||||
return;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// TextureCache.h
|
||||
// libraries/gpu-networking/src
|
||||
// libraries/model-networking/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 8/6/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
|
@ -98,7 +98,7 @@ public:
|
|||
~Texture();
|
||||
|
||||
const gpu::TexturePointer getGPUTexture() const { return _textureSource->getGPUTexture(); }
|
||||
model::TextureSourcePointer _textureSource;
|
||||
gpu::TextureSourcePointer _textureSource;
|
||||
|
||||
protected:
|
||||
|
|
@ -9,4 +9,4 @@ add_dependency_external_projects(glm)
|
|||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared networking gpu octree)
|
||||
link_hifi_libraries(shared gpu)
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.h>
|
||||
// #include <procedural/Procedural.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include "Skybox_vert.h"
|
||||
|
@ -39,16 +38,7 @@ Skybox::Skybox() {
|
|||
void Skybox::setColor(const Color& color) {
|
||||
_color = color;
|
||||
}
|
||||
/*
|
||||
void Skybox::setProcedural(QSharedPointer<Procedural> procedural) {
|
||||
_procedural = procedural;
|
||||
if (_procedural) {
|
||||
_procedural->_vertexSource = Skybox_vert;
|
||||
_procedural->_fragmentSource = Skybox_frag;
|
||||
// No pipeline state customization
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
|
||||
_cubemap = cubemap;
|
||||
}
|
||||
|
@ -58,7 +48,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
|||
static gpu::BufferPointer theBuffer;
|
||||
static gpu::Stream::FormatPointer theFormat;
|
||||
|
||||
if (/*skybox._procedural || */skybox.getCubemap()) {
|
||||
if (skybox._procedural || skybox.getCubemap()) {
|
||||
if (!theBuffer) {
|
||||
const float CLIP = 1.0f;
|
||||
const glm::vec2 vertices[4] = { { -CLIP, -CLIP }, { CLIP, -CLIP }, { -CLIP, CLIP }, { CLIP, CLIP } };
|
||||
|
@ -78,14 +68,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
|||
batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
|
||||
batch.setInputFormat(theFormat);
|
||||
|
||||
/*if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) {
|
||||
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
||||
batch.setResourceTexture(0, skybox.getCubemap());
|
||||
}
|
||||
|
||||
skybox._procedural->prepare(batch, glm::vec3(1));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
} else*/ if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
||||
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
||||
static gpu::BufferPointer theConstants;
|
||||
static gpu::PipelinePointer thePipeline;
|
||||
static int SKYBOX_CONSTANTS_SLOT = 0; // need to be defined by the compilation of the shader
|
||||
|
|
|
@ -11,13 +11,14 @@
|
|||
#ifndef hifi_model_Skybox_h
|
||||
#define hifi_model_Skybox_h
|
||||
|
||||
//#include <QtCore/QSharedPointer>
|
||||
#include <gpu/Texture.h>
|
||||
|
||||
#include "Light.h"
|
||||
|
||||
class ViewFrustum;
|
||||
struct Procedural;
|
||||
typedef std::shared_ptr<Procedural> ProceduralPointer;
|
||||
|
||||
namespace gpu { class Batch; }
|
||||
|
||||
namespace model {
|
||||
|
@ -36,13 +37,13 @@ public:
|
|||
void setCubemap(const gpu::TexturePointer& cubemap);
|
||||
const gpu::TexturePointer& getCubemap() const { return _cubemap; }
|
||||
|
||||
// void setProcedural(QSharedPointer<Procedural> procedural);
|
||||
void setProcedural(const ProceduralPointer& procedural);
|
||||
|
||||
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox);
|
||||
|
||||
protected:
|
||||
gpu::TexturePointer _cubemap;
|
||||
// QSharedPointer<Procedural> _procedural;
|
||||
ProceduralPointer _procedural;
|
||||
Color _color{1.0f, 1.0f, 1.0f};
|
||||
};
|
||||
typedef std::shared_ptr< Skybox > SkyboxPointer;
|
||||
|
|
|
@ -19,35 +19,9 @@
|
|||
using namespace model;
|
||||
using namespace gpu;
|
||||
|
||||
// TextureSource
|
||||
TextureSource::TextureSource()
|
||||
{/* : Texture::Storage()//,
|
||||
// _gpuTexture(Texture::createFromStorage(this))*/
|
||||
}
|
||||
|
||||
TextureSource::~TextureSource() {
|
||||
}
|
||||
|
||||
void TextureSource::reset(const QUrl& url, const TextureUsage& usage) {
|
||||
_imageUrl = url;
|
||||
_usage = usage;
|
||||
}
|
||||
|
||||
void TextureSource::resetTexture(gpu::Texture* texture) {
|
||||
_gpuTexture.reset(texture);
|
||||
}
|
||||
|
||||
bool TextureSource::isDefined() const {
|
||||
if (_gpuTexture) {
|
||||
return _gpuTexture->isDefined();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TextureMap::setTextureSource(TextureSourcePointer& texStorage) {
|
||||
_textureSource = texStorage;
|
||||
void TextureMap::setTextureSource(TextureSourcePointer& textureSource) {
|
||||
_textureSource = textureSource;
|
||||
}
|
||||
|
||||
bool TextureMap::isDefined() const {
|
||||
|
@ -78,7 +52,7 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
|
|||
|
||||
|
||||
|
||||
gpu::Texture* TextureSource::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
int imageArea = image.width() * image.height();
|
||||
|
@ -175,7 +149,7 @@ double mapComponent(double sobelValue) {
|
|||
return (sobelValue + 1.0) * factor;
|
||||
}
|
||||
|
||||
gpu::Texture* TextureSource::createNormalTextureFromBumpImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
// PR 5540 by AlessandroSigna
|
||||
|
@ -285,7 +259,7 @@ public:
|
|||
_faceZNeg(fZN) {}
|
||||
};
|
||||
|
||||
gpu::Texture* TextureSource::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
int imageArea = image.width() * image.height();
|
||||
|
|
|
@ -30,36 +30,11 @@ public:
|
|||
Material::MapFlags _materialUsage{ MaterialKey::DIFFUSE_MAP };
|
||||
|
||||
int _environmentUsage = 0;
|
||||
};
|
||||
|
||||
// TextureSource is a specialized version of the gpu::Texture::Storage
|
||||
// It provides the mechanism to create a texture from a Url and the intended usage
|
||||
// that guides the internal format used
|
||||
class TextureSource {
|
||||
public:
|
||||
TextureSource();
|
||||
~TextureSource();
|
||||
|
||||
const QUrl& getUrl() const { return _imageUrl; }
|
||||
gpu::Texture::Type getType() const { return _usage._type; }
|
||||
const gpu::TexturePointer getGPUTexture() const { return _gpuTexture; }
|
||||
|
||||
void reset(const QUrl& url, const TextureUsage& usage);
|
||||
|
||||
void resetTexture(gpu::Texture* texture);
|
||||
|
||||
bool isDefined() const;
|
||||
|
||||
static gpu::Texture* create2DTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createNormalTextureFromBumpImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
|
||||
protected:
|
||||
gpu::TexturePointer _gpuTexture;
|
||||
TextureUsage _usage;
|
||||
QUrl _imageUrl;
|
||||
};
|
||||
typedef std::shared_ptr< TextureSource > TextureSourcePointer;
|
||||
|
||||
|
||||
|
||||
|
@ -67,7 +42,7 @@ class TextureMap {
|
|||
public:
|
||||
TextureMap() {}
|
||||
|
||||
void setTextureSource(TextureSourcePointer& texStorage);
|
||||
void setTextureSource(gpu::TextureSourcePointer& textureSource);
|
||||
|
||||
bool isDefined() const;
|
||||
gpu::TextureView getTextureView() const;
|
||||
|
@ -79,7 +54,7 @@ public:
|
|||
const glm::vec2& getLightmapOffsetScale() const { return _lightmapOffsetScale; }
|
||||
|
||||
protected:
|
||||
TextureSourcePointer _textureSource;
|
||||
gpu::TextureSourcePointer _textureSource;
|
||||
|
||||
Transform _texcoordTransform;
|
||||
glm::vec2 _lightmapOffsetScale{ 0.0f, 1.0f };
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
set(TARGET_NAME procedural)
|
||||
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
|
@ -7,4 +9,4 @@ add_dependency_external_projects(glm)
|
|||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared gpu networking gpu-networking)
|
||||
link_hifi_libraries(shared gpu model model-networking)
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
#include <gpu-networking/ShaderCache.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
#include <gpu/Shader.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu-networking/ShaderCache.h>
|
||||
|
||||
#include <model-networking/ShaderCache.h>
|
||||
|
||||
// FIXME better encapsulation
|
||||
// FIXME better mechanism for extending to things rendered using shaders other than simple.slv
|
||||
|
|
71
libraries/procedural/src/procedural/ProceduralSkybox.cpp
Normal file
71
libraries/procedural/src/procedural/ProceduralSkybox.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// ProceduralSkybox.cpp
|
||||
// libraries/procedural/src/procedural
|
||||
//
|
||||
// Created by Sam Gateau on 9/21/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 "ProceduralSkybox.h"
|
||||
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include "ProceduralSkybox_vert.h"
|
||||
#include "ProceduralSkybox_frag.h"
|
||||
|
||||
ProceduralSkybox::ProceduralSkybox() : model::Skybox() {
|
||||
}
|
||||
|
||||
void ProceduralSkybox::setProcedural(const ProceduralPointer& procedural) {
|
||||
_procedural = procedural;
|
||||
if (_procedural) {
|
||||
_procedural->_vertexSource = ProceduralSkybox_vert;
|
||||
_procedural->_fragmentSource = ProceduralSkybox_frag;
|
||||
// No pipeline state customization
|
||||
}
|
||||
}
|
||||
|
||||
void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const ProceduralSkybox& skybox) {
|
||||
static gpu::BufferPointer theBuffer;
|
||||
static gpu::Stream::FormatPointer theFormat;
|
||||
|
||||
if (skybox._procedural || skybox.getCubemap()) {
|
||||
if (!theBuffer) {
|
||||
const float CLIP = 1.0f;
|
||||
const glm::vec2 vertices[4] = { { -CLIP, -CLIP }, { CLIP, -CLIP }, { -CLIP, CLIP }, { CLIP, CLIP } };
|
||||
theBuffer = std::make_shared<gpu::Buffer>(sizeof(vertices), (const gpu::Byte*) vertices);
|
||||
theFormat = std::make_shared<gpu::Stream::Format>();
|
||||
theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ));
|
||||
}
|
||||
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
|
||||
Transform viewTransform;
|
||||
viewFrustum.evalViewTransform(viewTransform);
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewTransform);
|
||||
batch.setModelTransform(Transform()); // only for Mac
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
|
||||
batch.setInputFormat(theFormat);
|
||||
|
||||
if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) {
|
||||
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
||||
batch.setResourceTexture(0, skybox.getCubemap());
|
||||
}
|
||||
|
||||
skybox._procedural->prepare(batch, glm::vec3(1));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
} else {
|
||||
// skybox has no cubemap, just clear the color buffer
|
||||
auto color = skybox.getColor();
|
||||
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.0f, 0, true);
|
||||
}
|
||||
}
|
||||
|
35
libraries/procedural/src/procedural/ProceduralSkybox.h
Normal file
35
libraries/procedural/src/procedural/ProceduralSkybox.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// ProceduralSkybox.h
|
||||
// libraries/procedural/src/procedural
|
||||
//
|
||||
// Created by Sam Gateau on 9/21/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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_ProceduralSkybox_h
|
||||
#define hifi_ProceduralSkybox_h
|
||||
|
||||
#include <model/Skybox.h>
|
||||
|
||||
#include "Procedural.h"
|
||||
|
||||
class ProceduralSkybox: public model::Skybox {
|
||||
public:
|
||||
ProceduralSkybox();
|
||||
ProceduralSkybox& operator= (const ProceduralSkybox& skybox);
|
||||
virtual ~ProceduralSkybox() {};
|
||||
|
||||
void setProcedural(const ProceduralPointer& procedural);
|
||||
|
||||
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const ProceduralSkybox& skybox);
|
||||
|
||||
protected:
|
||||
ProceduralPointer _procedural;
|
||||
};
|
||||
typedef std::shared_ptr< ProceduralSkybox > ProceduralSkyboxPointer;
|
||||
|
||||
#endif
|
50
libraries/procedural/src/procedural/ProceduralSkybox.slf
Normal file
50
libraries/procedural/src/procedural/ProceduralSkybox.slf
Normal file
|
@ -0,0 +1,50 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// skybox.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 5/5/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
|
||||
//
|
||||
|
||||
uniform samplerCube cubeMap;
|
||||
|
||||
struct Skybox {
|
||||
vec4 _color;
|
||||
};
|
||||
|
||||
uniform skyboxBuffer {
|
||||
Skybox _skybox;
|
||||
};
|
||||
|
||||
in vec3 _normal;
|
||||
out vec4 _fragColor;
|
||||
|
||||
//PROCEDURAL_COMMON_BLOCK
|
||||
|
||||
#line 1001
|
||||
//PROCEDURAL_BLOCK
|
||||
|
||||
#line 2033
|
||||
void main(void) {
|
||||
|
||||
#ifdef PROCEDURAL
|
||||
|
||||
vec3 color = getSkyboxColor();
|
||||
_fragColor = vec4(color, 0.0);
|
||||
|
||||
#else
|
||||
|
||||
vec3 coord = normalize(_normal);
|
||||
vec3 texel = texture(cubeMap, coord).rgb;
|
||||
vec3 color = texel * _skybox._color.rgb;
|
||||
vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction
|
||||
_fragColor = vec4(pixel, 0.0);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
34
libraries/procedural/src/procedural/ProceduralSkybox.slv
Normal file
34
libraries/procedural/src/procedural/ProceduralSkybox.slv
Normal file
|
@ -0,0 +1,34 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// skybox.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Sam Gateau on 5/5/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/Inputs.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec3 _normal;
|
||||
|
||||
void main(void) {
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
vec3 clipDir = vec3(inPosition.xy, 0.0);
|
||||
vec3 eyeDir;
|
||||
|
||||
<$transformClipToEyeDir(cam, clipDir, eyeDir)$>
|
||||
<$transformEyeToWorldDir(cam, eyeDir, _normal)$>
|
||||
|
||||
// Position is supposed to come in clip space
|
||||
gl_Position = vec4(inPosition.xy, 0.0, 1.0);
|
||||
}
|
|
@ -40,4 +40,4 @@ add_dependency_external_projects(oglplus)
|
|||
find_package(OGLPLUS REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared gpu gpu-networking procedural model render environment animation fbx)
|
||||
link_hifi_libraries(shared gpu procedural model model-networking render environment animation fbx)
|
||||
|
|
|
@ -38,8 +38,6 @@ const int GeometryCache::UNKNOWN_ID = -1;
|
|||
GeometryCache::GeometryCache() :
|
||||
_nextID(0)
|
||||
{
|
||||
const qint64 GEOMETRY_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE;
|
||||
setUnusedResourceCacheSize(GEOMETRY_DEFAULT_UNUSED_MAX_SIZE);
|
||||
}
|
||||
|
||||
GeometryCache::~GeometryCache() {
|
||||
|
@ -51,13 +49,6 @@ GeometryCache::~GeometryCache() {
|
|||
#endif //def WANT_DEBUG
|
||||
}
|
||||
|
||||
QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
bool delayLoad, const void* extra) {
|
||||
// NetworkGeometry is no longer a subclass of Resource, but requires this method because, it is pure virtual.
|
||||
assert(false);
|
||||
return QSharedPointer<Resource>();
|
||||
}
|
||||
|
||||
const int NUM_VERTICES_PER_TRIANGLE = 3;
|
||||
const int NUM_TRIANGLES_PER_QUAD = 2;
|
||||
const int NUM_VERTICES_PER_TRIANGULATED_QUAD = NUM_VERTICES_PER_TRIANGLE * NUM_TRIANGLES_PER_QUAD;
|
||||
|
@ -1713,463 +1704,3 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
|
|||
batch.setPipeline(_standardDrawPipeline);
|
||||
}
|
||||
}
|
||||
|
||||
GeometryReader::GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping) :
|
||||
_url(url),
|
||||
_data(data),
|
||||
_mapping(mapping) {
|
||||
}
|
||||
|
||||
void GeometryReader::run() {
|
||||
try {
|
||||
if (_data.isEmpty()) {
|
||||
throw QString("Reply is NULL ?!");
|
||||
}
|
||||
QString urlname = _url.path().toLower();
|
||||
bool urlValid = true;
|
||||
urlValid &= !urlname.isEmpty();
|
||||
urlValid &= !_url.path().isEmpty();
|
||||
urlValid &= _url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj");
|
||||
|
||||
if (urlValid) {
|
||||
// Let's read the binaries from the network
|
||||
FBXGeometry* fbxgeo = nullptr;
|
||||
if (_url.path().toLower().endsWith(".fbx")) {
|
||||
const bool grabLightmaps = true;
|
||||
const float lightmapLevel = 1.0f;
|
||||
fbxgeo = readFBX(_data, _mapping, _url.path(), grabLightmaps, lightmapLevel);
|
||||
} else if (_url.path().toLower().endsWith(".obj")) {
|
||||
fbxgeo = OBJReader().readOBJ(_data, _mapping, _url);
|
||||
} else {
|
||||
QString errorStr("usupported format");
|
||||
emit onError(NetworkGeometry::ModelParseError, errorStr);
|
||||
}
|
||||
emit onSuccess(fbxgeo);
|
||||
} else {
|
||||
throw QString("url is invalid");
|
||||
}
|
||||
|
||||
} catch (const QString& error) {
|
||||
qCDebug(renderutils) << "Error reading " << _url << ": " << error;
|
||||
emit onError(NetworkGeometry::ModelParseError, error);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkGeometry::NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl) :
|
||||
_url(url),
|
||||
_mapping(mapping),
|
||||
_textureBaseUrl(textureBaseUrl.isValid() ? textureBaseUrl : url) {
|
||||
|
||||
if (delayLoad) {
|
||||
_state = DelayState;
|
||||
} else {
|
||||
attemptRequestInternal();
|
||||
}
|
||||
}
|
||||
|
||||
NetworkGeometry::~NetworkGeometry() {
|
||||
if (_resource) {
|
||||
_resource->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkGeometry::attemptRequest() {
|
||||
if (_state == DelayState) {
|
||||
attemptRequestInternal();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkGeometry::attemptRequestInternal() {
|
||||
if (_url.path().toLower().endsWith(".fst")) {
|
||||
_mappingUrl = _url;
|
||||
requestMapping(_url);
|
||||
} else {
|
||||
_modelUrl = _url;
|
||||
requestModel(_url);
|
||||
}
|
||||
}
|
||||
|
||||
bool NetworkGeometry::isLoaded() const {
|
||||
return _state == SuccessState;
|
||||
}
|
||||
|
||||
bool NetworkGeometry::isLoadedWithTextures() const {
|
||||
if (!isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_isLoadedWithTextures) {
|
||||
for (auto&& material : _materials) {
|
||||
if ((material->diffuseTexture && !material->diffuseTexture->isLoaded()) ||
|
||||
(material->normalTexture && !material->normalTexture->isLoaded()) ||
|
||||
(material->specularTexture && !material->specularTexture->isLoaded()) ||
|
||||
(material->emissiveTexture && !material->emissiveTexture->isLoaded())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_isLoadedWithTextures = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) {
|
||||
|
||||
|
||||
if (_meshes.size() > 0) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
for (auto&& material : _materials) {
|
||||
QSharedPointer<NetworkTexture> matchingTexture = QSharedPointer<NetworkTexture>();
|
||||
if (material->diffuseTextureName == name) {
|
||||
material->diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE);
|
||||
} else if (material->normalTextureName == name) {
|
||||
material->normalTexture = textureCache->getTexture(url);
|
||||
} else if (material->specularTextureName == name) {
|
||||
material->specularTexture = textureCache->getTexture(url);
|
||||
} else if (material->emissiveTextureName == name) {
|
||||
material->emissiveTexture = textureCache->getTexture(url);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCWarning(renderutils) << "Ignoring setTextureWirthNameToURL() geometry not ready." << name << url;
|
||||
}
|
||||
_isLoadedWithTextures = false;
|
||||
}
|
||||
|
||||
QStringList NetworkGeometry::getTextureNames() const {
|
||||
QStringList result;
|
||||
for (auto&& material : _materials) {
|
||||
if (!material->diffuseTextureName.isEmpty() && material->diffuseTexture) {
|
||||
QString textureURL = material->diffuseTexture->getURL().toString();
|
||||
result << material->diffuseTextureName + ":" + textureURL;
|
||||
}
|
||||
|
||||
if (!material->normalTextureName.isEmpty() && material->normalTexture) {
|
||||
QString textureURL = material->normalTexture->getURL().toString();
|
||||
result << material->normalTextureName + ":" + textureURL;
|
||||
}
|
||||
|
||||
if (!material->specularTextureName.isEmpty() && material->specularTexture) {
|
||||
QString textureURL = material->specularTexture->getURL().toString();
|
||||
result << material->specularTextureName + ":" + textureURL;
|
||||
}
|
||||
|
||||
if (!material->emissiveTextureName.isEmpty() && material->emissiveTexture) {
|
||||
QString textureURL = material->emissiveTexture->getURL().toString();
|
||||
result << material->emissiveTextureName + ":" + textureURL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void NetworkGeometry::requestMapping(const QUrl& url) {
|
||||
_state = RequestMappingState;
|
||||
if (_resource) {
|
||||
_resource->deleteLater();
|
||||
}
|
||||
_resource = new Resource(url, false);
|
||||
connect(_resource, &Resource::loaded, this, &NetworkGeometry::mappingRequestDone);
|
||||
connect(_resource, &Resource::failed, this, &NetworkGeometry::mappingRequestError);
|
||||
}
|
||||
|
||||
void NetworkGeometry::requestModel(const QUrl& url) {
|
||||
_state = RequestModelState;
|
||||
if (_resource) {
|
||||
_resource->deleteLater();
|
||||
}
|
||||
_modelUrl = url;
|
||||
_resource = new Resource(url, false);
|
||||
connect(_resource, &Resource::loaded, this, &NetworkGeometry::modelRequestDone);
|
||||
connect(_resource, &Resource::failed, this, &NetworkGeometry::modelRequestError);
|
||||
}
|
||||
|
||||
void NetworkGeometry::mappingRequestDone(const QByteArray& data) {
|
||||
assert(_state == RequestMappingState);
|
||||
|
||||
// parse the mapping file
|
||||
_mapping = FSTReader::readMapping(data);
|
||||
|
||||
QUrl replyUrl = _mappingUrl;
|
||||
QString modelUrlStr = _mapping.value("filename").toString();
|
||||
if (modelUrlStr.isNull()) {
|
||||
qCDebug(renderutils) << "Mapping file " << _url << "has no \"filename\" entry";
|
||||
emit onFailure(*this, MissingFilenameInMapping);
|
||||
} else {
|
||||
// read _textureBase from mapping file, if present
|
||||
QString texdir = _mapping.value("texdir").toString();
|
||||
if (!texdir.isNull()) {
|
||||
if (!texdir.endsWith('/')) {
|
||||
texdir += '/';
|
||||
}
|
||||
_textureBaseUrl = replyUrl.resolved(texdir);
|
||||
}
|
||||
|
||||
_modelUrl = replyUrl.resolved(modelUrlStr);
|
||||
requestModel(_modelUrl);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) {
|
||||
assert(_state == RequestMappingState);
|
||||
_state = ErrorState;
|
||||
emit onFailure(*this, MappingRequestError);
|
||||
}
|
||||
|
||||
void NetworkGeometry::modelRequestDone(const QByteArray& data) {
|
||||
assert(_state == RequestModelState);
|
||||
|
||||
_state = ParsingModelState;
|
||||
|
||||
// asynchronously parse the model file.
|
||||
GeometryReader* geometryReader = new GeometryReader(_modelUrl, data, _mapping);
|
||||
connect(geometryReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(modelParseSuccess(FBXGeometry*)));
|
||||
connect(geometryReader, SIGNAL(onError(int, QString)), SLOT(modelParseError(int, QString)));
|
||||
|
||||
QThreadPool::globalInstance()->start(geometryReader);
|
||||
}
|
||||
|
||||
void NetworkGeometry::modelRequestError(QNetworkReply::NetworkError error) {
|
||||
assert(_state == RequestModelState);
|
||||
_state = ErrorState;
|
||||
emit onFailure(*this, ModelRequestError);
|
||||
}
|
||||
|
||||
static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBaseUrl) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
NetworkMesh* networkMesh = new NetworkMesh();
|
||||
|
||||
int totalIndices = 0;
|
||||
bool checkForTexcoordLightmap = false;
|
||||
|
||||
|
||||
|
||||
// process network parts
|
||||
foreach (const FBXMeshPart& part, mesh.parts) {
|
||||
totalIndices += (part.quadIndices.size() + part.triangleIndices.size());
|
||||
}
|
||||
|
||||
// initialize index buffer
|
||||
{
|
||||
networkMesh->_indexBuffer = std::make_shared<gpu::Buffer>();
|
||||
networkMesh->_indexBuffer->resize(totalIndices * sizeof(int));
|
||||
int offset = 0;
|
||||
foreach(const FBXMeshPart& part, mesh.parts) {
|
||||
networkMesh->_indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int),
|
||||
(gpu::Byte*) part.quadIndices.constData());
|
||||
offset += part.quadIndices.size() * sizeof(int);
|
||||
networkMesh->_indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int),
|
||||
(gpu::Byte*) part.triangleIndices.constData());
|
||||
offset += part.triangleIndices.size() * sizeof(int);
|
||||
}
|
||||
}
|
||||
|
||||
// initialize vertex buffer
|
||||
{
|
||||
networkMesh->_vertexBuffer = std::make_shared<gpu::Buffer>();
|
||||
// if we don't need to do any blending, the positions/normals can be static
|
||||
if (mesh.blendshapes.isEmpty()) {
|
||||
int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
|
||||
int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);
|
||||
int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);
|
||||
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
|
||||
int texCoords1Offset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
|
||||
int clusterIndicesOffset = texCoords1Offset + mesh.texCoords1.size() * sizeof(glm::vec2);
|
||||
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
|
||||
|
||||
networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
|
||||
|
||||
networkMesh->_vertexBuffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.vertices.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(normalsOffset, mesh.normals.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.normals.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(tangentsOffset,
|
||||
mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(texCoordsOffset,
|
||||
mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(texCoords1Offset,
|
||||
mesh.texCoords1.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords1.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset,
|
||||
mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset,
|
||||
mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
|
||||
|
||||
// otherwise, at least the cluster indices/weights can be static
|
||||
networkMesh->_vertexStream = std::make_shared<gpu::BufferStream>();
|
||||
networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3));
|
||||
if (mesh.normals.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, normalsOffset, sizeof(glm::vec3));
|
||||
if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, tangentsOffset, sizeof(glm::vec3));
|
||||
if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3));
|
||||
if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
|
||||
if (mesh.texCoords1.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoords1Offset, sizeof(glm::vec2));
|
||||
if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
|
||||
if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
|
||||
|
||||
int channelNum = 0;
|
||||
networkMesh->_vertexFormat = std::make_shared<gpu::Stream::Format>();
|
||||
networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||
if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
|
||||
if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
if (mesh.texCoords1.size()) {
|
||||
networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
// } else if (checkForTexcoordLightmap && mesh.texCoords.size()) {
|
||||
} else if (mesh.texCoords.size()) {
|
||||
// need lightmap texcoord UV but doesn't have uv#1 so just reuse the same channel
|
||||
networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum - 1, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
}
|
||||
if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
|
||||
if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
|
||||
}
|
||||
else {
|
||||
int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
|
||||
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
|
||||
int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
|
||||
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
|
||||
|
||||
networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
|
||||
networkMesh->_vertexBuffer->setSubData(0, mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(texCoordsOffset,
|
||||
mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset,
|
||||
mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
|
||||
networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset,
|
||||
mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
|
||||
|
||||
networkMesh->_vertexStream = std::make_shared<gpu::BufferStream>();
|
||||
if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3));
|
||||
if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3));
|
||||
if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
|
||||
if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
|
||||
if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
|
||||
|
||||
int channelNum = 0;
|
||||
networkMesh->_vertexFormat = std::make_shared<gpu::Stream::Format>();
|
||||
networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
|
||||
if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
|
||||
if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
|
||||
if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
|
||||
}
|
||||
}
|
||||
|
||||
return networkMesh;
|
||||
}
|
||||
|
||||
static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
NetworkMaterial* networkMaterial = new NetworkMaterial();
|
||||
|
||||
int totalIndices = 0;
|
||||
bool checkForTexcoordLightmap = false;
|
||||
|
||||
networkMaterial->_material = material._material;
|
||||
|
||||
if (!material.diffuseTexture.filename.isEmpty()) {
|
||||
networkMaterial->diffuseTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.diffuseTexture.filename)), DEFAULT_TEXTURE, material.diffuseTexture.content);
|
||||
networkMaterial->diffuseTextureName = material.diffuseTexture.name;
|
||||
|
||||
auto diffuseMap = model::TextureMapPointer(new model::TextureMap());
|
||||
diffuseMap->setTextureSource(networkMaterial->diffuseTexture->_textureSource);
|
||||
diffuseMap->setTextureTransform(material.diffuseTexture.transform);
|
||||
|
||||
material._material->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap);
|
||||
}
|
||||
if (!material.normalTexture.filename.isEmpty()) {
|
||||
networkMaterial->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content);
|
||||
networkMaterial->normalTextureName = material.normalTexture.name;
|
||||
|
||||
auto normalMap = model::TextureMapPointer(new model::TextureMap());
|
||||
normalMap->setTextureSource(networkMaterial->normalTexture->_textureSource);
|
||||
|
||||
material._material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap);
|
||||
}
|
||||
if (!material.specularTexture.filename.isEmpty()) {
|
||||
networkMaterial->specularTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.specularTexture.filename)), SPECULAR_TEXTURE, material.specularTexture.content);
|
||||
networkMaterial->specularTextureName = material.specularTexture.name;
|
||||
|
||||
auto glossMap = model::TextureMapPointer(new model::TextureMap());
|
||||
glossMap->setTextureSource(networkMaterial->specularTexture->_textureSource);
|
||||
|
||||
material._material->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap);
|
||||
}
|
||||
if (!material.emissiveTexture.filename.isEmpty()) {
|
||||
networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), EMISSIVE_TEXTURE, material.emissiveTexture.content);
|
||||
networkMaterial->emissiveTextureName = material.emissiveTexture.name;
|
||||
|
||||
checkForTexcoordLightmap = true;
|
||||
|
||||
auto lightmapMap = model::TextureMapPointer(new model::TextureMap());
|
||||
lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource);
|
||||
lightmapMap->setTextureTransform(material.emissiveTexture.transform);
|
||||
lightmapMap->setLightmapOffsetScale(material.emissiveParams.x, material.emissiveParams.y);
|
||||
|
||||
material._material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap);
|
||||
}
|
||||
|
||||
return networkMaterial;
|
||||
}
|
||||
|
||||
|
||||
void NetworkGeometry::modelParseSuccess(FBXGeometry* geometry) {
|
||||
// assume owner ship of geometry pointer
|
||||
_geometry.reset(geometry);
|
||||
|
||||
|
||||
|
||||
foreach(const FBXMesh& mesh, _geometry->meshes) {
|
||||
_meshes.emplace_back(buildNetworkMesh(mesh, _textureBaseUrl));
|
||||
}
|
||||
|
||||
QHash<QString, int> fbxMatIDToMatID;
|
||||
foreach(const FBXMaterial& material, _geometry->materials) {
|
||||
fbxMatIDToMatID[material.materialID] = _materials.size();
|
||||
_materials.emplace_back(buildNetworkMaterial(material, _textureBaseUrl));
|
||||
}
|
||||
|
||||
|
||||
int meshID = 0;
|
||||
foreach(const FBXMesh& mesh, _geometry->meshes) {
|
||||
int partID = 0;
|
||||
foreach (const FBXMeshPart& part, mesh.parts) {
|
||||
NetworkShape* networkShape = new NetworkShape();
|
||||
networkShape->_meshID = meshID;
|
||||
networkShape->_partID = partID;
|
||||
networkShape->_materialID = fbxMatIDToMatID[part.materialID];
|
||||
_shapes.emplace_back(networkShape);
|
||||
partID++;
|
||||
}
|
||||
meshID++;
|
||||
}
|
||||
|
||||
_state = SuccessState;
|
||||
emit onSuccess(*this, *_geometry.get());
|
||||
|
||||
delete _resource;
|
||||
_resource = nullptr;
|
||||
}
|
||||
|
||||
void NetworkGeometry::modelParseError(int error, QString str) {
|
||||
_state = ErrorState;
|
||||
emit onFailure(*this, (NetworkGeometry::Error)error);
|
||||
|
||||
delete _resource;
|
||||
_resource = nullptr;
|
||||
}
|
||||
|
||||
|
||||
const NetworkMaterial* NetworkGeometry::getShapeMaterial(int shapeID) {
|
||||
if ((shapeID >= 0) && (shapeID < _shapes.size())) {
|
||||
int materialID = _shapes[shapeID]->_materialID;
|
||||
if ((materialID >= 0) && (materialID < _materials.size())) {
|
||||
return _materials[materialID].get();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,14 +12,12 @@
|
|||
#ifndef hifi_GeometryCache_h
|
||||
#define hifi_GeometryCache_h
|
||||
|
||||
#include "model-networking/ModelCache.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QRunnable>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <ResourceCache.h>
|
||||
|
||||
#include "FBXReader.h"
|
||||
#include "OBJReader.h"
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Stream.h>
|
||||
|
@ -28,13 +26,6 @@
|
|||
#include <model/Material.h>
|
||||
#include <model/Asset.h>
|
||||
|
||||
class NetworkGeometry;
|
||||
class NetworkMesh;
|
||||
class NetworkTexture;
|
||||
class NetworkMaterial;
|
||||
class NetworkShape;
|
||||
|
||||
|
||||
typedef glm::vec3 Vec3Key;
|
||||
|
||||
typedef QPair<glm::vec2, glm::vec2> Vec2Pair;
|
||||
|
@ -125,17 +116,13 @@ inline uint qHash(const Vec4PairVec4Pair& v, uint seed) {
|
|||
}
|
||||
|
||||
/// Stores cached geometry.
|
||||
class GeometryCache : public ResourceCache, public Dependency {
|
||||
Q_OBJECT
|
||||
class GeometryCache : public Dependency {
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
int allocateID() { return _nextID++; }
|
||||
static const int UNKNOWN_ID;
|
||||
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
bool delayLoad, const void* extra);
|
||||
|
||||
gpu::BufferPointer getCubeVertices(float size);
|
||||
void setupCubeVertices(gpu::Batch& batch, gpu::BufferPointer& verticesBuffer);
|
||||
|
||||
|
@ -313,152 +300,6 @@ private:
|
|||
QHash<Vec3Pair, gpu::BufferPointer> _sphereColors;
|
||||
QHash<int, gpu::BufferPointer> _registeredSphereColors;
|
||||
QHash<int, Vec3Pair> _lastRegisteredSphereColors;
|
||||
|
||||
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
|
||||
};
|
||||
|
||||
class NetworkGeometry : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// mapping is only used if url is a .fbx or .obj file, it is essentially the content of an fst file.
|
||||
// if delayLoad is true, the url will not be immediately downloaded.
|
||||
// use the attemptRequest method to initiate the download.
|
||||
NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl = QUrl());
|
||||
~NetworkGeometry();
|
||||
|
||||
const QUrl& getURL() const { return _url; }
|
||||
|
||||
void attemptRequest();
|
||||
|
||||
// true when the geometry is loaded (but maybe not it's associated textures)
|
||||
bool isLoaded() const;
|
||||
|
||||
// true when the requested geometry and its textures are loaded.
|
||||
bool isLoadedWithTextures() const;
|
||||
|
||||
// WARNING: only valid when isLoaded returns true.
|
||||
const FBXGeometry& getFBXGeometry() const { return *_geometry; }
|
||||
const std::vector<std::unique_ptr<NetworkMesh>>& getMeshes() const { return _meshes; }
|
||||
// const model::AssetPointer getAsset() const { return _asset; }
|
||||
|
||||
// model::MeshPointer getShapeMesh(int shapeID);
|
||||
// int getShapePart(int shapeID);
|
||||
|
||||
// This would be the final verison
|
||||
// model::MaterialPointer getShapeMaterial(int shapeID);
|
||||
const NetworkMaterial* getShapeMaterial(int shapeID);
|
||||
|
||||
|
||||
void setTextureWithNameToURL(const QString& name, const QUrl& url);
|
||||
QStringList getTextureNames() const;
|
||||
|
||||
enum Error {
|
||||
MissingFilenameInMapping = 0,
|
||||
MappingRequestError,
|
||||
ModelRequestError,
|
||||
ModelParseError
|
||||
};
|
||||
|
||||
signals:
|
||||
// Fired when everything has downloaded and parsed successfully.
|
||||
void onSuccess(NetworkGeometry& networkGeometry, FBXGeometry& fbxGeometry);
|
||||
|
||||
// Fired when something went wrong.
|
||||
void onFailure(NetworkGeometry& networkGeometry, Error error);
|
||||
|
||||
protected slots:
|
||||
void mappingRequestDone(const QByteArray& data);
|
||||
void mappingRequestError(QNetworkReply::NetworkError error);
|
||||
|
||||
void modelRequestDone(const QByteArray& data);
|
||||
void modelRequestError(QNetworkReply::NetworkError error);
|
||||
|
||||
void modelParseSuccess(FBXGeometry* geometry);
|
||||
void modelParseError(int error, QString str);
|
||||
|
||||
protected:
|
||||
void attemptRequestInternal();
|
||||
void requestMapping(const QUrl& url);
|
||||
void requestModel(const QUrl& url);
|
||||
|
||||
enum State { DelayState,
|
||||
RequestMappingState,
|
||||
RequestModelState,
|
||||
ParsingModelState,
|
||||
SuccessState,
|
||||
ErrorState };
|
||||
State _state;
|
||||
|
||||
QUrl _url;
|
||||
QUrl _mappingUrl;
|
||||
QUrl _modelUrl;
|
||||
QVariantHash _mapping;
|
||||
QUrl _textureBaseUrl;
|
||||
|
||||
Resource* _resource = nullptr;
|
||||
std::unique_ptr<FBXGeometry> _geometry; // This should go away evenutally once we can put everything we need in the model::AssetPointer
|
||||
std::vector<std::unique_ptr<NetworkMesh>> _meshes;
|
||||
std::vector<std::unique_ptr<NetworkMaterial>> _materials;
|
||||
std::vector<std::unique_ptr<NetworkShape>> _shapes;
|
||||
|
||||
|
||||
// The model asset created from this NetworkGeometry
|
||||
// model::AssetPointer _asset;
|
||||
|
||||
// cache for isLoadedWithTextures()
|
||||
mutable bool _isLoadedWithTextures = false;
|
||||
};
|
||||
|
||||
/// Reads geometry in a worker thread.
|
||||
class GeometryReader : public QObject, public QRunnable {
|
||||
Q_OBJECT
|
||||
public:
|
||||
GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping);
|
||||
virtual void run();
|
||||
signals:
|
||||
void onSuccess(FBXGeometry* geometry);
|
||||
void onError(int error, QString str);
|
||||
private:
|
||||
QUrl _url;
|
||||
QByteArray _data;
|
||||
QVariantHash _mapping;
|
||||
};
|
||||
|
||||
|
||||
class NetworkShape {
|
||||
public:
|
||||
int _meshID{ -1 };
|
||||
int _partID{ -1 };
|
||||
int _materialID{ -1 };
|
||||
};
|
||||
|
||||
class NetworkMaterial {
|
||||
public:
|
||||
model::MaterialPointer _material;
|
||||
QString diffuseTextureName;
|
||||
QSharedPointer<NetworkTexture> diffuseTexture;
|
||||
QString normalTextureName;
|
||||
QSharedPointer<NetworkTexture> normalTexture;
|
||||
QString specularTextureName;
|
||||
QSharedPointer<NetworkTexture> specularTexture;
|
||||
QString emissiveTextureName;
|
||||
QSharedPointer<NetworkTexture> emissiveTexture;
|
||||
};
|
||||
|
||||
|
||||
/// The state associated with a single mesh.
|
||||
class NetworkMesh {
|
||||
public:
|
||||
gpu::BufferPointer _indexBuffer;
|
||||
gpu::BufferPointer _vertexBuffer;
|
||||
|
||||
gpu::BufferStreamPointer _vertexStream;
|
||||
|
||||
gpu::Stream::FormatPointer _vertexFormat;
|
||||
|
||||
int getTranslucentPartCount(const FBXMesh& fbxMesh) const;
|
||||
bool isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const;
|
||||
};
|
||||
|
||||
#endif // hifi_GeometryCache_h
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
// Compatibility
|
||||
#include <gpu-networking/TextureCache.h>
|
||||
#include <model-networking/TextureCache.h>
|
||||
|
|
|
@ -7,4 +7,4 @@ add_dependency_external_projects(glm)
|
|||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared networking octree gpu gpu-networking procedural model fbx entities animation audio physics)
|
||||
link_hifi_libraries(shared networking octree gpu procedural model model-networking fbx entities animation audio physics)
|
||||
|
|
|
@ -10,6 +10,6 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
|||
#include_oglplus()
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(networking gpu gpu-networking procedural shared fbx model animation script-engine render-utils )
|
||||
link_hifi_libraries(networking gpu procedural shared fbx model model-networking animation script-engine render-utils )
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
Loading…
Reference in a new issue