3 * kStart OpenGL screensave for KDE
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.
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
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
50 //#define QT_CLEAN_NAMESPACE
55 #include <QVBoxLayout>
56 #include <QHBoxLayout>
59 #include <krandomsequence.h>
64 #include "../../config.h"
74 #include <X11/Intrinsic.h>
75 #ifdef HAVE_GL_XMESA_H
81 // We don't need GLUT, but some BROKEN GLU implemenations, such as the one
82 // used in SuSE Linux 6.3, do. :(
91 #define PI 3.141592657
108 #define MAXANGLES 6000
111 typedef struct _starRec
{
113 float x
[2], y
[2], z
[2];
114 float offsetX
, offsetY
, offsetR
, rotation
;
118 GLenum doubleBuffer
, directRender
;
121 GLint starCount
= MAXSTARS
/ 2;
123 float warpinterval
= 30000.0;
125 starRec stars
[MAXSTARS
];
126 float sinTable
[MAXANGLES
];
128 static GLXContext glx_context
;
129 static KRandomSequence
*rnd
= 0;
131 float Sin(float angle
)
134 return (sinTable
[(GLint
)angle
]);
137 float Cos(float angle
)
140 return (sinTable
[((GLint
)angle
+(MAXANGLES
/4))%MAXANGLES
]);
143 void NewStar(GLint n
, GLint d
)
146 if (rnd
->getLong(4) == 0) {
147 stars
[n
].type
= CIRCLE
;
149 stars
[n
].type
= STREAK
;
151 stars
[n
].x
[0] = rnd
->getDouble() * MAXPOS
- MAXPOS
/ 2;
152 stars
[n
].y
[0] = rnd
->getDouble() * MAXPOS
- MAXPOS
/ 2;
153 stars
[n
].z
[0] = rnd
->getDouble() * MAXPOS
+ d
;
154 if (rnd
->getLong(4) == 0 && flag
== WEIRD
) {
155 stars
[n
].offsetX
= rnd
->getDouble()* 100 - 100 / 2;
156 stars
[n
].offsetY
= rnd
->getDouble()* 100 - 100 / 2;
157 stars
[n
].offsetR
= rnd
->getDouble()* 25 - 25 / 2;
159 stars
[n
].offsetX
= 0.0;
160 stars
[n
].offsetY
= 0.0;
161 stars
[n
].offsetR
= 0.0;
165 void RotatePoint(float *x
, float *y
, float rotation
)
169 tmpX
= *x
* Cos(rotation
) - *y
* Sin(rotation
);
170 tmpY
= *y
* Cos(rotation
) + *x
* Sin(rotation
);
180 offset
= speed
* 60.0;
182 for (n
= 0; n
< starCount
; n
++) {
183 stars
[n
].x
[1] = stars
[n
].x
[0];
184 stars
[n
].y
[1] = stars
[n
].y
[0];
185 stars
[n
].z
[1] = stars
[n
].z
[0];
186 stars
[n
].x
[0] += stars
[n
].offsetX
;
187 stars
[n
].y
[0] += stars
[n
].offsetY
;
188 stars
[n
].z
[0] -= offset
;
189 stars
[n
].rotation
+= stars
[n
].offsetR
;
190 if (stars
[n
].rotation
> MAXANGLES
) {
191 stars
[n
].rotation
= 0.0;
196 GLenum
StarPoint(GLint n
)
198 float x0
, y0
, x1
, y1
, width
;
201 x0
= stars
[n
].x
[0] * windW
/ stars
[n
].z
[0];
202 y0
= stars
[n
].y
[0] * windH
/ stars
[n
].z
[0];
203 RotatePoint(&x0
, &y0
, stars
[n
].rotation
);
207 if (x0
>= 0.0 && x0
< windW
&& y0
>= 0.0 && y0
< windH
) {
208 if (stars
[n
].type
== STREAK
) {
209 x1
= stars
[n
].x
[1] * windW
/ stars
[n
].z
[1];
210 y1
= stars
[n
].y
[1] * windH
/ stars
[n
].z
[1];
211 RotatePoint(&x1
, &y1
, stars
[n
].rotation
);
215 glLineWidth(MAXPOS
/100.0/stars
[n
].z
[0]+1.0);
216 glColor3f((MAXWARP1
-speed
)/MAXWARP1
, (MAXWARP1
-speed
)/MAXWARP1
, .9);
217 if (fabs(x0
-x1
) < 1.0 && fabs(y0
-y1
) < 1.0) {
228 width
= MAXPOS
/ 10.0 / stars
[n
].z
[0] + 1.0;
229 glColor3f(1.0, 0.0, 0.0);
231 for (i
= 0; i
< 8; i
++) {
232 float x
= x0
+ width
* Cos((float)i
*MAXANGLES
/8.0);
233 float y
= y0
+ width
* Sin((float)i
*MAXANGLES
/8.0);
248 glClear(GL_COLOR_BUFFER_BIT
);
250 for (n
= 0; n
< starCount
; n
++) {
251 if (stars
[n
].z
[0] > speed
|| (stars
[n
].z
[0] > 0.0 && speed
< MAXWARP1
)) {
252 if (StarPoint(n
) == GL_FALSE
) {
261 static void Init(void)
266 for (n
= 0; n
< MAXSTARS
; n
++) {
271 for (n
= 0; n
< MAXANGLES
; n
++) {
272 sinTable
[n
] = sin(angle
);
273 angle
+= PI
/ (MAXANGLES
/ 2.0);
276 glClearColor(0.0, 0.0, 0.0, 0.0);
278 glDisable(GL_DITHER
);
281 void reshape(int width
, int height
)
284 windW
= (GLint
)width
;
285 windH
= (GLint
)height
;
287 glViewport(0, 0, windW
, windH
);
289 glMatrixMode(GL_PROJECTION
);
291 gluOrtho2D(-0.5, windW
+0.5, -0.5, windH
+0.5);
292 glMatrixMode(GL_MODELVIEW
);
302 speed
= (float)(nitro
/ 10) + 1.0;
303 if (speed
> MAXWARP1
) {
306 if (++nitro
> MAXWARP1
*10) {
309 } else if (nitro
< 0) {
311 speed
= (float)(-nitro
/ 10) + 1.0;
312 if (speed
> MAXWARP1
) {
319 /* if (doubleBuffer) {
326 drawSpace(Window
/*window*/)
330 Display *display = dsp;
331 //glXMakeCurrent(display, window, mp->glx_context);
332 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
334 glXSwapBuffers(display, window);
342 void release_Space(){
344 glXDestroyContext(dsp
, glx_context
);
348 static XVisualInfo
*glVis
[MAXSCREENS
];
351 getVisual(XVisualInfo
* wantVis
, int visual_count
)
353 Display
*display
= dsp
;
358 for (screen
= 0; screen
< MAXSCREENS
; screen
++)
359 glVis
[screen
] = NULL
;
362 if (!glVis
[screen
]) {
364 /* Monochrome display - use color index mode */
365 int attribList
[] = {GLX_DOUBLEBUFFER
, None
};
367 glVis
[screen
] = glXChooseVisual(display
, screen
, attribList
);
370 {GLX_RGBA
, GLX_DOUBLEBUFFER
, GLX_DEPTH_SIZE
, 1, None
};
372 glVis
[screen
] = glXChooseVisual(display
, screen
, attribList
);
375 // Make sure we have a visual
376 if (!glVis
[screen
]) {
380 /* check if GL can render into root window. */
381 for(i
=0;i
<visual_count
;i
++)
382 if ( (glVis
[screen
]->visual
== (wantVis
+i
)->visual
) )
383 return (1); // success
385 // The visual we received did not match one we asked for
390 initSpace(Window window
)
392 Display
*display
= dsp
;
393 XWindowAttributes xwa
;
396 (void) XGetWindowAttributes(dsp
, window
, &xwa
);
398 XVisualInfo
*wantVis
, vTemplate
;
399 int VisualClassWanted
=-1;
401 vTemplate
.screen
= screen
;
402 vTemplate
.depth
= xwa
.depth
;
404 if (VisualClassWanted
== -1) {
405 vTemplate
.c_class
= DefaultVisual(display
, screen
)->c_class
;
407 vTemplate
.c_class
= VisualClassWanted
;
410 wantVis
= XGetVisualInfo(display
,
411 VisualScreenMask
| VisualDepthMask
| VisualClassMask
,
414 if (VisualClassWanted
!= -1 && n
== 0) {
415 /* Wanted visual not found so use default */
417 vTemplate
.c_class
= DefaultVisual(display
, screen
)->c_class
;
419 wantVis
= XGetVisualInfo(display
,
420 VisualScreenMask
| VisualDepthMask
| VisualClassMask
,
423 /* if User asked for color, try that first, then try mono */
424 /* if User asked for mono. Might fail on 16/24 bit displays,
425 so fall back on color, but keep the mono "look & feel". */
427 if (!getVisual(wantVis
, n
)) {
428 if (!getVisual(wantVis
, n
)) {
429 kdError() << i18n("GL can not render with root visual\n") << endl
;
434 /* PURIFY 3.0a on SunOS4 reports a 104 byte memory leak on the next line each
435 * time that morph3d mode is run in random mode. */
437 glx_context
= glXCreateContext(display
, wantVis
, 0, True
);
439 XFree((char *) wantVis
);
442 glXMakeCurrent(display
, window
, glx_context
);
443 glDrawBuffer(GL_FRONT
);
446 glIndexi(WhitePixel(display
, screen
));
447 glClearIndex(BlackPixel(display
, screen
));
450 reshape(xwa
.width
, xwa
.height
);
465 #define WARPFACTOR 100
466 //-----------------------------------------------------------------------------
468 #include <qpushbutton.h>
469 #include <qcheckbox.h>
473 #include <kmessagebox.h>
479 static kSpaceSaver
*saver
= NULL
;
481 void startScreenSaver( Drawable d
)
485 saver
= new kSpaceSaver( d
);
488 void stopScreenSaver()
495 int setupScreenSaver()
502 //-----------------------------------------------------------------------------
504 kSpaceSaver::kSpaceSaver( Drawable drawable
) : kScreenSaver( drawable
)
506 rnd
= new KRandomSequence();
508 counter
= (int)warpinterval
*WARPFACTOR
;
510 colorContext
= QColor::enterAllocContext();
513 initSpace( mDrawable
);
515 timer
.start( speed
);
516 connect( &timer
, SIGNAL( timeout() ), SLOT( slotTimeout() ) );
519 kSpaceSaver::~kSpaceSaver()
523 QColor::leaveAllocContext();
524 QColor::destroyAllocContext( colorContext
);
528 void kSpaceSaver::setSpeed( int spd
)
531 speed
= MAXSPEED
- spd
;
532 // printf("speed %d\n",speed);
534 timer
.start( speed
);
537 void kSpaceSaver::setWarp( int w
)
540 counter
= (int)warpinterval
;
541 initSpace( mDrawable
);
544 void kSpaceSaver::readSettings()
546 KConfig
*config
= klock_config();
547 config
->setGroup( "Settings" );
551 str
= config
->readEntry( "Speed" );
553 speed
= MAXSPEED
- str
.toInt();
557 warpinterval
= config
->readNumEntry( "WarpInterval", 15 );
561 void kSpaceSaver::slotTimeout()
563 //printf("%d %d \n",(int)warpinterval, MAXWARP);
564 if(warpinterval
!= MAXWARP
){
570 counter
= (int) warpinterval
*WARPFACTOR
;
576 drawSpace( mDrawable
);
579 //-----------------------------------------------------------------------------
581 kSpaceSetup::kSpaceSetup( QWidget
*parent
, const char *name
)
582 : KDialogBase( parent
, name
, true, i18n("Setup Space Screen Saver"),
583 Ok
|Cancel
|Help
, Ok
, true )
585 setButtonText( Help
, i18n( "A&bout" ) );
588 QWidget
*page
= new QWidget( this );
589 setMainWidget( page
);
590 QHBoxLayout
*hb
= new QHBoxLayout( page
, 0, spacingHint() );
591 QVBoxLayout
*vb
= new QVBoxLayout( hb
, spacingHint() );
596 label
= new QLabel( i18n("Speed:"), page
);
597 vb
->addWidget( label
);
599 slider
= new QSlider(MINSPEED
, MAXSPEED
, 10, speed
, QSlider::Horizontal
,
601 vb
->addWidget( slider
);
602 slider
->setTickmarks(QSlider::TicksBelow
);
603 slider
->setTickInterval(10);
604 connect( slider
, SIGNAL( valueChanged( int ) ), SLOT( slotSpeed( int ) ) );
606 label
= new QLabel( i18n("Warp interval:"), page
);
607 vb
->addWidget( label
);
609 slider
= new QSlider(MINWARP
, MAXWARP
, 3, warpinterval
, Horizontal
, page
);
610 vb
->addWidget( slider
);
611 slider
->setTickmarks(QSlider::TicksBelow
);
612 slider
->setTickInterval(3);
613 connect( slider
, SIGNAL( valueChanged( int ) ), SLOT( slotWarp( int ) ) );
618 preview
= new QWidget( page
);
619 hb
->addWidget( preview
);
620 preview
->setFixedSize( 220, 170 );
621 preview
->setBackgroundColor( black
);
622 preview
->show(); // otherwise saver does not get correct size
623 saver
= new kSpaceSaver( preview
->winId() );
626 void kSpaceSetup::readSettings()
628 KConfig
*config
= klock_config();
629 config
->setGroup( "Settings" );
631 speed
= config
->readNumEntry( "Speed", speed
);
633 if ( speed
> MAXSPEED
)
635 else if ( speed
< MINSPEED
)
638 warpinterval
= config
->readNumEntry( "WarpInterval", 15 );
643 void kSpaceSetup::slotSpeed( int num
)
648 saver
->setSpeed( speed
);
651 void kSpaceSetup::slotWarp( int num
)
655 saver
->setWarp( warpinterval
);
658 void kSpaceSetup::slotOk()
660 KConfig
*config
= klock_config();
661 config
->setGroup( "Settings" );
664 sspeed
.setNum( speed
);
665 config
->writeEntry( "Speed", sspeed
);
668 interval
.setNum( (int)warpinterval
);
669 config
->writeEntry( "WarpInterval", interval
);
676 void kSpaceSetup::slotHelp()
678 KMessageBox::about(this,
679 i18n("KSpace\nCopyright (c) 1998\n"
680 "Bernd Johannes Wuebben <wuebben@kde.org>"));
685 static GLenum Args(int argc, char **argv)
689 doubleBuffer = GL_FALSE;
690 directRender = GL_TRUE;
692 for (i = 1; i < argc; i++) {
693 if (strcmp(argv[i], "-sb") == 0) {
694 doubleBuffer = GL_FALSE;
695 } else if (strcmp(argv[i], "-db") == 0) {
696 doubleBuffer = GL_TRUE;
697 } else if (strcmp(argv[i], "-dr") == 0) {
698 directRender = GL_TRUE;
699 } else if (strcmp(argv[i], "-ir") == 0) {
700 directRender = GL_FALSE;
708 void main(int argc, char **argv)
712 if (Args(argc, argv) == GL_FALSE) {
718 tkInitPosition(0, 0, 300, 300);
721 type |= (doubleBuffer) ? TK_DOUBLE : TK_SINGLE;
722 type |= (directRender) ? TK_DIRECT : TK_INDIRECT;
723 tkInitDisplayMode(type);
725 if (tkInitWindow("Stars") == GL_FALSE) {
731 tkExposeFunc(Reshape);
732 tkReshapeFunc(Reshape);