768 lines
21 KiB
C++
Executable file
768 lines
21 KiB
C++
Executable file
//----------------------------------------------------------------------------
|
|
// 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 <cstring>
|
|
#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 > 0)
|
|
{
|
|
pod_allocator<cell_type>::deallocate(*ptr, cell_block_size);
|
|
ptr--;
|
|
--m_num_blocks;
|
|
}
|
|
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(0x7FFFFFFF),
|
|
m_min_y(0x7FFFFFFF),
|
|
m_max_x(-0x7FFFFFFF),
|
|
m_max_y(-0x7FFFFFFF),
|
|
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 = 0x7FFFFFFF;
|
|
m_min_y = 0x7FFFFFFF;
|
|
m_max_x = -0x7FFFFFFF;
|
|
m_max_y = -0x7FFFFFFF;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
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, 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 = x2 - x1;
|
|
|
|
if(dx < 0)
|
|
{
|
|
p = fx1 * (y2 - y1);
|
|
first = 0;
|
|
incr = -1;
|
|
dx = -dx;
|
|
}
|
|
|
|
delta = p / dx;
|
|
mod = p % dx;
|
|
|
|
if(mod < 0)
|
|
{
|
|
delta--;
|
|
mod += 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 = p / dx;
|
|
rem = p % dx;
|
|
|
|
if (rem < 0)
|
|
{
|
|
lift--;
|
|
rem += dx;
|
|
}
|
|
|
|
mod -= dx;
|
|
|
|
while (ex1 != ex2)
|
|
{
|
|
delta = lift;
|
|
mod += rem;
|
|
if(mod >= 0)
|
|
{
|
|
mod -= 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 };
|
|
|
|
int dx = x2 - x1;
|
|
|
|
if(dx >= dx_limit || dx <= -dx_limit)
|
|
{
|
|
int cx = (x1 + x2) >> 1;
|
|
int cy = (y1 + y2) >> 1;
|
|
|
|
// Bail if values are so large they are likely to wrap
|
|
if ((std::abs(x1) >= std::numeric_limits<int>::max()/2) || (std::abs(y1) >= std::numeric_limits<int>::max()/2) ||
|
|
(std::abs(x2) >= std::numeric_limits<int>::max()/2) || (std::abs(y2) >= std::numeric_limits<int>::max()/2))
|
|
return;
|
|
|
|
line(x1, y1, cx, cy);
|
|
line(cx, cy, x2, y2);
|
|
}
|
|
|
|
int dy = y2 - 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 p, rem, mod, lift, delta, first, incr;
|
|
|
|
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 = p / dy;
|
|
mod = p % dy;
|
|
|
|
if(mod < 0)
|
|
{
|
|
delta--;
|
|
mod += 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 = p / dy;
|
|
rem = p % dy;
|
|
|
|
if(rem < 0)
|
|
{
|
|
lift--;
|
|
rem += dy;
|
|
}
|
|
mod -= dy;
|
|
|
|
while(ey1 != ey2)
|
|
{
|
|
delta = lift;
|
|
mod += rem;
|
|
if (mod >= 0)
|
|
{
|
|
mod -= 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 = 0x7FFFFFFF;
|
|
m_curr_cell.y = 0x7FFFFFFF;
|
|
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 >> cell_block_shift;
|
|
unsigned i;
|
|
while(nb > 0)
|
|
{
|
|
cell_ptr = *block_ptr++;
|
|
i = cell_block_size;
|
|
while(i > 0)
|
|
{
|
|
m_sorted_y[cell_ptr->y - m_min_y].start++;
|
|
++cell_ptr;
|
|
--i;
|
|
}
|
|
--nb;
|
|
}
|
|
|
|
cell_ptr = *block_ptr++;
|
|
i = m_num_cells & cell_block_mask;
|
|
while(i > 0)
|
|
{
|
|
m_sorted_y[cell_ptr->y - m_min_y].start++;
|
|
++cell_ptr;
|
|
--i;
|
|
}
|
|
|
|
// 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 >> cell_block_shift;
|
|
while(nb > 0)
|
|
{
|
|
cell_ptr = *block_ptr++;
|
|
i = cell_block_size;
|
|
while(i > 0)
|
|
{
|
|
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;
|
|
--i;
|
|
}
|
|
--nb;
|
|
}
|
|
|
|
cell_ptr = *block_ptr++;
|
|
i = m_num_cells & cell_block_mask;
|
|
while(i > 0)
|
|
{
|
|
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;
|
|
--i;
|
|
}
|
|
|
|
// 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
|