Updating the changelog in the VERSION file, and version_sync.
[shapes.git] / source / zsorterto2D.cc
blob9670e154be3e41c8126a0dd88109208ee1ecd629
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
6 * any later version.
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
19 #include <cmath>
21 #include "shapestypes.h"
22 #include "shapesexceptions.h"
23 #include "astexpr.h"
24 #include "consts.h"
25 #include "angleselect.h"
26 #include "astvar.h"
27 #include "astclass.h"
28 #include "statetypes.h"
29 #include "lighttypes.h"
30 #include "shadingtypes.h"
31 #include "globals.h"
32 #include "zbufinternals.h"
33 #include "constructorrepresentation.h"
35 #include <ctype.h>
36 #include <list>
37 #include <algorithm>
39 using namespace Shapes;
41 namespace Shapes
43 namespace Computation
46 struct SplitJob
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 )
57 { }
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 ) );
79 else
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 ) );
128 goto splitFound1;
132 splitFound1:
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_;
150 ++j;
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
156 // the beginning).
157 if( o != currentJob.splittingObject_ )
159 j = (*o)->begin( );
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 ) );
167 goto splitFound2;
171 splitFound2:
172 continue; // this is just a no-op to make this a valid jump destination
175 tmpList->erase( currentJob.splitted_ );
176 job.pop_front( );
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.
233 continue;
235 if( t0->isOnTopOfAt( *t1, commonPoint ) )
237 waitingObjects[ i1 ].push_back( i0 );
238 ++waitCounters[ i0 ];
240 else
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 )
256 if( *wi == 0 )
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
279 // this!
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;
290 best_j = j;
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; )
304 size_t i = *ii;
305 if( triangleMem[ i ]->painter_ != painter )
307 ++ii;
308 continue;
311 std::list< size_t >::iterator erase_i = ii;
312 ++ii;
313 drawQueue.erase( erase_i );
314 --bestCount;
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 )
328 // {
329 // throw Exceptions::InternalError( "Triangle waiting for another triangle in the same polygon!" );
330 // }
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;
343 size_t besti = 0;
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 )
349 if( *ti == 0 )
351 continue;
353 Concrete::Area tmpArea = (*ti)->area( );
354 if( tmpArea < bestArea )
356 bestArea = tmpArea;
357 besti = i;
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 );
407 delete currentLine;
409 else
411 otherQueue->push_back( currentLine );
416 // swap the queues
417 std::list< const Computation::ZBufLine * > * tmp = currentQueue;
418 currentQueue = otherQueue;
419 otherQueue = tmp;
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( );
436 ++i )
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,
443 & disjointLines,
444 currentQueue );
445 foundOverlap = true;
446 break;
449 if( ! foundOverlap )
451 disjointLines.push_back( current );
457 RefCountPtr< const Lang::Group2D > res = Lang::THE_NULL2D;
459 const bool SHOW_TRIXELS = false;
460 if( SHOW_TRIXELS )
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( ),
468 res,
469 metaState_ ) );
472 else
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 )
484 ++i;
485 continue;
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.
495 ++i;
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 ),
508 res,
509 metaState_ ) );
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( ),
523 res,
524 metaState_ ) );
525 delete current;
529 return res;