mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 10:30:28 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into lod_slider
This commit is contained in:
commit
d1fbe242ab
19 changed files with 407 additions and 84 deletions
BIN
interface/resources/images/body.png
Normal file
BIN
interface/resources/images/body.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
BIN
interface/resources/images/head.png
Normal file
BIN
interface/resources/images/head.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
|
@ -1,7 +1,7 @@
|
||||||
#version 120
|
#version 120
|
||||||
|
|
||||||
//
|
//
|
||||||
// blendface.frag
|
// model.frag
|
||||||
// fragment shader
|
// fragment shader
|
||||||
//
|
//
|
||||||
// Created by Andrzej Kapolka on 10/14/13.
|
// Created by Andrzej Kapolka on 10/14/13.
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
// the diffuse texture
|
// the diffuse texture
|
||||||
uniform sampler2D texture;
|
uniform sampler2D diffuseMap;
|
||||||
|
|
||||||
// the interpolated normal
|
// the interpolated normal
|
||||||
varying vec4 normal;
|
varying vec4 normal;
|
||||||
|
@ -24,6 +24,6 @@ void main(void) {
|
||||||
float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), normalizedNormal));
|
float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), normalizedNormal));
|
||||||
|
|
||||||
// modulate texture by base color and add specular contribution
|
// modulate texture by base color and add specular contribution
|
||||||
gl_FragColor = base * texture2D(texture, gl_TexCoord[0].st) +
|
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) +
|
||||||
pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular;
|
pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#version 120
|
#version 120
|
||||||
|
|
||||||
//
|
//
|
||||||
// blendface.vert
|
// model.vert
|
||||||
// vertex shader
|
// vertex shader
|
||||||
//
|
//
|
||||||
// Created by Andrzej Kapolka on 10/14/13.
|
// Created by Andrzej Kapolka on 10/14/13.
|
||||||
|
|
41
interface/resources/shaders/model_normal_map.frag
Normal file
41
interface/resources/shaders/model_normal_map.frag
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
//
|
||||||
|
// model_normal_map.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 10/29/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
// the diffuse texture
|
||||||
|
uniform sampler2D diffuseMap;
|
||||||
|
|
||||||
|
// the normal map texture
|
||||||
|
uniform sampler2D normalMap;
|
||||||
|
|
||||||
|
// the interpolated normal
|
||||||
|
varying vec4 interpolatedNormal;
|
||||||
|
|
||||||
|
// the interpolated tangent
|
||||||
|
varying vec4 interpolatedTangent;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
vec3 normalizedNormal = normalize(vec3(interpolatedNormal));
|
||||||
|
vec3 normalizedTangent = normalize(vec3(interpolatedTangent));
|
||||||
|
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
|
||||||
|
vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
// compute the base color based on OpenGL lighting model
|
||||||
|
vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
|
||||||
|
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
|
||||||
|
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||||
|
gl_FrontLightProduct[0].diffuse * max(0.0, dot(viewNormal, gl_LightSource[0].position)));
|
||||||
|
|
||||||
|
// compute the specular component (sans exponent)
|
||||||
|
float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), viewNormal));
|
||||||
|
|
||||||
|
// modulate texture by base color and add specular contribution
|
||||||
|
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) +
|
||||||
|
pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular;
|
||||||
|
}
|
34
interface/resources/shaders/model_normal_map.vert
Normal file
34
interface/resources/shaders/model_normal_map.vert
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
//
|
||||||
|
// model.vert
|
||||||
|
// vertex shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 10/14/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
// the tangent vector
|
||||||
|
attribute vec3 tangent;
|
||||||
|
|
||||||
|
// the interpolated normal
|
||||||
|
varying vec4 interpolatedNormal;
|
||||||
|
|
||||||
|
// the interpolated tangent
|
||||||
|
varying vec4 interpolatedTangent;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
|
||||||
|
// transform and store the normal and tangent for interpolation
|
||||||
|
interpolatedNormal = gl_ModelViewMatrix * vec4(gl_Normal, 0.0);
|
||||||
|
interpolatedTangent = gl_ModelViewMatrix * vec4(tangent, 0.0);
|
||||||
|
|
||||||
|
// pass along the vertex color
|
||||||
|
gl_FrontColor = gl_Color;
|
||||||
|
|
||||||
|
// and the texture coordinates
|
||||||
|
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||||
|
|
||||||
|
// use standard pipeline transform
|
||||||
|
gl_Position = ftransform();
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#version 120
|
#version 120
|
||||||
|
|
||||||
//
|
//
|
||||||
// skin_blendface.vert
|
// skin_model.vert
|
||||||
// vertex shader
|
// vertex shader
|
||||||
//
|
//
|
||||||
// Created by Andrzej Kapolka on 10/14/13.
|
// Created by Andrzej Kapolka on 10/14/13.
|
||||||
|
|
50
interface/resources/shaders/skin_model_normal_map.vert
Normal file
50
interface/resources/shaders/skin_model_normal_map.vert
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
//
|
||||||
|
// skin_model_normal_map.vert
|
||||||
|
// vertex shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 10/29/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
const int MAX_CLUSTERS = 64;
|
||||||
|
const int INDICES_PER_VERTEX = 4;
|
||||||
|
|
||||||
|
uniform mat4 clusterMatrices[MAX_CLUSTERS];
|
||||||
|
|
||||||
|
// the tangent vector
|
||||||
|
attribute vec3 tangent;
|
||||||
|
|
||||||
|
attribute vec4 clusterIndices;
|
||||||
|
attribute vec4 clusterWeights;
|
||||||
|
|
||||||
|
// the interpolated normal
|
||||||
|
varying vec4 interpolatedNormal;
|
||||||
|
|
||||||
|
// the interpolated tangent
|
||||||
|
varying vec4 interpolatedTangent;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
|
||||||
|
mat4 clusterMatrix = clusterMatrices[int(clusterIndices[i])];
|
||||||
|
float clusterWeight = clusterWeights[i];
|
||||||
|
position += clusterMatrix * gl_Vertex * clusterWeight;
|
||||||
|
interpolatedNormal += clusterMatrix * vec4(gl_Normal, 0.0) * clusterWeight;
|
||||||
|
interpolatedTangent += clusterMatrix * vec4(tangent, 0.0) * clusterWeight;
|
||||||
|
}
|
||||||
|
position = gl_ModelViewProjectionMatrix * position;
|
||||||
|
interpolatedNormal = gl_ModelViewMatrix * interpolatedNormal;
|
||||||
|
interpolatedTangent = gl_ModelViewMatrix * interpolatedTangent;
|
||||||
|
|
||||||
|
// pass along the vertex color
|
||||||
|
gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
// and the texture coordinates
|
||||||
|
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||||
|
|
||||||
|
gl_Position = position;
|
||||||
|
}
|
|
@ -89,6 +89,8 @@ const int MIRROR_VIEW_TOP_PADDING = 5;
|
||||||
const int MIRROR_VIEW_LEFT_PADDING = 10;
|
const int MIRROR_VIEW_LEFT_PADDING = 10;
|
||||||
const int MIRROR_VIEW_WIDTH = 265;
|
const int MIRROR_VIEW_WIDTH = 265;
|
||||||
const int MIRROR_VIEW_HEIGHT = 215;
|
const int MIRROR_VIEW_HEIGHT = 215;
|
||||||
|
const float MAX_ZOOM_DISTANCE = 0.3f;
|
||||||
|
const float MIN_ZOOM_DISTANCE = 2.0f;
|
||||||
|
|
||||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) {
|
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) {
|
||||||
fprintf(stdout, "%s", message.toLocal8Bit().constData());
|
fprintf(stdout, "%s", message.toLocal8Bit().constData());
|
||||||
|
@ -213,13 +215,13 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
// start the nodeList threads
|
// start the nodeList threads
|
||||||
NodeList::getInstance()->startSilentNodeRemovalThread();
|
NodeList::getInstance()->startSilentNodeRemovalThread();
|
||||||
|
|
||||||
_window->setCentralWidget(_glWidget);
|
|
||||||
|
|
||||||
_networkAccessManager = new QNetworkAccessManager(this);
|
_networkAccessManager = new QNetworkAccessManager(this);
|
||||||
QNetworkDiskCache* cache = new QNetworkDiskCache(_networkAccessManager);
|
QNetworkDiskCache* cache = new QNetworkDiskCache(_networkAccessManager);
|
||||||
cache->setCacheDirectory("interfaceCache");
|
cache->setCacheDirectory("interfaceCache");
|
||||||
_networkAccessManager->setCache(cache);
|
_networkAccessManager->setCache(cache);
|
||||||
|
|
||||||
|
_window->setCentralWidget(_glWidget);
|
||||||
|
|
||||||
restoreSizeAndPosition();
|
restoreSizeAndPosition();
|
||||||
_window->setVisible(true);
|
_window->setVisible(true);
|
||||||
_glWidget->setFocusPolicy(Qt::StrongFocus);
|
_glWidget->setFocusPolicy(Qt::StrongFocus);
|
||||||
|
@ -384,7 +386,7 @@ void Application::paintGL() {
|
||||||
|
|
||||||
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||||
_myCamera.setTightness(0.0f);
|
_myCamera.setTightness(0.0f);
|
||||||
_myCamera.setDistance(0.3f);
|
_myCamera.setDistance(MAX_ZOOM_DISTANCE);
|
||||||
_myCamera.setTargetPosition(_myAvatar.getHead().calculateAverageEyePosition());
|
_myCamera.setTargetPosition(_myAvatar.getHead().calculateAverageEyePosition());
|
||||||
_myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
_myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
||||||
}
|
}
|
||||||
|
@ -434,8 +436,15 @@ void Application::paintGL() {
|
||||||
_glowEffect.render();
|
_glowEffect.render();
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||||
_mirrorCamera.setDistance(0.3f);
|
|
||||||
_mirrorCamera.setTargetPosition(_myAvatar.getHead().calculateAverageEyePosition());
|
if (_rearMirrorTools->getZoomLevel() == BODY) {
|
||||||
|
_mirrorCamera.setDistance(MIN_ZOOM_DISTANCE);
|
||||||
|
_mirrorCamera.setTargetPosition(_myAvatar.getChestJointPosition());
|
||||||
|
} else { // HEAD zoom level
|
||||||
|
_mirrorCamera.setDistance(MAX_ZOOM_DISTANCE);
|
||||||
|
_mirrorCamera.setTargetPosition(_myAvatar.getHead().calculateAverageEyePosition());
|
||||||
|
}
|
||||||
|
|
||||||
_mirrorCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
_mirrorCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
||||||
_mirrorCamera.update(1.0f/_fps);
|
_mirrorCamera.update(1.0f/_fps);
|
||||||
|
|
||||||
|
@ -1328,8 +1337,8 @@ void Application::terminate() {
|
||||||
// close(serial_fd);
|
// close(serial_fd);
|
||||||
|
|
||||||
LeapManager::terminate();
|
LeapManager::terminate();
|
||||||
|
|
||||||
Menu::getInstance()->saveSettings();
|
Menu::getInstance()->saveSettings();
|
||||||
|
_rearMirrorTools->saveSettings(_settings);
|
||||||
_settings->sync();
|
_settings->sync();
|
||||||
|
|
||||||
if (_enableNetworkThread) {
|
if (_enableNetworkThread) {
|
||||||
|
@ -1725,7 +1734,7 @@ void Application::init() {
|
||||||
|
|
||||||
_audio.init(_glWidget);
|
_audio.init(_glWidget);
|
||||||
|
|
||||||
_rearMirrorTools = new RearMirrorTools(_glWidget, _mirrorViewRect);
|
_rearMirrorTools = new RearMirrorTools(_glWidget, _mirrorViewRect, _settings);
|
||||||
connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView()));
|
connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView()));
|
||||||
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
|
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
|
||||||
connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
|
connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
|
||||||
|
|
|
@ -150,6 +150,7 @@ public:
|
||||||
SkeletonModel& getSkeletonModel() { return _skeletonModel; }
|
SkeletonModel& getSkeletonModel() { return _skeletonModel; }
|
||||||
float getHeadYawRate() const { return _head.yawRate; }
|
float getHeadYawRate() const { return _head.yawRate; }
|
||||||
const glm::vec3& getHeadJointPosition() const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position; }
|
const glm::vec3& getHeadJointPosition() const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position; }
|
||||||
|
const glm::vec3& getChestJointPosition() const { return _skeleton.joint[ AVATAR_JOINT_CHEST ].position; }
|
||||||
float getScale() const { return _scale; }
|
float getScale() const { return _scale; }
|
||||||
const glm::vec3& getVelocity() const { return _velocity; }
|
const glm::vec3& getVelocity() const { return _velocity; }
|
||||||
Head& getHead() { return _head; }
|
Head& getHead() { return _head; }
|
||||||
|
|
|
@ -677,6 +677,17 @@ FBXMesh extractMesh(const FBXNode& object) {
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setTangents(FBXMesh& mesh, int firstIndex, int secondIndex) {
|
||||||
|
glm::vec3 normal = mesh.normals.at(firstIndex);
|
||||||
|
glm::vec3 bitangent = glm::cross(normal, mesh.vertices.at(secondIndex) - mesh.vertices.at(firstIndex));
|
||||||
|
if (glm::length(bitangent) < EPSILON) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
glm::vec2 texCoordDelta = mesh.texCoords.at(secondIndex) - mesh.texCoords.at(firstIndex);
|
||||||
|
mesh.tangents[firstIndex] += glm::cross(glm::angleAxis(
|
||||||
|
-glm::degrees(atan2f(-texCoordDelta.t, texCoordDelta.s)), normal) * glm::normalize(bitangent), normal);
|
||||||
|
}
|
||||||
|
|
||||||
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
|
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
|
||||||
QHash<QString, FBXMesh> meshes;
|
QHash<QString, FBXMesh> meshes;
|
||||||
QVector<ExtractedBlendshape> blendshapes;
|
QVector<ExtractedBlendshape> blendshapes;
|
||||||
|
@ -1054,6 +1065,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
|
|
||||||
// look for textures, material properties
|
// look for textures, material properties
|
||||||
int partIndex = mesh.parts.size() - 1;
|
int partIndex = mesh.parts.size() - 1;
|
||||||
|
bool generateTangents = false;
|
||||||
foreach (const QString& childID, childMap.values(modelID)) {
|
foreach (const QString& childID, childMap.values(modelID)) {
|
||||||
if (partIndex < 0) {
|
if (partIndex < 0) {
|
||||||
break;
|
break;
|
||||||
|
@ -1084,10 +1096,29 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
QString bumpTextureID = bumpTextures.value(childID);
|
QString bumpTextureID = bumpTextures.value(childID);
|
||||||
if (!bumpTextureID.isNull()) {
|
if (!bumpTextureID.isNull()) {
|
||||||
part.normalFilename = textureFilenames.value(bumpTextureID);
|
part.normalFilename = textureFilenames.value(bumpTextureID);
|
||||||
|
generateTangents = true;
|
||||||
}
|
}
|
||||||
partIndex--;
|
partIndex--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we have a normal map (and texture coordinates), we must compute tangents
|
||||||
|
if (generateTangents && !mesh.texCoords.isEmpty()) {
|
||||||
|
mesh.tangents.resize(mesh.vertices.size());
|
||||||
|
foreach (const FBXMeshPart& part, mesh.parts) {
|
||||||
|
for (int i = 0; i < part.quadIndices.size(); i += 4) {
|
||||||
|
setTangents(mesh, part.quadIndices.at(i), part.quadIndices.at(i + 1));
|
||||||
|
setTangents(mesh, part.quadIndices.at(i + 1), part.quadIndices.at(i + 2));
|
||||||
|
setTangents(mesh, part.quadIndices.at(i + 2), part.quadIndices.at(i + 3));
|
||||||
|
setTangents(mesh, part.quadIndices.at(i + 3), part.quadIndices.at(i));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < part.triangleIndices.size(); i += 3) {
|
||||||
|
setTangents(mesh, part.triangleIndices.at(i), part.triangleIndices.at(i + 1));
|
||||||
|
setTangents(mesh, part.triangleIndices.at(i + 1), part.triangleIndices.at(i + 2));
|
||||||
|
setTangents(mesh, part.triangleIndices.at(i + 2), part.triangleIndices.at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// find the clusters with which the mesh is associated
|
// find the clusters with which the mesh is associated
|
||||||
mesh.isEye = false;
|
mesh.isEye = false;
|
||||||
QVector<QString> clusterIDs;
|
QVector<QString> clusterIDs;
|
||||||
|
|
|
@ -86,6 +86,7 @@ public:
|
||||||
|
|
||||||
QVector<glm::vec3> vertices;
|
QVector<glm::vec3> vertices;
|
||||||
QVector<glm::vec3> normals;
|
QVector<glm::vec3> normals;
|
||||||
|
QVector<glm::vec3> tangents;
|
||||||
QVector<glm::vec3> colors;
|
QVector<glm::vec3> colors;
|
||||||
QVector<glm::vec2> texCoords;
|
QVector<glm::vec2> texCoords;
|
||||||
QVector<glm::vec4> clusterIndices;
|
QVector<glm::vec4> clusterIndices;
|
||||||
|
|
|
@ -396,7 +396,8 @@ void NetworkGeometry::maybeReadModelWithMapping() {
|
||||||
// if we don't need to do any blending or springing, then the positions/normals can be static
|
// if we don't need to do any blending or springing, then the positions/normals can be static
|
||||||
if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) {
|
if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) {
|
||||||
int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
|
int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
|
||||||
int colorsOffset = normalsOffset + mesh.normals.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 texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
|
||||||
int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
|
int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
|
||||||
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
|
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
|
||||||
|
@ -404,6 +405,7 @@ void NetworkGeometry::maybeReadModelWithMapping() {
|
||||||
NULL, GL_STATIC_DRAW);
|
NULL, GL_STATIC_DRAW);
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.vertices.size() * sizeof(glm::vec3), mesh.vertices.constData());
|
glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.vertices.size() * sizeof(glm::vec3), mesh.vertices.constData());
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, normalsOffset, mesh.normals.size() * sizeof(glm::vec3), mesh.normals.constData());
|
glBufferSubData(GL_ARRAY_BUFFER, normalsOffset, mesh.normals.size() * sizeof(glm::vec3), mesh.normals.constData());
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, tangentsOffset, mesh.tangents.size() * sizeof(glm::vec3), mesh.tangents.constData());
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, colorsOffset, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData());
|
glBufferSubData(GL_ARRAY_BUFFER, colorsOffset, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData());
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2),
|
glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2),
|
||||||
mesh.texCoords.constData());
|
mesh.texCoords.constData());
|
||||||
|
@ -414,12 +416,14 @@ void NetworkGeometry::maybeReadModelWithMapping() {
|
||||||
|
|
||||||
// if there's no springiness, then the cluster indices/weights can be static
|
// if there's no springiness, then the cluster indices/weights can be static
|
||||||
} else if (mesh.springiness == 0.0f) {
|
} else if (mesh.springiness == 0.0f) {
|
||||||
int texCoordsOffset = mesh.colors.size() * sizeof(glm::vec3);
|
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 clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
|
||||||
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
|
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
|
||||||
glBufferData(GL_ARRAY_BUFFER, clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4),
|
glBufferData(GL_ARRAY_BUFFER, clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4),
|
||||||
NULL, GL_STATIC_DRAW);
|
NULL, GL_STATIC_DRAW);
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData());
|
glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.tangents.size() * sizeof(glm::vec3), mesh.tangents.constData());
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, colorsOffset, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData());
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2), mesh.texCoords.constData());
|
glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2), mesh.texCoords.constData());
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, clusterIndicesOffset, mesh.clusterIndices.size() * sizeof(glm::vec4),
|
glBufferSubData(GL_ARRAY_BUFFER, clusterIndicesOffset, mesh.clusterIndices.size() * sizeof(glm::vec4),
|
||||||
mesh.clusterIndices.constData());
|
mesh.clusterIndices.constData());
|
||||||
|
@ -427,9 +431,11 @@ void NetworkGeometry::maybeReadModelWithMapping() {
|
||||||
mesh.clusterWeights.constData());
|
mesh.clusterWeights.constData());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
int texCoordsOffset = mesh.colors.size() * sizeof(glm::vec3);
|
int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
|
||||||
|
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
|
||||||
glBufferData(GL_ARRAY_BUFFER, texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2), NULL, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2), NULL, GL_STATIC_DRAW);
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData());
|
glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.tangents.size() * sizeof(glm::vec3), mesh.tangents.constData());
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, colorsOffset, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData());
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2),
|
glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2),
|
||||||
mesh.texCoords.constData());
|
mesh.texCoords.constData());
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,10 +26,23 @@ Model::~Model() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramObject Model::_program;
|
ProgramObject Model::_program;
|
||||||
|
ProgramObject Model::_normalMapProgram;
|
||||||
ProgramObject Model::_skinProgram;
|
ProgramObject Model::_skinProgram;
|
||||||
int Model::_clusterMatricesLocation;
|
ProgramObject Model::_skinNormalMapProgram;
|
||||||
int Model::_clusterIndicesLocation;
|
int Model::_normalMapTangentLocation;
|
||||||
int Model::_clusterWeightsLocation;
|
Model::SkinLocations Model::_skinLocations;
|
||||||
|
Model::SkinLocations Model::_skinNormalMapLocations;
|
||||||
|
|
||||||
|
void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations) {
|
||||||
|
program.bind();
|
||||||
|
locations.clusterMatrices = program.uniformLocation("clusterMatrices");
|
||||||
|
locations.clusterIndices = program.attributeLocation("clusterIndices");
|
||||||
|
locations.clusterWeights = program.attributeLocation("clusterWeights");
|
||||||
|
locations.tangent = program.attributeLocation("tangent");
|
||||||
|
program.setUniformValue("diffuseMap", 0);
|
||||||
|
program.setUniformValue("normalMap", 1);
|
||||||
|
program.release();
|
||||||
|
}
|
||||||
|
|
||||||
void Model::init() {
|
void Model::init() {
|
||||||
if (!_program.isLinked()) {
|
if (!_program.isLinked()) {
|
||||||
|
@ -42,16 +55,27 @@ void Model::init() {
|
||||||
_program.setUniformValue("texture", 0);
|
_program.setUniformValue("texture", 0);
|
||||||
_program.release();
|
_program.release();
|
||||||
|
|
||||||
|
_normalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/model_normal_map.vert");
|
||||||
|
_normalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/model_normal_map.frag");
|
||||||
|
_normalMapProgram.link();
|
||||||
|
|
||||||
|
_normalMapProgram.bind();
|
||||||
|
_normalMapProgram.setUniformValue("diffuseMap", 0);
|
||||||
|
_normalMapProgram.setUniformValue("normalMap", 1);
|
||||||
|
_normalMapTangentLocation = _normalMapProgram.attributeLocation("tangent");
|
||||||
|
_normalMapProgram.release();
|
||||||
|
|
||||||
_skinProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/skin_model.vert");
|
_skinProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/skin_model.vert");
|
||||||
_skinProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/model.frag");
|
_skinProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/model.frag");
|
||||||
_skinProgram.link();
|
_skinProgram.link();
|
||||||
|
|
||||||
_skinProgram.bind();
|
initSkinProgram(_skinProgram, _skinLocations);
|
||||||
_clusterMatricesLocation = _skinProgram.uniformLocation("clusterMatrices");
|
|
||||||
_clusterIndicesLocation = _skinProgram.attributeLocation("clusterIndices");
|
_skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/skin_model_normal_map.vert");
|
||||||
_clusterWeightsLocation = _skinProgram.attributeLocation("clusterWeights");
|
_skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/model_normal_map.frag");
|
||||||
_skinProgram.setUniformValue("texture", 0);
|
_skinNormalMapProgram.link();
|
||||||
_skinProgram.release();
|
|
||||||
|
initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,38 +269,61 @@ bool Model::render(float alpha) {
|
||||||
int vertexCount = mesh.vertices.size();
|
int vertexCount = mesh.vertices.size();
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID);
|
glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID);
|
||||||
|
|
||||||
|
ProgramObject* program = &_program;
|
||||||
|
ProgramObject* skinProgram = &_skinProgram;
|
||||||
|
SkinLocations* skinLocations = &_skinLocations;
|
||||||
|
if (!mesh.tangents.isEmpty()) {
|
||||||
|
program = &_normalMapProgram;
|
||||||
|
skinProgram = &_skinNormalMapProgram;
|
||||||
|
skinLocations = &_skinNormalMapLocations;
|
||||||
|
}
|
||||||
|
|
||||||
const MeshState& state = _meshStates.at(i);
|
const MeshState& state = _meshStates.at(i);
|
||||||
|
ProgramObject* activeProgram = program;
|
||||||
|
int tangentLocation = _normalMapTangentLocation;
|
||||||
if (state.worldSpaceVertices.isEmpty()) {
|
if (state.worldSpaceVertices.isEmpty()) {
|
||||||
if (state.clusterMatrices.size() > 1) {
|
if (state.clusterMatrices.size() > 1) {
|
||||||
_skinProgram.bind();
|
skinProgram->bind();
|
||||||
glUniformMatrix4fvARB(_clusterMatricesLocation, state.clusterMatrices.size(), false,
|
glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false,
|
||||||
(const float*)state.clusterMatrices.constData());
|
(const float*)state.clusterMatrices.constData());
|
||||||
int offset = mesh.colors.size() * sizeof(glm::vec3) + mesh.texCoords.size() * sizeof(glm::vec2) +
|
int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) +
|
||||||
|
mesh.texCoords.size() * sizeof(glm::vec2) +
|
||||||
(mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0);
|
(mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0);
|
||||||
_skinProgram.setAttributeBuffer(_clusterIndicesLocation, GL_FLOAT, offset, 4);
|
skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4);
|
||||||
_skinProgram.setAttributeBuffer(_clusterWeightsLocation, GL_FLOAT,
|
skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT,
|
||||||
offset + vertexCount * sizeof(glm::vec4), 4);
|
offset + vertexCount * sizeof(glm::vec4), 4);
|
||||||
_skinProgram.enableAttributeArray(_clusterIndicesLocation);
|
skinProgram->enableAttributeArray(skinLocations->clusterIndices);
|
||||||
_skinProgram.enableAttributeArray(_clusterWeightsLocation);
|
skinProgram->enableAttributeArray(skinLocations->clusterWeights);
|
||||||
|
activeProgram = skinProgram;
|
||||||
|
tangentLocation = skinLocations->tangent;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]);
|
glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]);
|
||||||
_program.bind();
|
program->bind();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_program.bind();
|
program->bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) {
|
if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) {
|
||||||
glColorPointer(3, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3)));
|
if (!mesh.tangents.isEmpty()) {
|
||||||
|
activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3);
|
||||||
|
activeProgram->enableAttributeArray(tangentLocation);
|
||||||
|
}
|
||||||
|
glColorPointer(3, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) +
|
||||||
|
mesh.tangents.size() * sizeof(glm::vec3)));
|
||||||
glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) +
|
glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) +
|
||||||
mesh.colors.size() * sizeof(glm::vec3)));
|
(mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3)));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
glColorPointer(3, GL_FLOAT, 0, 0);
|
if (!mesh.tangents.isEmpty()) {
|
||||||
glTexCoordPointer(2, GL_FLOAT, 0, (void*)(mesh.colors.size() * sizeof(glm::vec3)));
|
activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, 0, 3);
|
||||||
|
activeProgram->enableAttributeArray(tangentLocation);
|
||||||
|
}
|
||||||
|
glColorPointer(3, GL_FLOAT, 0, (void*)(mesh.tangents.size() * sizeof(glm::vec3)));
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 0, (void*)((mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3)));
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i));
|
glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i));
|
||||||
|
|
||||||
if (!state.worldSpaceVertices.isEmpty()) {
|
if (!state.worldSpaceVertices.isEmpty()) {
|
||||||
|
@ -337,15 +384,23 @@ bool Model::render(float alpha) {
|
||||||
glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular);
|
glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular);
|
||||||
glMaterialf(GL_FRONT, GL_SHININESS, part.shininess);
|
glMaterialf(GL_FRONT, GL_SHININESS, part.shininess);
|
||||||
|
|
||||||
Texture* texture = networkPart.diffuseTexture.data();
|
Texture* diffuseMap = networkPart.diffuseTexture.data();
|
||||||
if (mesh.isEye) {
|
if (mesh.isEye) {
|
||||||
if (texture != NULL) {
|
if (diffuseMap != NULL) {
|
||||||
texture = (_dilatedTextures[i][j] = static_cast<DilatableNetworkTexture*>(texture)->getDilatedTexture(
|
diffuseMap = (_dilatedTextures[i][j] =
|
||||||
_pupilDilation)).data();
|
static_cast<DilatableNetworkTexture*>(diffuseMap)->getDilatedTexture(_pupilDilation)).data();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glBindTexture(GL_TEXTURE_2D, texture == NULL ? Application::getInstance()->getTextureCache()->getWhiteTextureID() :
|
glBindTexture(GL_TEXTURE_2D, diffuseMap == NULL ?
|
||||||
texture->getID());
|
Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID());
|
||||||
|
|
||||||
|
if (!mesh.tangents.isEmpty()) {
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
Texture* normalMap = networkPart.normalTexture.data();
|
||||||
|
glBindTexture(GL_TEXTURE_2D, normalMap == NULL ?
|
||||||
|
Application::getInstance()->getTextureCache()->getBlueTextureID() : normalMap->getID());
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
}
|
||||||
|
|
||||||
glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset);
|
glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset);
|
||||||
offset += part.quadIndices.size() * sizeof(int);
|
offset += part.quadIndices.size() * sizeof(int);
|
||||||
|
@ -361,19 +416,24 @@ bool Model::render(float alpha) {
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mesh.tangents.isEmpty()) {
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
activeProgram->disableAttributeArray(tangentLocation);
|
||||||
|
}
|
||||||
|
|
||||||
if (state.worldSpaceVertices.isEmpty()) {
|
if (state.worldSpaceVertices.isEmpty()) {
|
||||||
if (state.clusterMatrices.size() > 1) {
|
if (state.clusterMatrices.size() > 1) {
|
||||||
_skinProgram.disableAttributeArray(_clusterIndicesLocation);
|
skinProgram->disableAttributeArray(skinLocations->clusterIndices);
|
||||||
_skinProgram.disableAttributeArray(_clusterWeightsLocation);
|
skinProgram->disableAttributeArray(skinLocations->clusterWeights);
|
||||||
_skinProgram.release();
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
_program.release();
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
_program.release();
|
|
||||||
}
|
}
|
||||||
|
activeProgram->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// deactivate vertex arrays after drawing
|
// deactivate vertex arrays after drawing
|
||||||
|
|
|
@ -148,10 +148,24 @@ private:
|
||||||
QVector<Model*> _attachments;
|
QVector<Model*> _attachments;
|
||||||
|
|
||||||
static ProgramObject _program;
|
static ProgramObject _program;
|
||||||
|
static ProgramObject _normalMapProgram;
|
||||||
static ProgramObject _skinProgram;
|
static ProgramObject _skinProgram;
|
||||||
static int _clusterMatricesLocation;
|
static ProgramObject _skinNormalMapProgram;
|
||||||
static int _clusterIndicesLocation;
|
|
||||||
static int _clusterWeightsLocation;
|
static int _normalMapTangentLocation;
|
||||||
|
|
||||||
|
class SkinLocations {
|
||||||
|
public:
|
||||||
|
int clusterMatrices;
|
||||||
|
int clusterIndices;
|
||||||
|
int clusterWeights;
|
||||||
|
int tangent;
|
||||||
|
};
|
||||||
|
|
||||||
|
static SkinLocations _skinLocations;
|
||||||
|
static SkinLocations _skinNormalMapLocations;
|
||||||
|
|
||||||
|
static void initSkinProgram(ProgramObject& program, SkinLocations& locations);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__Model__) */
|
#endif /* defined(__interface__Model__) */
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
TextureCache::TextureCache() :
|
TextureCache::TextureCache() :
|
||||||
_permutationNormalTextureID(0),
|
_permutationNormalTextureID(0),
|
||||||
_whiteTextureID(0),
|
_whiteTextureID(0),
|
||||||
|
_blueTextureID(0),
|
||||||
_primaryFramebufferObject(NULL),
|
_primaryFramebufferObject(NULL),
|
||||||
_secondaryFramebufferObject(NULL),
|
_secondaryFramebufferObject(NULL),
|
||||||
_tertiaryFramebufferObject(NULL)
|
_tertiaryFramebufferObject(NULL)
|
||||||
|
@ -74,9 +75,11 @@ GLuint TextureCache::getPermutationNormalTextureID() {
|
||||||
return _permutationNormalTextureID;
|
return _permutationNormalTextureID;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadWhiteTexture() {
|
const char OPAQUE_WHITE[] = { 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
const char OPAQUE_WHITE[] = { 0xFF, 0xFF, 0xFF, 0xFF };
|
const char OPAQUE_BLUE[] = { 0x80, 0x80, 0xFF, 0xFF };
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, OPAQUE_WHITE);
|
|
||||||
|
static void loadSingleColorTexture(const char* color) {
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, color);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,12 +87,22 @@ GLuint TextureCache::getWhiteTextureID() {
|
||||||
if (_whiteTextureID == 0) {
|
if (_whiteTextureID == 0) {
|
||||||
glGenTextures(1, &_whiteTextureID);
|
glGenTextures(1, &_whiteTextureID);
|
||||||
glBindTexture(GL_TEXTURE_2D, _whiteTextureID);
|
glBindTexture(GL_TEXTURE_2D, _whiteTextureID);
|
||||||
loadWhiteTexture();
|
loadSingleColorTexture(OPAQUE_WHITE);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
return _whiteTextureID;
|
return _whiteTextureID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLuint TextureCache::getBlueTextureID() {
|
||||||
|
if (_blueTextureID == 0) {
|
||||||
|
glGenTextures(1, &_blueTextureID);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _blueTextureID);
|
||||||
|
loadSingleColorTexture(OPAQUE_BLUE);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
return _blueTextureID;
|
||||||
|
}
|
||||||
|
|
||||||
GLuint TextureCache::getFileTextureID(const QString& filename) {
|
GLuint TextureCache::getFileTextureID(const QString& filename) {
|
||||||
GLuint id = _fileTextureIDs.value(filename);
|
GLuint id = _fileTextureIDs.value(filename);
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
|
@ -219,7 +232,7 @@ NetworkTexture::NetworkTexture(const QUrl& url) : _reply(NULL), _averageColor(1.
|
||||||
|
|
||||||
// default to white
|
// default to white
|
||||||
glBindTexture(GL_TEXTURE_2D, getID());
|
glBindTexture(GL_TEXTURE_2D, getID());
|
||||||
loadWhiteTexture();
|
loadSingleColorTexture(OPAQUE_WHITE);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,9 @@ public:
|
||||||
/// Returns the ID of an opaque white texture (useful for a default).
|
/// Returns the ID of an opaque white texture (useful for a default).
|
||||||
GLuint getWhiteTextureID();
|
GLuint getWhiteTextureID();
|
||||||
|
|
||||||
|
/// Returns the ID of a pale blue texture (useful for a normal map).
|
||||||
|
GLuint getBlueTextureID();
|
||||||
|
|
||||||
/// Returns the ID of a texture containing the contents of the specified file, loading it if necessary.
|
/// Returns the ID of a texture containing the contents of the specified file, loading it if necessary.
|
||||||
GLuint getFileTextureID(const QString& filename);
|
GLuint getFileTextureID(const QString& filename);
|
||||||
|
|
||||||
|
@ -69,6 +72,7 @@ private:
|
||||||
|
|
||||||
GLuint _permutationNormalTextureID;
|
GLuint _permutationNormalTextureID;
|
||||||
GLuint _whiteTextureID;
|
GLuint _whiteTextureID;
|
||||||
|
GLuint _blueTextureID;
|
||||||
|
|
||||||
QHash<QString, GLuint> _fileTextureIDs;
|
QHash<QString, GLuint> _fileTextureIDs;
|
||||||
|
|
||||||
|
|
|
@ -6,48 +6,81 @@
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
|
||||||
#include "RearMirrorTools.h"
|
#include "RearMirrorTools.h"
|
||||||
|
#include "Util.h"
|
||||||
|
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
|
||||||
const int ICON_SIZE = 16;
|
const char SETTINGS_GROUP_NAME[] = "Rear View Tools";
|
||||||
|
const char ZOOM_LEVEL_SETTINGS[] = "ZoomLevel";
|
||||||
|
const int ICON_SIZE = 20;
|
||||||
const int ICON_PADDING = 5;
|
const int ICON_PADDING = 5;
|
||||||
|
const int MID_ICON_PADDING = 70;
|
||||||
|
|
||||||
RearMirrorTools::RearMirrorTools(QGLWidget* parent, QRect& bounds) : _parent(parent), _bounds(bounds), _windowed(false), _fullScreen(false) {
|
RearMirrorTools::RearMirrorTools(QGLWidget* parent, QRect& bounds, QSettings* settings) :
|
||||||
|
_parent(parent),
|
||||||
|
_bounds(bounds),
|
||||||
|
_windowed(false),
|
||||||
|
_fullScreen(false)
|
||||||
|
{
|
||||||
|
_zoomLevel = HEAD,
|
||||||
switchToResourcesParentIfRequired();
|
switchToResourcesParentIfRequired();
|
||||||
_closeTextureId = _parent->bindTexture(QImage("./resources/images/close.png"));
|
_closeTextureId = _parent->bindTexture(QImage("./resources/images/close.png"));
|
||||||
_resetTextureId = _parent->bindTexture(QImage("./resources/images/reset.png"));
|
_resetTextureId = _parent->bindTexture(QImage("./resources/images/reset.png"));
|
||||||
|
_zoomHeadTextureId = _parent->bindTexture(QImage("./resources/images/head.png"));
|
||||||
|
_zoomBodyTextureId = _parent->bindTexture(QImage("./resources/images/body.png"));
|
||||||
|
|
||||||
|
_shrinkIconRect = QRect(ICON_PADDING, ICON_PADDING, ICON_SIZE, ICON_SIZE);
|
||||||
|
_closeIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE);
|
||||||
|
_resetIconRect = QRect(_bounds.width() - ICON_SIZE - ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE);
|
||||||
|
_bodyZoomIconRect = QRect(_bounds.width() - MID_ICON_PADDING - ICON_SIZE, _bounds.bottom() - ICON_PADDING - ICON_SIZE, ICON_SIZE, ICON_SIZE);
|
||||||
|
_headZoomIconRect = QRect(_bounds.left() + MID_ICON_PADDING, _bounds.bottom() - ICON_PADDING - ICON_SIZE, ICON_SIZE, ICON_SIZE);
|
||||||
|
|
||||||
|
settings->beginGroup(SETTINGS_GROUP_NAME);
|
||||||
|
_zoomLevel = loadSetting(settings, ZOOM_LEVEL_SETTINGS, 0) == HEAD ? HEAD : BODY;
|
||||||
|
settings->endGroup();
|
||||||
};
|
};
|
||||||
|
|
||||||
void RearMirrorTools::render(bool fullScreen) {
|
void RearMirrorTools::render(bool fullScreen) {
|
||||||
if (fullScreen) {
|
if (fullScreen) {
|
||||||
_fullScreen = true;
|
_fullScreen = true;
|
||||||
displayIcon(_parent->geometry(), ICON_PADDING, ICON_PADDING, _closeTextureId);
|
displayIcon(_parent->geometry(), _shrinkIconRect, _closeTextureId);
|
||||||
} else {
|
} else {
|
||||||
// render rear view tools if mouse is in the bounds
|
// render rear view tools if mouse is in the bounds
|
||||||
QPoint mousePosition = _parent->mapFromGlobal(QCursor::pos());
|
QPoint mousePosition = _parent->mapFromGlobal(QCursor::pos());
|
||||||
_windowed = _bounds.contains(mousePosition.x(), mousePosition.y());
|
_windowed = _bounds.contains(mousePosition.x(), mousePosition.y());
|
||||||
if (_windowed) {
|
if (_windowed) {
|
||||||
displayIcon(_bounds, _bounds.left() + ICON_PADDING, _bounds.top() + ICON_PADDING, _closeTextureId);
|
displayIcon(_bounds, _closeIconRect, _closeTextureId);
|
||||||
displayIcon(_bounds, _bounds.width() - ICON_SIZE - ICON_PADDING, _bounds.top() + ICON_PADDING, _resetTextureId);
|
displayIcon(_bounds, _resetIconRect, _resetTextureId);
|
||||||
|
displayIcon(_bounds, _headZoomIconRect, _zoomHeadTextureId, _zoomLevel == HEAD);
|
||||||
|
displayIcon(_bounds, _bodyZoomIconRect, _zoomBodyTextureId, _zoomLevel == BODY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RearMirrorTools::mousePressEvent(int x, int y) {
|
bool RearMirrorTools::mousePressEvent(int x, int y) {
|
||||||
if (_windowed) {
|
if (_windowed) {
|
||||||
QRect closeIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE);
|
if (_closeIconRect.contains(x, y)) {
|
||||||
if (closeIconRect.contains(x, y)) {
|
|
||||||
_windowed = false;
|
_windowed = false;
|
||||||
emit closeView();
|
emit closeView();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect resetIconRect = QRect(_bounds.width() - ICON_SIZE - ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE);
|
if (_resetIconRect.contains(x, y)) {
|
||||||
if (resetIconRect.contains(x, y)) {
|
|
||||||
emit resetView();
|
emit resetView();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_headZoomIconRect.contains(x, y)) {
|
||||||
|
_zoomLevel = HEAD;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_bodyZoomIconRect.contains(x, y)) {
|
||||||
|
_zoomLevel = BODY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (_bounds.contains(x, y)) {
|
if (_bounds.contains(x, y)) {
|
||||||
_windowed = false;
|
_windowed = false;
|
||||||
emit restoreView();
|
emit restoreView();
|
||||||
|
@ -56,8 +89,7 @@ bool RearMirrorTools::mousePressEvent(int x, int y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_fullScreen) {
|
if (_fullScreen) {
|
||||||
QRect shrinkIconRect = QRect(ICON_PADDING, ICON_PADDING, ICON_SIZE, ICON_SIZE);
|
if (_shrinkIconRect.contains(x, y)) {
|
||||||
if (shrinkIconRect.contains(x, y)) {
|
|
||||||
_fullScreen = false;
|
_fullScreen = false;
|
||||||
emit shrinkView();
|
emit shrinkView();
|
||||||
return true;
|
return true;
|
||||||
|
@ -66,10 +98,14 @@ bool RearMirrorTools::mousePressEvent(int x, int y) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RearMirrorTools::displayIcon(QRect bounds, int left, int top, GLuint textureId) {
|
void RearMirrorTools::saveSettings(QSettings* settings) {
|
||||||
|
settings->beginGroup(SETTINGS_GROUP_NAME);
|
||||||
|
settings->setValue(ZOOM_LEVEL_SETTINGS, _zoomLevel);
|
||||||
|
settings->endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RearMirrorTools::displayIcon(QRect bounds, QRect iconBounds, GLuint textureId, bool selected) {
|
||||||
|
|
||||||
int twp = ICON_SIZE + top;
|
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
@ -78,23 +114,28 @@ void RearMirrorTools::displayIcon(QRect bounds, int left, int top, GLuint textur
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
glColor3f(1, 1, 1);
|
if (selected) {
|
||||||
|
glColor3f(1, 1, 0);
|
||||||
|
} else {
|
||||||
|
glColor3f(1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
{
|
{
|
||||||
|
glTexCoord2f(0, 0);
|
||||||
|
glVertex2f(iconBounds.left(), iconBounds.bottom());
|
||||||
|
|
||||||
glTexCoord2f(0, 1);
|
glTexCoord2f(0, 1);
|
||||||
glVertex2f(left, top);
|
glVertex2f(iconBounds.left(), iconBounds.top());
|
||||||
|
|
||||||
glTexCoord2f(1, 1);
|
glTexCoord2f(1, 1);
|
||||||
glVertex2f(ICON_SIZE + left, top);
|
glVertex2f(iconBounds.right(), iconBounds.top());
|
||||||
|
|
||||||
glTexCoord2f(1, 0);
|
glTexCoord2f(1, 0);
|
||||||
glVertex2f(ICON_SIZE + left, twp);
|
glVertex2f(iconBounds.right(), iconBounds.bottom());
|
||||||
|
|
||||||
glTexCoord2f(0, 0);
|
|
||||||
glVertex2f(left, twp);
|
|
||||||
}
|
}
|
||||||
glEnd();
|
glEnd();
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
|
@ -12,13 +12,21 @@
|
||||||
#include "InterfaceConfig.h"
|
#include "InterfaceConfig.h"
|
||||||
|
|
||||||
#include <QGLWidget>
|
#include <QGLWidget>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
enum ZoomLevel {
|
||||||
|
HEAD,
|
||||||
|
BODY
|
||||||
|
};
|
||||||
|
|
||||||
class RearMirrorTools : public QObject {
|
class RearMirrorTools : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
RearMirrorTools(QGLWidget* parent, QRect& bounds);
|
RearMirrorTools(QGLWidget* parent, QRect& bounds, QSettings* settings);
|
||||||
void render(bool fullScreen);
|
void render(bool fullScreen);
|
||||||
bool mousePressEvent(int x, int y);
|
bool mousePressEvent(int x, int y);
|
||||||
|
ZoomLevel getZoomLevel() { return _zoomLevel; }
|
||||||
|
void saveSettings(QSettings* settings);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void closeView();
|
void closeView();
|
||||||
|
@ -31,10 +39,20 @@ private:
|
||||||
QRect _bounds;
|
QRect _bounds;
|
||||||
GLuint _closeTextureId;
|
GLuint _closeTextureId;
|
||||||
GLuint _resetTextureId;
|
GLuint _resetTextureId;
|
||||||
|
GLuint _zoomBodyTextureId;
|
||||||
|
GLuint _zoomHeadTextureId;
|
||||||
|
ZoomLevel _zoomLevel;
|
||||||
|
|
||||||
|
QRect _closeIconRect;
|
||||||
|
QRect _resetIconRect;
|
||||||
|
QRect _shrinkIconRect;
|
||||||
|
QRect _headZoomIconRect;
|
||||||
|
QRect _bodyZoomIconRect;
|
||||||
|
|
||||||
bool _windowed;
|
bool _windowed;
|
||||||
bool _fullScreen;
|
bool _fullScreen;
|
||||||
|
|
||||||
void displayIcon(QRect bounds, int left, int top, GLuint textureId);
|
void displayIcon(QRect bounds, QRect iconBounds, GLuint textureId, bool selected = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__RearMirrorTools__) */
|
#endif /* defined(__hifi__RearMirrorTools__) */
|
||||||
|
|
Loading…
Reference in a new issue