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 animateMyself(double milliseconds); // how buffer data is processed
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.

void ImageLeafGL::specificRender(bool forPicking)
{  
  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:

void ImageLeafGL::animateMyself(double milliseconds)
{
  // 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.