Anti-Grain Geometry Tutorial
agg_renderer_scanline.h
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 // mcseemagg@yahoo.com
13 // http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 
16 #ifndef AGG_RENDERER_SCANLINE_INCLUDED
17 #define AGG_RENDERER_SCANLINE_INCLUDED
18 
19 #include <limits>
20 #include <cstdlib>
21 #include <cstring>
22 #include "agg_basics.h"
23 #include "agg_renderer_base.h"
24 
25 namespace agg
26 {
27 
28  //================================================render_scanline_aa_solid
29  template<class Scanline, class BaseRenderer, class ColorT>
30  void render_scanline_aa_solid(const Scanline& sl,
31  BaseRenderer& ren,
32  const ColorT& color)
33  {
34  int y = sl.y();
35  unsigned num_spans = sl.num_spans();
36  typename Scanline::const_iterator span = sl.begin();
37 
38  for(;;)
39  {
40  int x = span->x;
41  if(span->len > 0)
42  {
43  ren.blend_solid_hspan(x, y, (unsigned)span->len,
44  color,
45  span->covers);
46  }
47  else
48  {
49  ren.blend_hline(x, y, (unsigned)(x - span->len - 1),
50  color,
51  *(span->covers));
52  }
53  if(--num_spans == 0) break;
54  ++span;
55  }
56  }
57 
58  //===============================================render_scanlines_aa_solid
59  template<class Rasterizer, class Scanline,
60  class BaseRenderer, class ColorT>
61  void render_scanlines_aa_solid(Rasterizer& ras, Scanline& sl,
62  BaseRenderer& ren, const ColorT& color)
63  {
64  if(ras.rewind_scanlines())
65  {
66  // Explicitly convert "color" to the BaseRenderer color type.
67  // For example, it can be called with color type "rgba", while
68  // "rgba8" is needed. Otherwise it will be implicitly
69  // converted in the loop many times.
70  //----------------------
71  typename BaseRenderer::color_type ren_color = color;
72 
73  sl.reset(ras.min_x(), ras.max_x());
74  while(ras.sweep_scanline(sl))
75  {
76  //render_scanline_aa_solid(sl, ren, ren_color);
77 
78  // This code is equivalent to the above call (copy/paste).
79  // It's just a "manual" optimization for old compilers,
80  // like Microsoft Visual C++ v6.0
81  //-------------------------------
82  int y = sl.y();
83  unsigned num_spans = sl.num_spans();
84  typename Scanline::const_iterator span = sl.begin();
85 
86  for(;;)
87  {
88  int x = span->x;
89  if(span->len > 0)
90  {
91  ren.blend_solid_hspan(x, y, (unsigned)span->len,
92  ren_color,
93  span->covers);
94  }
95  else
96  {
97  ren.blend_hline(x, y, (unsigned)(x - span->len - 1),
98  ren_color,
99  *(span->covers));
100  }
101  if(--num_spans == 0) break;
102  ++span;
103  }
104  }
105  }
106  }
107 
108  //==============================================renderer_scanline_aa_solid
109  template<class BaseRenderer> class renderer_scanline_aa_solid
110  {
111  public:
112  typedef BaseRenderer base_ren_type;
113  typedef typename base_ren_type::color_type color_type;
114 
115  //--------------------------------------------------------------------
116  renderer_scanline_aa_solid() : m_ren(0) {}
117  explicit renderer_scanline_aa_solid(base_ren_type& ren) : m_ren(&ren) {}
118  void attach(base_ren_type& ren)
119  {
120  m_ren = &ren;
121  }
122 
123  //--------------------------------------------------------------------
124  void color(const color_type& c) { m_color = c; }
125  const color_type& color() const { return m_color; }
126 
127  //--------------------------------------------------------------------
128  void prepare() {}
129 
130  //--------------------------------------------------------------------
131  template<class Scanline> void render(const Scanline& sl)
132  {
133  render_scanline_aa_solid(sl, *m_ren, m_color);
134  }
135 
136  private:
137  base_ren_type* m_ren;
138  color_type m_color;
139  };
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
150 
151 
152 
153  //======================================================render_scanline_aa
154  template<class Scanline, class BaseRenderer,
155  class SpanAllocator, class SpanGenerator>
156  void render_scanline_aa(const Scanline& sl, BaseRenderer& ren,
157  SpanAllocator& alloc, SpanGenerator& span_gen)
158  {
159  int y = sl.y();
160 
161  unsigned num_spans = sl.num_spans();
162  typename Scanline::const_iterator span = sl.begin();
163  for(;;)
164  {
165  int x = span->x;
166  int len = span->len;
167  const typename Scanline::cover_type* covers = span->covers;
168 
169  if(len < 0) len = -len;
170  typename BaseRenderer::color_type* colors = alloc.allocate(len);
171  span_gen.generate(colors, x, y, len);
172  ren.blend_color_hspan(x, y, len, colors,
173  (span->len < 0) ? 0 : covers, *covers);
174 
175  if(--num_spans == 0) break;
176  ++span;
177  }
178  }
179 
180  //=====================================================render_scanlines_aa
181  template<class Rasterizer, class Scanline, class BaseRenderer,
182  class SpanAllocator, class SpanGenerator>
183  void render_scanlines_aa(Rasterizer& ras, Scanline& sl, BaseRenderer& ren,
184  SpanAllocator& alloc, SpanGenerator& span_gen)
185  {
186  if(ras.rewind_scanlines())
187  {
188  sl.reset(ras.min_x(), ras.max_x());
189  span_gen.prepare();
190  while(ras.sweep_scanline(sl))
191  {
192  render_scanline_aa(sl, ren, alloc, span_gen);
193  }
194  }
195  }
196 
197  //====================================================renderer_scanline_aa
198  template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
200  {
201  public:
202  typedef BaseRenderer base_ren_type;
203  typedef SpanAllocator alloc_type;
204  typedef SpanGenerator span_gen_type;
205 
206  //--------------------------------------------------------------------
207  renderer_scanline_aa() : m_ren(0), m_alloc(0), m_span_gen(0) {}
208  renderer_scanline_aa(base_ren_type& ren,
209  alloc_type& alloc,
210  span_gen_type& span_gen) :
211  m_ren(&ren),
212  m_alloc(&alloc),
213  m_span_gen(&span_gen)
214  {}
215  void attach(base_ren_type& ren,
216  alloc_type& alloc,
217  span_gen_type& span_gen)
218  {
219  m_ren = &ren;
220  m_alloc = &alloc;
221  m_span_gen = &span_gen;
222  }
223 
224  //--------------------------------------------------------------------
225  void prepare() { m_span_gen->prepare(); }
226 
227  //--------------------------------------------------------------------
228  template<class Scanline> void render(const Scanline& sl)
229  {
230  render_scanline_aa(sl, *m_ren, *m_alloc, *m_span_gen);
231  }
232 
233  private:
234  base_ren_type* m_ren;
235  alloc_type* m_alloc;
236  span_gen_type* m_span_gen;
237  };
238 
239 
240 
241 
242 
243 
244  //===============================================render_scanline_bin_solid
245  template<class Scanline, class BaseRenderer, class ColorT>
246  void render_scanline_bin_solid(const Scanline& sl,
247  BaseRenderer& ren,
248  const ColorT& color)
249  {
250  unsigned num_spans = sl.num_spans();
251  typename Scanline::const_iterator span = sl.begin();
252  for(;;)
253  {
254  ren.blend_hline(span->x,
255  sl.y(),
256  span->x - 1 + ((span->len < 0) ?
257  -span->len :
258  span->len),
259  color,
260  cover_full);
261  if(--num_spans == 0) break;
262  ++span;
263  }
264  }
265 
266  //==============================================render_scanlines_bin_solid
267  template<class Rasterizer, class Scanline,
268  class BaseRenderer, class ColorT>
269  void render_scanlines_bin_solid(Rasterizer& ras, Scanline& sl,
270  BaseRenderer& ren, const ColorT& color)
271  {
272  if(ras.rewind_scanlines())
273  {
274  // Explicitly convert "color" to the BaseRenderer color type.
275  // For example, it can be called with color type "rgba", while
276  // "rgba8" is needed. Otherwise it will be implicitly
277  // converted in the loop many times.
278  //----------------------
279  typename BaseRenderer::color_type ren_color(color);
280 
281  sl.reset(ras.min_x(), ras.max_x());
282  while(ras.sweep_scanline(sl))
283  {
284  //render_scanline_bin_solid(sl, ren, ren_color);
285 
286  // This code is equivalent to the above call (copy/paste).
287  // It's just a "manual" optimization for old compilers,
288  // like Microsoft Visual C++ v6.0
289  //-------------------------------
290  unsigned num_spans = sl.num_spans();
291  typename Scanline::const_iterator span = sl.begin();
292  for(;;)
293  {
294  ren.blend_hline(span->x,
295  sl.y(),
296  span->x - 1 + ((span->len < 0) ?
297  -span->len :
298  span->len),
299  ren_color,
300  cover_full);
301  if(--num_spans == 0) break;
302  ++span;
303  }
304  }
305  }
306  }
307 
308  //=============================================renderer_scanline_bin_solid
309  template<class BaseRenderer> class renderer_scanline_bin_solid
310  {
311  public:
312  typedef BaseRenderer base_ren_type;
313  typedef typename base_ren_type::color_type color_type;
314 
315  //--------------------------------------------------------------------
316  renderer_scanline_bin_solid() : m_ren(0) {}
317  explicit renderer_scanline_bin_solid(base_ren_type& ren) : m_ren(&ren) {}
318  void attach(base_ren_type& ren)
319  {
320  m_ren = &ren;
321  }
322 
323  //--------------------------------------------------------------------
324  void color(const color_type& c) { m_color = c; }
325  const color_type& color() const { return m_color; }
326 
327  //--------------------------------------------------------------------
328  void prepare() {}
329 
330  //--------------------------------------------------------------------
331  template<class Scanline> void render(const Scanline& sl)
332  {
333  render_scanline_bin_solid(sl, *m_ren, m_color);
334  }
335 
336  private:
337  base_ren_type* m_ren;
338  color_type m_color;
339  };
340 
341 
342 
343 
344 
345 
346 
347 
348  //======================================================render_scanline_bin
349  template<class Scanline, class BaseRenderer,
350  class SpanAllocator, class SpanGenerator>
351  void render_scanline_bin(const Scanline& sl, BaseRenderer& ren,
352  SpanAllocator& alloc, SpanGenerator& span_gen)
353  {
354  int y = sl.y();
355 
356  unsigned num_spans = sl.num_spans();
357  typename Scanline::const_iterator span = sl.begin();
358  for(;;)
359  {
360  int x = span->x;
361  int len = span->len;
362  if(len < 0) len = -len;
363  typename BaseRenderer::color_type* colors = alloc.allocate(len);
364  span_gen.generate(colors, x, y, len);
365  ren.blend_color_hspan(x, y, len, colors, 0, cover_full);
366  if(--num_spans == 0) break;
367  ++span;
368  }
369  }
370 
371  //=====================================================render_scanlines_bin
372  template<class Rasterizer, class Scanline, class BaseRenderer,
373  class SpanAllocator, class SpanGenerator>
374  void render_scanlines_bin(Rasterizer& ras, Scanline& sl, BaseRenderer& ren,
375  SpanAllocator& alloc, SpanGenerator& span_gen)
376  {
377  if(ras.rewind_scanlines())
378  {
379  sl.reset(ras.min_x(), ras.max_x());
380  span_gen.prepare();
381  while(ras.sweep_scanline(sl))
382  {
383  render_scanline_bin(sl, ren, alloc, span_gen);
384  }
385  }
386  }
387 
388  //====================================================renderer_scanline_bin
389  template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
391  {
392  public:
393  typedef BaseRenderer base_ren_type;
394  typedef SpanAllocator alloc_type;
395  typedef SpanGenerator span_gen_type;
396 
397  //--------------------------------------------------------------------
398  renderer_scanline_bin() : m_ren(0), m_alloc(0), m_span_gen(0) {}
399  renderer_scanline_bin(base_ren_type& ren,
400  alloc_type& alloc,
401  span_gen_type& span_gen) :
402  m_ren(&ren),
403  m_alloc(&alloc),
404  m_span_gen(&span_gen)
405  {}
406  void attach(base_ren_type& ren,
407  alloc_type& alloc,
408  span_gen_type& span_gen)
409  {
410  m_ren = &ren;
411  m_alloc = &alloc;
412  m_span_gen = &span_gen;
413  }
414 
415  //--------------------------------------------------------------------
416  void prepare() { m_span_gen->prepare(); }
417 
418  //--------------------------------------------------------------------
419  template<class Scanline> void render(const Scanline& sl)
420  {
421  render_scanline_bin(sl, *m_ren, *m_alloc, *m_span_gen);
422  }
423 
424  private:
425  base_ren_type* m_ren;
426  alloc_type* m_alloc;
427  span_gen_type* m_span_gen;
428  };
429 
430 
431 
432 
433 
434 
435 
436 
437 
438 
439  //========================================================render_scanlines
440  template<class Rasterizer, class Scanline, class Renderer>
441  void render_scanlines(Rasterizer& ras, Scanline& sl, Renderer& ren)
442  {
443  if(ras.rewind_scanlines())
444  {
445  sl.reset(ras.min_x(), ras.max_x());
446  ren.prepare();
447  while(ras.sweep_scanline(sl))
448  {
449  ren.render(sl);
450  }
451  }
452  }
453 
454  //========================================================render_all_paths
455  template<class Rasterizer, class Scanline, class Renderer,
456  class VertexSource, class ColorStorage, class PathId>
457  void render_all_paths(Rasterizer& ras,
458  Scanline& sl,
459  Renderer& r,
460  VertexSource& vs,
461  const ColorStorage& as,
462  const PathId& path_id,
463  unsigned num_paths)
464  {
465  for(unsigned i = 0; i < num_paths; i++)
466  {
467  ras.reset();
468  ras.add_path(vs, path_id[i]);
469  r.color(as[i]);
470  render_scanlines(ras, sl, r);
471  }
472  }
473 
474 
475 
476 
477 
478 
479  //=============================================render_scanlines_compound
480  template<class Rasterizer,
481  class ScanlineAA,
482  class ScanlineBin,
483  class BaseRenderer,
484  class SpanAllocator,
485  class StyleHandler>
486  void render_scanlines_compound(Rasterizer& ras,
487  ScanlineAA& sl_aa,
488  ScanlineBin& sl_bin,
489  BaseRenderer& ren,
490  SpanAllocator& alloc,
491  StyleHandler& sh)
492  {
493  if(ras.rewind_scanlines())
494  {
495  int min_x = ras.min_x();
496  int len = ras.max_x() - min_x + 2;
497  sl_aa.reset(min_x, ras.max_x());
498  sl_bin.reset(min_x, ras.max_x());
499 
500  typedef typename BaseRenderer::color_type color_type;
501  color_type* color_span = alloc.allocate(len * 2);
502  color_type* mix_buffer = color_span + len;
503  unsigned num_spans;
504 
505  unsigned num_styles;
506  unsigned style;
507  bool solid;
508  while((num_styles = ras.sweep_styles()) > 0)
509  {
510  typename ScanlineAA::const_iterator span_aa;
511  if(num_styles == 1)
512  {
513  // Optimization for a single style. Happens often
514  //-------------------------
515  if(ras.sweep_scanline(sl_aa, 0))
516  {
517  style = ras.style(0);
518  if(sh.is_solid(style))
519  {
520  // Just solid fill
521  //-----------------------
522  render_scanline_aa_solid(sl_aa, ren, sh.color(style));
523  }
524  else
525  {
526  // Arbitrary span generator
527  //-----------------------
528  span_aa = sl_aa.begin();
529  num_spans = sl_aa.num_spans();
530  for(;;)
531  {
532  len = span_aa->len;
533  sh.generate_span(color_span,
534  span_aa->x,
535  sl_aa.y(),
536  len,
537  style);
538 
539  ren.blend_color_hspan(span_aa->x,
540  sl_aa.y(),
541  span_aa->len,
542  color_span,
543  span_aa->covers);
544  if(--num_spans == 0) break;
545  ++span_aa;
546  }
547  }
548  }
549  }
550  else
551  {
552  if(ras.sweep_scanline(sl_bin, -1))
553  {
554  // Clear the spans of the mix_buffer
555  //--------------------
556  typename ScanlineBin::const_iterator span_bin = sl_bin.begin();
557  num_spans = sl_bin.num_spans();
558  for(;;)
559  {
560  std::memset(mix_buffer + span_bin->x - min_x,
561  0,
562  span_bin->len * sizeof(color_type));
563 
564  if(--num_spans == 0) break;
565  ++span_bin;
566  }
567 
568  unsigned i;
569  for(i = 0; i < num_styles; i++)
570  {
571  style = ras.style(i);
572  solid = sh.is_solid(style);
573 
574  if(ras.sweep_scanline(sl_aa, i))
575  {
576  color_type* colors;
577  color_type* cspan;
578  typename ScanlineAA::cover_type* covers;
579  span_aa = sl_aa.begin();
580  num_spans = sl_aa.num_spans();
581  if(solid)
582  {
583  // Just solid fill
584  //-----------------------
585  for(;;)
586  {
587  color_type c = sh.color(style);
588  len = span_aa->len;
589  colors = mix_buffer + span_aa->x - min_x;
590  covers = span_aa->covers;
591  do
592  {
593  if(*covers == cover_full)
594  {
595  *colors = c;
596  }
597  else
598  {
599  colors->add(c, *covers);
600  }
601  ++colors;
602  ++covers;
603  }
604  while(--len);
605  if(--num_spans == 0) break;
606  ++span_aa;
607  }
608  }
609  else
610  {
611  // Arbitrary span generator
612  //-----------------------
613  for(;;)
614  {
615  len = span_aa->len;
616  colors = mix_buffer + span_aa->x - min_x;
617  cspan = color_span;
618  sh.generate_span(cspan,
619  span_aa->x,
620  sl_aa.y(),
621  len,
622  style);
623  covers = span_aa->covers;
624  do
625  {
626  if(*covers == cover_full)
627  {
628  *colors = *cspan;
629  }
630  else
631  {
632  colors->add(*cspan, *covers);
633  }
634  ++cspan;
635  ++colors;
636  ++covers;
637  }
638  while(--len);
639  if(--num_spans == 0) break;
640  ++span_aa;
641  }
642  }
643  }
644  }
645 
646  // Emit the blended result as a color hspan
647  //-------------------------
648  span_bin = sl_bin.begin();
649  num_spans = sl_bin.num_spans();
650  for(;;)
651  {
652  ren.blend_color_hspan(span_bin->x,
653  sl_bin.y(),
654  span_bin->len,
655  mix_buffer + span_bin->x - min_x,
656  0,
657  cover_full);
658  if(--num_spans == 0) break;
659  ++span_bin;
660  }
661  } // if(ras.sweep_scanline(sl_bin, -1))
662  } // if(num_styles == 1) ... else
663  } // while((num_styles = ras.sweep_styles()) > 0)
664  } // if(ras.rewind_scanlines())
665  }
666 
667  //=======================================render_scanlines_compound_layered
668  template<class Rasterizer,
669  class ScanlineAA,
670  class BaseRenderer,
671  class SpanAllocator,
672  class StyleHandler>
673  void render_scanlines_compound_layered(Rasterizer& ras,
674  ScanlineAA& sl_aa,
675  BaseRenderer& ren,
676  SpanAllocator& alloc,
677  StyleHandler& sh)
678  {
679  if(ras.rewind_scanlines())
680  {
681  int min_x = ras.min_x();
682  int len = ras.max_x() - min_x + 2;
683  sl_aa.reset(min_x, ras.max_x());
684 
685  typedef typename BaseRenderer::color_type color_type;
686  color_type* color_span = alloc.allocate(len * 2);
687  color_type* mix_buffer = color_span + len;
688  cover_type* cover_buffer = ras.allocate_cover_buffer(len);
689  unsigned num_spans;
690 
691  unsigned num_styles;
692  unsigned style;
693  bool solid;
694  while((num_styles = ras.sweep_styles()) > 0)
695  {
696  typename ScanlineAA::const_iterator span_aa;
697  if(num_styles == 1)
698  {
699  // Optimization for a single style. Happens often
700  //-------------------------
701  if(ras.sweep_scanline(sl_aa, 0))
702  {
703  style = ras.style(0);
704  if(sh.is_solid(style))
705  {
706  // Just solid fill
707  //-----------------------
708  render_scanline_aa_solid(sl_aa, ren, sh.color(style));
709  }
710  else
711  {
712  // Arbitrary span generator
713  //-----------------------
714  span_aa = sl_aa.begin();
715  num_spans = sl_aa.num_spans();
716  for(;;)
717  {
718  len = span_aa->len;
719  sh.generate_span(color_span,
720  span_aa->x,
721  sl_aa.y(),
722  len,
723  style);
724 
725  ren.blend_color_hspan(span_aa->x,
726  sl_aa.y(),
727  span_aa->len,
728  color_span,
729  span_aa->covers);
730  if(--num_spans == 0) break;
731  ++span_aa;
732  }
733  }
734  }
735  }
736  else
737  {
738  int sl_start = ras.scanline_start();
739  unsigned sl_len = ras.scanline_length();
740 
741  if(sl_len)
742  {
743  std::memset(mix_buffer + sl_start - min_x,
744  0,
745  sl_len * sizeof(color_type));
746 
747  std::memset(cover_buffer + sl_start - min_x,
748  0,
749  sl_len * sizeof(cover_type));
750 
751  int sl_y = std::numeric_limits<int>::max();
752  unsigned i;
753  for(i = 0; i < num_styles; i++)
754  {
755  style = ras.style(i);
756  solid = sh.is_solid(style);
757 
758  if(ras.sweep_scanline(sl_aa, i))
759  {
760  unsigned cover;
761  color_type* colors;
762  color_type* cspan;
763  cover_type* src_covers;
764  cover_type* dst_covers;
765  span_aa = sl_aa.begin();
766  num_spans = sl_aa.num_spans();
767  sl_y = sl_aa.y();
768  if(solid)
769  {
770  // Just solid fill
771  //-----------------------
772  for(;;)
773  {
774  color_type c = sh.color(style);
775  len = span_aa->len;
776  colors = mix_buffer + span_aa->x - min_x;
777  src_covers = span_aa->covers;
778  dst_covers = cover_buffer + span_aa->x - min_x;
779  do
780  {
781  cover = *src_covers;
782  if(*dst_covers + cover > cover_full)
783  {
784  cover = cover_full - *dst_covers;
785  }
786  if(cover)
787  {
788  colors->add(c, cover);
789  *dst_covers += cover;
790  }
791  ++colors;
792  ++src_covers;
793  ++dst_covers;
794  }
795  while(--len);
796  if(--num_spans == 0) break;
797  ++span_aa;
798  }
799  }
800  else
801  {
802  // Arbitrary span generator
803  //-----------------------
804  for(;;)
805  {
806  len = span_aa->len;
807  colors = mix_buffer + span_aa->x - min_x;
808  cspan = color_span;
809  sh.generate_span(cspan,
810  span_aa->x,
811  sl_aa.y(),
812  len,
813  style);
814  src_covers = span_aa->covers;
815  dst_covers = cover_buffer + span_aa->x - min_x;
816  do
817  {
818  cover = *src_covers;
819  if(*dst_covers + cover > cover_full)
820  {
821  cover = cover_full - *dst_covers;
822  }
823  if(cover)
824  {
825  colors->add(*cspan, cover);
826  *dst_covers += cover;
827  }
828  ++cspan;
829  ++colors;
830  ++src_covers;
831  ++dst_covers;
832  }
833  while(--len);
834  if(--num_spans == 0) break;
835  ++span_aa;
836  }
837  }
838  }
839  }
840  ren.blend_color_hspan(sl_start,
841  sl_y,
842  sl_len,
843  mix_buffer + sl_start - min_x,
844  0,
845  cover_full);
846  } //if(sl_len)
847  } //if(num_styles == 1) ... else
848  } //while((num_styles = ras.sweep_styles()) > 0)
849  } //if(ras.rewind_scanlines())
850  }
851 
852 
853 }
854 
855 #endif
Definition: agg_arc.cpp:24