2014-11-29 20:07:01 +01:00
|
|
|
/* This file is part of Clementine.
|
|
|
|
Copyright 2004, Enrico Ros <eros.kde@email.it>
|
|
|
|
Copyright 2009, David Sansome <davidsansome@gmail.com>
|
|
|
|
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
|
|
|
Copyright 2014, John Maguire <john.maguire@gmail.com>
|
|
|
|
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Original Author: Enrico Ros <eros.kde@email.it> 2004
|
|
|
|
*/
|
2009-12-24 20:16:07 +01:00
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_QGLWIDGET
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include "glanalyzer3.h"
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <qimage.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
|
|
|
#ifndef HAVE_FABSF
|
2014-02-07 16:34:20 +01:00
|
|
|
inline float fabsf(float f) { return f < 0.f ? -f : f; }
|
2009-12-24 20:16:07 +01:00
|
|
|
#endif
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
class Ball {
|
|
|
|
public:
|
|
|
|
Ball()
|
|
|
|
: x(drand48() - drand48()),
|
|
|
|
y(1 - 2.0 * drand48()),
|
|
|
|
z(drand48()),
|
|
|
|
vx(0.0),
|
|
|
|
vy(0.0),
|
|
|
|
vz(0.0),
|
2014-11-29 20:07:01 +01:00
|
|
|
mass(0.01 + drand48() / 10.0),
|
|
|
|
color((float[3]) { 0.0, drand48()*0.5, 0.7 + drand48() * 0.3 }) {}
|
2014-02-07 16:34:20 +01:00
|
|
|
float x, y, z, vx, vy, vz, mass;
|
|
|
|
float color[3];
|
|
|
|
|
|
|
|
void updatePhysics(float dT) {
|
|
|
|
x += vx * dT; // position
|
|
|
|
y += vy * dT; // position
|
|
|
|
z += vz * dT; // position
|
|
|
|
if (y < -0.8) vy = fabsf(vy);
|
|
|
|
if (y > 0.8) vy = -fabsf(vy);
|
|
|
|
if (z < 0.1) vz = fabsf(vz);
|
|
|
|
if (z > 0.9) vz = -fabsf(vz);
|
|
|
|
vx += ((x > 0) ? 4.94 : -4.94) * dT; // G-force
|
|
|
|
vx *= (1 - 2.9 * dT); // air friction
|
|
|
|
vy *= (1 - 2.9 * dT); // air friction
|
|
|
|
vz *= (1 - 2.9 * dT); // air friction
|
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
};
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
class Paddle {
|
|
|
|
public:
|
2014-11-29 20:07:01 +01:00
|
|
|
explicit Paddle(float xPos)
|
|
|
|
: onLeft(xPos < 0), mass(1.0), X(xPos), x(xPos), vx(0.0) {}
|
2014-02-07 16:34:20 +01:00
|
|
|
|
|
|
|
void updatePhysics(float dT) {
|
|
|
|
x += vx * dT; // posision
|
|
|
|
vx += (1300 * (X - x) / mass) * dT; // elasticity
|
|
|
|
vx *= (1 - 4.0 * dT); // air friction
|
|
|
|
}
|
|
|
|
|
|
|
|
void renderGL() {
|
|
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
|
|
glColor3f(0.0f, 0.1f, 0.3f);
|
|
|
|
glVertex3f(x, -1.0f, 0.0);
|
|
|
|
glVertex3f(x, 1.0f, 0.0);
|
|
|
|
glColor3f(0.1f, 0.2f, 0.6f);
|
|
|
|
glVertex3f(x, -1.0f, 1.0);
|
|
|
|
glVertex3f(x, 1.0f, 1.0);
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
void bounce(Ball* ball) {
|
|
|
|
if (onLeft && ball->x < x) {
|
|
|
|
ball->vx = vx * mass / (mass + ball->mass) + fabsf(ball->vx);
|
|
|
|
ball->vy = (drand48() - drand48()) * 1.8;
|
|
|
|
ball->vz = (drand48() - drand48()) * 0.9;
|
|
|
|
ball->x = x;
|
|
|
|
} else if (!onLeft && ball->x > x) {
|
|
|
|
ball->vx = vx * mass / (mass + ball->mass) - fabsf(ball->vx);
|
|
|
|
ball->vy = (drand48() - drand48()) * 1.8;
|
|
|
|
ball->vz = (drand48() - drand48()) * 0.9;
|
|
|
|
ball->x = x;
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
2014-02-07 16:34:20 +01:00
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void impulse(float strength) {
|
|
|
|
if ((onLeft && strength > vx) || (!onLeft && strength < vx)) vx += strength;
|
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
private:
|
|
|
|
bool onLeft;
|
|
|
|
float mass, X, x, vx;
|
2009-12-24 20:16:07 +01:00
|
|
|
};
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
GLAnalyzer3::GLAnalyzer3(QWidget* parent) : Analyzer::Base3D(parent, 15) {
|
|
|
|
// initialize openGL context before managing GL calls
|
|
|
|
makeCurrent();
|
|
|
|
loadTexture(locate("data", "amarok/data/ball.png"), ballTexture);
|
|
|
|
loadTexture(locate("data", "amarok/data/grid.png"), gridTexture);
|
|
|
|
|
|
|
|
balls.setAutoDelete(true);
|
|
|
|
leftPaddle = new Paddle(-1.0);
|
|
|
|
rightPaddle = new Paddle(1.0);
|
|
|
|
for (int i = 0; i < NUMBER_OF_BALLS; i++) balls.append(new Ball());
|
|
|
|
|
|
|
|
show.colorK = 0.0;
|
|
|
|
show.gridScrollK = 0.0;
|
|
|
|
show.gridEnergyK = 0.0;
|
|
|
|
show.camRot = 0.0;
|
|
|
|
show.camRoll = 0.0;
|
|
|
|
show.peakEnergy = 1.0;
|
|
|
|
frame.silence = true;
|
|
|
|
frame.energy = 0.0;
|
|
|
|
frame.dEnergy = 0.0;
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
GLAnalyzer3::~GLAnalyzer3() {
|
|
|
|
freeTexture(ballTexture);
|
|
|
|
freeTexture(gridTexture);
|
|
|
|
delete leftPaddle;
|
|
|
|
delete rightPaddle;
|
|
|
|
balls.clear();
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GLAnalyzer3::initializeGL() {
|
|
|
|
// Set a smooth shade model
|
|
|
|
glShadeModel(GL_SMOOTH);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// Disable depth test (all is drawn 'z-sorted')
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// Set blending function (Alpha addition)
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// Clear frame with a black background
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GLAnalyzer3::resizeGL(int w, int h) {
|
|
|
|
// Setup screen. We're going to manually do the perspective projection
|
|
|
|
glViewport(0, 0, (GLint)w, (GLint)h);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glFrustum(-0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 4.5f);
|
|
|
|
|
|
|
|
// Get the aspect ratio of the screen to draw 'circular' particles
|
2014-11-29 21:05:59 +01:00
|
|
|
float ratio = static_cast<float>(w) / static_cast<float>(h);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (ratio >= 1.0) {
|
2009-12-24 20:16:07 +01:00
|
|
|
unitX = 0.34 / ratio;
|
|
|
|
unitY = 0.34;
|
2014-02-07 16:34:20 +01:00
|
|
|
} else {
|
2009-12-24 20:16:07 +01:00
|
|
|
unitX = 0.34;
|
|
|
|
unitY = 0.34 * ratio;
|
2014-02-07 16:34:20 +01:00
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// Get current timestamp.
|
|
|
|
timeval tv;
|
|
|
|
gettimeofday(&tv, nullptr);
|
2014-11-29 21:05:59 +01:00
|
|
|
show.timeStamp = static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) / 1000000.0;
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GLAnalyzer3::paused() { analyze(Scope()); }
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GLAnalyzer3::analyze(const Scope& s) {
|
|
|
|
// compute the dTime since the last call
|
|
|
|
timeval tv;
|
|
|
|
gettimeofday(&tv, nullptr);
|
2014-11-29 21:05:59 +01:00
|
|
|
double currentTime = static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) / 1000000.0;
|
2014-02-07 16:34:20 +01:00
|
|
|
show.dT = currentTime - show.timeStamp;
|
|
|
|
show.timeStamp = currentTime;
|
|
|
|
|
|
|
|
// compute energy integrating frame's spectrum
|
|
|
|
if (!s.empty()) {
|
2009-12-24 20:16:07 +01:00
|
|
|
int bands = s.size();
|
2014-02-07 16:34:20 +01:00
|
|
|
float currentEnergy = 0, maxValue = 0;
|
2009-12-24 20:16:07 +01:00
|
|
|
// integrate spectrum -> energy
|
2014-02-07 16:34:20 +01:00
|
|
|
for (int i = 0; i < bands; i++) {
|
|
|
|
float value = s[i];
|
|
|
|
currentEnergy += value;
|
|
|
|
if (value > maxValue) maxValue = value;
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
2014-11-29 21:05:59 +01:00
|
|
|
currentEnergy *= 100.0 / static_cast<float>(bands);
|
2009-12-24 20:16:07 +01:00
|
|
|
// emulate a peak detector: currentEnergy -> peakEnergy (3tau = 30 seconds)
|
2014-02-07 16:34:20 +01:00
|
|
|
show.peakEnergy = 1.0 + (show.peakEnergy - 1.0) * exp(-show.dT / 10.0);
|
|
|
|
if (currentEnergy > show.peakEnergy) show.peakEnergy = currentEnergy;
|
2009-12-24 20:16:07 +01:00
|
|
|
// check for silence
|
|
|
|
frame.silence = currentEnergy < 0.001;
|
|
|
|
// normalize frame energy against peak energy and compute frame stats
|
|
|
|
currentEnergy /= show.peakEnergy;
|
|
|
|
frame.dEnergy = currentEnergy - frame.energy;
|
|
|
|
frame.energy = currentEnergy;
|
2014-11-29 20:07:01 +01:00
|
|
|
} else {
|
2009-12-24 20:16:07 +01:00
|
|
|
frame.silence = true;
|
2014-11-29 20:07:01 +01:00
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
// update the frame
|
|
|
|
updateGL();
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GLAnalyzer3::paintGL() {
|
|
|
|
// limit max dT to 0.05 and update color and scroll constants
|
|
|
|
if (show.dT > 0.05) show.dT = 0.05;
|
|
|
|
show.colorK += show.dT * 0.4;
|
|
|
|
if (show.colorK > 3.0) show.colorK -= 3.0;
|
|
|
|
show.gridScrollK += 0.2 * show.peakEnergy * show.dT;
|
|
|
|
|
|
|
|
// Switch to MODEL matrix and clear screen
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
|
|
|
// Draw scrolling grid
|
|
|
|
if ((show.gridEnergyK > 0.05) || (!frame.silence && frame.dEnergy < -0.3)) {
|
|
|
|
show.gridEnergyK *= exp(-show.dT / 0.1);
|
|
|
|
if (-frame.dEnergy > show.gridEnergyK)
|
|
|
|
show.gridEnergyK = -frame.dEnergy * 2.0;
|
|
|
|
float gridColor[4] = {0.0, 1.0, 0.6, show.gridEnergyK};
|
|
|
|
drawScrollGrid(show.gridScrollK, gridColor);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Roll camera up/down handling the beat
|
|
|
|
show.camRot += show.camRoll * show.dT; // posision
|
|
|
|
show.camRoll -= 400 * show.camRot * show.dT; // elasticity
|
|
|
|
show.camRoll *= (1 - 2.0 * show.dT); // friction
|
|
|
|
if (!frame.silence && frame.dEnergy > 0.4)
|
|
|
|
show.camRoll += show.peakEnergy * 2.0;
|
|
|
|
glRotatef(show.camRoll / 2.0, 1, 0, 0);
|
|
|
|
|
|
|
|
// Translate the drawing plane
|
|
|
|
glTranslatef(0.0f, 0.0f, -1.8f);
|
|
|
|
|
|
|
|
// Draw upper/lower planes and paddles
|
|
|
|
drawHFace(-1.0);
|
|
|
|
drawHFace(1.0);
|
|
|
|
leftPaddle->renderGL();
|
|
|
|
rightPaddle->renderGL();
|
|
|
|
|
|
|
|
// Draw Balls
|
|
|
|
if (ballTexture) {
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, ballTexture);
|
2014-11-29 20:07:01 +01:00
|
|
|
} else {
|
2014-02-07 16:34:20 +01:00
|
|
|
glDisable(GL_TEXTURE_2D);
|
2014-11-29 20:07:01 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
glEnable(GL_BLEND);
|
|
|
|
Ball* ball = balls.first();
|
|
|
|
for (; ball; ball = balls.next()) {
|
|
|
|
float color[3], angle = show.colorK;
|
2009-12-24 20:16:07 +01:00
|
|
|
// Rotate the color based on 'angle' value [0,3)
|
2014-02-07 16:34:20 +01:00
|
|
|
if (angle < 1.0) {
|
|
|
|
color[0] = ball->color[0] * (1 - angle) + ball->color[1] * angle;
|
|
|
|
color[1] = ball->color[1] * (1 - angle) + ball->color[2] * angle;
|
|
|
|
color[2] = ball->color[2] * (1 - angle) + ball->color[0] * angle;
|
|
|
|
} else if (angle < 2.0) {
|
|
|
|
angle -= 1.0;
|
|
|
|
color[0] = ball->color[1] * (1 - angle) + ball->color[2] * angle;
|
|
|
|
color[1] = ball->color[2] * (1 - angle) + ball->color[0] * angle;
|
|
|
|
color[2] = ball->color[0] * (1 - angle) + ball->color[1] * angle;
|
|
|
|
} else {
|
|
|
|
angle -= 2.0;
|
|
|
|
color[0] = ball->color[2] * (1 - angle) + ball->color[0] * angle;
|
|
|
|
color[1] = ball->color[0] * (1 - angle) + ball->color[1] * angle;
|
|
|
|
color[2] = ball->color[1] * (1 - angle) + ball->color[2] * angle;
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
// Draw the dot and update its physics also checking at bounces
|
2014-02-07 16:34:20 +01:00
|
|
|
glColor3fv(color);
|
|
|
|
drawDot3s(ball->x, ball->y, ball->z, 1.0);
|
|
|
|
ball->updatePhysics(show.dT);
|
|
|
|
if (ball->x < 0)
|
|
|
|
leftPaddle->bounce(ball);
|
2009-12-24 20:16:07 +01:00
|
|
|
else
|
2014-02-07 16:34:20 +01:00
|
|
|
rightPaddle->bounce(ball);
|
|
|
|
}
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
// Update physics of paddles
|
|
|
|
leftPaddle->updatePhysics(show.dT);
|
|
|
|
rightPaddle->updatePhysics(show.dT);
|
|
|
|
if (!frame.silence) {
|
|
|
|
leftPaddle->impulse(frame.energy * 3.0 + frame.dEnergy * 6.0);
|
|
|
|
rightPaddle->impulse(-frame.energy * 3.0 - frame.dEnergy * 6.0);
|
|
|
|
}
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GLAnalyzer3::drawDot3s(float x, float y, float z, float size) {
|
|
|
|
// Circular XY dot drawing functions
|
|
|
|
float sizeX = size * unitX, sizeY = size * unitY, pXm = x - sizeX,
|
|
|
|
pXM = x + sizeX, pYm = y - sizeY, pYM = y + sizeY;
|
|
|
|
// Draw the Dot
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glTexCoord2f(0, 0); // Bottom Left
|
|
|
|
glVertex3f(pXm, pYm, z);
|
|
|
|
glTexCoord2f(0, 1); // Top Left
|
|
|
|
glVertex3f(pXm, pYM, z);
|
|
|
|
glTexCoord2f(1, 1); // Top Right
|
|
|
|
glVertex3f(pXM, pYM, z);
|
|
|
|
glTexCoord2f(1, 0); // Bottom Right
|
|
|
|
glVertex3f(pXM, pYm, z);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
// Shadow XZ drawing functions
|
|
|
|
float sizeZ = size / 10.0, pZm = z - sizeZ, pZM = z + sizeZ, currentColor[4];
|
|
|
|
glGetFloatv(GL_CURRENT_COLOR, currentColor);
|
|
|
|
float alpha = currentColor[3], topSide = (y + 1) / 4,
|
|
|
|
bottomSide = (1 - y) / 4;
|
|
|
|
// Draw the top shadow
|
|
|
|
currentColor[3] = topSide * topSide * alpha;
|
|
|
|
glColor4fv(currentColor);
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glTexCoord2f(0, 0); // Bottom Left
|
|
|
|
glVertex3f(pXm, 1, pZm);
|
|
|
|
glTexCoord2f(0, 1); // Top Left
|
|
|
|
glVertex3f(pXm, 1, pZM);
|
|
|
|
glTexCoord2f(1, 1); // Top Right
|
|
|
|
glVertex3f(pXM, 1, pZM);
|
|
|
|
glTexCoord2f(1, 0); // Bottom Right
|
|
|
|
glVertex3f(pXM, 1, pZm);
|
|
|
|
glEnd();
|
|
|
|
// Draw the bottom shadow
|
|
|
|
currentColor[3] = bottomSide * bottomSide * alpha;
|
|
|
|
glColor4fv(currentColor);
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glTexCoord2f(0, 0); // Bottom Left
|
|
|
|
glVertex3f(pXm, -1, pZm);
|
|
|
|
glTexCoord2f(0, 1); // Top Left
|
|
|
|
glVertex3f(pXm, -1, pZM);
|
|
|
|
glTexCoord2f(1, 1); // Top Right
|
|
|
|
glVertex3f(pXM, -1, pZM);
|
|
|
|
glTexCoord2f(1, 0); // Bottom Right
|
|
|
|
glVertex3f(pXM, -1, pZm);
|
|
|
|
glEnd();
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GLAnalyzer3::drawHFace(float y) {
|
|
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
|
|
glColor3f(0.0f, 0.1f, 0.2f);
|
|
|
|
glVertex3f(-1.0f, y, 0.0);
|
|
|
|
glVertex3f(1.0f, y, 0.0);
|
|
|
|
glColor3f(0.1f, 0.6f, 0.5f);
|
|
|
|
glVertex3f(-1.0f, y, 2.0);
|
|
|
|
glVertex3f(1.0f, y, 2.0);
|
|
|
|
glEnd();
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GLAnalyzer3::drawScrollGrid(float scroll, float color[4]) {
|
|
|
|
if (!gridTexture) return;
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
|
|
|
glTranslatef(0.0, -scroll, 0.0);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
float backColor[4] = {1.0, 1.0, 1.0, 0.0};
|
|
|
|
for (int i = 0; i < 3; i++) backColor[i] = color[i];
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, gridTexture);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
|
|
glColor4fv(color); // top face
|
|
|
|
glTexCoord2f(0.0f, 1.0f);
|
|
|
|
glVertex3f(-1.0f, 1.0f, -1.0f);
|
|
|
|
glTexCoord2f(1.0f, 1.0f);
|
|
|
|
glVertex3f(1.0f, 1.0f, -1.0f);
|
|
|
|
glColor4fv(backColor); // central points
|
|
|
|
glTexCoord2f(0.0f, 0.0f);
|
|
|
|
glVertex3f(-1.0f, 0.0f, -3.0f);
|
|
|
|
glTexCoord2f(1.0f, 0.0f);
|
|
|
|
glVertex3f(1.0f, 0.0f, -3.0f);
|
|
|
|
glColor4fv(color); // bottom face
|
|
|
|
glTexCoord2f(0.0f, 1.0f);
|
|
|
|
glVertex3f(-1.0f, -1.0f, -1.0f);
|
|
|
|
glTexCoord2f(1.0f, 1.0f);
|
|
|
|
glVertex3f(1.0f, -1.0f, -1.0f);
|
|
|
|
glEnd();
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bool GLAnalyzer3::loadTexture(QString fileName, GLuint& textureID) {
|
|
|
|
// reset texture ID to the default EMPTY value
|
|
|
|
textureID = 0;
|
|
|
|
|
|
|
|
// load image
|
|
|
|
QImage tmp;
|
|
|
|
if (!tmp.load(fileName)) return false;
|
|
|
|
|
|
|
|
// convert it to suitable format (flipped RGBA)
|
|
|
|
QImage texture = QGLWidget::convertToGLFormat(tmp);
|
|
|
|
if (texture.isNull()) return false;
|
|
|
|
|
|
|
|
// get texture number and bind loaded image to that texture
|
|
|
|
glGenTextures(1, &textureID);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, 4, texture.width(), texture.height(), 0,
|
|
|
|
GL_RGBA, GL_UNSIGNED_BYTE, texture.bits());
|
|
|
|
return true;
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GLAnalyzer3::freeTexture(GLuint& textureID) {
|
|
|
|
if (textureID > 0) glDeleteTextures(1, &textureID);
|
|
|
|
textureID = 0;
|
2009-12-24 20:16:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|