mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 15:23:56 +02:00
Dilate our network-downloaded textures.
This commit is contained in:
parent
d87fe204e0
commit
c98dec8a65
9 changed files with 94 additions and 47 deletions
Binary file not shown.
Before Width: | Height: | Size: 862 KiB |
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__) */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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__) */
|
||||
|
|
Loading…
Reference in a new issue