Write your own Einstein@home screensaver

Mike Hewson
Mike Hewson
Moderator
Joined: 1 Dec 05
Posts: 6,020
Credit: 102,111,364
RAC: 166,451

Thanks guys for the

Thanks guys for the corrections! That is really very, very helpful. :-) :-)

[aside]
Some textbooks, tutors, and authors really don't have sufficient precision .... they're not all saying quite the same thing. Even within a given topic/language. And OO abounds with terminology, a minefield of words. No wonder students of such languages, like myself, get confused at times. Many no doubt give up, or move along quickly from the trickier bits leaving a fuzzy patch in their understanding - perhaps thinking they do understand when they don't. Possibly later the products of their work fail, blow up or fall over in some important ways. ( Sorry for the waffling, I often teach medical students how to approach & interact with sick people. Over the years I have made a bit of a study of the idea of 'understanding'. )
[/aside]

Right. Back to screensaver development.

Cheers, Mike.

I have made this letter longer than usual because I lack the time to make it shorter. Blaise Pascal

Mike Hewson
Mike Hewson
Moderator
Joined: 1 Dec 05
Posts: 6,020
Credit: 102,111,364
RAC: 166,451

One tiny query : in the

One tiny query : in the ResourceCompiler class we have a virtual destructor. I assume this might indicate the possibility of allowing subclassing later on, in the sense of further development of the ResourceCompiler idea? And/or a good habit to get into generally?

I think, in the general case : so that you'll get the right destructor(s) on a delete call ( or if an automatic goes out of scope ). It is both common and legal to use a pointer to a derived class when a base class pointer is expected. A derived class object is also a base class object aka polymorphism. So if the base class destructor is virtual then the derived class destructor will also be called in addition to the base class destructor. That is, no potential for memory leaks happening due to not cleaning up whatever the derived class constructor may have allocated?

I don't want to totally turn this thread into a tute for Mike Hewson's C++ Boners, but have I expressed this right? :-) :-)

Cheers, Mike.

I have made this letter longer than usual because I lack the time to make it shorter. Blaise Pascal

PovAddict
PovAddict
Joined: 31 Mar 05
Posts: 45
Credit: 1,634,604
RAC: 741

RE: One tiny query : in the

Message 78040 in response to message 78039

Quote:

One tiny query : in the ResourceCompiler class we have a virtual destructor. I assume this might indicate the possibility of allowing subclassing later on, in the sense of further development of the ResourceCompiler idea? And/or a good habit to get into generally?

I think, in the general case : so that you'll get the right destructor(s) on a delete call ( or if an automatic goes out of scope ). It is both common and legal to use a pointer to a derived class when a base class pointer is expected. A derived class object is also a base class object aka polymorphism. So if the base class destructor is virtual then the derived class destructor will also be called in addition to the base class destructor. That is, no potential for memory leaks happening due to not cleaning up whatever the derived class constructor may have allocated?


You are correct. If you have a class A with a virtual function foo() (and will be used in a polymorphic way), and a class B that inherits from it, and maybe adds more dynamically-allocated members, then there is a really bad problem here: http://pastebin.com/f47c0b06f

As you say, there would be a memory leak because the destructor of the derived class wouldn't be called. The solution is making the dtor virtual. That way, destructing a B via an A* pointer would call the overridden dtor ~B. (note that ~A is also called, but that's because ~B implicitly calls ~A at the end, just like B constructor implicitly calls A constructor at the beginning).

The C++ FAQ Lite (a great C++ resource, btw) says:

Quote:

Here's when you need to make your destructor virtual:

* if someone will derive from your class,
* and if someone will say new Derived, where Derived is derived from your class,
* and if someone will say delete p, where the actual object's type is Derived but the pointer p's type is your class.

Confused? Here's a simplified rule of thumb that usually protects you and usually doesn't cost you anything: make your destructor virtual if your class has any virtual functions.

Mike Hewson
Mike Hewson
Moderator
Joined: 1 Dec 05
Posts: 6,020
Credit: 102,111,364
RAC: 166,451

RE: You are correct .....

Message 78041 in response to message 78040

Quote:
You are correct ..... if your class has any virtual functions.


Thank you kindly again! :-) The sources I had made a lot of talk of cost ( time/space ), but that's not really relevant here. Better to be correct, of course. Implementation dependent anyway ( virtual tables et al ), and it's the wrong end of the process to be optimising also. What is the speed of a wrong design? : zero, when measured along the axis of interest ..... :-)

Cheers, Mike.

I have made this letter longer than usual because I lack the time to make it shorter. Blaise Pascal

Mike Hewson
Mike Hewson
Moderator
Joined: 1 Dec 05
Posts: 6,020
Credit: 102,111,364
RAC: 166,451

Some thoughts and excavations

Some thoughts and excavations ( upon OpenGL® Programming Guide: The Official Guide to Learning OpenGL®, Versions 3.0 and 3.1, Seventh Edition ) if you'll suffer it. Me thinking out loud again. :-)

An example of how one might work backwards from a proposed visual feature implemented in a certain OpenGL manner, back through to what data/format you'd want presented to the Open Resource Compiler of Oliver's. That way you can hook up hard-coded data in the executable to an actual rendering function call. The rubber has to meet the road eventually. :-)

Texture time:

- broadly a texture is a mapping of a pattern/image to a geometric object/polygon. Glue a picture onto something.

- the smallest elements of the texture are called 'texels'. These ultimately are mapped to pixels via the OpenGL rendering engine.

- a key texture function in OpenGL seems to be :
[pre]void glTexImage2D(GLenum target, GLint level, GLint internalFormat,
GLsizei width, GLsizei height, GLint border,
GLenum format, GLenum type, const GLvoid *texels);[/pre]
[ There is no shortage of other functions to pay attention to, like what do you do if you get to the edge of the texture but there's more polygon to go : do you repeat? etc ... ]

For what I currently have in mind ( a picture of dear Albert's face overlaid upon a filled ellipse representing the Earth's orbit ) :

target = GL_TEXTURE_2D. Believe it or not, there are 1D and 3D textures.

level = 0. Indicates only a single resolution of the texture map will be used.

internalFormat = GL_RGBA. Answers the question : which of the possible components of a texel ( RGBA, depth, luminance, or intensity ) will I be using when rendering occurs? A blizzard of options specifying how you want to use your texture. Alot regarding whether it's normalised ( to range [0,1], or range [-1,1] ) , fixed-point, floating-point ........

width & height. Apropos to the texture size.

border = 0. No border.

format = GL_RGBA. Answers the question : which of the possible components of a texel ( RGBA, depth, luminance, or intensity ) have I provided in my bit store? Again a snow storm of options, but I'm going to supply 3 colors and an alpha value ( per texel ).

type = GL_UNSIGNED_BYTE. The ResourceCompiler will ultimately lead, as discussed earlier, to access to a const vector. This and format says we'll be accessing red, green, blue and alpha values ( in that consecutive order ) each as 8-bit quantities ( 0 - 255 decimal ).

texels = &yourBitStore. ( Pass the address of your bit store ). Note the const GLvoid so your store won't be altered and can contain any type of data. But a successful interpretation of this store depends on you correctly specifying it's implicit structure via the above parameters.

Clearly it's possible to provide a particular bit store and use it in different ways with different calls. In effect there is some 'cast'-ing going on. Thus the parameters internalFormat and format. In my case I'll be providing exactly what I want used, GL_RGBA, no more and no less. NB - there are important OpenGL version differences with these two parameters.

So here is the picture:

This is a 24 bit colour-depth bitmap file, but is not yet Resource Compiler ready. I have to :

- trim irrelevant stuff out like BMP File Header, Device Independent Bitmap Header, Color Palette.

- keep the height and the width.

- keep the bitmap! ( NB this has a varied offset into the file )

- add an alpha value for each pixel.

Also I want to 'clamp' the darker pixels to black ( RGB = {0,0,0} ) and/or give them an alpha of 0 ( fully transparent ). Pixels brighter than 'dark' ( threshold yet to be decided ) should be unchanged RGB wise but given some constant alpha. ( Alpha is a blending value, and there are more than a few modes of blending ).

Why? Well I want to paste Albert's features only, partially transparent over some underlying color ( of the filled ellipse ), and I don't want the dark background clearly indicating that I got it from a rectangular image. A non-zero alpha for the 'dark' pixels ( well texels now ) will give a ( fainter ) rectangle over the underlying polygon color, with Albert's face in the middle.

I'm using the fact that the picture has great contrast between his head and the background, so the final result will effectively look like a 'cut-out' around his outer hairline and lower face. I've already painted out his shoulders, suit and tie. This roughly follows how it's done for the green/blue screen technique for movie CGI. Better watch the ellipse color though - do I want his eyes purple? :-)

I'll have to experiment with different combinations of Albert in the foreground, transparency levels and some background colors. :-)

To this end I'm writing a tool to suck up a *.bmp file, do those changes as above and spit out a binary file to be specified in a *.orc file. I figure that texturing of objects in the 3D viewpoint will be quite a useful skill to manage. For instance I'd like to have an Earth which actually shows continents, or a Sun with sunspots. Time will tell .... :-)

The closer one can present the data to the engine in the form of it's ultimate use ( as efficiently as desired ) then the less runtime fiddling. No doubt OpenGL could be arm-wrestled to provide a whole chain of texture/image alteration on the fly. Rather avoid that.

Cheers, Mike.

( edit ) GLenum, GLint, GLsizei, GLvoid .... are typedefs that map/correspond to more 'basic' types on a per OpenGL implementation/library basis. These are reasonably defined. But use these rather than explicit C++ types wherever possible to retain portability. As we are effectively cross-compiling to lots of system target types with the E@H supplied screensaver graphics framework, this is quite important.

( edit ) And BMP is an older & simpler ( uncompressed ) format, likely to be readily available for conversion from some other image format into it, by even basic image software. I worked with the above image purely within M$ Paint, starting with a jpeg.

I have made this letter longer than usual because I lack the time to make it shorter. Blaise Pascal

Oliver Behnke
Oliver Behnke
Moderator
Administrator
Joined: 4 Sep 07
Posts: 768
Credit: 25,160,422
RAC: 0

Hi Mike, I'd like to

Message 78043 in response to message 78042

Hi Mike,

I'd like to comment on your intended image resource handling. IMHO it's much easier to simply add your favourite images "as is" using ORC, so don't strip them down to the bare naked pixel data. The reason for this is that SDL provides methods to import a variety of image data which can then be turned into an OpenGL texture! This way you (almost) don't have to care about the individual image file formats.

The first step is to create a SDL_Surface from a Resource. You'll find an example in the framework's WindowManager::setWindowIcon() that's being called in starsphere's main().

In the second step you use the SDL_Surface you just created and turn it into an OpenGL texture. You can find one example of this procedure here.

Edit: BTW, I like your idea and I'm very curious to see a first picture of how Einstein looks like!

HTH,
Oliver

 


Einstein@Home Project

Mike Hewson
Mike Hewson
Moderator
Joined: 1 Dec 05
Posts: 6,020
Credit: 102,111,364
RAC: 166,451

RE: I'd like to comment on

Message 78044 in response to message 78043

Quote:
I'd like to comment on your intended image resource handling.


Comment away! Many hands make the blinkin' light work .... ;-)

Quote:
IMHO it's much easier to simply add your favourite images "as is" using ORC, so don't strip them down to the bare naked pixel data.


Hmmmm ..... for some reason I've evidently acquired the idea that I have to stuff everything into the one executable with maximal efficiency. Not so. Ah, that makes life easier. :-)

I honestly can't say why that assumption snuck in! I'm solving the wrong problem. No kidding, my first programming experience ever was assembler on an 8088. The old habit of crawling on hands 'n knees. Just can't get away from the bit twiddling, shaving them bytes 'n cycles. 'Spelunker' anyone? :-)

Quote:
The reason for this is that SDL provides methods to import a variety of image data which can then be turned into an OpenGL texture! This way you (almost) don't have to care about the individual image file formats.


Neat, so for my plans I'll still need a format with per pixel alpha's. Can do ( reaches for PhotoShop ..... ) and I can set the eyeball/pupils to no-blend. I think I'd focussed on the bit about OpenGL per se not loading image files, but if SDL_Image is written to do so then one can easily go that route.

Quote:

The first step is to create a SDL_Surface from a Resource. You'll find an example in the framework's WindowManager::setWindowIcon() that's being called in starsphere's main().

In the second step you use the SDL_Surface you just created and turn it into an OpenGL texture. You can find one example of this procedure here.


Thank you so much for taking the time ! And thanks for those links. :-)

Quote:
Edit: BTW, I like your idea and I'm very curious to see a first picture of how Einstein looks like!


Well, I originally thought of using the photo where he pokes his tongue out. But I thought I'd stay more conservative for a first attempt. :-)

Since I seem to be doing a spot of trailblazing here, I'll keep the commentary up. Might be useful to others, and ought be entertaining for y'all to watch. :-)

[ Certainly helps me. ]

Cheers, Mike.

( edit ) Here's an interesting challenge. Easy to shade the Earth, right? Just specify a light source at .... the Sun! Get a nice shadow effect on the dark side. Be nice to have a 3D effect for the Sun though, so it doesn't just look like a flat circle. Texture helps, yes. However it would look a tad odd having a light source off the ecliptic and causing the Sun to cast a shadow on the orbit ellipse! Not to mention the Earth having two shadows from two sources. Maybe wrap a texture around the sphere object that will be the Sun, then apply 'limb darkening'. This is a real astronomical effect where the outer area of the Sun's disc appears darker than the middle of the face. Depth of photosphere etc. Try a mask of sorts b/w the Sun and the viewpoint/camera? Needs work ....

I have made this letter longer than usual because I lack the time to make it shorter. Blaise Pascal

Mike Hewson
Mike Hewson
Moderator
Joined: 1 Dec 05
Posts: 6,020
Credit: 102,111,364
RAC: 166,451

Here's my first try at

Here's my first try at massaging the framework ( sorry, only a Linux executable today ) :

- no constellations drawn
- supernovae and pulsars have some transparency
- a new list drawn up of some 250 stars with their visual magnitudes and spectral type employed, such that brighter stars are rendered larger and in the rough color of their spectral class.

To do / wish list :

- expand the diameter of starsphere dramatically
- start rendering a solar system at the centre
- default viewing position nearby the solar system
- default 'lazy orbit' / 'tour' when unattended
- 'fly-by-wire' using keypad ( speed, pitch and roll ), with some basic kinematic model
- switching of graphics complexity ( low/medium/high )

A key efficiency is using openGL display lists ( create once, use many times ).

Cheers, Mike

I have made this letter longer than usual because I lack the time to make it shorter. Blaise Pascal

PovAddict
PovAddict
Joined: 31 Mar 05
Posts: 45
Credit: 1,634,604
RAC: 741

RE: Here's my first try at

Message 78046 in response to message 78045

Quote:
Here's my first try at massaging the framework ( sorry, only a Linux executable today )


You are using Einstein screensaver framework code as a base, which is GPL. So if you release an executable, you have to release the corresponding code.

Mike Hewson
Mike Hewson
Moderator
Joined: 1 Dec 05
Posts: 6,020
Credit: 102,111,364
RAC: 166,451

RE: RE: Here's my first

Message 78047 in response to message 78046

Quote:
Quote:
Here's my first try at massaging the framework ( sorry, only a Linux executable today )

You are using Einstein screensaver framework code as a base, which is GPL. So if you release an executable, you have to release the corresponding code.


Whoops .. thanks for that. :-)
Here it is. Very much a work in progress, lacks full commenting etc. However some main points are:

- you have to fiddle with the build script alot. Slot in yourprojectname for starsphere where mentioned mutatis mutandis. Here is the build script that I use, BUT as I've had to massage it for my Linux system, it's very specific.

- you need to fiddle with the makefiles alot ( I now see Oliver's earlier point about automake et al .... ). Only the Linux makefile is valid, yet.

- my SolarSystem class directly derives from AbstractGraphicsEngine ( so no starsphere and subsequent variants ), thus trimmed the relevant files and other entries. Mind you, I've pinched the Starsphere interface/code and re-named to suit, but deleted some aspects ( additional observatories, constellations ).

- you have to fiddle with the GraphicsEngineFactory class. Insert an enumeration constant for your variant and have the code able to select that.

- a small change to main.cpp too.

- the underlying Starmap data structure is a fudge/kludge around the fact that you can't have array style initialisation of the std::vector class ( which I'd prefer to use ). Otherwise you'd have to load the vector from an array ( do-able, but it double handles stuff ), or not bother encapsulating at all ( retaining the original C style array and extern ).

Cheers, Mike.

( edit ) Here is the source of the star data from which I derived the Starmap entries. I included in the Starmap class, but have not yet utilised, the star names.

( edit ) Might extract some commonalities and make Starmap a base class ......

I have made this letter longer than usual because I lack the time to make it shorter. Blaise Pascal

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.