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"
32 #include "zbufinternals.h"
33 #include "constructorrepresentation.h"
39 using namespace Shapes
;
48 // This is not the most natural place to define CompoundObject, but since we need it...
49 typedef std::list
< Computation::ZBufTriangle
> CompoundObject
;
51 CompoundObject::iterator splitted_
;
52 std::vector
< CompoundObject
* >::iterator splittingObject_
;
53 CompoundObject::iterator splitting_
;
55 SplitJob( const CompoundObject::iterator
& splitted
, const std::vector
< CompoundObject
* >::iterator
& splittingObject
, const CompoundObject::iterator
& splitting
)
56 : splitted_( splitted
), splittingObject_( splittingObject
), splitting_( splitting
)
63 RefCountPtr
< const Lang::Drawable2D
>
64 Lang::ZSorter::typed_to2D( const Kernel::PassedDyn
& dyn
, const Lang::Transform3D
& tf
, const RefCountPtr
< const Lang::Drawable3D
> & self
) const
66 Concrete::Length eyez
= dyn
->getEyeZ( );
68 std::list
< RefCountPtr
< const Lang::LightSource
> > commonLights
;
69 std::list
< RefCountPtr
< const Lang::LightSource
> > allShadowLights
;
72 typedef typeof *lightPile_ PileType
;
73 for( PileType::const_iterator src
= lightPile_
->begin( ); src
!= lightPile_
->end( ); ++src
)
75 if( (*src
)->shadows( ) )
77 allShadowLights
.push_back( (*src
)->typed_transformed( tf
) );
81 commonLights
.push_back( (*src
)->typed_transformed( tf
) );
86 if( ! allShadowLights
.empty( ) )
88 throw Exceptions::MiscellaneousRequirement( "Shadow lights cannot be used in a z-sorter." );
91 // There is one queue per original object. This structure will be where all the
92 // triangles resides at the beginning of the treatment of each shadow light or the
93 // view occlusion computation.
95 // We begin by initializing these queues.
96 typedef Computation::SplitJob::CompoundObject CompoundObject
; // It is a bit unnatural to define the type somewhere but here...
98 const size_t pileSize
= pile_
->size( );
99 size_t triangleCount
= 0;
101 // Now the main storage for triangles is set up
102 typedef PtrOwner_back_Access
< std::vector
< CompoundObject
* > > CompoundMemType
;
103 CompoundMemType compoundMem
;
104 compoundMem
.reserve( pileSize
);
106 // Then we fill it with triangles that don't intersect.
107 // Note that it is a responsibility of push_zBufTriangles to not push any tiny triangles.
109 Computation::SplicingLine spliceLine
;
110 std::list
< Computation::SplitJob
> job
;
111 typedef typeof *pile_ PileType
;
112 for( PileType::const_iterator src
= pile_
->begin( ); src
!= pile_
->end( ); ++src
)
114 std::list
< Computation::ZBufTriangle
> * tmpList
= new std::list
< Computation::ZBufTriangle
>;
115 // Since there cannot be shadow lights in a z sorter, it is OK not to include the backsides of single sided facets.
116 (*src
)->push_zBufTriangles( tf
, eyez
, tmpList
, true ); // true means allow dropping back sides of single sided objects
117 for( CompoundObject::iterator i
= tmpList
->begin( ); i
!= tmpList
->end( ); ++i
)
119 typedef std::vector
< CompoundObject
* >::iterator ObjectIterator
;
120 for( ObjectIterator o
= compoundMem
.begin( ); o
!= compoundMem
.end( ); ++o
)
122 for( CompoundObject::iterator j
= (*o
)->begin( ); j
!= (*o
)->end( ); ++j
)
124 if( j
->intersection( *i
, & spliceLine
) &&
125 j
->overlapsAlong( *i
, spliceLine
, Computation::theTrixelizeOverlapTol
) )
127 job
.push_back( Computation::SplitJob( i
, o
, j
) );
133 continue; // this is just a no-op to make this a valid jump destination
135 while( ! job
.empty( ) )
137 Computation::SplitJob
& currentJob
= job
.front( );
138 if( ! currentJob
.splitted_
->intersection( *currentJob
.splitting_
, & spliceLine
) )
140 throw Exceptions::InternalError( "These triangles were known to intsersect, and now they're parallel!" );
143 // New triangles are added to the end of tmpList, and the iterator to the first new triangle is returned.
144 CompoundObject::iterator i
= currentJob
.splitted_
->spliceAlong( spliceLine
, tmpList
);
146 // Now the procedure from above is repeated, but not comparing against triangles that have already been checked.
147 for( ; i
!= tmpList
->end( ); ++i
)
149 CompoundObject::iterator j
= currentJob
.splitting_
;
151 typedef std::vector
< CompoundObject
* >::iterator ObjectIterator
;
152 for( ObjectIterator o
= currentJob
.splittingObject_
; o
!= compoundMem
.end( ); ++o
)
154 // For the splitting object object (the first in this loop), the first triangle to compare against
155 // was set above. For the other object, all triangles shall be compared against (that is, j starts from
157 if( o
!= currentJob
.splittingObject_
)
161 for( ; j
!= (*o
)->end( ); ++j
)
163 if( j
->intersection( *i
, & spliceLine
) &&
164 j
->overlapsAlong( *i
, spliceLine
, Computation::theTrixelizeOverlapTol
) )
166 job
.push_back( Computation::SplitJob( i
, o
, j
) );
172 continue; // this is just a no-op to make this a valid jump destination
175 tmpList
->erase( currentJob
.splitted_
);
178 compoundMem
.push_back( tmpList
);
179 triangleCount
+= tmpList
->size( );
184 // In order to be able to deal with the triangles efficiently from here on, I put them all in a long vector.
185 // This has one drawback, though, being that we will lose track of the fact that triangles belonging to the same
186 // facet does not have to be checked for depth order. However, I count on them not being ordered thanks to the
187 // tolerance used in the overlap test.
188 std::vector
< const Computation::ZBufTriangle
* > triangleMem
;
189 triangleMem
.reserve( triangleCount
);
190 for( std::vector
< CompoundObject
* >::iterator o
= compoundMem
.begin( ); o
!= compoundMem
.end( ); ++o
)
192 for( CompoundObject::iterator j
= (*o
)->begin( ); j
!= (*o
)->end( ); ++j
)
194 triangleMem
.push_back( & *j
);
197 if( triangleMem
.size( ) != triangleCount
)
199 throw Exceptions::InternalError( "Some triangles are missing!" );
203 // I keep track of which objects an object has to be drawn after. The objects that are not
204 // waiting for other objects to be drawn are kept in a special list.
205 // To do this efficiently, each object need to know how many objects it is waiting for to be
206 // drawn. It must also know what objects to update when it has been drawn. An object is identified
207 // by the pointer to its list, so the additional information must be kept in a separate structure.
208 // As usual, objects are identified by their position in a memory vector.
209 // At this state, "to draw" an object means to place it in drawOrder.
211 std::list
< const Computation::ZBufTriangle
* > drawOrder
;
212 if( triangleCount
> 0 ) // This avoids a bug that would otherwise occur due to computing triangleCount - 1
214 std::vector
< size_t > waitCounters
;
215 waitCounters
.resize( triangleCount
, 0 );
216 std::vector
< std::list
< size_t > > waitingObjects
;
217 waitingObjects
.resize( triangleCount
);
219 // We begin by setting up waitingObjects and waitCounters.
220 // This involves testing each object against all other objects.
221 for( size_t i0
= 0; i0
< triangleCount
- 1; ++i0
) // Ugly bug if triangleCount == 0
223 const Computation::ZBufTriangle
* t0
= triangleMem
[ i0
];
224 for( size_t i1
= i0
+ 1; i1
< triangleCount
; ++i1
)
226 const Computation::ZBufTriangle
* t1
= triangleMem
[ i1
];
227 if( t0
->overlaps( *t1
) )
229 Concrete::Coords2D
commonPoint( 0, 0 );
230 if( ! t0
->overlaps( *t1
, & commonPoint
, Computation::theTrixelizeOverlapTol
) )
232 // Too little overlap.
235 if( t0
->isOnTopOfAt( *t1
, commonPoint
) )
237 waitingObjects
[ i1
].push_back( i0
);
238 ++waitCounters
[ i0
];
242 waitingObjects
[ i0
].push_back( i1
);
243 ++waitCounters
[ i1
];
249 // Then the queue of objects to be "drawn" is initialized.
250 std::list
< size_t > drawQueue
;
251 std::map
< const Computation::PaintedPolygon3D
*, size_t > trianglesInPolygon
;
253 std::vector
< size_t >::iterator wi
= waitCounters
.begin( );
254 for( size_t i
= 0; i
< triangleCount
; ++i
, ++wi
)
258 drawQueue
.push_back( i
);
259 ++trianglesInPolygon
[ triangleMem
[ i
]->painter_
];
264 // Now, when the triangles are "drawn", that is, placed in drawOrder, they shall be placed so
265 // in such a way that triangles that belong to the same polygon appear in sequence as often as possible.
266 // While there is probably accurate ways to treat this problem, I resort to some simple heuristics here.
267 // The question is basically how to pick a polygon among those than contain a triangle that may be drawn.
269 size_t drawnCount
= 0;
270 while( drawnCount
< triangleCount
)
272 while( ! drawQueue
.empty( ) )
274 // First, use find the polygon whith the most triangles in drawQueue.
275 const Computation::PaintedPolygon3D
* painter
= 0;
277 // Note that triangles that belong to the same polygon will never overlap, and hence drawing triangles that belong
278 // to painter will not make other triangles that belong to painter ready to be drawn. This algorithm depends on
281 size_t bestCount
= 0;
283 typedef typeof trianglesInPolygon MapType
;
284 MapType::iterator best_j
;
285 for( MapType::iterator j
= trianglesInPolygon
.begin( ); j
!= trianglesInPolygon
.end( ); ++j
)
287 if( j
->second
> bestCount
)
289 bestCount
= j
->second
;
293 painter
= best_j
->first
;
294 trianglesInPolygon
.erase( best_j
); // If we need this again it will be re-created.
297 // Soon, bestCount triangles will have been drawn, but the value of bestCount will then be destroyed.
298 drawnCount
+= bestCount
;
300 // There shall be bestCount triangles to draw, so by counting the number of triangles we find we may not
301 // have to search all of drawQueue.
302 for( std::list
< size_t >::iterator ii
= drawQueue
.begin( ); bestCount
> 0; )
305 if( triangleMem
[ i
]->painter_
!= painter
)
311 std::list
< size_t >::iterator erase_i
= ii
;
313 drawQueue
.erase( erase_i
);
316 drawOrder
.push_back( triangleMem
[ i
] );
317 triangleMem
[ i
] = 0;
319 const std::list
< size_t > & waitList
= waitingObjects
[ i
];
320 for( std::list
< size_t >::const_iterator j
= waitList
.begin( ); j
!= waitList
.end( ); ++j
)
322 --waitCounters
[ *j
];
323 if( waitCounters
[ *j
] == 0 )
325 drawQueue
.push_back( *j
);
326 // Note that it is assumed that ( triangleMem[ *j ]->painter_ != painter ) !
327 // if( triangleMem[ *j ]->painter_ == painter )
329 // throw Exceptions::InternalError( "Triangle waiting for another triangle in the same polygon!" );
331 ++trianglesInPolygon
[ triangleMem
[ *j
]->painter_
];
338 if( drawnCount
< triangleCount
)
340 // Resolve cyclic overlap the hard way...
341 std::cerr
<< "A cyclic overlap situation in a z sorter required a small triangle to be drawn too deep." << std::endl
;
342 Concrete::Area bestArea
= HUGE_VAL
;
344 // This search is a somewhat expensive since we must search the whole list.
345 typedef typeof triangleMem ListType
;
346 ListType::iterator ti
= triangleMem
.begin( );
347 for( size_t i
= 0; i
< triangleCount
; ++i
, ++ti
)
353 Concrete::Area tmpArea
= (*ti
)->area( );
354 if( tmpArea
< bestArea
)
360 drawQueue
.push_back( besti
);
361 ++trianglesInPolygon
[ triangleMem
[ besti
]->painter_
];
362 waitCounters
[ besti
] = 0; // This will avoid that this is drawn again, since the counter will never _reach_ 0 now.
368 // It is now time to take care of the lines.
369 // The first thing we shall do is to remove what is occluded by triangles.
370 // Note that triangles will be drawn before the lines, and that is the only way lines
371 // can occlude triangles.
372 // Then, we make sure that the lines are drawn in back-to-front order, clipping occluded lines
373 // behind the line occluding them to avoid cyclic locking.
375 std::list
< const Computation::ZBufLine
* > lineQueue
;
377 typedef typeof *linePile_ PileType
;
378 for( PileType::const_iterator src
= linePile_
->begin( ); src
!= linePile_
->end( ); ++src
)
380 (*src
)->push_zBufLine( tf
, eyez
, & lineQueue
);
384 std::list
< const Computation::ZBufLine
* > disjointLines
;
385 while( ! lineQueue
.empty( ) )
388 std::list
< const Computation::ZBufLine
* > queue1
;
389 std::list
< const Computation::ZBufLine
* > queue2
;
391 std::list
< const Computation::ZBufLine
* > * currentQueue
= & queue1
;
392 std::list
< const Computation::ZBufLine
* > * otherQueue
= & queue2
;
394 currentQueue
->push_back( lineQueue
.front( ) );
395 lineQueue
.pop_front( );
397 typedef typeof drawOrder ListType
;
398 for( ListType::const_iterator i
= drawOrder
.begin( ); i
!= drawOrder
.end( ); ++i
)
400 while( ! currentQueue
->empty( ) )
402 const Computation::ZBufLine
* currentLine
= currentQueue
->front( );
403 currentQueue
->pop_front( );
404 if( currentLine
->overlaps( **i
) )
406 currentLine
->splice( **i
, otherQueue
);
411 otherQueue
->push_back( currentLine
);
417 std::list
< const Computation::ZBufLine
* > * tmp
= currentQueue
;
418 currentQueue
= otherQueue
;
423 // When we reach here the line segments are in currentQueue.
424 // These segments are ready to be inserted in the line z buffer.
426 // The algorithm below is inefficient, because it will generally make the overlap comparison
427 // several times for any overlaping pair of line segments.
428 while( ! currentQueue
->empty( ) )
430 const Computation::ZBufLine
* current
= currentQueue
->front( );
431 currentQueue
->pop_front( );
433 bool foundOverlap
= false;
434 typedef typeof disjointLines ListType
;
435 for( ListType::iterator i
= disjointLines
.begin( ); i
!= disjointLines
.end( );
438 if( current
->overlaps( **i
) )
440 disjointLines
.erase( i
);
441 // Note that splice is responsible for deleting that of *i and current which is not used.
442 Computation::ZBufLine::splice( *i
, current
,
451 disjointLines
.push_back( current
);
457 RefCountPtr
< const Lang::Group2D
> res
= Lang::THE_NULL2D
;
459 const bool SHOW_TRIXELS
= false;
462 // This is a debug mode
464 typedef typeof drawOrder ListType
;
465 for( ListType::const_iterator i
= drawOrder
.begin( ); i
!= drawOrder
.end( ); ++i
)
467 res
= RefCountPtr
< const Lang::Group2D
>( new Lang::GroupPair2D( (*i
)->debugFrame( ),
474 // This is the standard mode
476 // Remember that the grouping of triangles into polygons can probably be improved!
478 typedef typeof drawOrder ListType
;
479 for( ListType::iterator i
= drawOrder
.begin( ); i
!= drawOrder
.end( ); ) // Note that i shall not be incremented here.
481 const Computation::PaintedPolygon3D
* painter
= (*i
)->painter_
;
482 if( painter
->getColor( ) == Lang::THE_OCCLUDING_WHITE
)
488 std::list
< Computation::ZBufTriangle
> regions
;
489 // This is a hideous copy!
490 regions
.push_back( **i
);
492 // Now we'll simply join the triangle **i with the immediately following triangles sharing the same painter.
493 // The job of joining triangles thus consists in placing them in a good order in drawOrder.
496 for( ; i
!= drawOrder
.end( ) && (*i
)->painter_
== painter
; ++i
)
498 // Another hideous copy!
499 regions
.push_back( **i
);
502 // If this would have been a z-buffer, we should add the common lights to the shadow lights here,
503 // but in a z-sorter there are no shadow lights.
504 RefCountPtr
< const Lang::PaintedPolygon2D
> tmp
= painter
->polygon_to2D( dyn
, tf
, commonLights
);
506 // The following statement will consume the objects in regions.
507 res
= RefCountPtr
< const Lang::Group2D
>( new Lang::GroupPair2D( tmp
->clip( & regions
, tmp
),
514 // Memory cleanup of the triangles should be taken care of by compoundMem.
517 // Finally we draw the lines.
518 while( ! disjointLines
.empty( ) )
520 const Computation::ZBufLine
* current
= disjointLines
.front( );
521 disjointLines
.pop_front( );
522 res
= RefCountPtr
< const Lang::Group2D
>( new Lang::GroupPair2D( current
->stroke2D( ),