Dilate our network-downloaded textures.

This commit is contained in:
Andrzej Kapolka 2013-10-02 11:59:14 -07:00
parent d87fe204e0
commit c98dec8a65
9 changed files with 94 additions and 47 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 KiB

View file

@ -27,7 +27,6 @@ BlendFace::~BlendFace() {
}
ProgramObject BlendFace::_eyeProgram;
DilatedTextureCache BlendFace::_eyeTextureCache("resources/images/eye.png", 50, 210);
void BlendFace::init() {
if (!_eyeProgram.isLinked()) {
@ -65,6 +64,9 @@ bool BlendFace::render(float alpha) {
}
_blendedVertexBufferIDs.append(id);
}
// make sure we have the right number of dilated texture pointers
_dilatedTextures.resize(geometry.meshes.size());
}
glPushMatrix();
@ -99,6 +101,7 @@ bool BlendFace::render(float alpha) {
glPushMatrix();
// apply eye rotation if appropriate
Texture* texture = networkMesh.diffuseTexture.data();
if (mesh.isEye) {
glTranslatef(mesh.pivot.x, mesh.pivot.y, mesh.pivot.z);
glm::quat rotation = glm::inverse(orientation) * _owningHead->getEyeRotation(orientation *
@ -108,6 +111,11 @@ bool BlendFace::render(float alpha) {
glTranslatef(-mesh.pivot.x, -mesh.pivot.y, -mesh.pivot.z);
_eyeProgram.bind();
if (texture != NULL) {
texture = (_dilatedTextures[i] = static_cast<DilatableNetworkTexture*>(texture)->getDilatedTexture(
_owningHead->getPupilDilation())).data();
}
}
glMultMatrixf((const GLfloat*)&mesh.transform);
@ -117,7 +125,7 @@ bool BlendFace::render(float alpha) {
glColor4f(1.0f, 1.0f, 1.0f, alpha);
}
glBindTexture(GL_TEXTURE_2D, networkMesh.diffuseTexture ? networkMesh.diffuseTexture->getID() : 0);
glBindTexture(GL_TEXTURE_2D, texture == NULL ? 0 : texture->getID());
glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID);
if (mesh.blendshapes.isEmpty()) {
@ -218,8 +226,9 @@ void BlendFace::setModelURL(const QUrl& url) {
}
_modelURL = url;
// delete our local geometry
// delete our local geometry and custom textures
deleteGeometry();
_dilatedTextures.clear();
_geometry = Application::getInstance()->getGeometryCache()->getGeometry(url);
}

View file

@ -51,14 +51,12 @@ private:
QSharedPointer<NetworkGeometry> _geometry;
QVector<GLuint> _blendedVertexBufferIDs;
QVector<QSharedPointer<Texture> > _dilatedTextures;
QVector<glm::vec3> _blendedVertices;
QVector<glm::vec3> _blendedNormals;
QSharedPointer<Texture> _eyeTexture;
static ProgramObject _eyeProgram;
static DilatedTextureCache _eyeTextureCache;
};
#endif /* defined(__interface__BlendFace__) */

View file

@ -46,7 +46,7 @@ const float IRIS_PROTRUSION = 0.0145f;
const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png";
ProgramObject Head::_irisProgram;
DilatedTextureCache Head::_irisTextureCache(IRIS_TEXTURE_FILENAME, 53, 127);
QSharedPointer<DilatableNetworkTexture> Head::_irisTexture;
int Head::_eyePositionLocation;
Head::Head(Avatar* owningAvatar) :
@ -103,6 +103,9 @@ void Head::init() {
_irisProgram.setUniformValue("texture", 0);
_eyePositionLocation = _irisProgram.uniformLocation("eyePosition");
_irisTexture = Application::getInstance()->getTextureCache()->getTexture(QUrl::fromLocalFile(IRIS_TEXTURE_FILENAME),
true).staticCast<DilatableNetworkTexture>();
}
_blendFace.init();
}
@ -624,8 +627,8 @@ void Head::renderEyeBalls() {
_irisProgram.bind();
_irisTexture = _irisTextureCache.getTexture(_pupilDilation);
glBindTexture(GL_TEXTURE_2D, _irisTexture->getID());
_dilatedIrisTexture = _irisTexture->getDilatedTexture(_pupilDilation);
glBindTexture(GL_TEXTURE_2D, _dilatedIrisTexture->getID());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

View file

@ -139,10 +139,10 @@ private:
PerlinFace _perlinFace;
BlendFace _blendFace;
QSharedPointer<Texture> _irisTexture;
QSharedPointer<Texture> _dilatedIrisTexture;
static ProgramObject _irisProgram;
static DilatedTextureCache _irisTextureCache;
static QSharedPointer<DilatableNetworkTexture> _irisTexture;
static int _eyePositionLocation;
// private methods

View file

@ -248,8 +248,8 @@ void PerlinFace::render() {
Head::_irisProgram.bind();
_owningHead->_irisTexture = Head::_irisTextureCache.getTexture(_owningHead->_pupilDilation);
glBindTexture(GL_TEXTURE_2D, _owningHead->_irisTexture->getID());
_owningHead->_dilatedIrisTexture = Head::_irisTexture->getDilatedTexture(_owningHead->_pupilDilation);
glBindTexture(GL_TEXTURE_2D, _owningHead->_dilatedIrisTexture->getID());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

View file

@ -329,7 +329,7 @@ void NetworkGeometry::handleDownloadProgress(qint64 bytesReceived, qint64 bytesT
}
if (!mesh.diffuseFilename.isEmpty()) {
url.setPath(basePath + mesh.diffuseFilename);
networkMesh.diffuseTexture = Application::getInstance()->getTextureCache()->getTexture(url);
networkMesh.diffuseTexture = Application::getInstance()->getTextureCache()->getTexture(url, mesh.isEye);
}
if (!mesh.normalFilename.isEmpty()) {
url.setPath(basePath + mesh.normalFilename);

View file

@ -84,10 +84,10 @@ GLuint TextureCache::getFileTextureID(const QString& filename) {
return id;
}
QSharedPointer<NetworkTexture> TextureCache::getTexture(const QUrl& url) {
QSharedPointer<NetworkTexture> TextureCache::getTexture(const QUrl& url, bool dilatable) {
QSharedPointer<NetworkTexture> texture = _networkTextures.value(url);
if (texture.isNull()) {
texture = QSharedPointer<NetworkTexture>(new NetworkTexture(url));
texture = QSharedPointer<NetworkTexture>(dilatable ? new DilatableNetworkTexture(url) : new NetworkTexture(url));
_networkTextures.insert(url, texture);
}
return texture;
@ -191,6 +191,10 @@ NetworkTexture::~NetworkTexture() {
}
}
void NetworkTexture::imageLoaded(const QImage& image) {
// nothing by default
}
void NetworkTexture::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
if (bytesReceived < bytesTotal && !_reply->isFinished()) {
return;
@ -202,6 +206,7 @@ void NetworkTexture::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTo
_reply = NULL;
QImage image = QImage::fromData(entirety).convertToFormat(QImage::Format_ARGB32);
imageLoaded(image);
glBindTexture(GL_TEXTURE_2D, getID());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1,
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
@ -217,35 +222,57 @@ void NetworkTexture::handleReplyError() {
_reply = NULL;
}
DilatedTextureCache::DilatedTextureCache(const QString& filename, int innerRadius, int outerRadius) :
_innerRadius(innerRadius),
_outerRadius(outerRadius)
DilatableNetworkTexture::DilatableNetworkTexture(const QUrl& url) :
NetworkTexture(url),
_innerRadius(0),
_outerRadius(0)
{
switchToResourcesParentIfRequired();
_image = QImage(filename).convertToFormat(QImage::Format_ARGB32);
}
QSharedPointer<Texture> DilatedTextureCache::getTexture(float dilation) {
QSharedPointer<Texture> texture = _textures.value(dilation);
void DilatableNetworkTexture::imageLoaded(const QImage& image) {
_image = image;
// scan out from the center to find inner and outer radii
int halfWidth = image.width() / 2;
int halfHeight = image.height() / 2;
const int BLACK_THRESHOLD = 32;
while (_innerRadius < halfWidth && qGray(image.pixel(halfWidth + _innerRadius, halfHeight)) < BLACK_THRESHOLD) {
_innerRadius++;
}
_outerRadius = _innerRadius;
const int TRANSPARENT_THRESHOLD = 32;
while (_outerRadius < halfWidth && qAlpha(image.pixel(halfWidth + _outerRadius, halfHeight)) > TRANSPARENT_THRESHOLD) {
_outerRadius++;
}
// clear out any textures we generated before loading
_dilatedTextures.clear();
}
QSharedPointer<Texture> DilatableNetworkTexture::getDilatedTexture(float dilation) {
QSharedPointer<Texture> texture = _dilatedTextures.value(dilation);
if (texture.isNull()) {
texture = QSharedPointer<Texture>(new Texture());
QImage dilatedImage = _image;
QPainter painter;
painter.begin(&dilatedImage);
QPainterPath path;
qreal radius = glm::mix(_innerRadius, _outerRadius, dilation);
path.addEllipse(QPointF(_image.width() / 2.0, _image.height() / 2.0), radius, radius);
painter.fillPath(path, Qt::black);
painter.end();
if (!_image.isNull()) {
QImage dilatedImage = _image;
QPainter painter;
painter.begin(&dilatedImage);
QPainterPath path;
qreal radius = glm::mix(_innerRadius, _outerRadius, dilation);
path.addEllipse(QPointF(_image.width() / 2.0, _image.height() / 2.0), radius, radius);
painter.fillPath(path, Qt::black);
painter.end();
glBindTexture(GL_TEXTURE_2D, texture->getID());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 1,
GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
}
glBindTexture(GL_TEXTURE_2D, texture->getID());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 1,
GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
_textures.insert(dilation, texture);
_dilatedTextures.insert(dilation, texture);
}
return texture;
}

View file

@ -41,7 +41,7 @@ public:
GLuint getFileTextureID(const QString& filename);
/// Loads a texture from the specified URL.
QSharedPointer<NetworkTexture> getTexture(const QUrl& url);
QSharedPointer<NetworkTexture> getTexture(const QUrl& url, bool dilatable = false);
/// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is
/// used for scene rendering.
@ -99,6 +99,10 @@ public:
NetworkTexture(const QUrl& url);
~NetworkTexture();
protected:
virtual void imageLoaded(const QImage& image);
private slots:
void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
@ -109,22 +113,28 @@ private:
QNetworkReply* _reply;
};
/// Caches textures according to pupillary dilation.
class DilatedTextureCache {
/// Caches derived, dilated textures.
class DilatableNetworkTexture : public NetworkTexture {
Q_OBJECT
public:
DilatedTextureCache(const QString& filename, int innerRadius, int outerRadius);
DilatableNetworkTexture(const QUrl& url);
/// Returns a pointer to a texture with the requested amount of dilation.
QSharedPointer<Texture> getTexture(float dilation);
QSharedPointer<Texture> getDilatedTexture(float dilation);
protected:
virtual void imageLoaded(const QImage& image);
private:
QImage _image;
int _innerRadius;
int _outerRadius;
QMap<float, QWeakPointer<Texture> > _textures;
QMap<float, QWeakPointer<Texture> > _dilatedTextures;
};
#endif /* defined(__interface__TextureCache__) */