Adding 4 status icons.
[kdeartwork.git] / kscreensaver / xsavers / space.cpp
blob166108844dfe04ff99faa7399b2d5e91a3ef5167
1 /*
3 * kStart OpenGL screensave for KDE
5 * $Id$
7 * Copyright (C) 1998 Bernd Johannes Wuebben
8 * wuebben@math.cornell.edu
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free
22 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 * Based on star.c:
26 * Copyright (c) 1991, 1992, 1993 Silicon Graphics, Inc.
28 * Permission to use, copy, modify, distribute, and sell this software and
29 * its documentation for any purpose is hereby granted without fee, provided
30 * that (i) the above copyright notices and this permission notice appear in
31 * all copies of the software and related documentation, and (ii) the name of
32 * Silicon Graphics may not be used in any advertising or
33 * publicity relating to the software without the specific, prior written
34 * permission of Silicon Graphics.
36 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF
37 * ANY KIND,
38 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
39 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
41 * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR
42 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
43 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
44 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
45 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
46 * OF THIS SOFTWARE.
49 #define LONG64
50 //#define QT_CLEAN_NAMESPACE
52 #include <qslider.h>
53 #include <qlayout.h>
54 //Added by qt3to4:
55 #include <QVBoxLayout>
56 #include <QHBoxLayout>
57 #include <kglobal.h>
58 #include <kconfig.h>
59 #include <krandomsequence.h>
60 #include <kdebug.h>
61 #include "xlock.h"
62 #include "helpers.h"
63 #include <config-xsavers.h> // HAVE_GL
65 #ifdef HAVE_GL
67 #include <klocale.h>
69 #undef index
70 #include "space.h"
71 #include <math.h>
72 #include <X11/Intrinsic.h>
73 #ifdef HAVE_GL_XMESA_H
74 #include <GL/xmesa.h>
75 #endif
76 #include <GL/gl.h>
77 #include <GL/glx.h>
78 #ifdef HAVE_GL_GLUT_H
79 // We don't need GLUT, but some BROKEN GLU implemenations, such as the one
80 // used in SuSE Linux 6.3, do. :(
81 #include <GL/glut.h>
82 #endif
83 #include <GL/glu.h>
85 #ifndef PI
86 #ifdef M_PI
87 #define PI M_PI
88 #else
89 #define PI 3.141592657
90 #endif
91 #endif
93 enum {
94 NORMAL = 0,
95 WEIRD = 1
96 } flag = NORMAL;
98 enum {
99 STREAK = 0,
100 CIRCLE = 1
103 #define MAXSTARS 400
104 #define MAXPOS 10000
105 #define MAXWARP1 10
106 #define MAXANGLES 6000
109 typedef struct _starRec {
110 GLint type;
111 float x[2], y[2], z[2];
112 float offsetX, offsetY, offsetR, rotation;
113 } starRec;
116 GLenum doubleBuffer, directRender;
117 GLint windW, windH;
119 GLint starCount = MAXSTARS / 2;
120 float speed = 1.0;
121 float warpinterval = 30000.0;
122 GLint nitro = 0;
123 starRec stars[MAXSTARS];
124 float sinTable[MAXANGLES];
126 static GLXContext glx_context;
127 static KRandomSequence *rnd = 0;
129 float Sin(float angle)
132 return (sinTable[(GLint)angle]);
135 float Cos(float angle)
138 return (sinTable[((GLint)angle+(MAXANGLES/4))%MAXANGLES]);
141 void NewStar(GLint n, GLint d)
144 if (rnd->getLong(4) == 0) {
145 stars[n].type = CIRCLE;
146 } else {
147 stars[n].type = STREAK;
149 stars[n].x[0] = rnd->getDouble() * MAXPOS - MAXPOS / 2;
150 stars[n].y[0] = rnd->getDouble() * MAXPOS - MAXPOS / 2;
151 stars[n].z[0] = rnd->getDouble() * MAXPOS + d;
152 if (rnd->getLong(4) == 0 && flag == WEIRD) {
153 stars[n].offsetX = rnd->getDouble()* 100 - 100 / 2;
154 stars[n].offsetY = rnd->getDouble()* 100 - 100 / 2;
155 stars[n].offsetR = rnd->getDouble()* 25 - 25 / 2;
156 } else {
157 stars[n].offsetX = 0.0;
158 stars[n].offsetY = 0.0;
159 stars[n].offsetR = 0.0;
163 void RotatePoint(float *x, float *y, float rotation)
165 float tmpX, tmpY;
167 tmpX = *x * Cos(rotation) - *y * Sin(rotation);
168 tmpY = *y * Cos(rotation) + *x * Sin(rotation);
169 *x = tmpX;
170 *y = tmpY;
173 void MoveStars(void)
175 float offset;
176 GLint n;
178 offset = speed * 60.0;
180 for (n = 0; n < starCount; n++) {
181 stars[n].x[1] = stars[n].x[0];
182 stars[n].y[1] = stars[n].y[0];
183 stars[n].z[1] = stars[n].z[0];
184 stars[n].x[0] += stars[n].offsetX;
185 stars[n].y[0] += stars[n].offsetY;
186 stars[n].z[0] -= offset;
187 stars[n].rotation += stars[n].offsetR;
188 if (stars[n].rotation > MAXANGLES) {
189 stars[n].rotation = 0.0;
194 GLenum StarPoint(GLint n)
196 float x0, y0, x1, y1, width;
197 GLint i;
199 x0 = stars[n].x[0] * windW / stars[n].z[0];
200 y0 = stars[n].y[0] * windH / stars[n].z[0];
201 RotatePoint(&x0, &y0, stars[n].rotation);
202 x0 += windW / 2.0;
203 y0 += windH / 2.0;
205 if (x0 >= 0.0 && x0 < windW && y0 >= 0.0 && y0 < windH) {
206 if (stars[n].type == STREAK) {
207 x1 = stars[n].x[1] * windW / stars[n].z[1];
208 y1 = stars[n].y[1] * windH / stars[n].z[1];
209 RotatePoint(&x1, &y1, stars[n].rotation);
210 x1 += windW / 2.0;
211 y1 += windH / 2.0;
213 glLineWidth(MAXPOS/100.0/stars[n].z[0]+1.0);
214 glColor3f((MAXWARP1-speed)/MAXWARP1, (MAXWARP1-speed)/MAXWARP1, .9);
215 if (fabs(x0-x1) < 1.0 && fabs(y0-y1) < 1.0) {
216 glBegin(GL_POINTS);
217 glVertex2f(x0, y0);
218 glEnd();
219 } else {
220 glBegin(GL_LINES);
221 glVertex2f(x0, y0);
222 glVertex2f(x1, y1);
223 glEnd();
225 } else {
226 width = MAXPOS / 10.0 / stars[n].z[0] + 1.0;
227 glColor3f(1.0, 0.0, 0.0);
228 glBegin(GL_POLYGON);
229 for (i = 0; i < 8; i++) {
230 float x = x0 + width * Cos((float)i*MAXANGLES/8.0);
231 float y = y0 + width * Sin((float)i*MAXANGLES/8.0);
232 glVertex2f(x, y);
234 glEnd();
236 return GL_TRUE;
237 } else {
238 return GL_FALSE;
242 void ShowStars(void)
244 GLint n;
246 glClear(GL_COLOR_BUFFER_BIT);
248 for (n = 0; n < starCount; n++) {
249 if (stars[n].z[0] > speed || (stars[n].z[0] > 0.0 && speed < MAXWARP1)) {
250 if (StarPoint(n) == GL_FALSE) {
251 NewStar(n, MAXPOS);
253 } else {
254 NewStar(n, MAXPOS);
259 static void Init(void)
261 float angle;
262 GLint n;
264 for (n = 0; n < MAXSTARS; n++) {
265 NewStar(n, 100);
268 angle = 0.0;
269 for (n = 0; n < MAXANGLES ; n++) {
270 sinTable[n] = sin(angle);
271 angle += PI / (MAXANGLES / 2.0);
274 glClearColor(0.0, 0.0, 0.0, 0.0);
276 glDisable(GL_DITHER);
279 void reshape(int width, int height)
282 windW = (GLint)width;
283 windH = (GLint)height;
285 glViewport(0, 0, windW, windH);
287 glMatrixMode(GL_PROJECTION);
288 glLoadIdentity();
289 gluOrtho2D(-0.5, windW+0.5, -0.5, windH+0.5);
290 glMatrixMode(GL_MODELVIEW);
294 void Idle(void)
297 MoveStars();
298 ShowStars();
299 if (nitro > 0) {
300 speed = (float)(nitro / 10) + 1.0;
301 if (speed > MAXWARP1) {
302 speed = MAXWARP1;
304 if (++nitro > MAXWARP1*10) {
305 nitro = -nitro;
307 } else if (nitro < 0) {
308 nitro++;
309 speed = (float)(-nitro / 10) + 1.0;
310 if (speed > MAXWARP1) {
311 speed = MAXWARP1;
315 glFlush();
317 /* if (doubleBuffer) {
318 tkSwapBuffers();
323 void
324 drawSpace(Window /*window*/)
328 Display *display = dsp;
329 //glXMakeCurrent(display, window, mp->glx_context);
330 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
331 glFlush();
332 glXSwapBuffers(display, window);
335 Idle();
340 void release_Space(){
342 glXDestroyContext(dsp, glx_context);
346 static XVisualInfo *glVis[MAXSCREENS];
349 getVisual(XVisualInfo * wantVis, int visual_count)
351 Display *display = dsp;
352 static int first;
353 int i;
355 if (first) {
356 for (screen = 0; screen < MAXSCREENS; screen++)
357 glVis[screen] = NULL;
360 if (!glVis[screen]) {
361 if (mono) {
362 /* Monochrome display - use color index mode */
363 int attribList[] = {GLX_DOUBLEBUFFER, None};
365 glVis[screen] = glXChooseVisual(display, screen, attribList);
366 } else {
367 int attribList[] =
368 {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None};
370 glVis[screen] = glXChooseVisual(display, screen, attribList);
373 // Make sure we have a visual
374 if (!glVis[screen]) {
375 return (0);
378 /* check if GL can render into root window. */
379 for(i=0;i<visual_count;i++)
380 if ( (glVis[screen]->visual == (wantVis+i)->visual) )
381 return (1); // success
383 // The visual we received did not match one we asked for
384 return (0);
387 void
388 initSpace(Window window)
390 Display *display = dsp;
391 XWindowAttributes xwa;
394 (void) XGetWindowAttributes(dsp, window, &xwa);
395 int n;
396 XVisualInfo *wantVis, vTemplate;
397 int VisualClassWanted=-1;
399 vTemplate.screen = screen;
400 vTemplate.depth = xwa.depth;
402 if (VisualClassWanted == -1) {
403 vTemplate.c_class = DefaultVisual(display, screen)->c_class;
404 } else {
405 vTemplate.c_class = VisualClassWanted;
408 wantVis = XGetVisualInfo(display,
409 VisualScreenMask | VisualDepthMask | VisualClassMask,
410 &vTemplate, &n);
412 if (VisualClassWanted != -1 && n == 0) {
413 /* Wanted visual not found so use default */
415 vTemplate.c_class = DefaultVisual(display, screen)->c_class;
417 wantVis = XGetVisualInfo(display,
418 VisualScreenMask | VisualDepthMask | VisualClassMask,
419 &vTemplate, &n);
421 /* if User asked for color, try that first, then try mono */
422 /* if User asked for mono. Might fail on 16/24 bit displays,
423 so fall back on color, but keep the mono "look & feel". */
425 if (!getVisual(wantVis, n)) {
426 if (!getVisual(wantVis, n)) {
427 kError() << i18n("GL can not render with root visual\n") << endl;
428 return;
432 /* PURIFY 3.0a on SunOS4 reports a 104 byte memory leak on the next line each
433 * time that morph3d mode is run in random mode. */
435 glx_context = glXCreateContext(display, wantVis, 0, True);
437 XFree((char *) wantVis);
440 glXMakeCurrent(display, window, glx_context);
441 glDrawBuffer(GL_FRONT);
443 if (mono) {
444 glIndexi(WhitePixel(display, screen));
445 glClearIndex(BlackPixel(display, screen));
448 reshape(xwa.width, xwa.height);
449 Init();
455 #endif
457 #define MINSPEED 1
458 #define MAXSPEED 100
459 #define DEFSPEED 50
460 #define MINWARP 1
461 #define MAXWARP 30
462 #define DEFWARP 2
463 #define WARPFACTOR 100
464 //-----------------------------------------------------------------------------
466 #include <qpushbutton.h>
467 #include <qcheckbox.h>
468 #include <qlabel.h>
469 #include <qcolor.h>
471 #include <kmessagebox.h>
473 #include "space.moc"
475 #undef Below
477 static kSpaceSaver *saver = NULL;
479 void startScreenSaver( Drawable d )
481 if ( saver )
482 return;
483 saver = new kSpaceSaver( d );
486 void stopScreenSaver()
488 if ( saver )
489 delete saver;
490 saver = NULL;
493 int setupScreenSaver()
495 kSpaceSetup dlg;
497 return dlg.exec();
500 //-----------------------------------------------------------------------------
502 kSpaceSaver::kSpaceSaver( Drawable drawable ) : kScreenSaver( drawable )
504 rnd = new KRandomSequence();
505 readSettings();
506 counter = (int)warpinterval *WARPFACTOR;
508 initXLock( mGc );
509 initSpace( mDrawable );
511 timer.start( speed );
512 connect( &timer, SIGNAL( timeout() ), SLOT( slotTimeout() ) );
515 kSpaceSaver::~kSpaceSaver()
517 timer.stop();
518 release_Space();
519 delete rnd; rnd = 0;
522 void kSpaceSaver::setSpeed( int spd )
524 timer.stop();
525 speed = MAXSPEED - spd ;
526 // printf("speed %d\n",speed);
527 timer.stop();
528 timer.start( speed );
531 void kSpaceSaver::setWarp( int w )
533 warpinterval = w;
534 counter = (int)warpinterval;
535 initSpace( mDrawable );
538 void kSpaceSaver::readSettings()
540 KConfig *config = klock_config();
541 KConfigGroup group = config.group( "Settings" );
543 QString str;
545 str = group.readEntry( "Speed" );
546 if ( !str.isNull() )
547 speed = MAXSPEED - str.toInt();
548 else
549 speed = DEFSPEED;
551 warpinterval = group.readEntry( "WarpInterval", 15 );
552 delete config;
555 void kSpaceSaver::slotTimeout()
557 //printf("%d %d \n",(int)warpinterval, MAXWARP);
558 if(warpinterval != MAXWARP){
559 if(nitro == 0)
560 counter -= speed +1;
562 if(counter <= 0){
563 nitro = 1;
564 counter = (int) warpinterval *WARPFACTOR;
567 else
568 nitro = 0;
570 drawSpace( mDrawable );
573 //-----------------------------------------------------------------------------
575 kSpaceSetup::kSpaceSetup( QWidget *parent, const char *name )
576 : KDialogBase( parent, name, true, i18n("Setup Space Screen Saver"),
577 Ok|Cancel|Help, Ok, true )
579 setButtonText( Help, i18n( "A&bout" ) );
580 readSettings();
582 QWidget *page = new QWidget( this );
583 setMainWidget( page );
584 QHBoxLayout *hb = new QHBoxLayout( page, 0, spacingHint() );
585 QVBoxLayout *vb = new QVBoxLayout( hb, spacingHint() );
587 QLabel *label;
588 QSlider *slider;
590 label = new QLabel( i18n("Speed:"), page );
591 vb->addWidget( label );
593 slider = new QSlider(MINSPEED, MAXSPEED, 10, speed, Qt::Horizontal,
594 page );
595 vb->addWidget( slider );
596 slider->setTickmarks(QSlider::TicksBelow);
597 slider->setTickInterval(10);
598 connect( slider, SIGNAL( valueChanged( int ) ), SLOT( slotSpeed( int ) ) );
600 label = new QLabel( i18n("Warp interval:"), page );
601 vb->addWidget( label );
603 slider = new QSlider(MINWARP, MAXWARP, 3, warpinterval, Qt::Horizontal, page );
604 vb->addWidget( slider );
605 slider->setTickmarks(QSlider::TicksBelow);
606 slider->setTickInterval(3);
607 connect( slider, SIGNAL( valueChanged( int ) ), SLOT( slotWarp( int ) ) );
609 vb->addStrut( 150 );
610 vb->addStretch();
612 preview = new QWidget( page );
613 hb->addWidget( preview );
614 preview->setFixedSize( 220, 170 );
615 preview->setBackgroundColor( Qt::black );
616 preview->show(); // otherwise saver does not get correct size
617 saver = new kSpaceSaver( preview->winId() );
620 void kSpaceSetup::readSettings()
622 KConfig *config = klock_config();
623 KConfigGroup group = config->group( "Settings" );
625 speed = group.configEntry( "Speed", speed );
627 if ( speed > MAXSPEED )
628 speed = MAXSPEED;
629 else if ( speed < MINSPEED )
630 speed = MINSPEED;
632 warpinterval = group.configEntry( "WarpInterval", 15 );
634 delete config;
637 void kSpaceSetup::slotSpeed( int num )
639 speed = num ;
641 if ( saver )
642 saver->setSpeed( speed );
645 void kSpaceSetup::slotWarp( int num )
647 warpinterval = num;
648 if ( saver )
649 saver->setWarp( warpinterval );
652 void kSpaceSetup::slotOk()
654 KConfig *config = klock_config();
655 KConfigGroup group = config->group( "Settings" );
657 QString sspeed;
658 sspeed.setNum( speed );
659 group.writeEntry( "Speed", sspeed );
661 QString interval;
662 interval.setNum( (int)warpinterval );
663 group.writeEntry( "WarpInterval", interval );
665 config->sync();
666 delete config;
667 accept();
670 void kSpaceSetup::slotHelp()
672 KMessageBox::about(this,
673 i18n("KSpace\nCopyright (c) 1998\n"
674 "Bernd Johannes Wuebben <wuebben@kde.org>"));
679 static GLenum Args(int argc, char **argv)
681 GLint i;
683 doubleBuffer = GL_FALSE;
684 directRender = GL_TRUE;
686 for (i = 1; i < argc; i++) {
687 if (strcmp(argv[i], "-sb") == 0) {
688 doubleBuffer = GL_FALSE;
689 } else if (strcmp(argv[i], "-db") == 0) {
690 doubleBuffer = GL_TRUE;
691 } else if (strcmp(argv[i], "-dr") == 0) {
692 directRender = GL_TRUE;
693 } else if (strcmp(argv[i], "-ir") == 0) {
694 directRender = GL_FALSE;
697 return GL_TRUE;
702 void main(int argc, char **argv)
704 GLenum type;
706 if (Args(argc, argv) == GL_FALSE) {
707 tkQuit();
710 windW = 300;
711 windH = 300;
712 tkInitPosition(0, 0, 300, 300);
714 type = TK_RGB;
715 type |= (doubleBuffer) ? TK_DOUBLE : TK_SINGLE;
716 type |= (directRender) ? TK_DIRECT : TK_INDIRECT;
717 tkInitDisplayMode(type);
719 if (tkInitWindow("Stars") == GL_FALSE) {
720 tkQuit();
723 Init();
725 tkExposeFunc(Reshape);
726 tkReshapeFunc(Reshape);
727 tkKeyDownFunc(Key);
728 tkIdleFunc(Idle);
729 tkExec();