Write your own Einstein@home screensaver

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

RE: ***Blush***. That was a

Message 78362 in response to message 78361

Quote:
***Blush***. That was a Coding 101 Numpty Prize right there Mike ! :-)


;-)

 

Einstein@Home Project

Mike Hewson
Mike Hewson
Moderator
Joined: 1 Dec 05
Posts: 6,124
Credit: 124,555,221
RAC: 81,072

Hah ! Thank you Oliver ...

Hah ! Thank you Oliver ... :-)

Now here's a thing, when you use

TTF_RenderText_Solid() and then

SDL_Surface* SDL_ConvertSurfaceFormat(SDL_Surface* src,
                                      Uint32       pixel_format,
                                      Uint32       flags)

"Use this function to copy an existing surface into a new one that is optimized for blitting to a surface of a specified pixel format"


you actually get an SDL_Surface which is deemed suitable for blitting. Blitting ( generically ) = "several bitmaps are combined into one using a boolean function." This is not what is needed here. Especially as the 'Solid' surface option stores pixel values as "Palette index 0 is of course not drawn when blitted to another surface, since it is the colorkey, and thus transparent, though its actual color is 255 minus each of the RGB components of the foreground color". What this really means is that the color values stored per pixel are in a format that assumes one will use ( SDL ) blitting functions to finally render on screen. Thus some later boolean function use is implicit here. I won't be doing that as the 'screen' is an OpenGL entity ( a window with a context ) that I am managing in all it's glory, not an SDL_Surface, and so whatever underlying SDL blitting functions might be invoked don't refer to the visible display entity anyway.

[ Which is one reason why I bother with all this texture business, the other reason is that SDL_Surface's are 2D only with precisely no perspective semantics available. AFAIK no one else is attempting to do precisely what I am ie. a full 3D display engine, only using font facilities to yield the glyph patterns -> OpenGL textures. I am finally discovering why no one has done this before ..... :-) ]

The Good News : in any event by using the ApiTrace facility I have found that I have indeed succeeded in getting an OpenGL texture into the state machine ( rectangular surface representing the string : "Einstein At Home" ) for access by a texture shader at runtime. Yeah! It is recognisable as such when visited by ApiTrace, however it 'looks funny' on screen at the moment - to be exact invisible - because all the alpha values are zero. LOL! :-))

{ Instead of : RGB @ 8 bits per color, then that would be RGBA @ 8 bits per color, no ? }

To be continued ....

Cheers, Mike.

( edit ) One especial issue with some of the 'open' efforts is less-than-evident documentation with much unsaid, ambiguities etc. Thus one tends to slide towards Stack Overflow and the like, which is all too frequently the blind leading the blind and "well, it worked for me !" type of stuff. The contributors are rated by thumbs up/down voting rather than whether they are actually correct. Popular does not equate to true alas, or should I say that correctness is not the metric used. I am also amazed by the number of responders who tend to reply according to what they think they know, thus giving the appearance of cleverness at least, rather than with reference to the specific question(s) as asked to which they have definitely failed to provide an answer. This I'm guessing is the IT equivalent of Doctor Google.

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,124
Credit: 124,555,221
RAC: 81,072

Forgive me for thinking out

Forgive me for thinking out loud. The way forward is pretty clear.

So you can't assume a simple pointer to the interior of the SDL_Surface :

SDL_Surface named_sdl_surface_pointer_variable;
named_sdl_surface_pointer_variable->pixels;


.... gives access to an RGBA value straight off the bat. That as I have demonstrated just falls over. You have to go via the SDL interface and discover things. Hence first determine what the surface divulges as it's format :

disclosed_enum_format = named_sdl_surface_pointer_variable->format .... and inspect this SDL_PixelFormat value. That in turn has an SDL_PixelFormatEnum field, now check that with the macro SDL_ISPIXELFORMAT_INDEXED :

SDL_ISPIXELFORMAT_INDEXED(disclosed_enum_format) .... for truth ie. is a palette is involved ?

Quote:

As a double check you want a value of 1 ( one ) to be revealed by

named_sdl_surface_pointer_variable->format.BitsPerPixel

If so ( and you expect this to be so by the way TTF_RenderText_Solid() is defined ), you go back to the given SDL_PixelFormat value and examine the palette field :

disclosed_palette = disclosed_enum_format->palette ... which is turn you can use :

disclosed_palette.ncolors;
disclosed_palette.colors;


to check that you have 2 colors available. The first is that which gives a transparent background when blitted, the second ought be the color you originally nominated when blitted ! Good that I've cleared that up ..... :-))))

Believe it or not, having verified that one is in fact in The Right Sort Of Tiger Country, one can now just ignore the actual palette colors. "All you have to do now" is step through what is now truly a bitmap

named_sdl_surface_pointer_variable->pixels on the unconverted surface and directly construct an OpenGL texture with the following 32 bits per pixel fashion :

- if a bit is zero put an RGBA value showing black & transparent ie. {0, 0, 0, 0}.

- if a bit is one put an RGBA value showing desired_color & opaque ie. {R, G, B, 1}

Cheers, Mike.

( edit ) This would only work for the Solid option, there will have to be a related but similar heuristics for the Shaded and Blended varieties.

( edit ) For most text strings, notably with Starsphere, this would be a once-per-runtime procedure as content doesn't change much. For other varying text presentations then the obvious solution is to construct and cache individual glyphs in an array, and then composite per frame using ASCII values as indices. You'd lose kerning though but for numerical display eg. RAC etc that may be no big deal.

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,124
Credit: 124,555,221
RAC: 81,072

Some General Design

Some General Design Notes

As previously indicated ( somewhere in this thread ) it is the case that the new OpenGL paradigm ( version 3.2 + ) is to manipulate the pipeline internals directly via various API calls. You use the front-end to create/fashion in considerable detail the functionality of the back-end, AND you can't escape this requirement. My ogl_utility library is an attempt to blunt that daunting task.

While writing I have discovered several major ( but simple ) ideas which I will fully encapsulate as virtual classes ( later when the dust settles a bit and I have actually emitted working product ). These ideas are present now, but ad-hoc as it were, and relate to the management of the state machine's objects eg. a shader, a buffer, a vertex array object etc. In other words, while writing the library I have disclosed some useful abstractions not apparent earlier. You find out what you didn't know that you didn't know. :-)

Each OpenGL object is handled currently by an identifier ( represented as a 32 bit unsigned integer ) that the application programmer uses when referencing them via the API. This is rather like window handles in M$, process IDs in Linux etc. Thus some API call has an argument position that needs to be filled in with a valid instance of that identifier. Key issues to address :

- get an identifier ( the 'name' ) of correct type for purpose. So there isn't a generic 'get me an identifier' call, you have a 'get me an identifier that relates to OpenGL state machine object of type X'. The exact syntax of that request is per type.

- the awarding of a particular identifier, available to the application programmer on return from one of the above 'get me an identifier ...' calls. The state machine will create such an object with a default internal state and/or accounting what is specified with the call. But that per se does not always imply immediate readiness for use. So ...

- there needs to be a configuration aspect ie. is said object containing such as is needed to perform correctly for purpose ? Again that will in detailed syntax be varying according to what type is relevant. For example I would need to populate a texture with some sensible pixel pattern.

- at runtime there are typically many objects created and extant in the state machine. Some may be of the same type eg. several fragment shaders, but only one is used at a time. So one needs to bind and select - on the fly now - the appropriate one that also works with the appropriate one(s) of another type. Thus a particular fragment shader is expecting a specific type of instance of texture buffer. A vertex shader generally assumes a set of structures and relations amongst them, of input buffers and vertex array object ( the pipeline trigger ).

I could summarise these using the verbs : Acquire, Configure and Bind.

- firstly these must be separable behaviours by virtue of how the state machine goes around it's business ( complex explanation omitted ).

- secondly if placed in C++ class hierarchy they must be virtual ie. detail left to derived classes.

- thirdly on program startup you cannot assume the presence of a state machine ( read : valid rendering context ), thus none of this can be placed in constructors.

- fourthly one can enforce sequence dependencies ( and there are plenty! ) by hiding an acquisition call within a configuration call within a binding call, with the effect that first use of an object implies completely correct state is made available for each verb.

- fifthly these are enacted via multiple inheritance for many of the classes. But this is OK as we still have a directed acyclic graph for the inheritance structure ( no loops and thus no confusion about which intermediate entities one gets properties and methods from ).

For example here is my initial crack at a Configure base class :

Configure.h

/***************************************************************************
* Copyright (C) 2016 by Mike Hewson *
* hewsmike[AT]iinet.net.au *
* *
* This file is part of Einstein@Home. *
* *
* Einstein@Home is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
* by the Free Software Foundation, version 2 of the License. *
* *
* Einstein@Home 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 Einstein@Home. If not, see . *
* *
***************************************************************************/

#ifndef CONFIGURE_H_
#define CONFIGURE_H_

#include "ogl_utility.h"

/**
* \addtogroup ogl_utility OGL_Utility
* @{
*/

/**
* \brief This interface declares public methods to deal with those objects
* that require configuration/setup before first use.
*
* \author Mike Hewson\n
*/

class Configure {
public :
/**
* \brief Constructor.
*/
Configure(void);

/**
* \brief Destructor.
*/
virtual ~Configure();

/**
* \brief Use this object. Configuration is ensured.
*/
void utilise();

private:
bool m_configure_flag;

/**
* \brief actually configure the underlying object.
*
* \return a boolean indicating success of configuration
* - true, the configuration as successful.
* - false, the configuration was not successful.
*/
virtual bool m_configure(void) = 0;

virtual void m_utilise(void) = 0;
};

/**
* @}
*/

#endif /*CONFIGURE_H_*/


Configure.cpp

/***************************************************************************
* Copyright (C) 2016 by Mike Hewson *
* hewsmike[AT]iinet.net.au *
* *
* This file is part of Einstein@Home. *
* *
* Einstein@Home is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
* by the Free Software Foundation, version 2 of the License. *
* *
* Einstein@Home 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 Einstein@Home. If not, see . *
* *
***************************************************************************/

#include "Configure.h"

#include "ErrorHandler.h"

Configure::Configure(void) :
m_configure_flag(false) {
}

Configure::~Configure() {
}

Configure::utilise(void) {
// Has a successful configuration been achieved ?
if(m_configure_flag == false) {
// No, so attempt to do that.
bool check = m_configure();
// Did configuration succeed ?
if(check == false) {
// No, so that's a FATAL.
ErrorHandler::record("Configure::utilise() : object configuration failed", ErrorHandler::FATAL);
}
// Yes, so mark this aspect as having been done.
m_configure_flag = true;
}
// Now the object must have been successfully configured, so use it.
m_utilise();
}


... so there are pure virtual definitions within. Little by way of 'default' happens.

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,124
Credit: 124,555,221
RAC: 81,072

There you go, doesn't look

There you go, doesn't look like much :

but that's a snapshot of rotating text on a transparent parallelogram in 3D hovering within the StarSphere ! :-))

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,124
Credit: 124,555,221
RAC: 81,072

Managing The

Managing The Transforms

There are basically two modes of geometric transform for the screensaver to work :

- the 3D mode which gives the illusion of moving objects within some world space. This is called a perspective viewpoint.

- the 2D mode which gives alot of text, but maybe logo images, as if there was a Heads Up Display ( HUD ). This is called an orthographic viewpoint.

Now there are very many objects that need to know some basic information about the current geometric state of the AbstractGraphicsEngine instance. And you want these things to not have their interfaces/hierarchies etc polluted by passing such geometric state data via their argument lists. Lest one winds up with a non-intuitive mess, certainly inefficient, error prone and has a maintenance burden. How to solve this issue ?

The approach I have chosen is to use program level global variables, but I want to avoid many of the possible problems of using such creatures. In particular I want to make sure that someone, including myself, that uses the ogl_utility library has a low chance of screwing it up. After all the 3D illusion that is created by the OpenGL state machine requires that all objects in the world/model space agree upon what is the viewing transform. This is a 4x4 matrix of floats and serves to convert world space coordinates to what will be Normalised Device Coordinates ( after perspective division and a few other things ), that then wind up after rasterisation being emitted as the screen position of pixel candidates ( called fragments ). For correct HUD display you want to be able to transform 2D position coordinates to pixel positions. Yes, this is the modern OpenGL programming paradigm. You have to do all that stuffing about yourself .... :-(

so in the vertex shader GLSL code you want something like this for 3D work :

// This is the all important 3D transform matrix
// with values set from client code per rendering frame.
uniform mat4 CameraMatrix;
.
.
void main()
{
    vec3 position = vec3(0.0, 0.0, 0.0);
.
.
    // Stuff determining value of 'position' variable per vertex.
    // Plus whatever else floats your boat.
.
.
    // Emit final position of the vertex.
    gl_Position = CameraMatrix * vec4(position, 1.0f);
}


and likewise this for 2D work :

// These are the all important 2D transform scaling factors
// with values set from client code per rendering frame.
uniform vec2 OrthographicScalars;
.
.
void main()
{
    vec2 position = vec2(0.0, 0.0);
.
.
    // Stuff determining value of 'position' variable per vertex.
    // Plus whatever else floats your boat.
.
.
    // Emit final position of the vertex.
    gl_Position = position * OrthographicScalars - vec2(1,1);
}


Specifically I create a new class to manage this and put it in with the ogl_utility group to be incorporated into the runtime library.

/***************************************************************************
 *   Copyright (C) 2016 by Mike Hewson                                     *
 *   hewsmike[AT]iinet.net.au                                              *
 *                                                                         *
 *   This file is part of Einstein@Home.                                   *
 *                                                                         *
 *   Einstein@Home is free software: you can redistribute it and/or modify *
 *   it under the terms of the GNU General Public License as published     *
 *   by the Free Software Foundation, version 2 of the License.            *
 *                                                                         *
 *   Einstein@Home 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 Einstein@Home. If not, see . *
 *                                                                         *
 ***************************************************************************/

#ifndef TRANSFORM_GLOBALS_H_
#define TRANSFORM_GLOBALS_H_

#include "framework.h"

/**
* \addtogroup ogl_utility OGL_Utility
* @{
*/

/**
* \brief %OGL_Utility This class provides a common point for setting and
* accessing some global variables relevant to transforms.
*
* This static/singleton class was created to prevent pollution of
* function interfaces with the values of certain widely needed variables :
*
* - the location of the 4x4 float matrix representing the model/view
* perspective transform. It is a matter of programmer rigour to assure that :
* - inadvertent dereferencing does not occur ie. such a location
* ought be valid for all usage instances. Only one action of
* setting the value is allowed. A fatal error is generated if
* accessed before being set.
* - have suitable and consistent GLSL typing with respect to
* shader code as used.
*
* - the dimensions of the client screen area ie. it's width and height.
* These may be set to new values as often as desired eg. after screen resizing.
*
* - I include a helper function to precalculate the uniform variable that
* would be used for proper scaling to the screen client area in Normalised
* Device Coordinates. This could be useful for orthographic projections.
*
* \author Mike Hewson\n
*/

class TransformGlobals {
public:
/**
* \brief Destructor
*/
~TransformGlobals();

/**
* \brief Set the location of the 3D transform matrix. This is enacted
* so as to only allow this to happen once.
*
* \param load_point : an untyped address of the matrix in client code.
* Obviously that should be persistent and
* available before first dereference.
*/
static void setTransformMatrix(GLvoid* load_point);

/**
* \brief Get the location of the 3D transform matrix.
*
* \return the address of the matrix in client code as stored here.
* Obviously that should be set to a valid location prior
* to the first dereference. A FATAL error will be generated
* if this is called before value setting has occured via
* setTransformMatrix().
*/
static GLvoid* getTransformMatrix(void);

/**
* \brief Set the width and the height of the client screen area.
*
* \param height : the height of the client screen area in pixels.
* \param width : the width of the client screen area in pixels.
*/
static void setClientScreenDimensions(GLuint height, GLuint width);

/**
* \brief Get the height of the client screen area.
*
* \return the height of the client screen area in pixels.
*/
static GLuint getClientScreenHeight(void);

/**
* \brief Get the width of the client screen area.
*
* \return the width of the client screen area in pixels.
*/
static GLuint getClientScreenWidth(void);

/**
* \brief Get a value suitable for uniform use representing the
* scaling to Normalised Device Coordinates (NDC).
*
* The gl_Position value emitted by a vertex shader must lie
* within the range of NDC ie. [-1,+1]. Assuming the input position
* is in pixels then within GLSL code :
*
* gl_Position = position*vec2(2.0/width, 2.0/height) - vec2(1,1)
*
* gives : (0, 0) maps to [-1, -1] and
* (width, height) maps to [+1, +1].
*
* \return a glm::vec2 containing the correct values for use as described.
*/
static glm::vec2 getClientScreenUniform(void);

private:
/// The 3D transform matrix, which can be set once only.
static GLvoid* m_transform_matrix;
static bool m_transform_matrix_set;

/// The current width and height values of the client screen area.
/// This can be set/reset many times
static GLuint m_height;
static GLuint m_width;

/**
* \brief Constructor ( private since this a static class )
*/
TransformGlobals(void);
};

/**
* @}
*/

#endif // TRANSFORM_GLOBALS_H_


/***************************************************************************
 *   Copyright (C) 2016 by Mike Hewson                                     *
 *   hewsmike[AT]iinet.net.au                                              *
 *                                                                         *
 *   This file is part of Einstein@Home.                                   *
 *                                                                         *
 *   Einstein@Home is free software: you can redistribute it and/or modify *
 *   it under the terms of the GNU General Public License as published     *
 *   by the Free Software Foundation, version 2 of the License.            *
 *                                                                         *
 *   Einstein@Home 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 Einstein@Home. If not, see . *
 *                                                                         *
 ***************************************************************************/

#include "TransformGlobals.h"

#include "ErrorHandler.h"

/// Initial values of static variables.
/// 3D transform address unknown.
GLvoid* TransformGlobals::m_transform_matrix(NULL);
/// Transform address not yet set.
bool TransformGlobals::m_transform_matrix_set(false);
/// Screen has zero dimensions.
GLuint TransformGlobals::m_height(0);
GLuint TransformGlobals::m_width(0);

TransformGlobals::TransformGlobals(void) {
}

TransformGlobals::~TransformGlobals(){
}

void TransformGlobals::setTransformMatrix(GLvoid* load_point) {
// Can only do this once.
if(m_transform_matrix_set == false) {
m_transform_matrix = load_point;
m_transform_matrix_set = true;
}
}

GLvoid* TransformGlobals::getTransformMatrix(void) {
if(m_transform_matrix_set == false) {
ErrorHandler::record("TransformGlobals::getTransformMatrix() : access attempt before set !",
ErrorHandler::FATAL);
}
return m_transform_matrix;
}

void TransformGlobals::setClientScreenDimensions(GLuint height, GLuint width) {
m_height = height;
m_width = width;
}

GLuint TransformGlobals::getClientScreenHeight(void) {
return m_height;
}

GLuint TransformGlobals::getClientScreenWidth(void) {
return m_width;
}

glm::vec2 TransformGlobals::getClientScreenUniform(void) {
return glm::vec2(2.0/m_width, 2.0/m_height);
}


Another alternative solution considered was C++ 'friend' declarations, but that is generally worse again.

Cheers, Mike.

( edit ) Ooops. I'll add constant semantics to the pointer returned from getTransformMatrix() to prevent other entities changing the value being pointed to. Of course the object that ought set the value via setTransformMatrix() should be the owner/manipulator of that transform eg. Starsphere. Ditto for the screen dimensions.

( edit ) In case it is not clear : the values within the 4x4 transform matrix can be altered by whomsoever owns it as per C++ scoping rules. It is the location of that matrix which is being fixed once set. This allows efficient construction of many persistent OpenGL state machine objects ( please take my word for it ! ) with little per-frame overhead. Make each one once on program startup and then just run them once per frame in some desired order. All by magic .... :-))

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,124
Credit: 124,555,221
RAC: 81,072

Managing The Uniforms [ aka

Managing The Uniforms [ aka more boring programmer's detail .... ]

This is key for any serious rendering. A uniform is a pathway from your client code into the GLSL shaders ( all types ). At runtime any GLSL shader must first pass compilation and then be absorbed into a GLSL program entity which in it's turn must be successfully linked. During the linkage process uniform variables each acquire an index value. That index value is then used with glUniform*() calls ( very many types ) in order to load a client side value ( ie. in the address space of the application program that is hosting an instance of the OpenGL state machine ) into the shader. You would typically do that at least once per rendering frame. Examine this portion of vertex shader ( from the TexturedParallelogram class ) :

uniform vec3 base_position;
uniform vec3 height_offset;
uniform vec3 width_offset;
uniform mat4 CameraMatrix;


and note the correspondence with debug output ( on standard output ) :

INFO : Shader::compile() : GL_VERTEX_SHADER ( ID = 1 ) did compile ... 
INFO : Shader::compile() : GL_FRAGMENT_SHADER ( ID = 2 ) did compile ... 
INFO : Program::acquire() : attaching vertex shader with ID = 1 to program with ID = 3
INFO : Program::acquire() : attaching fragment shader with ID = 2 to program with ID = 3
INFO : Program::mapUniforms() : name = base_position		type = GL_FLOAT_VEC3		position = 0		client location = 0x128663c
INFO : Program::mapUniforms() : name = height_offset		type = GL_FLOAT_VEC3		position = 1		client location = 0x1286648
INFO : Program::mapUniforms() : name = width_offset		type = GL_FLOAT_VEC3		position = 2		client location = 0x1286654
INFO : Program::mapUniforms() : name = CameraMatrix		type = GL_FLOAT_MAT4		position = 3		client location = 0x11ac6f4
INFO : Program::frameCallBack() : uniform name = CameraMatrix
INFO : Program::loadUniform() : type = GL_FLOAT_MAT4		position = 3		client location = 0x11ac6f4
INFO : Program::frameCallBack() : uniform name = base_position
INFO : Program::loadUniform() : type = GL_FLOAT_VEC3		position = 0		client location = 0x128663c
INFO : Program::frameCallBack() : uniform name = height_offset
INFO : Program::loadUniform() : type = GL_FLOAT_VEC3		position = 1		client location = 0x1286648
INFO : Program::frameCallBack() : uniform name = width_offset
INFO : Program::loadUniform() : type = GL_FLOAT_VEC3		position = 2		client location = 0x1286654
INFO : Program::frameCallBack() : uniform name = CameraMatrix
INFO : Program::loadUniform() : type = GL_FLOAT_MAT4		position = 3		client location = 0x11ac6f4
INFO : Program::frameCallBack() : uniform name = base_position
INFO : Program::loadUniform() : type = GL_FLOAT_VEC3		position = 0		client location = 0x128663c
INFO : Program::frameCallBack() : uniform name = height_offset
INFO : Program::loadUniform() : type = GL_FLOAT_VEC3		position = 1		client location = 0x1286648
INFO : Program::frameCallBack() : uniform name = width_offset
INFO : Program::loadUniform() : type = GL_FLOAT_VEC3		position = 2		client location = 0x1286654


The Program::mapUniforms() member function interrogates the linker to determine what it believes to be 'active uniforms'. It is a key/important to establish that. You may have made an error writing GLSL code - I certainly have ! - that contains variables of no consequence. This means that analysis of your provided shader code by the linker ( read : OpenGL context/state-machine at runtime ) has determined that some useless variable(s) exist that have no effect on output. The linker is cleverly written and can't be fooled. Fortunately attempting to load a value into a non-active or otherwise invalid uniform has no effect other than generation of a warning message to that effect.

The 'position' field as reported in the "INFO : Program::mapUniforms()" lines give that crucial linker granted program index. That index is then used in the Program::loadUniform() function as a target for loading from client side. The Program::frameCallBack() function triggers the loading of each active uniform in turn.

Quote:
the implementation of which uses an std::map template type with key/value pairs being uniform variable name and a data structure :
private:
    // Data structure containing the relevant parameters for
    // a uniform variable.
    struct uniform_data{
	// Untyped pointer to location of persistent data in client space
	// which will be used to refresh the in-program value.
	GLvoid* client_load_point;

// The uniform variable type as known to OpenGL.
GLenum GLSL_type;

// The location of the uniform within the OpenGL program object.
GLint program_location;
};
.
.
.
/// Map to track the active uniform variables within the OpenGL
/// program entity. Active means those declared and used within
/// the shader code. Inactive uniforms are those that are declared
/// but not otherwise usefully referenced ie. the OpenGL compiler
/// may ( and probably will ) ignore them and thus discard any
/// reference to them.
typedef std::map uniformMap;
uniformMap uniforms;

The choice being either map or multimap from the C++ STL here. But as this code will not suffer duplicate keys then std::map is the go.

Cheers, Mike.

( edit ) FWIW my solarsystem-sld2 repo branch "... is 1005 commits ahead of master." :-)

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,124
Credit: 124,555,221
RAC: 81,072

Ha! Now that I've been

Ha! Now that I've been wasting an enormous amount of otherwise potentially productive time sporadically browsing CommitStrip [ .... thank you Oliver! ;-) ], I have discovered what Problem Exists Between Keyboard And Chair means :

One of the better LOL's this year to date. :-0

Cheers, Mike.

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: 827
Credit: 25,160,422
RAC: 0

So what's the moral of this?

Message 78370 in response to message 78369

So what's the moral of this? Without Flat Eric watching over your shoulders you're just a mere mortal...!

 

Einstein@Home Project

MAGIC Quantum Mechanic
MAGIC Quantum M...
Joined: 18 Jan 05
Posts: 1,298
Credit: 412,438,657
RAC: 58,569

(ok I had to fix that

(ok I had to fix that *viewed* total when I saw that 66666 views)

 

Comment viewing options

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