glut-state.cpp

Go to the documentation of this file.
00001 /*
00002  * glut-state.cpp
00003  *
00004  * Copyright (C) 2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * See glut-state.h
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "glut-state.h"                 // always include our own header first!
00036 
00037 #include "perf/perf.h"
00038 
00039 
00040 namespace glut {
00041 
00042 
00043 // interface destructors
00044 State::~State(void) throw() { }
00045 
00046 
00047 // statics
00048 
00049 
00050 
00051 
00052 ////////////////////////////////////////////////////////////////////////////////
00053 //
00054 //      StateImpl -- class that implements the glut::State interface
00055 //
00056 ////////////////////////////////////////////////////////////////////////////////
00057 
00058 class StateImpl : public State {
00059 public:
00060         // constructor, destructor ---------------------------------------------
00061         ~StateImpl(void) throw() { }
00062         StateImpl(void) throw() { }
00063 
00064         // public class methods ------------------------------------------------
00065         void snapshotFromOpenGL(void);
00066 
00067         // glut::State class interface methods ---------------------------------
00068         void dump(IN const char * msg) const throw();
00069         void diff(IN const State * other) const throw();
00070 
00071 private:
00072         // private typedefs ----------------------------------------------------
00073         enum eType {
00074                 eType_Bool              = 1,
00075                 eType_Int               = 2,
00076                 eType_Float             = 3,
00077                 eType_Double            = 4,
00078 
00079                 // keep this last!
00080                 eType_Invalid           = 0
00081         };
00082 
00083         struct value_t {
00084                 value_t(void) throw() { this->clear(); }
00085                 void clear(void) throw() {
00086                                 type = eType_Invalid;
00087                                 count = 0;
00088                         }
00089 
00090                 const char * getTypeString(void) const throw() {
00091                                 switch (type) {
00092                                 case eType_Bool:        return "Boolean";
00093                                 case eType_Int:         return "Integer";
00094                                 case eType_Float:       return "Float";
00095                                 case eType_Double:      return "Double";
00096                                 default:
00097                                         ASSERT(false, "bad type: %d", type);
00098                                 }
00099                                 return NULL;    // never get here
00100                         }
00101 
00102                 char * addValueToString(IN char * buffer,
00103                                 IN int index) const throw() {
00104                                 ASSERT(index >= 0 && index <= 3,
00105                                     "bad index: %d", index);
00106 
00107                                 if (index >= count) {
00108                                         // add nothing!
00109                                         return buffer;
00110                                 }
00111 
00112                                 switch (type) {
00113                                 case eType_Bool:        sprintf(buffer, " %s", bVal[index] ? "true" : "false"); break;
00114                                 case eType_Int:         sprintf(buffer, " %d", iVal[index]);    break;
00115                                 case eType_Float:       sprintf(buffer, " %f", fVal[index]);    break;
00116                                 case eType_Double:      sprintf(buffer, " %lf", dVal[index]);   break;
00117                                 default:                ASSERT(false, "bad type: %d", type);
00118                                 }
00119 
00120                                 int len = strlen(buffer);
00121                                 return buffer + len;
00122                         }
00123 
00124                 const char * getValueString(IN char * buffer) const throw() {
00125                                 ASSERT(buffer, "null");
00126                                 char * p = buffer;
00127                                 for (int i = 0; i < count; ++i) {
00128                                         p = this->addValueToString(p, i);
00129                                 }
00130                                 *p = 0;         // force null termination
00131                                 return buffer;
00132                         }
00133 
00134                 void dump(IN const char * txt) const throw() {
00135                                 char buffer[256];
00136 
00137                                 DPRINTF("%-19s %7s[%d] =%s", txt,
00138                                     this->getTypeString(), count,
00139                                     this->getValueString(buffer));
00140                         }
00141 
00142                 eType           type;
00143                 int             count;
00144                 union {
00145                         int     iVal[4];
00146                         float   fVal[4];
00147                         GLboolean       bVal[4];
00148                         double  dVal[4];
00149                 };
00150         };
00151 
00152         typedef std::map<std::string, value_t> value_map_t;
00153 
00154         // private helpler methods ---------------------------------------------
00155         void verifyFields(IN const StateImpl * p) const throw();
00156         void addLightFields(IN int light);
00157         void getMatrixTrace(IN int matrix);
00158 
00159         // private data members ------------------------------------------------
00160         value_map_t             m_values;
00161 };
00162 
00163 
00164 #define GET_INTEGER(flag, valCount)                                     \
00165         {                                                               \
00166                 value_t v;                                              \
00167                 v.type = eType_Int;                                     \
00168                 v.count = valCount;                                     \
00169                 ASSERT(valCount > 0 && valCount < 5,                    \
00170                     "Bad count for OpenGL int: %d", valCount);          \
00171                 glGetIntegerv( flag , v.iVal );                         \
00172                 m_values[ #flag ] = v;                                  \
00173         }
00174 
00175 #define GET_LIGHTF(light, flag, valCount)                               \
00176         {                                                               \
00177                 value_t v;                                              \
00178                 v.type = eType_Float;                                   \
00179                 v.count = valCount;                                     \
00180                 ASSERT(valCount > 0 && valCount < 5,                    \
00181                     "Bad count for OpenGL light float: %d", valCount);  \
00182                 glGetLightfv( light , flag , v.fVal );                  \
00183                 char buffer[64];                                        \
00184                 buffer[0] = '0' + light - GL_LIGHT0;                    \
00185                 buffer[1] = ':';                                        \
00186                 strcpy(buffer + 2, #flag );                             \
00187                 m_values[ buffer ] = v;                                 \
00188         }
00189 
00190 #define GET_FLOAT(flag, valCount)                                       \
00191         {                                                               \
00192                 value_t v;                                              \
00193                 v.type = eType_Float;                                   \
00194                 v.count = valCount;                                     \
00195                 ASSERT(valCount > 0 && valCount < 5,                    \
00196                     "Bad count for OpenGL int: %d", valCount);          \
00197                 glGetFloatv( flag , v.fVal );                           \
00198                 m_values[ #flag ] = v;                                  \
00199         }
00200 
00201 #define GET_BOOL(flag, valCount)                                        \
00202         {                                                               \
00203                 value_t v;                                              \
00204                 v.type = eType_Bool;                                    \
00205                 v.count = valCount;                                     \
00206                 ASSERT(valCount > 0 && valCount < 5,                    \
00207                     "Bad count for OpenGL int: %d", valCount);          \
00208                 glGetBooleanv( flag , v.bVal );                         \
00209                 m_values[ #flag ] = v;                                  \
00210         }
00211 
00212 #define GET_TEXTUREI(flag, valCount)                                    \
00213         {                                                               \
00214                 value_t v;                                              \
00215                 v.type = eType_Int;                                     \
00216                 v.count = valCount;                                     \
00217                 ASSERT(valCount > 0 && valCount < 5,                    \
00218                     "Bad count for OpenGL int: %d", valCount);          \
00219                 glGetTexParameteriv(GL_TEXTURE_2D, flag , v.iVal );     \
00220                 m_values[ #flag ] = v;                                  \
00221         }
00222 
00223 #define GET_MATERIALF(flag, valCount)                                   \
00224         {                                                               \
00225                 value_t v;                                              \
00226                 v.type = eType_Float;                                   \
00227                 v.count = valCount;                                     \
00228                 ASSERT(valCount > 0 && valCount < 5,                    \
00229                     "Bad count for OpenGL float: %d", valCount);        \
00230                 glGetMaterialfv(GL_FRONT, flag , v.fVal );              \
00231                 m_values[ "getMaterial_" #flag ] = v;                   \
00232         }
00233 
00234 #define GET_TEXENVI(flag, valCount)                                     \
00235         {                                                               \
00236                 value_t v;                                              \
00237                 v.type = eType_Int;                                     \
00238                 v.count = valCount;                                     \
00239                 ASSERT(valCount > 0 && valCount < 5,                    \
00240                     "Bad count for openGl Int: %d", valCount);          \
00241                 glGetTexEnviv(GL_TEXTURE_ENV, flag , v.iVal );          \
00242                 m_values[ #flag ] = v;                                  \
00243         }
00244 
00245 void
00246 StateImpl::addLightFields
00247 (
00248 IN int light
00249 )
00250 {
00251         ASSERT(light >= GL_LIGHT0 && light <= GL_LIGHT7,
00252             "Bad GL light enum: %d", light);
00253 
00254         GET_LIGHTF(     light,  GL_AMBIENT,             4);
00255         GET_LIGHTF(     light,  GL_DIFFUSE,             4);
00256         GET_LIGHTF(     light,  GL_SPECULAR,            4);
00257         GET_LIGHTF(     light,  GL_POSITION,            4);
00258         GET_LIGHTF(     light,  GL_SPOT_DIRECTION,      3);
00259         GET_LIGHTF(     light,  GL_SPOT_CUTOFF,         1);
00260 }
00261 
00262 
00263 
00264 void
00265 StateImpl::getMatrixTrace
00266 (
00267 IN int matrix
00268 )
00269 {
00270         float m[16];
00271         glGetFloatv(matrix, m);
00272 
00273         float trace = 0.0;
00274         for (int i = 0; i < 3; ++i) {
00275                 int idx = 5 * i;
00276                 trace += m[idx];
00277         }
00278 
00279         char buffer[32];
00280         sprintf(buffer, "MATRIX_TRACE_%d", matrix);
00281 
00282         value_t v;
00283         v.type = eType_Float;
00284         v.count = 1;
00285         v.fVal[0] = trace;
00286 
00287         m_values[buffer] = v;
00288 
00289         // dump matrix to std out!
00290         DPRINTF("Matrix %d", matrix);
00291         const float * p = m;
00292         for (int i = 0; i < 4; ++i, p += 4) {
00293                 DPRINTF("  %5.2f  %5.2f  %5.2f  %5.2f",
00294                     p[0], p[1], p[2], p[3]);
00295         }
00296 }
00297 
00298 
00299 
00300 void
00301 StateImpl::snapshotFromOpenGL
00302 (
00303 void
00304 )
00305 {
00306 
00307         //      type    lookup          number of values
00308         GET_INTEGER(    GL_ALPHA_BITS,          1);
00309         GET_FLOAT(      GL_ALPHA_SCALE,         1);
00310         GET_BOOL(       GL_ALPHA_TEST,          1);
00311         GET_INTEGER(    GL_ALPHA_TEST_FUNC,     1);
00312         GET_FLOAT(      GL_ALPHA_TEST_REF,      1);
00313         GET_INTEGER(    GL_AUX_BUFFERS,         1);
00314         GET_BOOL(       GL_BLEND,               1);
00315         GET_FLOAT(      GL_BLEND_COLOR,         4);
00316         GET_INTEGER(    GL_BLEND_DST,           1);
00317         GET_INTEGER(    GL_BLEND_EQUATION,      1);
00318         GET_INTEGER(    GL_BLEND_SRC,           1);
00319         GET_INTEGER(    GL_BLUE_BITS,           1);
00320         GET_BOOL(       GL_CLIP_PLANE0,         1);
00321         GET_BOOL(       GL_CLIP_PLANE1,         1);
00322         GET_BOOL(       GL_CLIP_PLANE2,         1);
00323         GET_BOOL(       GL_CLIP_PLANE3,         1);
00324         GET_BOOL(       GL_COLOR_ARRAY,         1);
00325         GET_INTEGER(    GL_COLOR_ARRAY_SIZE,    1);
00326         GET_FLOAT(      GL_COLOR_CLEAR_VALUE,   4);
00327         GET_INTEGER(    GL_COLOR_LOGIC_OP,      1);
00328         GET_BOOL(       GL_COLOR_MATERIAL,      1);
00329         GET_INTEGER(    GL_COLOR_MATERIAL_FACE, 1);
00330         GET_INTEGER(    GL_COLOR_MATERIAL_PARAMETER,    1);
00331         GET_INTEGER(    GL_COLOR_WRITEMASK,     4);
00332         GET_BOOL(       GL_CULL_FACE,           1);
00333         GET_INTEGER(    GL_CULL_FACE_MODE,      1);
00334         GET_FLOAT(      GL_CURRENT_COLOR,       4);
00335         GET_FLOAT(      GL_CURRENT_NORMAL,      3);
00336         GET_INTEGER(    GL_DEPTH_BITS,          1);
00337         GET_BOOL(       GL_DOUBLEBUFFER,        1);
00338         GET_INTEGER(    GL_DRAW_BUFFER,         1);
00339         GET_BOOL(       GL_FOG,                 1);
00340         GET_FLOAT(      GL_FOG_COLOR,           4);
00341         GET_INTEGER(    GL_FRONT_FACE,          1);
00342         GET_INTEGER(    GL_GREEN_BITS,          1);
00343         GET_BOOL(       GL_LIGHT0,              1);
00344         GET_BOOL(       GL_LIGHT1,              1);
00345         GET_BOOL(       GL_LIGHT2,              1);
00346         GET_BOOL(       GL_LIGHT3,              1);
00347         GET_BOOL(       GL_LIGHT4,              1);
00348         GET_BOOL(       GL_LIGHT5,              1);
00349         GET_BOOL(       GL_LIGHT6,              1);
00350         GET_BOOL(       GL_LIGHT7,              1);
00351         GET_BOOL(       GL_LIGHTING,            1);
00352         GET_FLOAT(      GL_LIGHT_MODEL_AMBIENT, 4);
00353         GET_INTEGER(    GL_LOGIC_OP_MODE,       1);
00354         GET_INTEGER(    GL_POLYGON_MODE,        1);
00355         GET_INTEGER(    GL_POLYGON_OFFSET_FACTOR, 1);
00356         GET_INTEGER(    GL_POLYGON_OFFSET_UNITS, 1);
00357         GET_BOOL(       GL_POLYGON_OFFSET_FILL, 1);
00358         GET_BOOL(       GL_POLYGON_OFFSET_LINE, 1);
00359         GET_BOOL(       GL_POLYGON_OFFSET_POINT, 1);
00360         GET_BOOL(       GL_POLYGON_SMOOTH,      1);
00361         GET_INTEGER(    GL_PROJECTION_STACK_DEPTH, 1);
00362         GET_INTEGER(    GL_RED_BITS,            1);
00363         GET_BOOL(       GL_RGBA_MODE,           1);
00364         GET_INTEGER(    GL_STENCIL_BITS,        1);
00365         GET_BOOL(       GL_TEXTURE_2D,          1);
00366         GET_INTEGER(    GL_TEXTURE_BINDING_2D,  1);
00367         GET_INTEGER(    GL_VIEWPORT,            4);
00368 
00369         // texture parameters
00370         GET_TEXTUREI(   GL_TEXTURE_MAG_FILTER,  1);
00371         GET_TEXTUREI(   GL_TEXTURE_MIN_FILTER,  1);
00372         GET_TEXTUREI(   GL_TEXTURE_MIN_LOD,     1);
00373         GET_TEXTUREI(   GL_TEXTURE_MAX_LOD,     1);
00374         GET_TEXTUREI(   GL_TEXTURE_BASE_LEVEL,  1);
00375         GET_TEXTUREI(   GL_TEXTURE_MAX_LEVEL,   1);
00376         GET_TEXTUREI(   GL_TEXTURE_WRAP_S,      1);
00377         GET_TEXTUREI(   GL_TEXTURE_WRAP_T,      1);
00378         GET_TEXTUREI(   GL_TEXTURE_WRAP_R,      1);
00379 
00380         GET_TEXENVI(    GL_TEXTURE_ENV_MODE,    1);
00381 
00382         // material parameters
00383         GET_MATERIALF(  GL_AMBIENT,             4);
00384         GET_MATERIALF(  GL_DIFFUSE,             4);
00385         GET_MATERIALF(  GL_SPECULAR,            4);
00386         GET_MATERIALF(  GL_EMISSION,            4);
00387         GET_MATERIALF(  GL_SHININESS,           1);
00388 
00389         // matrix traces
00390         this->getMatrixTrace(GL_MODELVIEW_MATRIX);
00391         this->getMatrixTrace(GL_PROJECTION_MATRIX);
00392         this->getMatrixTrace(GL_TEXTURE_MATRIX);
00393 
00394         // lighting parameters
00395         this->addLightFields(GL_LIGHT0);
00396         this->addLightFields(GL_LIGHT1);
00397         this->addLightFields(GL_LIGHT2);
00398         this->addLightFields(GL_LIGHT3);
00399         this->addLightFields(GL_LIGHT4);
00400 }
00401 
00402 
00403 
00404 void
00405 StateImpl::dump
00406 (
00407 IN const char * msg
00408 )
00409 const
00410 throw()
00411 {
00412         DPRINTF("%s: OpenGL State BEGIN --------------------------", msg);
00413 
00414         for (value_map_t::const_iterator i = m_values.begin();
00415              i != m_values.end(); ++i) {
00416                 const char * name = i->first.c_str();
00417                 const value_t& v = i->second;
00418                 v.dump(name);
00419         }
00420 
00421         DPRINTF("%s: OpenGL State END ----------------------------", msg);
00422 }
00423 
00424 
00425 
00426 void
00427 StateImpl::diff
00428 (
00429 IN const State * other
00430 )
00431 const
00432 throw()
00433 {
00434         ASSERT(other, "null");
00435         const StateImpl * p = dynamic_cast<const StateImpl*>(other);
00436         ASSERT(p, "other state object is not a StateImpl?");
00437 
00438         // verify every field in our map is in other map, with same value
00439         this->verifyFields(p);
00440 
00441         // do the reverse!
00442         // actually, don't.  I was going to catch missing fields, but not yet
00443 //      p->verifyFields(this, false);
00444 }
00445 
00446 
00447 
00448 void
00449 StateImpl::verifyFields
00450 (
00451 IN const StateImpl * p
00452 )
00453 const
00454 throw()
00455 {
00456         ASSERT(p, "null");
00457 
00458         // loop through all of our fields
00459         for (value_map_t::const_iterator i = m_values.begin();
00460              i != m_values.end(); ++i) {
00461                 const char * name = i->first.c_str();
00462 
00463                 // does this field exist in the other state object?
00464                 value_map_t::const_iterator j = p->m_values.find(name);
00465                 if (p->m_values.end() == j) {
00466                         DPRINTF("  Missing a field!  %s", name);
00467                         continue;
00468                 }
00469 
00470                 char buffer0[256];
00471                 char buffer1[256];
00472                 const value_t& v0 = i->second;
00473                 const value_t& v1 = j->second;
00474 
00475                 v0.getValueString(buffer0);
00476                 v1.getValueString(buffer1);
00477                 if (strcmp(buffer0, buffer1)) {
00478                         DPRINTF("%s: disagreement in values!", name);
00479                         DPRINTF("  Type: %s[%d]", v0.getTypeString(), v0.count);
00480                         DPRINTF("  our value:   %s", buffer0);
00481                         DPRINTF("  other value: %s", buffer1);
00482                 }
00483         }
00484 }
00485 
00486 
00487 
00488 ////////////////////////////////////////////////////////////////////////////////
00489 //
00490 //      public API (glut setup + running)
00491 //
00492 ////////////////////////////////////////////////////////////////////////////////
00493 
00494 smart_ptr<State>
00495 State::snapshotFromOpenGL
00496 (
00497 void
00498 )
00499 {
00500         smart_ptr<StateImpl> local = new StateImpl;
00501         ASSERT(local, "out of memory");
00502 
00503         local->snapshotFromOpenGL();
00504 
00505         return local;
00506 }
00507 
00508 
00509 
00510 
00511 };      // glut namespacv
00512