Correct code and enable tests for ETL "spline" and "value"
[synfig.git] / ETL / ETL / _pen.h
1 /*! ========================================================================
2 ** Extended Template Library
3 ** Pen Template Class Implementation
4 ** $Id$
5 **
6 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
7 **
8 ** This package is free software; you can redistribute it and/or
9 ** modify it under the terms of the GNU General Public License as
10 ** published by the Free Software Foundation; either version 2 of
11 ** the License, or (at your option) any later version.
12 **
13 ** This package is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 ** General Public License for more details.
17 **
18 ** === N O T E S ===========================================================
19 **
20 ** This is an internal header file, included by other ETL headers.
21 ** You should not attempt to use it directly.
22 **
23 ** ========================================================================= */
24
25 /* === S T A R T =========================================================== */
26
27 #ifndef __ETL__PEN_H
28 #define __ETL__PEN_H
29
30 /* === H E A D E R S ======================================================= */
31
32 #include "_curve_func.h"
33 #include <cassert>
34 #include <iterator>
35 #include <algorithm>
36
37 /* === M A C R O S ========================================================= */
38
39 /* === T Y P E D E F S ===================================================== */
40
41 /* === C L A S S E S & S T R U C T S ======================================= */
42
43 _ETL_BEGIN_NAMESPACE
44
45 template<typename T>
46 class generic_pen_row_iterator
47 {
48 public:
49         struct iterator_category : public std::random_access_iterator_tag {};
50         typedef T value_type;
51         typedef int difference_type;
52         typedef value_type* pointer;
53         typedef value_type& reference;
54
55         typedef generic_pen_row_iterator<value_type> self_type;
56
57         pointer data_;
58         int pitch_;
59
60         reference operator[](int i)const { assert(data_); return *(pointer)( (char*)data_+pitch_*i ); }
61         reference operator*()const { assert(data_); return *data_; }
62         pointer operator->() const { assert(data_); return &(operator*()); }
63
64         void inc() { assert(data_); data_ = (pointer)((char*)data_ + pitch_); }
65         void inc(int n) { assert(data_); data_ = (pointer)((char*)data_ + n*pitch_); }
66
67         void dec() { assert(data_); data_ = (pointer)((char*)data_ - pitch_); }
68         void dec(int n) { assert(data_); data_ = (pointer)((char*)data_ - n*pitch_); }
69
70         const self_type &operator++() { assert(data_); inc(); return *this; }
71         const self_type &operator--() { assert(data_); dec(); return *this; }
72
73         self_type operator++(int)
74                 { assert(data_); self_type ret(*this); inc(); return ret; }
75         self_type operator--(int)
76                 { assert(data_); self_type ret(*this); dec(); return ret; }
77
78         bool operator==(const self_type &rhs)const
79                 { return data_==rhs.data_; }
80
81         bool operator!=(const self_type &rhs)const
82                 { return data_!=rhs.data_; }
83
84         difference_type operator-(const self_type &rhs)const
85                 { assert(data_); return ((char*)data_-(char*)rhs.data_-1)/pitch_+1; }
86
87         self_type operator+(const difference_type &rhs)const
88         {
89                 assert(data_);
90                 self_type ret(*this);
91                 ret.inc(rhs);
92                 return ret;
93         }
94
95         self_type operator-(const difference_type &rhs)const
96         {
97                 assert(data_);
98                 self_type ret(*this);
99                 ret.dec(rhs);
100                 return ret;
101         }
102
103         operator const generic_pen_row_iterator<const value_type>()const
104         {
105                 return generic_pen_row_iterator<const value_type>(data_,pitch_);
106         }
107
108         operator bool()const { return (bool)data_; }
109         bool operator!()const { return !data_; }
110
111         generic_pen_row_iterator(pointer data, int pitch):data_(data),pitch_(pitch) { }
112         generic_pen_row_iterator():data_(NULL) { }
113 };
114
115 template<typename T, typename AT=T>
116 class generic_pen
117 {
118 public:
119         typedef T value_type;
120         typedef AT accumulator_type;
121         typedef value_type* pointer;
122         typedef const value_type* const_pointer;
123         typedef value_type& reference;
124         typedef const value_type& const_reference;
125
126         typedef pointer iterator_x;
127         typedef const_pointer const_iterator_x;
128
129         typedef generic_pen_row_iterator<value_type> iterator_y;
130         typedef generic_pen_row_iterator<const value_type> const_iterator_y;
131
132         struct difference_type
133         {
134                 typedef int value_type;
135                 value_type x,y;
136                 difference_type(value_type x, value_type y):x(x),y(y) { }
137                 value_type &operator[](int i)const { return i?y:x; }
138         };
139
140 protected:
141         int x_,y_;
142         int w_,h_;
143 private:
144         int pitch_;
145         value_type value_;
146         value_type *data_;
147
148         typedef generic_pen<T,AT> self_type;
149
150         void addptr(int nbytes)
151         {
152                 data_ = (pointer)((char*)data_ + nbytes);
153         }
154
155         void subptr(int nbytes)
156         {
157                 data_ = (pointer)((char*)data_ - nbytes);
158         }
159
160 public:
161
162         generic_pen(value_type *data, int w, int h, int pitch):
163                 x_(0),
164                 y_(0),
165                 w_(w),
166                 h_(h),
167                 pitch_(pitch),
168                 data_(data)
169         {
170         }
171
172         generic_pen(value_type *data, int w, int h):
173                 x_(0),
174                 y_(0),
175                 w_(w),
176                 h_(h),
177                 pitch_(sizeof(value_type)*w),
178                 data_(data)
179         {
180         }
181
182         generic_pen():data_(NULL) { }
183
184         self_type& move(int a, int b)
185         {
186                 assert(data_);
187                 x_ += a, y_ += b;
188                 addptr(b*pitch_ + a*sizeof(value_type));
189                 return *this;
190         }
191         self_type& move_to(int x, int y) { assert(data_); return move(x - x_,y - y_);}
192         void set_value(const value_type &v) { value_=v; }
193
194         void inc_x() { assert(data_); x_++; data_++; }
195         void dec_x() { assert(data_); x_--; data_--; }
196         void inc_y() { assert(data_); y_++; addptr(pitch_); }
197         void dec_y() { assert(data_); y_--; subptr(pitch_); }
198
199         void inc_x(int n) { assert(data_); x_+=n; data_+=n; }
200         void dec_x(int n) { assert(data_); x_-=n; data_-=n; }
201         void inc_y(int n) { assert(data_); y_+=n; data_ = (pointer)((char*)data_ + pitch_*n); }
202         void dec_y(int n) { assert(data_); y_-=n; data_ = (pointer)((char*)data_ - pitch_*n); }
203
204         void put_value(const value_type &v)const { assert(data_); *data_=v; }
205         void put_value()const { assert(data_); put_value(value_); }
206
207         void put_value_clip(const value_type &v)const
208                 { if(!clipped()) put_value(v); }
209         void put_value_clip()const { put_value_clip(value_); }
210
211         const_reference get_value()const { assert(data_); return *data_; }
212
213         const_reference get_value_at(int x, int y)const { assert(data_); return ((pointer)(((char*)data_)+y*pitch_))[x]; }
214
215         const_reference get_value_clip_at(int x, int y)const { assert(data_); if(clipped(x,y))return value_type(); return ((pointer)(((char*)data_)+y*pitch_))[x]; }
216
217         const value_type get_value_clip()const { assert(data_); if(clipped())return value_type(); return *data_; }
218
219         const value_type get_pen_value()const { return value_; }
220
221         void put_hline(int l,const value_type &v)
222         {for(;l>0;l--,inc_x())put_value(v);}
223
224         void put_hline(int l) {put_hline(l,value_);}
225
226         void put_hline_clip(int l, const value_type &v)
227         {l=std::min(l,w_-x_);for(;l>0;l--,inc_x())put_value_clip(v);}
228
229         void put_hline_clip(int l) {put_hline_clip(l,value_);}
230
231         //the put_block functions do not modify the pen
232         void put_block(int h, int w, const value_type &v)
233         {
234                 self_type row(*this);
235                 for(;h>0;h--,row.inc_y())
236                 {
237                         self_type col(row);
238                         col.put_hline(w,v);
239                 }
240         }
241
242         void put_block(int h, int w) { put_block(h,w,value_); }
243
244         void put_block_clip(int h, int w, const value_type &v)
245         {
246                 self_type row(*this);
247
248                 //clip start position
249                 if(row.x_ < 0) { w+=row.x_; row.inc_x(-row.x_); }
250                 if(row.y_ < 0) { h+=row.y_; row.inc_y(-row.y_); }
251
252                 //clip width and height of copy rect
253                 h = std::min(h,h_-y_);
254                 w = std::min(w,w_-x_);
255
256                 //copy rect
257                 for(;h>0;h--,row.inc_y())
258                 {
259                         self_type col(row);
260                         col.put_hline(w,v);     //already clipped
261                 }
262         }
263
264         void put_block_clip(int h, int w) { put_block(h,w,value_); }
265
266
267         iterator_x operator[](int i)const { assert(data_); return (pointer)(((char*)data_)+i*pitch_); }
268
269         iterator_x x() { assert(data_); return data_; }
270         iterator_x begin_x() { assert(data_); return data_-x_; }
271         iterator_x end_x() { assert(data_); return data_-x_+w_; }
272
273         iterator_y y() { assert(data_); return iterator_y(data_,pitch_); }
274         iterator_y begin_y() { assert(data_); return iterator_y((pointer)((char*)data_ - y_*pitch_),pitch_); }
275         iterator_y end_y() { assert(data_); return iterator_y((pointer)((char*)data_ + (h_-y_)*pitch_),pitch_); }
276
277         operator bool()const { return (bool)data_; }
278         bool operator!()const { return !data_; }
279         bool operator==(const self_type &rhs)const { return data_==rhs.data_; }
280         bool operator!=(const self_type &rhs)const { return data_!=rhs.data_; }
281         bool clipped(int x, int y)const { return !(x_+x>=0 && y_+y>=0 && x_+x<w_ && y_+y<h_); }
282         bool clipped()const { return !(x_>=0 && y_>=0 && x_<w_ && y_<h_); }
283
284         difference_type operator-(const self_type &rhs)const
285         {
286                 assert(data_);
287                 assert(pitch_==rhs.pitch_);
288                 int ptr_diff=(char*)data_-(char*)rhs.data_-1;
289                 return difference_type(ptr_diff%pitch_/sizeof(value_type)+1,ptr_diff/pitch_);
290         }
291
292         self_type operator+(const difference_type &rhs)const
293         {
294                 assert(data_);
295                 self_type ret(*this);
296                 ret.move(rhs.x,rhs.y);
297                 return ret;
298         }
299
300         difference_type diff_begin()const {return difference_type(-x_,-y_);}
301         difference_type diff_end()const {return difference_type(w_-x_,h_-y_);}
302
303         self_type get_start()const      {return *this + diff_begin(); }
304         self_type get_end()const        {return *this + diff_end(); }
305
306         int get_width()const {return w_;}
307         int get_height()const {return h_;}
308
309         int get_w()const {return w_;}
310         int get_h()const {return h_;}
311         int get_pitch()const {return pitch_;}
312 };
313
314 template <
315         typename PEN_,
316         typename A_=float,
317         class AFFINE_=affine_combo<typename PEN_::value_type,A_>
318 >
319 class alpha_pen : public PEN_
320 {
321 public:
322         typedef A_ alpha_type;
323         typedef AFFINE_ affine_func_type;
324
325         typedef typename PEN_::value_type value_type;
326         typedef alpha_pen self_type;
327
328 private:
329         alpha_type alpha_;
330
331 protected:
332         affine_func_type affine_func_;
333
334 public:
335         using PEN_::get_value;
336         using PEN_::get_pen_value;
337         using PEN_::inc_x;
338         using PEN_::dec_x;
339         using PEN_::inc_y;
340         using PEN_::dec_y;
341         using PEN_::clipped;
342         using PEN_::w_;
343         using PEN_::h_;
344         using PEN_::x_;
345         using PEN_::y_;
346
347         alpha_pen(const alpha_type &a = 1, const affine_func_type &func = affine_func_type()):alpha_(a),affine_func_(func) { }
348         alpha_pen(const PEN_ &x, const alpha_type &a=1, const affine_func_type &func=affine_func_type())
349                 :PEN_(x),alpha_(a),affine_func_(func) { }
350
351         const alpha_type& get_alpha()const { return alpha_; }
352         void get_alpha(alpha_type &a) const { a=alpha_; }
353         void set_alpha(alpha_type a) { alpha_=a; }
354
355         void put_value(const value_type &v, alpha_type a=1)const
356                 { PEN_::put_value(affine_func_(get_value(),v,alpha_*a)); }
357         void put_value()const { put_value(get_pen_value()); }
358         void put_value_alpha(alpha_type a)const { put_value(get_pen_value(),a); }
359         void put_hline(int l, const alpha_type &a = 1){for(;l>0;l--,inc_x())put_value_alpha(a);}
360
361         void put_value_clip(const value_type &v, alpha_type a=1)const
362                 { if(!clipped())PEN_::put_value(affine_func_(get_value(),v,alpha_*a)); }
363         void put_value_clip()const { put_value_clip(get_pen_value()); }
364         void put_value_clip_alpha(alpha_type a)const { put_value_clip(get_pen_value(),a); }
365         void put_hline_clip(int l, const alpha_type &a = 1){l=std::min(l,w_-x_);for(;l>0;l--,inc_x())put_value_clip_alpha(a);}
366
367         //the put_block functions do not modify the pen
368         void put_block(int h, int w, const alpha_type &a = 1)
369         {
370                 self_type row(*this);
371                 for(;h>0;h--,row.inc_y())
372                 {
373                         self_type col(row);
374                         col.put_hline(w,a);
375                 }
376         }
377
378         void put_block_clip(int h, int w, const alpha_type &a = 1)
379         {
380                 self_type row(*this);
381
382                 //clip start position
383                 if(row.x_ < 0) { w+=row.x_; row.inc_x(-row.x_); }
384                 if(row.y_ < 0) { h+=row.y_; row.inc_y(-row.y_); }
385
386                 //clip width and height of copy rect
387                 h = std::min(h,h_-y_);
388                 w = std::min(w,w_-x_);
389
390                 //copy rect
391                 for(;h>0;h--,row.inc_y())
392                 {
393                         self_type col(row);
394                         col.put_hline(w,a);     //already clipped
395                 }
396         }
397 };
398
399 _ETL_END_NAMESPACE
400
401 /* === E X T E R N S ======================================================= */
402
403 /* === E N D =============================================================== */
404
405 #endif