mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	
		
			
				
	
	
		
			741 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			741 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//----------------------------------------------------------------------------
 | 
						|
// Anti-Grain Geometry - Version 2.4
 | 
						|
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
 | 
						|
//
 | 
						|
// Permission to copy, use, modify, sell and distribute this software 
 | 
						|
// is granted provided this copyright notice appears in all copies. 
 | 
						|
// This software is provided "as is" without express or implied
 | 
						|
// warranty, and with no claim as to its suitability for any purpose.
 | 
						|
//
 | 
						|
//----------------------------------------------------------------------------
 | 
						|
//
 | 
						|
// The author gratefully acknowleges the support of David Turner, 
 | 
						|
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType 
 | 
						|
// libray - in producing this work. See http://www.freetype.org for details.
 | 
						|
//
 | 
						|
//----------------------------------------------------------------------------
 | 
						|
// Contact: mcseem@antigrain.com
 | 
						|
//          mcseemagg@yahoo.com
 | 
						|
//          http://www.antigrain.com
 | 
						|
//----------------------------------------------------------------------------
 | 
						|
//
 | 
						|
// Adaptation for 32-bit screen coordinates has been sponsored by 
 | 
						|
// Liberty Technology Systems, Inc., visit http://lib-sys.com
 | 
						|
//
 | 
						|
// Liberty Technology Systems, Inc. is the provider of
 | 
						|
// PostScript and PDF technology for software developers.
 | 
						|
// 
 | 
						|
//----------------------------------------------------------------------------
 | 
						|
#ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED
 | 
						|
#define AGG_RASTERIZER_CELLS_AA_INCLUDED
 | 
						|
 | 
						|
#include <string.h>
 | 
						|
#include <cstdlib>
 | 
						|
#include <limits>
 | 
						|
#include "agg_math.h"
 | 
						|
#include "agg_array.h"
 | 
						|
 | 
						|
 | 
						|
namespace agg
 | 
						|
{
 | 
						|
 | 
						|
    //-----------------------------------------------------rasterizer_cells_aa
 | 
						|
    // An internal class that implements the main rasterization algorithm.
 | 
						|
    // Used in the rasterizer. Should not be used direcly.
 | 
						|
    template<class Cell> class rasterizer_cells_aa
 | 
						|
    {
 | 
						|
        enum cell_block_scale_e
 | 
						|
        {
 | 
						|
            cell_block_shift = 12,
 | 
						|
            cell_block_size  = 1 << cell_block_shift,
 | 
						|
            cell_block_mask  = cell_block_size - 1,
 | 
						|
            cell_block_pool  = 256,
 | 
						|
            cell_block_limit = 1024
 | 
						|
        };
 | 
						|
 | 
						|
        struct sorted_y
 | 
						|
        {
 | 
						|
            unsigned start;
 | 
						|
            unsigned num;
 | 
						|
        };
 | 
						|
 | 
						|
    public:
 | 
						|
        typedef Cell cell_type;
 | 
						|
        typedef rasterizer_cells_aa<Cell> self_type;
 | 
						|
 | 
						|
        ~rasterizer_cells_aa();
 | 
						|
        rasterizer_cells_aa();
 | 
						|
 | 
						|
        void reset();
 | 
						|
        void style(const cell_type& style_cell);
 | 
						|
        void line(int x1, int y1, int x2, int y2);
 | 
						|
 | 
						|
        int min_x() const { return m_min_x; }
 | 
						|
        int min_y() const { return m_min_y; }
 | 
						|
        int max_x() const { return m_max_x; }
 | 
						|
        int max_y() const { return m_max_y; }
 | 
						|
 | 
						|
        void sort_cells();
 | 
						|
 | 
						|
        unsigned total_cells() const 
 | 
						|
        {
 | 
						|
            return m_num_cells;
 | 
						|
        }
 | 
						|
 | 
						|
        unsigned scanline_num_cells(unsigned y) const 
 | 
						|
        { 
 | 
						|
            return m_sorted_y[y - m_min_y].num; 
 | 
						|
        }
 | 
						|
 | 
						|
        const cell_type* const* scanline_cells(unsigned y) const
 | 
						|
        { 
 | 
						|
            return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start; 
 | 
						|
        }
 | 
						|
 | 
						|
        bool sorted() const { return m_sorted; }
 | 
						|
 | 
						|
    private:
 | 
						|
        rasterizer_cells_aa(const self_type&);
 | 
						|
        const self_type& operator = (const self_type&);
 | 
						|
 | 
						|
        void set_curr_cell(int x, int y);
 | 
						|
        void add_curr_cell();
 | 
						|
        void render_hline(int ey, int x1, int y1, int x2, int y2);
 | 
						|
        void allocate_block();
 | 
						|
        
 | 
						|
    private:
 | 
						|
        unsigned                m_num_blocks;
 | 
						|
        unsigned                m_max_blocks;
 | 
						|
        unsigned                m_curr_block;
 | 
						|
        unsigned                m_num_cells;
 | 
						|
        cell_type**             m_cells;
 | 
						|
        cell_type*              m_curr_cell_ptr;
 | 
						|
        pod_vector<cell_type*>  m_sorted_cells;
 | 
						|
        pod_vector<sorted_y>    m_sorted_y;
 | 
						|
        cell_type               m_curr_cell;
 | 
						|
        cell_type               m_style_cell;
 | 
						|
        int                     m_min_x;
 | 
						|
        int                     m_min_y;
 | 
						|
        int                     m_max_x;
 | 
						|
        int                     m_max_y;
 | 
						|
        bool                    m_sorted;
 | 
						|
    };
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template<class Cell> 
 | 
						|
    rasterizer_cells_aa<Cell>::~rasterizer_cells_aa()
 | 
						|
    {
 | 
						|
        if(m_num_blocks)
 | 
						|
        {
 | 
						|
            cell_type** ptr = m_cells + m_num_blocks - 1;
 | 
						|
            while(m_num_blocks--)
 | 
						|
            {
 | 
						|
                pod_allocator<cell_type>::deallocate(*ptr, cell_block_size);
 | 
						|
                ptr--;
 | 
						|
            }
 | 
						|
            pod_allocator<cell_type*>::deallocate(m_cells, m_max_blocks);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template<class Cell> 
 | 
						|
    rasterizer_cells_aa<Cell>::rasterizer_cells_aa() :
 | 
						|
        m_num_blocks(0),
 | 
						|
        m_max_blocks(0),
 | 
						|
        m_curr_block(0),
 | 
						|
        m_num_cells(0),
 | 
						|
        m_cells(0),
 | 
						|
        m_curr_cell_ptr(0),
 | 
						|
        m_sorted_cells(),
 | 
						|
        m_sorted_y(),
 | 
						|
        m_min_x(std::numeric_limits<int>::max()),
 | 
						|
        m_min_y(std::numeric_limits<int>::max()),
 | 
						|
        m_max_x(std::numeric_limits<int>::min()),
 | 
						|
        m_max_y(std::numeric_limits<int>::min()),
 | 
						|
        m_sorted(false)
 | 
						|
    {
 | 
						|
        m_style_cell.initial();
 | 
						|
        m_curr_cell.initial();
 | 
						|
    }
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template<class Cell> 
 | 
						|
    void rasterizer_cells_aa<Cell>::reset()
 | 
						|
    {
 | 
						|
        m_num_cells = 0; 
 | 
						|
        m_curr_block = 0;
 | 
						|
        m_curr_cell.initial();
 | 
						|
        m_style_cell.initial();
 | 
						|
        m_sorted = false;
 | 
						|
        m_min_x = std::numeric_limits<int>::max();
 | 
						|
        m_min_y = std::numeric_limits<int>::max();
 | 
						|
        m_max_x = std::numeric_limits<int>::min();
 | 
						|
        m_max_y = std::numeric_limits<int>::min();
 | 
						|
    }
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template<class Cell> 
 | 
						|
    AGG_INLINE void rasterizer_cells_aa<Cell>::add_curr_cell()
 | 
						|
    {
 | 
						|
        if(m_curr_cell.area | m_curr_cell.cover)
 | 
						|
        {
 | 
						|
            if((m_num_cells & cell_block_mask) == 0)
 | 
						|
            {
 | 
						|
                if(m_num_blocks >= cell_block_limit) return;
 | 
						|
                allocate_block();
 | 
						|
            }
 | 
						|
            *m_curr_cell_ptr++ = m_curr_cell;
 | 
						|
            ++m_num_cells;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template<class Cell> 
 | 
						|
    AGG_INLINE void rasterizer_cells_aa<Cell>::set_curr_cell(int x, int y)
 | 
						|
    {
 | 
						|
        if(m_curr_cell.not_equal(x, y, m_style_cell))
 | 
						|
        {
 | 
						|
            add_curr_cell();
 | 
						|
            m_curr_cell.style(m_style_cell);
 | 
						|
            m_curr_cell.x     = x;
 | 
						|
            m_curr_cell.y     = y;
 | 
						|
            m_curr_cell.cover = 0;
 | 
						|
            m_curr_cell.area  = 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template<class Cell> 
 | 
						|
    AGG_INLINE void rasterizer_cells_aa<Cell>::render_hline(int ey, 
 | 
						|
                                                            int x1, int y1, 
 | 
						|
                                                            int x2, int y2)
 | 
						|
    {
 | 
						|
        int ex1 = x1 >> poly_subpixel_shift;
 | 
						|
        int ex2 = x2 >> poly_subpixel_shift;
 | 
						|
        int fx1 = x1 & poly_subpixel_mask;
 | 
						|
        int fx2 = x2 & poly_subpixel_mask;
 | 
						|
 | 
						|
        int delta, p, first;
 | 
						|
        long long dx;
 | 
						|
        int incr, lift, mod, rem;
 | 
						|
 | 
						|
        //trivial case. Happens often
 | 
						|
        if(y1 == y2)
 | 
						|
        {
 | 
						|
            set_curr_cell(ex2, ey);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        //everything is located in a single cell.  That is easy!
 | 
						|
        if(ex1 == ex2)
 | 
						|
        {
 | 
						|
            delta = y2 - y1;
 | 
						|
            m_curr_cell.cover += delta;
 | 
						|
            m_curr_cell.area  += (fx1 + fx2) * delta;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        //ok, we'll have to render a run of adjacent cells on the same
 | 
						|
        //hline...
 | 
						|
        p     = (poly_subpixel_scale - fx1) * (y2 - y1);
 | 
						|
        first = poly_subpixel_scale;
 | 
						|
        incr  = 1;
 | 
						|
 | 
						|
        dx = (long long)x2 - (long long)x1;
 | 
						|
 | 
						|
        if(dx < 0)
 | 
						|
        {
 | 
						|
            p     = fx1 * (y2 - y1);
 | 
						|
            first = 0;
 | 
						|
            incr  = -1;
 | 
						|
            dx    = -dx;
 | 
						|
        }
 | 
						|
 | 
						|
        delta = (int)(p / dx);
 | 
						|
        mod   = (int)(p % dx);
 | 
						|
 | 
						|
        if(mod < 0)
 | 
						|
        {
 | 
						|
            delta--;
 | 
						|
            mod += static_cast<int>(dx);
 | 
						|
        }
 | 
						|
 | 
						|
        m_curr_cell.cover += delta;
 | 
						|
        m_curr_cell.area  += (fx1 + first) * delta;
 | 
						|
 | 
						|
        ex1 += incr;
 | 
						|
        set_curr_cell(ex1, ey);
 | 
						|
        y1  += delta;
 | 
						|
 | 
						|
        if(ex1 != ex2)
 | 
						|
        {
 | 
						|
            p     = poly_subpixel_scale * (y2 - y1 + delta);
 | 
						|
            lift  = (int)(p / dx);
 | 
						|
            rem   = (int)(p % dx);
 | 
						|
 | 
						|
            if (rem < 0)
 | 
						|
            {
 | 
						|
                lift--;
 | 
						|
                rem += static_cast<int>(dx);
 | 
						|
            }
 | 
						|
 | 
						|
            mod -= static_cast<int>(dx);
 | 
						|
 | 
						|
            while (ex1 != ex2)
 | 
						|
            {
 | 
						|
                delta = lift;
 | 
						|
                mod  += rem;
 | 
						|
                if(mod >= 0)
 | 
						|
                {
 | 
						|
                    mod -= static_cast<int>(dx);
 | 
						|
                    delta++;
 | 
						|
                }
 | 
						|
 | 
						|
                m_curr_cell.cover += delta;
 | 
						|
                m_curr_cell.area  += poly_subpixel_scale * delta;
 | 
						|
                y1  += delta;
 | 
						|
                ex1 += incr;
 | 
						|
                set_curr_cell(ex1, ey);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        delta = y2 - y1;
 | 
						|
        m_curr_cell.cover += delta;
 | 
						|
        m_curr_cell.area  += (fx2 + poly_subpixel_scale - first) * delta;
 | 
						|
    }
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template<class Cell> 
 | 
						|
    AGG_INLINE void rasterizer_cells_aa<Cell>::style(const cell_type& style_cell)
 | 
						|
    { 
 | 
						|
        m_style_cell.style(style_cell); 
 | 
						|
    }
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template<class Cell> 
 | 
						|
    void rasterizer_cells_aa<Cell>::line(int x1, int y1, int x2, int y2)
 | 
						|
    {
 | 
						|
        enum dx_limit_e { dx_limit = 16384 << poly_subpixel_shift };
 | 
						|
 | 
						|
        long long dx = (long long)x2 - (long long)x1;
 | 
						|
 | 
						|
        if(dx >= dx_limit || dx <= -dx_limit)
 | 
						|
        {
 | 
						|
            int cx = (int)(((long long)x1 + (long long)x2) >> 1);
 | 
						|
            int cy = (int)(((long long)y1 + (long long)y2) >> 1);
 | 
						|
            line(x1, y1, cx, cy);
 | 
						|
            line(cx, cy, x2, y2);
 | 
						|
        }
 | 
						|
 | 
						|
        long long dy = (long long)y2 - (long long)y1;
 | 
						|
        int ex1 = x1 >> poly_subpixel_shift;
 | 
						|
        int ex2 = x2 >> poly_subpixel_shift;
 | 
						|
        int ey1 = y1 >> poly_subpixel_shift;
 | 
						|
        int ey2 = y2 >> poly_subpixel_shift;
 | 
						|
        int fy1 = y1 & poly_subpixel_mask;
 | 
						|
        int fy2 = y2 & poly_subpixel_mask;
 | 
						|
 | 
						|
        int x_from, x_to;
 | 
						|
        int rem, mod, lift, delta, first, incr;
 | 
						|
        long long p;
 | 
						|
 | 
						|
        if(ex1 < m_min_x) m_min_x = ex1;
 | 
						|
        if(ex1 > m_max_x) m_max_x = ex1;
 | 
						|
        if(ey1 < m_min_y) m_min_y = ey1;
 | 
						|
        if(ey1 > m_max_y) m_max_y = ey1;
 | 
						|
        if(ex2 < m_min_x) m_min_x = ex2;
 | 
						|
        if(ex2 > m_max_x) m_max_x = ex2;
 | 
						|
        if(ey2 < m_min_y) m_min_y = ey2;
 | 
						|
        if(ey2 > m_max_y) m_max_y = ey2;
 | 
						|
 | 
						|
        set_curr_cell(ex1, ey1);
 | 
						|
 | 
						|
        //everything is on a single hline
 | 
						|
        if(ey1 == ey2)
 | 
						|
        {
 | 
						|
            render_hline(ey1, x1, fy1, x2, fy2);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        //Vertical line - we have to calculate start and end cells,
 | 
						|
        //and then - the common values of the area and coverage for
 | 
						|
        //all cells of the line. We know exactly there's only one 
 | 
						|
        //cell, so, we don't have to call render_hline().
 | 
						|
        incr  = 1;
 | 
						|
        if(dx == 0)
 | 
						|
        {
 | 
						|
            int ex = x1 >> poly_subpixel_shift;
 | 
						|
            int two_fx = (x1 - (ex << poly_subpixel_shift)) << 1;
 | 
						|
            int area;
 | 
						|
 | 
						|
            first = poly_subpixel_scale;
 | 
						|
            if(dy < 0)
 | 
						|
            {
 | 
						|
                first = 0;
 | 
						|
                incr  = -1;
 | 
						|
            }
 | 
						|
 | 
						|
            x_from = x1;
 | 
						|
 | 
						|
            //render_hline(ey1, x_from, fy1, x_from, first);
 | 
						|
            delta = first - fy1;
 | 
						|
            m_curr_cell.cover += delta;
 | 
						|
            m_curr_cell.area  += two_fx * delta;
 | 
						|
 | 
						|
            ey1 += incr;
 | 
						|
            set_curr_cell(ex, ey1);
 | 
						|
 | 
						|
            delta = first + first - poly_subpixel_scale;
 | 
						|
            area = two_fx * delta;
 | 
						|
            while(ey1 != ey2)
 | 
						|
            {
 | 
						|
                //render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, first);
 | 
						|
                m_curr_cell.cover = delta;
 | 
						|
                m_curr_cell.area  = area;
 | 
						|
                ey1 += incr;
 | 
						|
                set_curr_cell(ex, ey1);
 | 
						|
            }
 | 
						|
            //render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, fy2);
 | 
						|
            delta = fy2 - poly_subpixel_scale + first;
 | 
						|
            m_curr_cell.cover += delta;
 | 
						|
            m_curr_cell.area  += two_fx * delta;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        //ok, we have to render several hlines
 | 
						|
        p     = (poly_subpixel_scale - fy1) * dx;
 | 
						|
        first = poly_subpixel_scale;
 | 
						|
 | 
						|
        if(dy < 0)
 | 
						|
        {
 | 
						|
            p     = fy1 * dx;
 | 
						|
            first = 0;
 | 
						|
            incr  = -1;
 | 
						|
            dy    = -dy;
 | 
						|
        }
 | 
						|
 | 
						|
        delta = (int)(p / dy);
 | 
						|
        mod   = (int)(p % dy);
 | 
						|
 | 
						|
        if(mod < 0)
 | 
						|
        {
 | 
						|
            delta--;
 | 
						|
            mod += static_cast<int>(dy);
 | 
						|
        }
 | 
						|
 | 
						|
        x_from = x1 + delta;
 | 
						|
        render_hline(ey1, x1, fy1, x_from, first);
 | 
						|
 | 
						|
        ey1 += incr;
 | 
						|
        set_curr_cell(x_from >> poly_subpixel_shift, ey1);
 | 
						|
 | 
						|
        if(ey1 != ey2)
 | 
						|
        {
 | 
						|
            p     = poly_subpixel_scale * dx;
 | 
						|
            lift  = (int)(p / dy);
 | 
						|
            rem   = (int)(p % dy);
 | 
						|
 | 
						|
            if(rem < 0)
 | 
						|
            {
 | 
						|
                lift--;
 | 
						|
                rem += static_cast<int>(dy);
 | 
						|
            }
 | 
						|
            mod -= static_cast<int>(dy);
 | 
						|
 | 
						|
            while(ey1 != ey2)
 | 
						|
            {
 | 
						|
                delta = lift;
 | 
						|
                mod  += rem;
 | 
						|
                if (mod >= 0)
 | 
						|
                {
 | 
						|
                    mod -= static_cast<int>(dy);
 | 
						|
                    delta++;
 | 
						|
                }
 | 
						|
 | 
						|
                x_to = x_from + delta;
 | 
						|
                render_hline(ey1, x_from, poly_subpixel_scale - first, x_to, first);
 | 
						|
                x_from = x_to;
 | 
						|
 | 
						|
                ey1 += incr;
 | 
						|
                set_curr_cell(x_from >> poly_subpixel_shift, ey1);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        render_hline(ey1, x_from, poly_subpixel_scale - first, x2, fy2);
 | 
						|
    }
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template<class Cell> 
 | 
						|
    void rasterizer_cells_aa<Cell>::allocate_block()
 | 
						|
    {
 | 
						|
        if(m_curr_block >= m_num_blocks)
 | 
						|
        {
 | 
						|
            if(m_num_blocks >= m_max_blocks)
 | 
						|
            {
 | 
						|
                cell_type** new_cells = 
 | 
						|
                    pod_allocator<cell_type*>::allocate(m_max_blocks + 
 | 
						|
                                                        cell_block_pool);
 | 
						|
 | 
						|
                if(m_cells)
 | 
						|
                {
 | 
						|
                    memcpy(new_cells, m_cells, m_max_blocks * sizeof(cell_type*));
 | 
						|
                    pod_allocator<cell_type*>::deallocate(m_cells, m_max_blocks);
 | 
						|
                }
 | 
						|
                m_cells = new_cells;
 | 
						|
                m_max_blocks += cell_block_pool;
 | 
						|
            }
 | 
						|
 | 
						|
            m_cells[m_num_blocks++] = 
 | 
						|
                pod_allocator<cell_type>::allocate(cell_block_size);
 | 
						|
 | 
						|
        }
 | 
						|
        m_curr_cell_ptr = m_cells[m_curr_block++];
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template <class T> static AGG_INLINE void swap_cells(T* a, T* b)
 | 
						|
    {
 | 
						|
        T temp = *a;
 | 
						|
        *a = *b;
 | 
						|
        *b = temp;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    enum
 | 
						|
    {
 | 
						|
        qsort_threshold = 9
 | 
						|
    };
 | 
						|
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template<class Cell>
 | 
						|
    void qsort_cells(Cell** start, unsigned num)
 | 
						|
    {
 | 
						|
        Cell**  stack[80];
 | 
						|
        Cell*** top; 
 | 
						|
        Cell**  limit;
 | 
						|
        Cell**  base;
 | 
						|
 | 
						|
        limit = start + num;
 | 
						|
        base  = start;
 | 
						|
        top   = stack;
 | 
						|
 | 
						|
        for (;;)
 | 
						|
        {
 | 
						|
            int len = int(limit - base);
 | 
						|
 | 
						|
            Cell** i;
 | 
						|
            Cell** j;
 | 
						|
            Cell** pivot;
 | 
						|
 | 
						|
            if(len > qsort_threshold)
 | 
						|
            {
 | 
						|
                // we use base + len/2 as the pivot
 | 
						|
                pivot = base + len / 2;
 | 
						|
                swap_cells(base, pivot);
 | 
						|
 | 
						|
                i = base + 1;
 | 
						|
                j = limit - 1;
 | 
						|
 | 
						|
                // now ensure that *i <= *base <= *j 
 | 
						|
                if((*j)->x < (*i)->x)
 | 
						|
                {
 | 
						|
                    swap_cells(i, j);
 | 
						|
                }
 | 
						|
 | 
						|
                if((*base)->x < (*i)->x)
 | 
						|
                {
 | 
						|
                    swap_cells(base, i);
 | 
						|
                }
 | 
						|
 | 
						|
                if((*j)->x < (*base)->x)
 | 
						|
                {
 | 
						|
                    swap_cells(base, j);
 | 
						|
                }
 | 
						|
 | 
						|
                for(;;)
 | 
						|
                {
 | 
						|
                    int x = (*base)->x;
 | 
						|
                    do i++; while( (*i)->x < x );
 | 
						|
                    do j--; while( x < (*j)->x );
 | 
						|
 | 
						|
                    if(i > j)
 | 
						|
                    {
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
 | 
						|
                    swap_cells(i, j);
 | 
						|
                }
 | 
						|
 | 
						|
                swap_cells(base, j);
 | 
						|
 | 
						|
                // now, push the largest sub-array
 | 
						|
                if(j - base > limit - i)
 | 
						|
                {
 | 
						|
                    top[0] = base;
 | 
						|
                    top[1] = j;
 | 
						|
                    base   = i;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    top[0] = i;
 | 
						|
                    top[1] = limit;
 | 
						|
                    limit  = j;
 | 
						|
                }
 | 
						|
                top += 2;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                // the sub-array is small, perform insertion sort
 | 
						|
                j = base;
 | 
						|
                i = j + 1;
 | 
						|
 | 
						|
                for(; i < limit; j = i, i++)
 | 
						|
                {
 | 
						|
                    for(; j[1]->x < (*j)->x; j--)
 | 
						|
                    {
 | 
						|
                        swap_cells(j + 1, j);
 | 
						|
                        if (j == base)
 | 
						|
                        {
 | 
						|
                            break;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                if(top > stack)
 | 
						|
                {
 | 
						|
                    top  -= 2;
 | 
						|
                    base  = top[0];
 | 
						|
                    limit = top[1];
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    //------------------------------------------------------------------------
 | 
						|
    template<class Cell> 
 | 
						|
    void rasterizer_cells_aa<Cell>::sort_cells()
 | 
						|
    {
 | 
						|
        if(m_sorted) return; //Perform sort only the first time.
 | 
						|
 | 
						|
        add_curr_cell();
 | 
						|
        m_curr_cell.x     = std::numeric_limits<int>::max();
 | 
						|
        m_curr_cell.y     = std::numeric_limits<int>::max();
 | 
						|
        m_curr_cell.cover = 0;
 | 
						|
        m_curr_cell.area  = 0;
 | 
						|
 | 
						|
        if(m_num_cells == 0) return;
 | 
						|
 | 
						|
// DBG: Check to see if min/max works well.
 | 
						|
//for(unsigned nc = 0; nc < m_num_cells; nc++)
 | 
						|
//{
 | 
						|
//    cell_type* cell = m_cells[nc >> cell_block_shift] + (nc & cell_block_mask);
 | 
						|
//    if(cell->x < m_min_x || 
 | 
						|
//       cell->y < m_min_y || 
 | 
						|
//       cell->x > m_max_x || 
 | 
						|
//       cell->y > m_max_y)
 | 
						|
//    {
 | 
						|
//        cell = cell; // Breakpoint here
 | 
						|
//    }
 | 
						|
//}
 | 
						|
        // Allocate the array of cell pointers
 | 
						|
        m_sorted_cells.allocate(m_num_cells, 16);
 | 
						|
 | 
						|
        // Allocate and zero the Y array
 | 
						|
        m_sorted_y.allocate(m_max_y - m_min_y + 1, 16);
 | 
						|
        m_sorted_y.zero();
 | 
						|
 | 
						|
        // Create the Y-histogram (count the numbers of cells for each Y)
 | 
						|
        cell_type** block_ptr = m_cells;
 | 
						|
        cell_type*  cell_ptr;
 | 
						|
        unsigned nb = m_num_cells;
 | 
						|
        unsigned i;
 | 
						|
        while(nb)
 | 
						|
        {
 | 
						|
            cell_ptr = *block_ptr++;
 | 
						|
            i = (nb > cell_block_size) ? unsigned(cell_block_size) : nb;
 | 
						|
            nb -= i;
 | 
						|
            while(i--) 
 | 
						|
            {
 | 
						|
                m_sorted_y[cell_ptr->y - m_min_y].start++;
 | 
						|
                ++cell_ptr;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Convert the Y-histogram into the array of starting indexes
 | 
						|
        unsigned start = 0;
 | 
						|
        for(i = 0; i < m_sorted_y.size(); i++)
 | 
						|
        {
 | 
						|
            unsigned v = m_sorted_y[i].start;
 | 
						|
            m_sorted_y[i].start = start;
 | 
						|
            start += v;
 | 
						|
        }
 | 
						|
 | 
						|
        // Fill the cell pointer array sorted by Y
 | 
						|
        block_ptr = m_cells;
 | 
						|
        nb = m_num_cells;
 | 
						|
        while(nb)
 | 
						|
        {
 | 
						|
            cell_ptr = *block_ptr++;
 | 
						|
            i = (nb > cell_block_size) ? unsigned(cell_block_size) : nb;
 | 
						|
            nb -= i;
 | 
						|
            while(i--)
 | 
						|
            {
 | 
						|
                sorted_y& curr_y = m_sorted_y[cell_ptr->y - m_min_y];
 | 
						|
                m_sorted_cells[curr_y.start + curr_y.num] = cell_ptr;
 | 
						|
                ++curr_y.num;
 | 
						|
                ++cell_ptr;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Finally arrange the X-arrays
 | 
						|
        for(i = 0; i < m_sorted_y.size(); i++)
 | 
						|
        {
 | 
						|
            const sorted_y& curr_y = m_sorted_y[i];
 | 
						|
            if(curr_y.num)
 | 
						|
            {
 | 
						|
                qsort_cells(m_sorted_cells.data() + curr_y.start, curr_y.num);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        m_sorted = true;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    //------------------------------------------------------scanline_hit_test
 | 
						|
    class scanline_hit_test
 | 
						|
    {
 | 
						|
    public:
 | 
						|
        scanline_hit_test(int x) : m_x(x), m_hit(false) {}
 | 
						|
 | 
						|
        void reset_spans() {}
 | 
						|
        void finalize(int) {}
 | 
						|
        void add_cell(int x, int)
 | 
						|
        {
 | 
						|
            if(m_x == x) m_hit = true;
 | 
						|
        }
 | 
						|
        void add_span(int x, int len, int)
 | 
						|
        {
 | 
						|
            if(m_x >= x && m_x < x+len) m_hit = true;
 | 
						|
        }
 | 
						|
        unsigned num_spans() const { return 1; }
 | 
						|
        bool hit() const { return m_hit; }
 | 
						|
 | 
						|
    private:
 | 
						|
        int  m_x;
 | 
						|
        bool m_hit;
 | 
						|
    };
 | 
						|
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#endif
 |