Managing nested glPolygonOffset usage

Sage
Posts: 1,199
Joined: 2004.10
Post: #1
I have a surprising amount of nested glPolygonOffset usage in my game. I use it for solid wireframing, for decals, for projection of a shadow volume, for drawing the lit pass, etc etc. It's becoming a bit of a pain to manage correctly -- in fact, in twiddling to get output right on NVIDIA and ATI, I've managed to come up with -- at the best -- something which looks mediocre on all hardware ( as in, basically it looks good, but there's a little z-fighting of the shadow volume, and solid wireframing isn't as tight as I'd hope ).

So, I was thinking I might have a global polygon offset manager, of sorts. It seems to me, that I could maintain my own 'factor' and 'units', and add whatever is passed in to the global value, then set glPolygonOffset to that global sum. E.g.

Code:
static GLfloat gFactor = 0, gUnits = 0;

void addPolygonOffset( float factor, float units )
{
    gFactor += factor;
    gUnits += units;

    glPolygonOffset( gFactor, gUnits );
}

void resetPolygonOffset( void )
{
    gFactor = gUnits = 0;
    glPolygonOffset( gFactor, gUnits );
}

This way, nested calls to change the polygon offset would add up, instead of overriding one another.

Is this a good idea?

Or, conversely, I was thinking I might maintain a stack, where you could push and pop offsets, so once some inner class is done with its drawing, it could pop its offsets and you'd be back to the polygon offset set up by the caller.

Basically, I'm just wondering how you'd robustly manage glPolygonOffset in situations of complex ( and unpredictable ) nesting. Does anybody have any experience here on how best to do this?
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #2
So, in case anybody cares, I implemented a stack-based approach over the weekend, and it works *beautifully*. Just beautifully.

So, for the benefit of anybody who might need this in the future, here's my PolygonOffset class:

First the header:
Code:
/*
*  PolygonOffset.h
*  Legion
*
*  Created by Shamyl Zakariya on 6/5/05.
*  Copyright 2005 Shamyl Zakariya. All rights reserved.
*
*/

#ifndef __POLYGON_OFFSET_H__
#define __POLYGON_OFFSET_H__

#include <map>
#include <vector>

/**
    @class PolygonOffset
    This is a wrapper for the OpenGL mechanism glPolygonOffset.
    PolygonOffset maintains a stack of polygon offsets, such that
    deeply nested uses of glPolygonOffset will work cleanly. Imagine,
    for example, the situation where you have a solid-wireframed object
    being drawn in a multi-pass lighting situation. You'll need to offset
    the fill of the solid so the wireframe can be drawn, but since the
    object has to be drawn at least twice ( for lighting ) you need differing
    offsets for each pass to prevent z-fighting. In a normal usage of
    glPolygonOffset one would have to keep track of the current pass
    and set offsets accordingly.
    
    But, with the stack-nature of PolygonOffset, one can simply push
    an offset, which will be added to the current offset. When done drawing,
    one pops the offset ( important, don't forget to pop ).
    
    For reasons of cleanliness, one should never disable GL_POLYGON_OFFSET_FILL
    and one should call reset() at the beginning of every drawing loop to
    zero the offset.    
*/

class PolygonOffset
{
    public:
    
        /**
            Push an offset -- this will be added to the
            current offset. Always call ::pop() when
            done drawing with this offset.
        */
        static void push( float factor, float units );

        /**
            Pop the most recently added offset.
        */
        static void pop( void );

        /**
            Resets the offsets to zero and empties the stack.
        */
        static void reset( void );
        
        /**
            @return the current offset factor
        */
        static float currentFactor( void ) { return _currentFactor; }

        /**
            @return the current offset units
        */
        static float currentUnits( void ) { return _currentUnits; }

    protected:
    
        PolygonOffset( void ){}
        
        typedef std::pair< float, float > Offset;
        typedef std::vector< Offset > OffsetVec;
        
        static OffsetVec _offsetStack;
        static float _currentFactor, _currentUnits;

};

#endif

And now, the implementation:

Code:
/*
*  PolygonOffset.cpp
*  Legion
*
*  Created by Shamyl Zakariya on 6/5/05.
*  Copyright 2005 Shamyl Zakariya. All rights reserved.
*
*/

#include "PolygonOffset.h"
#include <GL/glew.h>


/*
        typedef std::pair< float, float > Offset;
        typedef std::vector< Offset > OffsetVec;
        
        static OffsetVec _offsetStack;
        static float _currentFactor, _currentUnits;
*/

PolygonOffset::OffsetVec PolygonOffset::_offsetStack;
float PolygonOffset::_currentFactor = 0;
float PolygonOffset::_currentUnits = 0;


void PolygonOffset::push( float factor, float units )
{
    _currentFactor += factor;
    _currentUnits += units;
    
    _offsetStack.push_back( Offset( factor, units ));
    
    glPolygonOffset( _currentFactor, _currentUnits );
}

void PolygonOffset::pop( void )
{
    Offset offset( _offsetStack.back() );
    _currentFactor -= offset.first;
    _currentUnits -= offset.second;    
    _offsetStack.pop_back();
    
    glPolygonOffset( _currentFactor, _currentUnits );
}

void PolygonOffset::reset( void )
{
    _offsetStack.clear();
    _currentFactor = _currentUnits = 0;
    glPolygonOffset( _currentFactor, _currentUnits );
}

This works, for me. It solved my problems with nested glPolygonOffset calls.
Quote this message in a reply
Oldtimer
Posts: 834
Joined: 2002.09
Post: #3
You have no idea how much you look like an angel to me. It's like you wrote it just for my next project. Massive thanks.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #4
Awesome! Glad to hear it. And, I should have mentioned: don't worry about crediting me or anything, if you need it, use it. I spent all of 10 minutes writing it and 20 migrating my game. Not a biggy.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Memory usage question nerman 3 2,764 Mar 1, 2006 10:56 AM
Last Post: nerman
  Managing framerates, time, and such Holmes 7 4,004 Dec 3, 2002 09:23 PM
Last Post: Holmes