Table Top Framework Simple Image Component
<< Back to the Tabletop Framework page
Building a simple image Component
This tutorial gives a brief overview how to build a simple square Component that can be decorated with a texture.
| It is very useful (if not even necessary) to have a good understanding of the framework architecture from reading the information provided in the Getting Started section. |
Overview
...
Implementing the interfaces
A Component has to take care of different things by itself. The most important of these are its geometrical representation and how it processes information retrieved from connected buffers.
Which interfaces to implement
To integrate this functionality automatically into the framework and an application, the following methods have to be implemented:
virtual void specificRender(bool forPicking); // how the Component renders itself
virtual void initialize(); // geometry and other setup
virtual void initializePassiveBuffers(); // specifies which passive buffers this Component can process
Render method
The render method reflects that there is a color picking scheme used in the framework. Thus, a special flag is provided with each call of the method to know what to render. The image Component does not need this flag, as it uses only textures (which are disabled anyway during rendering for picking) and no colors for decoration.
{
glPushMatrix();
// transformation that are applied to every Component
// rotation, scaling, ... with the respective attributes
doCommonTransformations();
glBindTexture(GL_TEXTURE_2D, _textureId); // exchange the texture
glCallList(_dlIdForAllImages); // base image display list
// if we are not picking we want to show the interaction hints
if (!forPicking && !getParent())
{
glCallList(_dlIdForAllImages+1);
}
Interaction can also be visalized, for this the attribute _selectionActive is set by the framework if the user is interacting with the Component. For the image Component, we render some special cues during interaction by calling the display list we build for this purpose (a red box around the Component).
// show the highlight if selected
if(_selectionActive)
{
glCallList(_dlIdForAllImages+2); // highlight display list
}
glPopMatrix();
return;
}
Local information processing
One of the most effective and important ideas of the buffer concept is the local information processing. This puts the smarts into the single Components and relieves the interface Components from complex calculations and steering operations.
To achieve this, a Component implements the following method and decides there, how to react to the values retrieved from connected buffers.
This is the general part of the logic that checks if there is a parent available and if buffers exist:
{
// we need a parent (for the buffers) and this parent should not be part of something else
if (getParent() && !getParent()->getParent())
{
// retrieve our passive buffers (the links to our parents' active buffers)
BufferTemplate<float>* _directionBuffer = (BufferTemplate<float>*) getPassiveBuffer(DIRECTION_2D_FLOAT);
BufferTemplate<float>* _speedBuffer = (BufferTemplate<float>*) getPassiveBuffer(SPEED_1D_FLOAT);
BufferTemplate<float>* _sizeBuffer = (BufferTemplate<float>*) getPassiveBuffer(SIZE_1D_FLOAT);
BufferTemplate<float>* _orientationBuffer = (BufferTemplate<float>*) getPassiveBuffer(ORIENTATION_2D_FLOAT);
BufferTemplate<unsigned char>* _colorBuffer = (BufferTemplate<unsigned char>*) getPassiveBuffer(COLOR_3D_UCHAR);
// temps
static float direction[2], orientation[2];
float speed, size;
double pX, pY;
getParent()->getLocalCoordinates(_pos[0], _pos[1], &pX, &pY);
if ( (pX > -1) && (pY > -1) )
{
Here, the specific values at the current location are retrieved and internal attributes adjusted accordingly. (For safety reasons, the existence of the respective buffer is checke before acccess.)
// move myself
if(_directionBuffer)
{
_directionBuffer->getTwoValues(pX, pY, direction);
if (_speedBuffer)
{
_mySpeed = _mySpeed + _mySpeed + _mySpeed;
speed = (_speedBuffer->getValue(pX, pY) * milliseconds + _mySpeed) * 0.25;
_mySpeed = speed;
_pos[0] += direction[0] * speed;
_pos[1] += direction[1] * speed;
}
}
if (_orientationBuffer)
{
// orient myself
_orientationBuffer->getTwoValues(pX, pY, orientation);
_rotationDegrees = -acos(orientation[1]) * _copysign(RADIANS_TO_DEGREES_FACTOR, orientation[0]);
}
if (_sizeBuffer)
{
// properties for myself
_mySize = _mySize + _mySize + _mySize;
size = (_sizeBuffer->getValue(pX, pY) + _mySize) * 0.25;
_mySize = size;
setRadius(size); // sets both to the same (size)
}
}
}
return;
}
Local rendering optimizations
The number of image Components can be very high. To save memory there is only one display list used for all images and only the texture is exchanged. If the last image is deleted, the display list is also discarded.