1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
21 #include "shapestypes.h"
22 #include "shapesexceptions.h"
25 #include "angleselect.h"
28 #include "statetypes.h"
29 #include "lighttypes.h"
30 #include "shadingtypes.h"
37 using namespace Shapes
;
39 #define SPLICEDEBUG( code ) // code
42 RefCountPtr
< const Lang::Drawable2D
>
43 Lang::ZBuf::typed_to2D( const Kernel::PassedDyn
& dyn
, const Lang::Transform3D
& tf
, const RefCountPtr
< const Lang::Drawable3D
> & self
) const
45 Concrete::Length eyez
= dyn
->getEyeZ( );
47 std::list
< RefCountPtr
< const Lang::LightSource
> > commonLights
;
48 std::list
< RefCountPtr
< const Lang::LightSource
> > allShadowLights
;
51 typedef typeof *lightPile_ PileType
;
52 for( PileType::const_iterator src
= lightPile_
->begin( ); src
!= lightPile_
->end( ); ++src
)
54 if( (*src
)->shadows( ) )
56 allShadowLights
.push_back( (*src
)->typed_transformed( tf
) );
60 commonLights
.push_back( (*src
)->typed_transformed( tf
) );
65 if( ! allShadowLights
.empty( ) )
67 throw Exceptions::NotImplemented( "Shadow lights in ZBuf::typed_to2D" );
70 size_t debugCounter
= 0;
72 // There is one queue per original object. This structure will be where all the
73 // triangles resides at the beginning of the treatment of each shadow light or the
74 // view occlusion computation.
76 // We begin by initializing these queues.
77 std::list
< std::list
< Computation::ZBufTriangle
> * > triangleQueues
;
79 typedef typeof *pile_ PileType
;
80 for( PileType::const_iterator src
= pile_
->begin( ); src
!= pile_
->end( ); ++src
)
82 std::list
< Computation::ZBufTriangle
> * triangleQueue
= new std::list
< Computation::ZBufTriangle
>;
83 (*src
)->push_zBufTriangles( tf
, eyez
, triangleQueue
);
84 triangleQueues
.push_back( triangleQueue
);
88 // The vectors triangleQueue and disjointTriangles share indices in the sense that same indices points to
89 // triangles with the same origin.
90 std::list
< std::list
< Computation::ZBufTriangle
> * > disjointTriangles
;
91 std::list
< std::list
< Computation::ZBufTriangle
> * > occludedTriangles
;
93 for( std::list
< std::list
< Computation::ZBufTriangle
> * >::iterator src
= triangleQueues
.begin( );
94 src
!= triangleQueues
.end( ); ++src
)
96 std::list
< Computation::ZBufTriangle
> * triangleQueue
= *src
;
98 std::list
< Computation::ZBufTriangle
> * currentDisjoint
= new std::list
< Computation::ZBufTriangle
>;
99 std::list
< Computation::ZBufTriangle
> * currentOccluded
= new std::list
< Computation::ZBufTriangle
>;
101 while( ! triangleQueue
->empty( ) )
103 SPLICEDEBUG( std::cerr
<< "====( Debug step number " << debugCounter
<< " )====" << std::endl
);
104 Computation::ZBufTriangle current
= triangleQueue
->front( );
105 triangleQueue
->pop_front( );
107 typedef typeof disjointTriangles ListType
;
108 bool foundOverlap
= false;
109 ListType::iterator iOccluded
= occludedTriangles
.begin( );
110 for( ListType::iterator iDisjoint
= disjointTriangles
.begin( ); iDisjoint
!= disjointTriangles
.end( );
111 ++iDisjoint
, ++iOccluded
)
113 typedef typeof **iDisjoint SubListType
;
114 for( SubListType::iterator j
= (*iDisjoint
)->begin( ); j
!= (*iDisjoint
)->end( ); ++j
)
116 if( current
.overlaps( *j
) )
118 Computation::ZBufTriangle
tOld( *j
);
119 (*iDisjoint
)->erase( j
);
120 Computation::ZBufTriangle::splice( tOld
, current
,
121 *iDisjoint
, *iOccluded
,
122 currentDisjoint
, currentOccluded
,
124 mergeTriangles( *iDisjoint
);
125 recombineTriangles( *iOccluded
);
134 currentDisjoint
->push_back( current
);
138 mergeTriangles( currentDisjoint
);
139 recombineTriangles( currentDisjoint
);
140 disjointTriangles
.push_back( currentDisjoint
);
142 mergeTriangles( currentOccluded
);
143 recombineTriangles( currentOccluded
);
144 occludedTriangles
.push_back( currentOccluded
);
147 if( debugCounter
>= Interaction::debugStep
)
155 typedef typeof disjointTriangles ListType
;
156 for( ListType::const_iterator i
= disjointTriangles
.begin( ); i
!= disjointTriangles
.end( ); ++i
)
158 sum
+= (*i
)->size( );
162 // It is now time to take care of the lines.
163 // The first thing we shall do is to remove what is occluded by triangles.
164 // Note that triangles will be drawn before the lines, and that is the only way lines
165 // can occlude triangles.
166 // Then, we make sure that the lines are drawn in back-to-front order, clipping occluded lines
167 // behind the line occluding them to avoid cyclic locking.
169 std::list
< const Computation::ZBufLine
* > lineQueue
;
171 typedef typeof *linePile_ PileType
;
172 for( PileType::const_iterator src
= linePile_
->begin( ); src
!= linePile_
->end( ); ++src
)
174 (*src
)->push_zBufLine( tf
, eyez
, & lineQueue
);
178 std::list
< const Computation::ZBufLine
* > disjointLines
;
179 while( ! lineQueue
.empty( ) )
182 std::list
< const Computation::ZBufLine
* > queue1
;
183 std::list
< const Computation::ZBufLine
* > queue2
;
185 std::list
< const Computation::ZBufLine
* > * currentQueue
= & queue1
;
186 std::list
< const Computation::ZBufLine
* > * otherQueue
= & queue2
;
188 currentQueue
->push_back( lineQueue
.front( ) );
189 lineQueue
.pop_front( );
191 typedef typeof disjointTriangles ListType
;
192 for( ListType::const_iterator i
= disjointTriangles
.begin( ); i
!= disjointTriangles
.end( ); ++i
)
194 typedef typeof **i SubListType
;
195 for( SubListType::iterator j
= (*i
)->begin( ); j
!= (*i
)->end( ); ++j
)
197 while( ! currentQueue
->empty( ) )
199 const Computation::ZBufLine
* currentLine
= currentQueue
->front( );
200 currentQueue
->pop_front( );
201 if( currentLine
->overlaps( *j
) )
203 currentLine
->splice( *j
, otherQueue
);
208 otherQueue
->push_back( currentLine
);
214 std::list
< const Computation::ZBufLine
* > * tmp
= currentQueue
;
215 currentQueue
= otherQueue
;
221 // When we reach here the line segments are in currentQueue.
222 // These segments are ready to be inserted in the line z buffer.
224 // The algorithm below is inefficient, because it will generally make the overlap comparison
225 // several times for any overlaping pair of line segments.
226 while( ! currentQueue
->empty( ) )
228 const Computation::ZBufLine
* current
= currentQueue
->front( );
229 currentQueue
->pop_front( );
231 bool foundOverlap
= false;
232 typedef typeof disjointLines ListType
;
233 for( ListType::iterator i
= disjointLines
.begin( ); i
!= disjointLines
.end( );
236 if( current
->overlaps( **i
) )
238 disjointLines
.erase( i
);
239 // Note that splice is responsible for deleting that of *i and current which is not used.
240 Computation::ZBufLine::splice( *i
, current
,
249 disjointLines
.push_back( current
);
255 RefCountPtr
< const Lang::Group2D
> res
= Lang::THE_NULL2D
;
257 const bool SHOW_TRIXELS
= false;
260 // This is a debug mode
262 typedef typeof disjointTriangles ListType
;
263 for( ListType::const_iterator i
= disjointTriangles
.begin( ); i
!= disjointTriangles
.end( ); ++i
)
265 typedef typeof **i SubListType
;
266 for( SubListType::iterator j
= (*i
)->begin( ); j
!= (*i
)->end( ); ++j
)
268 res
= RefCountPtr
< const Lang::Group2D
>( new Lang::GroupPair2D( j
->debugFrame( ),
276 // This is the standard mode
278 size_t commonLightCount
= commonLights
.size( );
280 typedef typeof disjointTriangles ListType
;
281 for( ListType::iterator i
= disjointTriangles
.begin( ); i
!= disjointTriangles
.end( ); ++i
)
287 typedef std::list
< RefCountPtr
< const Lang::LightSource
> > ShadowLightListType
;
288 const ShadowLightListType
& shadowLights
= (*i
)->front( ).shadowLights_
;
289 for( ShadowLightListType::const_iterator l
= shadowLights
.begin( ); l
!= shadowLights
.end( ); ++l
)
291 commonLights
.push_back( *l
);
293 RefCountPtr
< const Lang::PaintedPolygon2D
> tmp
= (*i
)->front( ).painter_
->polygon_to2D( dyn
, tf
, commonLights
);
294 while( commonLights
.size( ) > commonLightCount
)
296 commonLights
.pop_back( );
299 // The following statement will consume the objects in the list pointed to by *i
300 res
= RefCountPtr
< const Lang::Group2D
>( new Lang::GroupPair2D( tmp
->clip( *i
, tmp
),
307 while( ! disjointTriangles
.empty ( ) )
309 delete disjointTriangles
.back( );
310 disjointTriangles
.pop_back( );
312 delete occludedTriangles
.back( );
313 occludedTriangles
.pop_back( );
316 while( ! triangleQueues
.empty( ) )
318 delete triangleQueues
.back( );
319 triangleQueues
.pop_back( );
323 // Finally we draw the lines.
324 while( ! disjointLines
.empty( ) )
326 const Computation::ZBufLine
* current
= disjointLines
.front( );
327 disjointLines
.pop_front( );
328 res
= RefCountPtr
< const Lang::Group2D
>( new Lang::GroupPair2D( current
->stroke2D( ),