Merge pull request #2179 from ey6es/master

Better frame rates on loading by reading cached data from disk in worker thread, render billboards if we haven't loaded the models yet, use voxel LOD parameter to control avatar LODs, too.
This commit is contained in:
Philip Rosedale 2014-03-03 17:21:46 -08:00
commit 7ce427b35c
9 changed files with 35 additions and 28 deletions

View file

@ -1612,6 +1612,13 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) {
return false;
}
void Application::updateLOD() {
// adjust it unless we were asked to disable this feature
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD)) {
Menu::getInstance()->autoAdjustLOD(_fps);
}
}
void Application::updateMouseRay() {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
@ -1852,6 +1859,8 @@ void Application::update(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::update()");
updateLOD();
// check what's under the mouse and update the mouse voxel
updateMouseRay();
@ -2325,14 +2334,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... voxels...");
_voxels.render();
// double check that our LOD doesn't need to be auto-adjusted
// adjust it unless we were asked to disable this feature
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD)) {
Menu::getInstance()->autoAdjustLOD(_fps);
}
}
// also, metavoxels

View file

@ -284,6 +284,7 @@ private:
void update(float deltaTime);
// Various helper functions called during update()
void updateLOD();
void updateMouseRay();
void updateFaceshift();
void updateVisage();

View file

@ -84,6 +84,7 @@ public:
void autoAdjustLOD(float currentFPS);
void setVoxelSizeScale(float sizeScale);
float getVoxelSizeScale() const { return _voxelSizeScale; }
float getAvatarLODDistanceMultiplier() const { return DEFAULT_OCTREE_SIZE_SCALE / _voxelSizeScale; }
void setBoundaryLevelAdjust(int boundaryLevelAdjust);
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }

View file

@ -112,7 +112,8 @@ glm::quat Avatar::getWorldAlignedOrientation () const {
}
float Avatar::getLODDistance() const {
return glm::distance(Application::getInstance()->getCamera()->getPosition(), _position) / _scale;
return Menu::getInstance()->getAvatarLODDistanceMultiplier() *
glm::distance(Application::getInstance()->getCamera()->getPosition(), _position) / _scale;
}
void Avatar::simulate(float deltaTime) {
@ -305,13 +306,11 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
}
void Avatar::renderBody() {
if (_shouldRenderBillboard) {
if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
// render the billboard until both models are loaded
renderBillboard();
return;
}
if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
return; // wait until both models are loaded
}
_skeletonModel.render(1.0f);
getHead()->render(1.0f);
getHand()->render(false);

View file

@ -450,7 +450,7 @@ class GeometryReader : public QRunnable {
public:
GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
const QByteArray& data, const QVariantHash& mapping);
QNetworkReply* reply, const QVariantHash& mapping);
virtual void run();
@ -458,40 +458,41 @@ private:
QWeakPointer<Resource> _geometry;
QUrl _url;
QByteArray _data;
QNetworkReply* _reply;
QVariantHash _mapping;
};
GeometryReader::GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
const QByteArray& data, const QVariantHash& mapping) :
QNetworkReply* reply, const QVariantHash& mapping) :
_geometry(geometry),
_url(url),
_data(data),
_reply(reply),
_mapping(mapping) {
}
void GeometryReader::run() {
QSharedPointer<Resource> geometry = _geometry.toStrongRef();
if (geometry.isNull()) {
_reply->deleteLater();
return;
}
try {
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&,
_url.path().toLower().endsWith(".svo") ? readSVO(_data) : readFBX(_data, _mapping)));
_url.path().toLower().endsWith(".svo") ? readSVO(_reply->readAll()) : readFBX(_reply->readAll(), _mapping)));
} catch (const QString& error) {
qDebug() << "Error reading " << _url << ": " << error;
QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false));
}
_reply->deleteLater();
}
void NetworkGeometry::downloadFinished(QNetworkReply* reply) {
QUrl url = reply->url();
QByteArray data = reply->readAll();
if (url.path().toLower().endsWith(".fst")) {
// it's a mapping file; parse it and get the mesh filename
_mapping = readMapping(data);
_mapping = readMapping(reply->readAll());
reply->deleteLater();
QString filename = _mapping.value("filename").toString();
if (filename.isNull()) {
qDebug() << "Mapping file " << url << " has no filename.";
@ -525,7 +526,7 @@ void NetworkGeometry::downloadFinished(QNetworkReply* reply) {
}
// send the reader off to the thread pool
QThreadPool::globalInstance()->start(new GeometryReader(_self, url, data, _mapping));
QThreadPool::globalInstance()->start(new GeometryReader(_self, url, reply, _mapping));
}
void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {

View file

@ -273,27 +273,28 @@ NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) :
class ImageReader : public QRunnable {
public:
ImageReader(const QWeakPointer<Resource>& texture, const QByteArray& data);
ImageReader(const QWeakPointer<Resource>& texture, QNetworkReply* reply);
virtual void run();
private:
QWeakPointer<Resource> _texture;
QByteArray _data;
QNetworkReply* _reply;
};
ImageReader::ImageReader(const QWeakPointer<Resource>& texture, const QByteArray& data) :
ImageReader::ImageReader(const QWeakPointer<Resource>& texture, QNetworkReply* reply) :
_texture(texture),
_data(data) {
_reply(reply) {
}
void ImageReader::run() {
QSharedPointer<Resource> texture = _texture.toStrongRef();
if (texture.isNull()) {
_reply->deleteLater();
return;
}
QImage image = QImage::fromData(_data);
QImage image = QImage::fromData(_reply->readAll());
if (image.format() != QImage::Format_ARGB32) {
image = image.convertToFormat(QImage::Format_ARGB32);
}
@ -320,11 +321,12 @@ void ImageReader::run() {
QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image),
Q_ARG(const glm::vec4&, accumulated / (imageArea * EIGHT_BIT_MAXIMUM)),
Q_ARG(bool, translucentPixels >= imageArea / 2));
_reply->deleteLater();
}
void NetworkTexture::downloadFinished(QNetworkReply* reply) {
// send the reader off to the thread pool
QThreadPool::globalInstance()->start(new ImageReader(_self, reply->readAll()));
QThreadPool::globalInstance()->start(new ImageReader(_self, reply));
}
void NetworkTexture::setImage(const QImage& image, const glm::vec4& averageColor, bool translucent) {

View file

@ -61,6 +61,7 @@ NetworkProgram::NetworkProgram(ScriptCache* cache, const QUrl& url) :
void NetworkProgram::downloadFinished(QNetworkReply* reply) {
_program = QScriptProgram(QTextStream(reply).readAll(), reply->url().toString());
reply->deleteLater();
finishedLoading(true);
emit loaded();
}

View file

@ -161,7 +161,6 @@ void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
return;
}
_reply->disconnect(this);
_reply->deleteLater();
QNetworkReply* reply = _reply;
_reply = NULL;
ResourceCache::requestCompleted();

View file

@ -99,6 +99,7 @@ protected slots:
protected:
/// Called when the download has finished. The recipient should delete the reply when done with it.
virtual void downloadFinished(QNetworkReply* reply) = 0;
/// Should be called by subclasses when all the loading that will be done has been done.