diff --git a/interface/resources/shaders/iris.frag b/interface/resources/shaders/iris.frag new file mode 100644 index 0000000000..2f5b06d6c6 --- /dev/null +++ b/interface/resources/shaders/iris.frag @@ -0,0 +1,21 @@ +#version 120 + +// +// iris.frag +// fragment shader +// +// Created by Andrzej Kapolka on 6/13/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +// the iris texture +uniform sampler2D texture; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), normalize(normal))); + gl_FragColor = vec4(gl_Color.rgb * texture2D(texture, gl_TexCoord[0].st).rgb + + pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 1.0); +} diff --git a/interface/resources/shaders/iris.vert b/interface/resources/shaders/iris.vert new file mode 100644 index 0000000000..83602f3e99 --- /dev/null +++ b/interface/resources/shaders/iris.vert @@ -0,0 +1,20 @@ +#version 120 + +// +// iris.vert +// vertex shader +// +// Created by Andrzej Kapolka on 6/13/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +// the interpolated normal +varying vec4 normal; + +void main(void) { + normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); + gl_FrontColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient + + gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = ftransform(); +} diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index a3618b1726..8a1f1a67ce 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -271,6 +271,7 @@ Avatar::~Avatar() { } void Avatar::init() { + _head.init(); _voxels.init(); _initialized = true; } diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index e2b9fdb3ad..790b88ef6e 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -5,13 +5,16 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. #include + +#include + +#include + #include "Application.h" #include "Avatar.h" #include "Head.h" #include "Util.h" -#include -#include -#include +#include "renderer/ProgramObject.h" using namespace std; @@ -36,9 +39,8 @@ const float IRIS_RADIUS = 0.007; const float IRIS_PROTRUSION = 0.0145f; const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png"; -unsigned int IRIS_TEXTURE_WIDTH = 768; -unsigned int IRIS_TEXTURE_HEIGHT = 498; -vector irisTexture; +ProgramObject* Head::_irisProgram = 0; +GLuint Head::_irisTextureID; Head::Head(Avatar* owningAvatar) : HeadData((AvatarData*)owningAvatar), @@ -75,6 +77,26 @@ Head::Head(Avatar* owningAvatar) : } } +void Head::init() { + if (_irisProgram == 0) { + switchToResourcesParentIfRequired(); + _irisProgram = new ProgramObject(); + _irisProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/iris.vert"); + _irisProgram->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/iris.frag"); + _irisProgram->link(); + + _irisProgram->setUniformValue("texture", 0); + + QImage image = QImage(IRIS_TEXTURE_FILENAME).convertToFormat(QImage::Format_RGB888); + + glGenTextures(1, &_irisTextureID); + glBindTexture(GL_TEXTURE_2D, _irisTextureID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, image.constBits()); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + } +} + void Head::reset() { _yaw = _pitch = _roll = 0.0f; _leanForward = _leanSideways = 0.0f; @@ -440,22 +462,11 @@ void Head::renderEyeBrows() { void Head::renderEyeBalls() { - if (::irisTexture.size() == 0) { - switchToResourcesParentIfRequired(); - unsigned error = lodepng::decode(::irisTexture, IRIS_TEXTURE_WIDTH, IRIS_TEXTURE_HEIGHT, IRIS_TEXTURE_FILENAME); - if (error != 0) { - printLog("error %u: %s\n", error, lodepng_error_text(error)); - } - } - - // setup the texutre to be used on each iris + // setup the texture to be used on each iris GLUquadric* irisQuadric = gluNewQuadric(); gluQuadricTexture(irisQuadric, GL_TRUE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gluQuadricOrientation(irisQuadric, GLU_OUTSIDE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, IRIS_TEXTURE_WIDTH, IRIS_TEXTURE_HEIGHT, - 0, GL_RGBA, GL_UNSIGNED_BYTE, &::irisTexture[0]); // render white ball of left eyeball glPushMatrix(); @@ -464,6 +475,17 @@ void Head::renderEyeBalls() { gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30); glPopMatrix(); + //render white ball of right eyeball + glPushMatrix(); + glColor3fv(EYEBALL_COLOR); + glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); + gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30); + glPopMatrix(); + + _irisProgram->bind(); + glBindTexture(GL_TEXTURE_2D, _irisTextureID); + glEnable(GL_TEXTURE_2D); + glm::vec3 front = getFrontDirection(); // render left iris @@ -495,20 +517,11 @@ void Head::renderEyeBalls() { glTranslatef( 0.0f, -IRIS_PROTRUSION, 0.0f);//push the iris out a bit (otherwise - inside of eyeball!) glScalef( 1.0f, 0.5f, 1.0f); // flatten the iris - glEnable(GL_TEXTURE_2D); gluSphere(irisQuadric, IRIS_RADIUS, 15, 15); - glDisable(GL_TEXTURE_2D); glPopMatrix(); } glPopMatrix(); - //render white ball of right eyeball - glPushMatrix(); - glColor3fv(EYEBALL_COLOR); - glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); - gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30); - glPopMatrix(); - // render right iris glPushMatrix(); { glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); //translate to eyeball position @@ -540,12 +553,14 @@ void Head::renderEyeBalls() { glTranslatef( 0.0f, -IRIS_PROTRUSION, 0.0f);//push the iris out a bit (otherwise - inside of eyeball!) glScalef( 1.0f, 0.5f, 1.0f); // flatten the iris - glEnable(GL_TEXTURE_2D); gluSphere(irisQuadric, IRIS_RADIUS, 15, 15); - glDisable(GL_TEXTURE_2D); glPopMatrix(); } + _irisProgram->release(); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + // delete the iris quadric now that we're done with it gluDeleteQuadric(irisQuadric); glPopMatrix(); diff --git a/interface/src/Head.h b/interface/src/Head.h index a46571a99d..30636c37fe 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -26,11 +26,13 @@ enum eyeContactTargets const int NUM_HAIR_TUFTS = 4; class Avatar; +class ProgramObject; class Head : public HeadData { public: Head(Avatar* owningAvatar); + void init(); void reset(); void simulate(float deltaTime, bool isMine); void render(bool lookingInMirror, float alpha); @@ -105,6 +107,9 @@ private: glm::vec3 _saccade; glm::vec3 _saccadeTarget; + static ProgramObject* _irisProgram; + static GLuint _irisTextureID; + // private methods void createMohawk(); void renderHeadSphere();