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>
63 #include <config-xsavers.h> // HAVE_GL
72 #include <X11/Intrinsic.h>
73 #ifdef HAVE_GL_XMESA_H
79 // We don't need GLUT, but some BROKEN GLU implemenations, such as the one
80 // used in SuSE Linux 6.3, do. :(
89 #define PI 3.141592657
106 #define MAXANGLES 6000
109 typedef struct _starRec
{
111 float x
[2], y
[2], z
[2];
112 float offsetX
, offsetY
, offsetR
, rotation
;
116 GLenum doubleBuffer
, directRender
;
119 GLint starCount
= MAXSTARS
/ 2;
121 float warpinterval
= 30000.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
;
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;
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
)
167 tmpX
= *x
* Cos(rotation
) - *y
* Sin(rotation
);
168 tmpY
= *y
* Cos(rotation
) + *x
* Sin(rotation
);
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
;
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
);
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
);
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) {
226 width
= MAXPOS
/ 10.0 / stars
[n
].z
[0] + 1.0;
227 glColor3f(1.0, 0.0, 0.0);
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);
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
) {
259 static void Init(void)
264 for (n
= 0; n
< MAXSTARS
; n
++) {
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
);
289 gluOrtho2D(-0.5, windW
+0.5, -0.5, windH
+0.5);
290 glMatrixMode(GL_MODELVIEW
);
300 speed
= (float)(nitro
/ 10) + 1.0;
301 if (speed
> MAXWARP1
) {
304 if (++nitro
> MAXWARP1
*10) {
307 } else if (nitro
< 0) {
309 speed
= (float)(-nitro
/ 10) + 1.0;
310 if (speed
> MAXWARP1
) {
317 /* if (doubleBuffer) {
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);
332 glXSwapBuffers(display, window);
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
;
356 for (screen
= 0; screen
< MAXSCREENS
; screen
++)
357 glVis
[screen
] = NULL
;
360 if (!glVis
[screen
]) {
362 /* Monochrome display - use color index mode */
363 int attribList
[] = {GLX_DOUBLEBUFFER
, None
};
365 glVis
[screen
] = glXChooseVisual(display
, screen
, 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
]) {
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
388 initSpace(Window window
)
390 Display
*display
= dsp
;
391 XWindowAttributes xwa
;
394 (void) XGetWindowAttributes(dsp
, window
, &xwa
);
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
;
405 vTemplate
.c_class
= VisualClassWanted
;
408 wantVis
= XGetVisualInfo(display
,
409 VisualScreenMask
| VisualDepthMask
| VisualClassMask
,
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
,
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
;
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
);
444 glIndexi(WhitePixel(display
, screen
));
445 glClearIndex(BlackPixel(display
, screen
));
448 reshape(xwa
.width
, xwa
.height
);
463 #define WARPFACTOR 100
464 //-----------------------------------------------------------------------------
466 #include <qpushbutton.h>
467 #include <qcheckbox.h>
471 #include <kmessagebox.h>
477 static kSpaceSaver
*saver
= NULL
;
479 void startScreenSaver( Drawable d
)
483 saver
= new kSpaceSaver( d
);
486 void stopScreenSaver()
493 int setupScreenSaver()
500 //-----------------------------------------------------------------------------
502 kSpaceSaver::kSpaceSaver( Drawable drawable
) : kScreenSaver( drawable
)
504 rnd
= new KRandomSequence();
506 counter
= (int)warpinterval
*WARPFACTOR
;
509 initSpace( mDrawable
);
511 timer
.start( speed
);
512 connect( &timer
, SIGNAL( timeout() ), SLOT( slotTimeout() ) );
515 kSpaceSaver::~kSpaceSaver()
522 void kSpaceSaver::setSpeed( int spd
)
525 speed
= MAXSPEED
- spd
;
526 // printf("speed %d\n",speed);
528 timer
.start( speed
);
531 void kSpaceSaver::setWarp( int w
)
534 counter
= (int)warpinterval
;
535 initSpace( mDrawable
);
538 void kSpaceSaver::readSettings()
540 KConfig
*config
= klock_config();
541 KConfigGroup group
= config
.group( "Settings" );
545 str
= group
.readEntry( "Speed" );
547 speed
= MAXSPEED
- str
.toInt();
551 warpinterval
= group
.readEntry( "WarpInterval", 15 );
555 void kSpaceSaver::slotTimeout()
557 //printf("%d %d \n",(int)warpinterval, MAXWARP);
558 if(warpinterval
!= MAXWARP
){
564 counter
= (int) warpinterval
*WARPFACTOR
;
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" ) );
582 QWidget
*page
= new QWidget( this );
583 setMainWidget( page
);
584 QHBoxLayout
*hb
= new QHBoxLayout( page
, 0, spacingHint() );
585 QVBoxLayout
*vb
= new QVBoxLayout( hb
, spacingHint() );
590 label
= new QLabel( i18n("Speed:"), page
);
591 vb
->addWidget( label
);
593 slider
= new QSlider(MINSPEED
, MAXSPEED
, 10, speed
, Qt::Horizontal
,
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 ) ) );
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
)
629 else if ( speed
< MINSPEED
)
632 warpinterval
= group
.configEntry( "WarpInterval", 15 );
637 void kSpaceSetup::slotSpeed( int num
)
642 saver
->setSpeed( speed
);
645 void kSpaceSetup::slotWarp( int num
)
649 saver
->setWarp( warpinterval
);
652 void kSpaceSetup::slotOk()
654 KConfig
*config
= klock_config();
655 KConfigGroup group
= config
->group( "Settings" );
658 sspeed
.setNum( speed
);
659 group
.writeEntry( "Speed", sspeed
);
662 interval
.setNum( (int)warpinterval
);
663 group
.writeEntry( "WarpInterval", interval
);
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)
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;
702 void main(int argc, char **argv)
706 if (Args(argc, argv) == GL_FALSE) {
712 tkInitPosition(0, 0, 300, 300);
715 type |= (doubleBuffer) ? TK_DOUBLE : TK_SINGLE;
716 type |= (directRender) ? TK_DIRECT : TK_INDIRECT;
717 tkInitDisplayMode(type);
719 if (tkInitWindow("Stars") == GL_FALSE) {
725 tkExposeFunc(Reshape);
726 tkReshapeFunc(Reshape);