You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeartwork/kscreensaver/kdesavers/Euphoria.cpp

1085 lines
27 KiB

//============================================================================
//
// Terence Welsh Screensaver - Euphoria
// http://www.reallyslick.com/
//
// Ported to KDE by Karl Robillard
//
/*
* Copyright (C) 2002 Terence M. Welsh
*
* Euphoria is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Euphoria 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
//============================================================================
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <qtimer.h>
#include "Euphoria.h"
#include "Euphoria.moc"
#include "EuphoriaTexture.h"
#define NUMCONSTS 9
#define PIx2 6.28318530718f
//----------------------------------------------------------------------------
#include <sys/time.h>
#include <unistd.h>
// Returns the system time, in seconds.
double timeGetTime()
{
struct timeval tp;
gettimeofday( &tp, 0 );
return (double)tp.tv_sec + (double)tp.tv_usec / 1000000;
}
//----------------------------------------------------------------------------
class rsVec
{
public:
float v[3];
rsVec() {}
rsVec(float xx, float yy, float zz);
void set(float xx, float yy, float zz);
float normalize();
float dot(rsVec);
void cross(rsVec, rsVec);
float & operator [] (int i) {return v[i];}
const float & operator [] (int i) const {return v[i];}
rsVec & operator = (const rsVec &vec)
{v[0]=vec[0];v[1]=vec[1];v[2]=vec[2];return *this;};
rsVec operator + (const rsVec &vec)
{return(rsVec(v[0]+vec[0], v[1]+vec[1], v[2]+vec[2]));};
rsVec operator - (const rsVec &vec)
{return(rsVec(v[0]-vec[0], v[1]-vec[1], v[2]-vec[2]));};
rsVec operator * (const float &mul)
{return(rsVec(v[0]*mul, v[1]*mul, v[2]*mul));};
rsVec operator / (const float &div)
{float rec = 1.0f/div; return(rsVec(v[0]*rec, v[1]*rec, v[2]*rec));};
rsVec & operator += (const rsVec &vec)
{v[0]+=vec[0];v[1]+=vec[1];v[2]+=vec[2];return *this;};
rsVec & operator -= (const rsVec &vec)
{v[0]-=vec[0];v[1]-=vec[1];v[2]-=vec[2];return *this;};
rsVec & operator *= (const rsVec &vec)
{v[0]*=vec[0];v[1]*=vec[1];v[2]*=vec[2];return *this;};
rsVec & operator *= (const float &mul)
{v[0]*=mul;v[1]*=mul;v[2]*=mul;return *this;};
};
rsVec::rsVec(float xx, float yy, float zz){
v[0] = xx;
v[1] = yy;
v[2] = zz;
}
void rsVec::set(float xx, float yy, float zz){
v[0] = xx;
v[1] = yy;
v[2] = zz;
}
float rsVec::normalize(){
float length = float(sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
if(length == 0.0f){
v[1] = 1.0f;
return(0.0f);
}
float reciprocal = 1.0f / length;
v[0] *= reciprocal;
v[1] *= reciprocal;
v[2] *= reciprocal;
// Really freakin' stupid compiler bug fix for VC++ 5.0
/*v[0] /= length;
v[1] /= length;
v[2] /= length;*/
return(length);
}
float rsVec::dot(rsVec vec1){
return(v[0] * vec1[0] + v[1] * vec1[1] + v[2] * vec1[2]);
}
void rsVec::cross(rsVec vec1, rsVec vec2){
v[0] = vec1[1] * vec2[2] - vec2[1] * vec1[2];
v[1] = vec1[2] * vec2[0] - vec2[2] * vec1[0];
v[2] = vec1[0] * vec2[1] - vec2[0] * vec1[1];
}
//----------------------------------------------------------------------------
void hsl2rgb(float h, float s, float l, float &r, float &g, float &b)
{
// hue influence
if(h < 0.166667){ // full red, some green
r = 1.0;
g = h * 6.0f;
b = 0.0;
}
else {
if(h < 0.5){ // full green
g = 1.0;
if(h < 0.333333){ // some red
r = 1.0f - ((h - 0.166667f) * 6.0f);
b = 0.0;
}
else{ // some blue
b = (h - 0.333333f) * 6.0f;
r = 0.0;
}
}
else{
if(h < 0.833333){ // full blue
b = 1.0;
if(h < 0.666667){ // some green
g = 1.0f - ((h - 0.5f) * 6.0f);
r = 0.0;
}
else{ // some red
r = (h - 0.666667f) * 6.0f;
g = 0.0;
}
}
else{ // full red, some blue
r = 1.0;
b = 1.0f - ((h - 0.833333f) * 6.0f);
g = 0.0;
}
}
}
// saturation influence
r = 1.0f - (s * (1.0f - r));
g = 1.0f - (s * (1.0f - g));
b = 1.0f - (s * (1.0f - b));
// luminosity influence
r *= l;
g *= l;
b *= l;
}
// Useful random number macros
// Don't forget to initialize with srand()
inline int myRandi(int x){
return((rand() * x) / RAND_MAX);
}
inline float myRandf(float x){
return(float(rand() * x) / float(RAND_MAX));
}
//----------------------------------------------------------------------------
// Context pointer to allow many instances.
static EuphoriaWidget* _ec = 0;
class wisp
{
public:
wisp();
~wisp();
void update();
void draw();
void drawAsBackground();
int density;
float*** vertices;
float c[NUMCONSTS]; // constants
float cr[NUMCONSTS]; // constants' radial position
float cv[NUMCONSTS]; // constants' change velocities
float hsl[3];
float rgb[3];
float hueSpeed;
float saturationSpeed;
};
wisp::wisp()
{
int i, j;
float recHalfDens = 1.0f / (float(_ec->dDensity) * 0.5f);
density = _ec->dDensity;
vertices = new float**[density+1];
for(i=0; i<=density; i++)
{
vertices[i] = new float*[density+1];
for(j=0; j<=density; j++)
{
vertices[i][j] = new float[7];
vertices[i][j][3] = float(i) * recHalfDens - 1.0f; // x position on grid
vertices[i][j][4] = float(j) * recHalfDens - 1.0f; // y position on grid
// distance squared from the center
vertices[i][j][5] = vertices[i][j][3] * vertices[i][j][3]
+ vertices[i][j][4] * vertices[i][j][4];
vertices[i][j][6] = 0.0f; // intensity
}
}
// initialize constants
for(i=0; i<NUMCONSTS; i++)
{
c[i] = myRandf(2.0f) - 1.0f;
cr[i] = myRandf(PIx2);
cv[i] = myRandf(_ec->dSpeed * 0.03f) + (_ec->dSpeed * 0.001f);
}
// pick color
hsl[0] = myRandf(1.0f);
hsl[1] = 0.1f + myRandf(0.9f);
hsl[2] = 1.0f;
hueSpeed = myRandf(0.1f) - 0.05f;
saturationSpeed = myRandf(0.04f) + 0.001f;
}
wisp::~wisp()
{
int i, j;
for(i=0; i<=density; i++)
{
for(j=0; j<=density; j++)
{
delete[] vertices[i][j];
}
delete[] vertices[i];
}
delete[] vertices;
}
void wisp::update()
{
int i, j;
rsVec up, right, crossvec;
// visibility constants
static float viscon1 = float(_ec->dVisibility) * 0.01f;
static float viscon2 = 1.0f / viscon1;
// update constants
for(i=0; i<NUMCONSTS; i++){
cr[i] += cv[i] * _ec->elapsedTime;
if(cr[i] > PIx2)
cr[i] -= PIx2;
c[i] = cos(cr[i]);
}
// update vertex positions
for(i=0; i<=density; i++){
for(j=0; j<=density; j++){
vertices[i][j][0] = vertices[i][j][3] * vertices[i][j][3] * vertices[i][j][4] * c[0]
+ vertices[i][j][5] * c[1] + 0.5f * c[2];
vertices[i][j][1] = vertices[i][j][4] * vertices[i][j][4] * vertices[i][j][5] * c[3]
+ vertices[i][j][3] * c[4] + 0.5f * c[5];
vertices[i][j][2] = vertices[i][j][5] * vertices[i][j][5] * vertices[i][j][3] * c[6]
+ vertices[i][j][4] * c[7] + c[8];
}
}
// update vertex normals for most of mesh
for(i=1; i<density; i++){
for(j=1; j<density; j++){
up.set(vertices[i][j+1][0] - vertices[i][j-1][0],
vertices[i][j+1][1] - vertices[i][j-1][1],
vertices[i][j+1][2] - vertices[i][j-1][2]);
right.set(vertices[i+1][j][0] - vertices[i-1][j][0],
vertices[i+1][j][1] - vertices[i-1][j][1],
vertices[i+1][j][2] - vertices[i-1][j][2]);
up.normalize();
right.normalize();
crossvec.cross(right, up);
// Use depth component of normal to compute intensity
// This way only edges of wisp are bright
if(crossvec[2] < 0.0f)
crossvec[2] *= -1.0f;
vertices[i][j][6] = viscon2 * (viscon1 - crossvec[2]);
if(vertices[i][j][6] > 1.0f)
vertices[i][j][6] = 1.0f;
if(vertices[i][j][6] < 0.0f)
vertices[i][j][6] = 0.0f;
}
}
// update color
hsl[0] += hueSpeed * _ec->elapsedTime;
if(hsl[0] < 0.0f)
hsl[0] += 1.0f;
if(hsl[0] > 1.0f)
hsl[0] -= 1.0f;
hsl[1] += saturationSpeed * _ec->elapsedTime;
if(hsl[1] <= 0.1f){
hsl[1] = 0.1f;
saturationSpeed = -saturationSpeed;
}
if(hsl[1] >= 1.0f){
hsl[1] = 1.0f;
saturationSpeed = -saturationSpeed;
}
hsl2rgb(hsl[0], hsl[1], hsl[2], rgb[0], rgb[1], rgb[2]);
}
void wisp::draw()
{
int i, j;
glPushMatrix();
if(_ec->dWireframe)
{
for(i=1; i<density; i++){
glBegin(GL_LINE_STRIP);
for(j=0; j<=density; j++){
glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
glVertex3fv(vertices[i][j]);
}
glEnd();
}
for(j=1; j<density; j++){
glBegin(GL_LINE_STRIP);
for(i=0; i<=density; i++){
glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
glVertex3fv(vertices[i][j]);
}
glEnd();
}
}
else
{
for(i=0; i<density; i++){
glBegin(GL_TRIANGLE_STRIP);
for(j=0; j<=density; j++){
glColor3f(rgb[0] + vertices[i+1][j][6] - 1.0f, rgb[1] + vertices[i+1][j][6] - 1.0f, rgb[2] + vertices[i+1][j][6] - 1.0f);
glTexCoord2d(vertices[i+1][j][3] - vertices[i+1][j][0], vertices[i+1][j][4] - vertices[i+1][j][1]);
glVertex3fv(vertices[i+1][j]);
glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
glVertex3fv(vertices[i][j]);
}
glEnd();
}
}
glPopMatrix();
}
void wisp::drawAsBackground()
{
int i, j;
glPushMatrix();
glTranslatef(c[0] * 0.2f, c[1] * 0.2f, 1.6f);
if(_ec->dWireframe)
{
for(i=1; i<density; i++){
glBegin(GL_LINE_STRIP);
for(j=0; j<=density; j++){
glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
glVertex3f(vertices[i][j][3], vertices[i][j][4], vertices[i][j][6]);
}
glEnd();
}
for(j=1; j<density; j++){
glBegin(GL_LINE_STRIP);
for(i=0; i<=density; i++){
glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
glVertex3f(vertices[i][j][3], vertices[i][j][4], vertices[i][j][6]);
}
glEnd();
}
}
else
{
for(i=0; i<density; i++){
glBegin(GL_TRIANGLE_STRIP);
for(j=0; j<=density; j++){
glColor3f(rgb[0] + vertices[i+1][j][6] - 1.0f, rgb[1] + vertices[i+1][j][6] - 1.0f, rgb[2] + vertices[i+1][j][6] - 1.0f);
glTexCoord2d(vertices[i+1][j][3] - vertices[i+1][j][0], vertices[i+1][j][4] - vertices[i+1][j][1]);
glVertex3f(vertices[i+1][j][3], vertices[i+1][j][4], vertices[i+1][j][6]);
glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
glVertex3f(vertices[i][j][3], vertices[i][j][4], vertices[i][j][6]);
}
glEnd();
}
}
glPopMatrix();
}
//----------------------------------------------------------------------------
EuphoriaWidget::EuphoriaWidget( QWidget* parent, const char* name )
: QGLWidget(parent, name), texName(0), _wisps(0), _backwisps(0),
feedbackmap(0), feedbacktex(0)
{
setDefaults( Regular );
_frameTime = 1000 / 60;
_timer = new QTimer( this );
connect( _timer, SIGNAL(timeout()), this, SLOT(nextFrame()) );
}
EuphoriaWidget::~EuphoriaWidget()
{
// Free memory
if ( texName )
glDeleteTextures( 1, &texName );
if ( feedbacktex )
glDeleteTextures( 1, &feedbacktex );
delete[] _wisps;
delete[] _backwisps;
}
void EuphoriaWidget::paintGL()
{
int i;
static double lastTime = timeGetTime();
// update time
elapsedTime = timeGetTime() - lastTime;
lastTime += elapsedTime;
_ec = this;
// Update wisps
for(i=0; i<dWisps; i++)
_wisps[i].update();
for(i=0; i<dBackground; i++)
_backwisps[i].update();
if(dFeedback)
{
float feedbackIntensity = float(dFeedback) / 101.0f;
// update feedback variables
for(i=0; i<4; i++)
{
fr[i] += elapsedTime * fv[i];
if(fr[i] > PIx2)
fr[i] -= PIx2;
}
f[0] = 30.0f * cos(fr[0]);
f[1] = 0.2f * cos(fr[1]);
f[2] = 0.2f * cos(fr[2]);
f[3] = 0.8f * cos(fr[3]);
for(i=0; i<3; i++)
{
lr[i] += elapsedTime * lv[i];
if(lr[i] > PIx2)
lr[i] -= PIx2;
l[i] = cos(lr[i]);
l[i] = l[i] * l[i];
}
// Create drawing area for feedback texture
glViewport(0, 0, feedbacktexsize, feedbacktexsize);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, aspectRatio, 0.01f, 20.0f);
glMatrixMode(GL_MODELVIEW);
// Draw
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(feedbackIntensity, feedbackIntensity, feedbackIntensity);
glBindTexture(GL_TEXTURE_2D, feedbacktex);
glPushMatrix();
glTranslatef(f[1] * l[1], f[2] * l[1], f[3] * l[2]);
glRotatef(f[0] * l[0], 0, 0, 1);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(-0.5f, -0.5f);
glVertex3f(-aspectRatio*2.0f, -2.0f, 1.25f);
glTexCoord2f(1.5f, -0.5f);
glVertex3f(aspectRatio*2.0f, -2.0f, 1.25f);
glTexCoord2f(-0.5f, 1.5f);
glVertex3f(-aspectRatio*2.0f, 2.0f, 1.25f);
glTexCoord2f(1.5f, 1.5f);
glVertex3f(aspectRatio*2.0f, 2.0f, 1.25f);
glEnd();
glPopMatrix();
glBindTexture(GL_TEXTURE_2D, texName);
for(i=0; i<dBackground; i++)
_backwisps[i].drawAsBackground();
for(i=0; i<dWisps; i++)
_wisps[i].draw();
// readback feedback texture
glReadBuffer(GL_BACK);
glPixelStorei(GL_UNPACK_ROW_LENGTH, feedbacktexsize);
glBindTexture(GL_TEXTURE_2D, feedbacktex);
glReadPixels(0, 0, feedbacktexsize, feedbacktexsize, GL_RGB, GL_UNSIGNED_BYTE, feedbackmap);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, feedbacktexsize, feedbacktexsize, GL_RGB, GL_UNSIGNED_BYTE, feedbackmap);
// create regular drawing area
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(20.0, aspectRatio, 0.01f, 20.0f);
glMatrixMode(GL_MODELVIEW);
// Draw again
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(feedbackIntensity, feedbackIntensity, feedbackIntensity);
glPushMatrix();
glTranslatef(f[1] * l[1], f[2] * l[1], f[3] * l[2]);
glRotatef(f[0] * l[0], 0, 0, 1);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(-0.5f, -0.5f);
glVertex3f(-aspectRatio*2.0f, -2.0f, 1.25f);
glTexCoord2f(1.5f, -0.5f);
glVertex3f(aspectRatio*2.0f, -2.0f, 1.25f);
glTexCoord2f(-0.5f, 1.5f);
glVertex3f(-aspectRatio*2.0f, 2.0f, 1.25f);
glTexCoord2f(1.5f, 1.5f);
glVertex3f(aspectRatio*2.0f, 2.0f, 1.25f);
glEnd();
glPopMatrix();
glBindTexture(GL_TEXTURE_2D, texName);
}
else
glClear(GL_COLOR_BUFFER_BIT);
//
for(i=0; i<dBackground; i++)
_backwisps[i].drawAsBackground();
for(i=0; i<dWisps; i++)
_wisps[i].draw();
glFlush();
}
void EuphoriaWidget::resizeGL( int w, int h )
{
glViewport(0, 0, w, h );
viewport[0] = 0;
viewport[1] = 0;
viewport[2] = w;
viewport[3] = h;
aspectRatio = (float) w / (float) h;
// setup regular drawing area just in case feedback isn't used
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(20.0, aspectRatio, 0.01, 20);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -5.0);
}
// Window initialization
void EuphoriaWidget::initializeGL()
{
// Need to call this to setup viewport[] parameters used in
// the next updateParameters() call
resizeGL( width(), height() );
updateParameters();
_timer->start( _frameTime, true );
}
#ifdef UNIT_TEST
void EuphoriaWidget::keyPressEvent( QKeyEvent* e )
{
if( e->key() == Qt::Key_0 ) { setDefaults( 0 ); updateParameters(); }
if( e->key() == Qt::Key_1 ) { setDefaults( 1 ); updateParameters(); }
if( e->key() == Qt::Key_2 ) { setDefaults( 2 ); updateParameters(); }
if( e->key() == Qt::Key_3 ) { setDefaults( 3 ); updateParameters(); }
if( e->key() == Qt::Key_4 ) { setDefaults( 4 ); updateParameters(); }
if( e->key() == Qt::Key_5 ) { setDefaults( 5 ); updateParameters(); }
if( e->key() == Qt::Key_6 ) { setDefaults( 6 ); updateParameters(); }
if( e->key() == Qt::Key_7 ) { setDefaults( 7 ); updateParameters(); }
if( e->key() == Qt::Key_8 ) { setDefaults( 8 ); updateParameters(); }
}
#endif
void EuphoriaWidget::nextFrame()
{
updateGL();
_timer->start( _frameTime, true );
}
void EuphoriaWidget::updateParameters()
{
srand((unsigned)time(NULL));
rand(); rand(); rand(); rand(); rand();
elapsedTime = 0.0f;
fr[0] = 0.0f;
fr[1] = 0.0f;
fr[2] = 0.0f;
fr[3] = 0.0f;
lr[0] = 0.0f;
lr[1] = 0.0f;
lr[2] = 0.0f;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glLineWidth(2.0f);
// Commented out because smooth lines and textures don't mix on my TNT.
// It's like it rendering in software mode
glEnable(GL_LINE_SMOOTH);
//glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
if(dTexture)
{
int whichtex = dTexture;
if(whichtex == 4) // random texture
whichtex = myRandi(3) + 1;
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// Initialize texture
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
switch(whichtex){
case 1:
gluBuild2DMipmaps(GL_TEXTURE_2D, 1, TEXSIZE, TEXSIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, plasmamap);
break;
case 2:
gluBuild2DMipmaps(GL_TEXTURE_2D, 1, TEXSIZE, TEXSIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, stringymap);
break;
case 3:
gluBuild2DMipmaps(GL_TEXTURE_2D, 1, TEXSIZE, TEXSIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, linesmap);
}
} else if ( texName ) {
glDeleteTextures( 1, &texName );
texName = 0;
}
if(dFeedback)
{
feedbacktexsize = int(pow(2.0, dFeedbacksize));
while(feedbacktexsize > viewport[2] || feedbacktexsize > viewport[3]){
dFeedbacksize -= 1;
feedbacktexsize = int(pow(2.0, dFeedbacksize));
}
// feedback texture setup
glEnable(GL_TEXTURE_2D);
delete [] feedbackmap;
feedbackmap = new unsigned char[feedbacktexsize*feedbacktexsize*3];
glGenTextures(1, &feedbacktex);
glBindTexture(GL_TEXTURE_2D, feedbacktex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, 3, feedbacktexsize, feedbacktexsize, 0, GL_RGB, GL_UNSIGNED_BYTE, feedbackmap);
// feedback velocity variable setup
fv[0] = float(dFeedbackspeed) * (myRandf(0.025f) + 0.025f);
fv[1] = float(dFeedbackspeed) * (myRandf(0.05f) + 0.05f);
fv[2] = float(dFeedbackspeed) * (myRandf(0.05f) + 0.05f);
fv[3] = float(dFeedbackspeed) * (myRandf(0.1f) + 0.1f);
lv[0] = float(dFeedbackspeed) * (myRandf(0.0025f) + 0.0025f);
lv[1] = float(dFeedbackspeed) * (myRandf(0.0025f) + 0.0025f);
lv[2] = float(dFeedbackspeed) * (myRandf(0.0025f) + 0.0025f);
} else if ( feedbacktex ) {
glDeleteTextures( 1, &feedbacktex );
feedbacktex = 0;
}
// Initialize wisps
_ec = this;
delete[] _wisps;
delete[] _backwisps;
_wisps = new wisp[dWisps];
_backwisps = new wisp[dBackground];
}
/**
May be called at any time - makes no OpenGL calls.
*/
void EuphoriaWidget::setDefaults(int which)
{
switch(which)
{
case Grid:
dWisps = 4;
dBackground = 1;
dDensity = 25;
dVisibility = 70;
dSpeed = 15;
dFeedback = 0;
dFeedbackspeed = 1;
dFeedbacksize = 8;
dWireframe = 1;
dTexture = 0;
break;
case Cubism:
dWisps = 15;
dBackground = 0;
dDensity = 4;
dVisibility = 15;
dSpeed = 10;
dFeedback = 0;
dFeedbackspeed = 1;
dFeedbacksize = 8;
dWireframe = 0;
dTexture = 0;
break;
case BadMath:
dWisps = 2;
dBackground = 2;
dDensity = 20;
dVisibility = 40;
dSpeed = 30;
dFeedback = 40;
dFeedbackspeed = 5;
dFeedbacksize = 8;
dWireframe = 1;
dTexture = 2;
break;
case MTheory:
dWisps = 3;
dBackground = 0;
dDensity = 25;
dVisibility = 15;
dSpeed = 20;
dFeedback = 40;
dFeedbackspeed = 20;
dFeedbacksize = 8;
dWireframe = 0;
dTexture = 0;
break;
case UHFTEM:
dWisps = 0;
dBackground = 3;
dDensity = 35;
dVisibility = 5;
dSpeed = 50;
dFeedback = 0;
dFeedbackspeed = 1;
dFeedbacksize = 8;
dWireframe = 0;
dTexture = 0;
break;
case Nowhere:
dWisps = 0;
dBackground = 3;
dDensity = 30;
dVisibility = 40;
dSpeed = 20;
dFeedback = 80;
dFeedbackspeed = 10;
dFeedbacksize = 8;
dWireframe = 1;
dTexture = 3;
break;
case Echo:
dWisps = 3;
dBackground = 0;
dDensity = 25;
dVisibility = 30;
dSpeed = 20;
dFeedback = 85;
dFeedbackspeed = 30;
dFeedbacksize = 8;
dWireframe = 0;
dTexture = 1;
break;
case Kaleidoscope:
dWisps = 3;
dBackground = 0;
dDensity = 25;
dVisibility = 40;
dSpeed = 15;
dFeedback = 90;
dFeedbackspeed = 3;
dFeedbacksize = 8;
dWireframe = 0;
dTexture = 0;
break;
case Regular:
default:
dWisps = 5;
dBackground = 0;
dDensity = 25;
dVisibility = 35;
dSpeed = 15;
dFeedback = 0;
dFeedbackspeed = 1;
dFeedbacksize = 8;
dWireframe = 0;
dTexture = 2;
break;
}
}
//----------------------------------------------------------------------------
#ifndef UNIT_TEST
#include <klocale.h>
#include <kglobal.h>
#include <kconfig.h>
// libkscreensaver interface
extern "C"
{
KDE_EXPORT const char* kss_applicationName = "keuphoria.kss";
KDE_EXPORT const char* kss_description = I18N_NOOP( "Euphoria" );
KDE_EXPORT const char* kss_version = "1.0";
KDE_EXPORT KScreenSaver* kss_create( WId id )
{
return new KEuphoriaScreenSaver( id );
}
KDE_EXPORT QDialog* kss_setup()
{
return new KEuphoriaSetup;
}
}
//----------------------------------------------------------------------------
KEuphoriaScreenSaver::KEuphoriaScreenSaver( WId id ) : KScreenSaver( id )
{
_effect = new EuphoriaWidget;
readSettings();
embed( _effect );
_effect->show();
}
KEuphoriaScreenSaver::~KEuphoriaScreenSaver()
{
}
static int filterRandom( int n )
{
if( (n < 0) || (n >= EuphoriaWidget::DefaultModes) )
{
srand((unsigned)time(NULL));
n = rand() % EuphoriaWidget::DefaultModes;
}
return n;
}
void KEuphoriaScreenSaver::readSettings()
{
KConfig* config = KGlobal::config();
config->setGroup("Settings");
_mode = config->readNumEntry( "Mode", EuphoriaWidget::Regular );
_effect->setDefaults( filterRandom(_mode) );
}
/**
Any invalid mode will select one at random.
*/
void KEuphoriaScreenSaver::setMode( int id )
{
_mode = id;
_effect->setDefaults( filterRandom(id) );
_effect->updateParameters();
}
//----------------------------------------------------------------------------
#include <qlayout.h>
#include <qlabel.h>
#include <qcombobox.h>
#include <kmessagebox.h>
static const char* defaultText[] =
{
I18N_NOOP( "Regular" ),
I18N_NOOP( "Grid" ),
I18N_NOOP( "Cubism" ),
I18N_NOOP( "Bad Math" ),
I18N_NOOP( "M-Theory" ),
I18N_NOOP( "UHFTEM" ), //"ultra high frequency tunneling electron microscope",
I18N_NOOP( "Nowhere" ),
I18N_NOOP( "Echo" ),
I18N_NOOP( "Kaleidoscope" ),
I18N_NOOP( "(Random)" ),
0
};
KEuphoriaSetup::KEuphoriaSetup( QWidget* parent, const char* name )
: KDialogBase( parent, name, true, i18n("Setup Euphoria Screen Saver"),
Ok|Cancel|Help, Ok, true )
{
setButtonText( Help, i18n( "A&bout" ) );
QWidget *main = makeMainWidget();
QHBoxLayout* top = new QHBoxLayout(main, 0, spacingHint());
QVBoxLayout* leftCol = new QVBoxLayout;
top->addLayout( leftCol );
QLabel* label = new QLabel( i18n("Mode:"), main );
leftCol->addWidget( label );
modeW = new QComboBox( main );
int i = 0;
while (defaultText[i])
modeW->insertItem( i18n(defaultText[i++]) );
leftCol->addWidget( modeW );
leftCol->addStretch();
// Preview
QWidget* preview;
preview = new QWidget( main );
preview->setFixedSize( 220, 170 );
preview->setBackgroundColor( black );
preview->show(); // otherwise saver does not get correct size
_saver = new KEuphoriaScreenSaver( preview->winId() );
top->addWidget(preview);
// Now that we have _saver...
modeW->setCurrentItem( _saver->mode() ); // set before we connect
connect( modeW, SIGNAL(activated(int)), _saver, SLOT(setMode(int)) );
setMinimumSize( sizeHint() );
}
KEuphoriaSetup::~KEuphoriaSetup()
{
delete _saver;
}
void KEuphoriaSetup::slotHelp()
{
KMessageBox::about(this,
i18n("<h3>Euphoria 1.0</h3>\n<p>Copyright (c) 2002 Terence M. Welsh<br>\n<a href=\"http://www.reallyslick.com/\">http://www.reallyslick.com/</a></p>\n\n<p>Ported to KDE by Karl Robillard</p>"),
QString::null, KMessageBox::AllowLink);
}
/**
Ok pressed - save settings and exit
*/
void KEuphoriaSetup::slotOk()
{
KConfig* config = KGlobal::config();
config->setGroup("Settings");
QString val;
val.setNum( modeW->currentItem() );
config->writeEntry("Mode", val );
config->sync();
accept();
}
#endif
//----------------------------------------------------------------------------
#ifdef UNIT_TEST
// moc Euphoria.h -o Euphoria.moc
// g++ -g -DUNIT_TEST Euphoria.cpp -I/usr/lib/qt3/include -lqt -L/usr/lib/qt3/lib -lGLU -lGL
#include <qapplication.h>
int main( int argc, char** argv )
{
QApplication app( argc, argv );
EuphoriaWidget w;
w.setDefaults( EuphoriaWidget::UHFTEM );
app.setMainWidget( &w );
w.show();
return app.exec();
}
#endif
//EOF