1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 //---------------------------------------------------------------------------
41 //---------------------------------------------------------------------------
46 #include "OSGConfig.h"
50 #include "OSGStateChunk.h"
54 #include "OSGTextureBaseChunk.h"
55 #include "OSGMaterialChunk.h"
56 #include "OSGShaderExecutableChunk.h"
57 #include "OSGShaderExecutableVarChunk.h"
58 #include "OSGLightChunk.h"
59 #include "OSGMaterial.h"
63 // Documentation for this class is emited in the
64 // OSGStateBase.cpp file.
65 // To modify it, please change the .fcd file (OSGState.fcd) and
66 // regenerate the base file.
68 /***************************************************************************\
70 \***************************************************************************/
72 /***************************************************************************\
74 \***************************************************************************/
76 /*-------------------------------------------------------------------------*\
78 \*-------------------------------------------------------------------------*/
80 void State::initMethod(InitPhase ePhase
)
82 Inherited::initMethod(ePhase
);
85 /***************************************************************************\
87 \***************************************************************************/
89 /*-------------------------------------------------------------------------*\
91 \*-------------------------------------------------------------------------*/
93 void State::onCreateAspect(const State
*createAspect
,
96 Inherited::onCreateAspect(createAspect
, source
);
98 UInt32 uiTId
= TextureBaseChunk ::getStaticClassId() & 0x000003FF;
99 UInt32 uiShId
= ShaderExecutableChunk ::getStaticClassId() & 0x000003FF;
100 UInt32 uiMId
= ShaderExecutableVarChunk::getStaticClassId() & 0x000003FF;
102 _uiKeyGen
= ( (uiShId
) | (uiTId
<< 10) | (uiMId
<< 20) );
105 fprintf(stderr, "CreateKeyGen (%p | %p | %p) from %d %d -> %08x\n",
109 TextureChunk ::getStaticClassId(),
110 MaterialChunk::getStaticClassId(),
115 /*------------- constructors & destructors --------------------------------*/
119 _uiDefaultSortKey (0 ),
122 #if defined(OSG_OGL_COREONLY)
123 _uiCoreGLChunkLimit(LightChunk::getStaticClassId())
125 _uiCoreGLChunkLimit(4096 ) // Arbitrary high value
130 State::State(const State
&source
) :
132 _uiDefaultSortKey ( 0),
135 #if defined(OSG_OGL_COREONLY)
136 _uiCoreGLChunkLimit(LightChunk::getStaticClassId())
138 _uiCoreGLChunkLimit(4096 ) // Arbitrary high value
147 void State::rebuildSortKey(void)
149 UInt32 uiKey1
= _uiKeyGen
& Key1Mask
;
150 UInt32 uiKey2
= (_uiKeyGen
& Key2Mask
) >> 10;
151 UInt32 uiKey3
= (_uiKeyGen
& Key3Mask
) >> 20;
153 UInt32 uiSizeChunks
= _mfChunks
.size32();
155 // fprintf(stderr, "Got Keys %d %d %d\n", uiKey1, uiKey2, uiKey3);
157 const State
*pThis
= this;
159 if(uiKey1
!= InvalidKey
&& uiKey1
< uiSizeChunks
)
162 (pThis
->_mfChunks
[uiKey1
] != NULL
&&
163 pThis
->_mfChunks
[uiKey1
]->getIgnore() == false ) ?
165 pThis
->_mfChunks
[uiKey1
]->getChunkId() : 0;
172 if(uiKey2
!= InvalidKey
&& uiKey2
< uiSizeChunks
)
175 (pThis
->_mfChunks
[uiKey2
] != NULL
&&
176 pThis
->_mfChunks
[uiKey2
]->getIgnore() == false ) ?
178 pThis
->_mfChunks
[uiKey2
]->getChunkId() : 0;
185 if(uiKey3
!= InvalidKey
&& uiKey3
< uiSizeChunks
)
188 (pThis
->_mfChunks
[uiKey3
] != NULL
&&
189 pThis
->_mfChunks
[uiKey3
]->getIgnore() == false ) ?
191 pThis
->_mfChunks
[uiKey3
]->getChunkId() : 0;
199 (uiKey1
& Key1Mask
) |
200 ((uiKey2
& Key1Mask
) << 10) |
201 ((uiKey3
& Key1Mask
) << 20);
203 if(_uiSortKey
== 0x00000000)
205 _uiSortKey
= _uiDefaultSortKey
;
209 fprintf(stderr, "Use Sort Key : %08x %08x %08x %08x -> %08x\n",
218 void State::changed(ConstFieldMaskArg whichField
,
222 Inherited::changed(whichField
, origin
, details
);
227 /*------------------------------- dump ----------------------------------*/
229 void State::dump( UInt32
OSG_CHECK_ARG(uiIndent
),
230 const BitVector
OSG_CHECK_ARG(bvFlags
)) const
232 std::cerr
<< "State at " << this << std::endl
;
234 MFChunksType::const_iterator it
;
237 for(it
= _mfChunks
.begin(), cind
= 0; it
!= _mfChunks
.end(); ++it
, ++cind
)
239 std::cerr
<< "[" << cind
<< "]["
240 << StateChunkClass::getName(cind
) << "]\t";
244 std::cerr
<< "NullChunk" << std::endl
;
248 std::cerr
<< *it
<< std::endl
;
253 /*-------------------- OpenGL State Management --------------------------*/
255 /*! Activate (i.e. call all their OpenGL commands) the current set of
256 StateChunks. Activate will simply overwrite whatever was set before.
259 void State::activate(DrawEnv
*pEnv
) const
261 MFChunksType::const_iterator cIt
= _mfChunks
.begin();
262 MFChunksType::const_iterator cEnd
= _mfChunks
.end ();
264 UInt32 cind
= osgMin(State::SkipNumChunks
,
265 _mfChunks
.size32() );
266 UInt32
const climit
= _uiCoreGLChunkLimit
;
268 OSG_SKIP_IT(cIt
, cind
);
270 for(; (cIt
!= cEnd
) && (cind
< climit
); ++cIt
, ++cind
)
272 if(*cIt
!= NULL
&& (*cIt
)->getIgnore() == false)
274 (*cIt
)->activate(pEnv
, UInt32(ind
));
277 if(++ind
>= StateChunkClass::getNumSlots(cind
))
283 /*! Switch to this state from the given old State. The chunks will try to
284 optimize the transition.
287 void State::changeFrom(DrawEnv
*pEnv
, State
*pOld
) const
289 MFChunksType::const_iterator cIt
= _mfChunks
.begin();
290 MFChunksType::const_iterator cEnd
= _mfChunks
.end ();
293 UInt32 cind
= osgMin(State::SkipNumChunks
,
294 _mfChunks
.size32() );
295 UInt32
const climit
= _uiCoreGLChunkLimit
;
297 OSG_SKIP_IT(cIt
, cind
);
299 for(; (cIt
!= cEnd
) && (cind
< climit
); ++cIt
, ++cind
)
301 StateChunk
*o
= pOld
->getChunk(cind
);
302 StateChunk
*n
= *cIt
;
304 if(n
!= NULL
&& n
->getIgnore() == false)
306 if(o
!= NULL
&& o
->getIgnore() == false)
308 n
->changeFrom(pEnv
, o
, UInt32(ind
));
312 n
->activate(pEnv
, UInt32(ind
));
315 else if(o
!= NULL
&& o
->getIgnore() == false)
317 o
->deactivate(pEnv
, UInt32(ind
));
320 if(++ind
>= StateChunkClass::getNumSlots(cind
))
324 if(ind
>= StateChunkClass::getNumSlots(cind
))
327 for(i
= cind
; (i
< pOld
->getMFChunks()->size()) && (i
< climit
); ++i
)
329 StateChunk
*o
= pOld
->getChunk(i
);
331 if(o
!= NULL
&& o
->getIgnore() == false)
333 o
->deactivate(pEnv
, UInt32(ind
));
336 if(++ind
>= StateChunkClass::getNumSlots(i
))
344 /*! Deactivate the current set of StateChunks, i.e. switch everything back to
345 the default state for the OpenGL state covered by the given chunks.
348 void State::deactivate(DrawEnv
*pEnv
) const
350 MFChunksType::const_iterator cIt
= _mfChunks
.begin();
351 MFChunksType::const_iterator cEnd
= _mfChunks
.end ();
353 UInt32 cind
= osgMin(State::SkipNumChunks
,
354 _mfChunks
.size32() );
355 UInt32
const climit
= _uiCoreGLChunkLimit
;
357 OSG_SKIP_IT(cIt
, cind
);
359 for(; (cIt
!= cEnd
) && (cind
< climit
); ++cIt
, ++cind
)
361 if(*cIt
!= NULL
&& (*cIt
)->getIgnore() == false)
362 (*cIt
)->deactivate(pEnv
, UInt32(ind
));
364 if(++ind
>= StateChunkClass::getNumSlots(cind
))
369 /*---------------------------- Access -----------------------------------*/
371 /*! Add the given chunk to the State. The index defines the behaviour,
372 especially for multi-slot chunks.
374 If it is set to AutoSlotReplace (the default), addChunk will try to find an
375 empty slot for the chunk class, if it doesn't find one the last one will be
376 replaced with the new entry. This is also useful for chunk classes with
377 only a single slot, as it will override an old instance of the chunk class,
378 which is usually the desired behaviour.
380 If it is set to AutoSlot, the new chunk will only be added to the State if
381 there is a free slot. If there is no free slot true will be returned, in
382 all other cases it will be false.
384 If the index is explicitly given (i.e. it is >=0) the chunk will be set
385 into the given slot, possibly overwriting an old entry. If the index is
386 larger than the number of slots for the given chunck class true will be
390 bool State::addChunk(StateChunk
*chunk
, Int32 index
)
392 if(index
> 0 && index
> chunk
->getClass()->getNumSlots())
394 SWARNING
<< "addChunk: index "
397 << chunk
->getClass()->getNumSlots()
403 UInt32 cindex
= chunk
->getClassId();
404 UInt32 csize
= _mfChunks
.size32();
406 const State
*pThis
= this;
408 // special case: find empty slot automatically
409 if(index
== AutoSlot
|| index
== AutoSlotReplace
)
411 UInt8 nslots
= chunk
->getClass()->getNumSlots();
414 for(ci
= cindex
; ci
< cindex
+ nslots
&& ci
< csize
; ++ci
)
416 if(pThis
->_mfChunks
[ci
] == NULL
)
422 if(ci
>= cindex
+ nslots
) // no free slot found
424 if(index
== AutoSlot
)
426 SWARNING
<< "addChunk: no free slot found for "
427 << chunk
->getClass()->getName()
428 << " class, ignored!" << std::endl
;
442 editMField(ChunksFieldMask
, _mfChunks
);
444 // add the chunk to the state at cindex
447 UInt32 oldsize
= csize
;
448 UInt32 newsize
= cindex
+ 1;
450 _mfChunks
.resize(newsize
);
452 for(UInt32 i
= oldsize
; i
< newsize
; i
++)
454 _mfChunks
.replace(i
, NULL
);
458 _mfChunks
.replace(cindex
, chunk
);
463 /*! Remove the given chunk from the State. Returns false if successful, true if
464 the chunk wasn't found.
467 bool State::subChunk(StateChunk
*chunk
)
472 UInt32 cindex
= chunk
->getClassId();
473 UInt32 csize
= _mfChunks
.size32();
475 // special case: find it in the slots
476 UInt8 nslots
= chunk
->getClass()->getNumSlots();
479 const State
*pThis
= this;
481 for(ci
= cindex
; ci
< cindex
+ nslots
&& ci
< csize
; ci
++)
483 if(pThis
->_mfChunks
[ci
] == chunk
)
489 if(ci
>= cindex
+ nslots
) // chunk not found
491 SWARNING
<< "subChunk: chunk "
494 << chunk
->getClass()->getName()
500 editMField(ChunksFieldMask
, _mfChunks
);
502 // remove the chunk from the state
504 _mfChunks
.replace(ci
, NULL
);
510 /*! Remove the chunk defined by the class id and the slot index from the State.
511 Returns false if successful, true if the chunk wasn't found.
514 bool State::subChunk(UInt32 classid
, Int32 index
)
516 if(index
< 0 || index
> StateChunkClass::getNumSlots(classid
))
518 SWARNING
<< "subChunk: index " << index
<< " > Numslots "
519 << StateChunkClass::getNumSlots(classid
)
520 << ", ignored!" << std::endl
;
524 const State
*pThis
= this;
526 if(pThis
->_mfChunks
[classid
+ index
] == NULL
)
529 editMField(ChunksFieldMask
, _mfChunks
);
531 // remove the chunk from the state
533 _mfChunks
.replace(classid
+ index
, NULL
);
538 /*! Remove all chunks from the state
541 void State::clearChunks(void)
543 editMField(ChunksFieldMask
, _mfChunks
);
545 MFChunksType::iterator chunksIt
= _mfChunks
.begin_nc();
546 MFChunksType::iterator chunksEnd
= _mfChunks
.end_nc ();
548 for(; chunksIt
!= chunksEnd
; ++chunksIt
)
550 _mfChunks
.replace(chunksIt
, NULL
);
554 bool State::isTransparent(void) const
556 Int32 tm
= getTransparencyMode();
558 if(tm
!= Material::TransparencyAutoDetection
)
560 return (tm
== Material::TransparencyForceTransparent
);
563 bool returnValue
= false;
565 MFChunksType::const_iterator chunksIt
= _mfChunks
.begin();
566 MFChunksType::const_iterator chunksEnd
= _mfChunks
.end();
568 for(; chunksIt
!= chunksEnd
&& returnValue
== false; ++chunksIt
)
570 if((*chunksIt
) != NULL
)
571 returnValue
=(*chunksIt
)->isTransparent();
577 /*-------------------------- comparison -----------------------------------*/
580 /*! Calculate the switch cost for the whole state, which is the sum of the
581 switch cost of all its chunks. Right now it's always 0.
584 Real32
State::switchCost(State
*OSG_CHECK_ARG(state
))
589 bool State::operator < (const State
&other
) const
591 return this < &other
;
594 /*! Compare the two states. Not implemented yet, always false.
597 bool State::operator == (const State
&OSG_CHECK_ARG(other
)) const
602 bool State::operator != (const State
&other
) const
604 return ! (*this == other
);
607 void State::resolveLinks(void)
611 Inherited::resolveLinks();