ragg/0000755000176200001440000000000014153425042011172 5ustar liggesusersragg/NAMESPACE0000644000176200001440000000124414010214106012377 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(agg_capture) export(agg_jpeg) export(agg_png) export(agg_ppm) export(agg_supertransparent) export(agg_tiff) export(font_feature) export(get_font_features) export(register_font) export(register_variant) importFrom(grDevices,dev.capture) importFrom(grDevices,dev.cur) importFrom(grDevices,dev.list) importFrom(grDevices,dev.off) importFrom(grDevices,dev.set) importFrom(systemfonts,font_feature) importFrom(systemfonts,match_font) importFrom(systemfonts,register_font) importFrom(systemfonts,register_variant) importFrom(textshaping,get_font_features) importFrom(textshaping,text_width) useDynLib(ragg, .registration = TRUE) ragg/LICENSE.note0000644000176200001440000000333413504615001013141 0ustar liggesusersThis package contain source files from the AGG framework version 2.4 developed by Maxim Shemanarev and released under the BSD version 2 license as reproduced below: AGG License -------------------------------------------------------------------- Copyright (c) 2002-2005, Maxim Shemanarev All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ragg/LICENSE0000644000176200001440000000006113504406270012175 0ustar liggesusersYEAR: 2019 COPYRIGHT HOLDER: Thomas Lin Pedersen ragg/tools/0000755000176200001440000000000014147724651012345 5ustar liggesusersragg/tools/winlibs.R0000644000176200001440000000057014000010424014107 0ustar liggesusersVERSION <- commandArgs(TRUE) if(!file.exists(sprintf("../windows/harfbuzz-%s/include/png.h", VERSION))){ if(getRversion() < "3.3.0") setInternet2() download.file(sprintf("https://github.com/rwinlib/harfbuzz/archive/v%s.zip", VERSION), "lib.zip", quiet = TRUE) dir.create("../windows", showWarnings = FALSE) unzip("lib.zip", exdir = "../windows") unlink("lib.zip") } ragg/README.md0000644000176200001440000000746414136434257012475 0ustar liggesusers # ragg [![Codecov test coverage](https://codecov.io/gh/r-lib/ragg/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-lib/ragg?branch=main) [![CRAN status](https://www.r-pkg.org/badges/version/ragg)](https://cran.r-project.org/package=ragg) [![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) [![R-CMD-check](https://github.com/r-lib/ragg/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/ragg/actions) This package provides graphic devices for R based on the AGG library developed by the late Maxim Shemanarev. AGG provides both higher performance and higher quality than the standard raster devices provided by grDevices. For a comparison with the default devices, see the [performance](https://ragg.r-lib.org/articles/ragg_performance.html) and [quality](https://ragg.r-lib.org/articles/ragg_quality.html) vignettes. ## Installation The package can be installed from CRAN with `install.packages('ragg')` or, if the development version is desired, directly from github: ``` r # install.packages('devtools') devtools::install_github('r-lib/ragg') ``` ## Use ragg provides drop-in replacements for the png, jpeg, and tiff graphic devices provided by default from the grDevices packages and can both produce png, jpeg and tiff files. Notable features, that sets itself apart from the build-in devices, includes: - Faster (up to 40% faster than anti-aliased cairo device) - Direct access to all system fonts - Advanced text rendering, including support for right-to-left text, emojis, and font fallback - High quality anti-aliasing - High quality rotated text - Support 16-bit output - System independent rendering (output from Mac, Windows, and Linux should be identical) You can use it like any other device. The main functions are `agg_png()`, `agg_jpeg()` and `agg_tiff()`, all of which have arguments that closely match those of the `png()`, `jpeg()` and `tiff()` functions, so switching over should be easy. ``` r library(ragg) library(ggplot2) file <- knitr::fig_path('.png') on_linux <- tolower(Sys.info()[['sysname']]) == 'linux' fancy_font <- if (on_linux) 'URW Chancery L' else 'Papyrus' agg_png(file, width = 1000, height = 500, res = 144) ggplot(mtcars) + geom_point(aes(mpg, disp, colour = hp)) + labs(title = 'System fonts — Oh My! 😱') + theme(text = element_text(family = fancy_font)) invisible(dev.off()) knitr::include_graphics(file) ``` Further, it provides an `agg_capture()` device that lets you access the device buffer directly from your R session. ``` r cap <- agg_capture(width = 1000, height = 500, res = 144) plot(1:10, 1:10) scatter <- cap() invisible(dev.off()) # Remove margins from raster plotting par(mai = c(0, 0, 0, 0)) plot(as.raster(scatter)) ``` ### Use ragg with knitr knitr supports png output from ragg by setting `dev = "ragg_png"` in the chunk settings or globally with `knitr::opts_chunk$set(dev = "ragg_png")`. ### Use ragg in RStudio ragg can be used as the graphic back-end to the RStudio device (for RStudio \>= 1.4) by choosing *AGG* as the backend in the graphics pane in general options (see screenshot) ![Setting ragg as backend in RStudio](https://i.imgur.com/4XgiPWy.png) ## Code of Conduct Please note that the ‘ragg’ project is released with a [Contributor Code of Conduct](https://ragg.r-lib.org/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. ragg/man/0000755000176200001440000000000014147726346011763 5ustar liggesusersragg/man/agg_jpeg.Rd0000644000176200001440000000644714010207522014003 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/agg_dev.R \name{agg_jpeg} \alias{agg_jpeg} \title{Draw to a JPEG file} \usage{ agg_jpeg( filename = "Rplot\%03d.jpeg", width = 480, height = 480, units = "px", pointsize = 12, background = "white", res = 72, scaling = 1, quality = 75, smoothing = FALSE, method = "slow", bg ) } \arguments{ \item{filename}{The name of the file. Follows the same semantics as the file naming in [grDevices::png()], meaning that you can provide a [sprintf()] compliant string format to name multiple plots (such as the default value)} \item{width}{The dimensions of the device} \item{height}{The dimensions of the device} \item{units}{The unit `width` and `height` is measured in, in either pixels (`'px'`), inches (`'in'`), millimeters (`'mm'`), or centimeter (`'cm'`).} \item{pointsize}{The default pointsize of the device in pt. This will in general not have any effect on grid graphics (including ggplot2) as text size is always set explicitly there.} \item{background}{The background colour of the device} \item{res}{The resolution of the device. This setting will govern how device dimensions given in inches, centimeters, or millimeters will be converted to pixels. Further, it will be used to scale text sizes and linewidths} \item{scaling}{A scaling factor to apply to the rendered line width and text size. Useful for getting the right dimensions at the resolution that you need. If e.g. you need to render a plot at 4000x3000 pixels for it to fit into a layout, but you find that the result appears to small, you can increase the `scaling` argument to make everything appear bigger at the same resolution.} \item{quality}{An integer between `0` and `100` defining the quality/size tradeoff. Setting this to `100` will result in no compression.} \item{smoothing}{A smoothing factor to apply before compression, from `0` (no smoothing) to `100` (full smoothing). Can also by `FALSE` (no smoothing) or `TRUE` (full smoothing).} \item{method}{The compression algorithm to use. Either `'slow'`, `'fast'`, or `'float'`. Default is `'slow'` which works best for most cases. `'fast'` should only be used when quality is below `97` as it may result in worse performance at high quality settings. `'float'` is a legacy options that calculate the compression using floating point precission instead of with integers. It offers no quality benefit and is often much slower.} \item{bg}{Same as `background` for compatibility with old graphic device APIs} } \description{ The JPEG file format is a lossy compressed file format developed in particular for digital photography. The format is not particularly well-suited for line drawings and text of the type normally associated with statistical plots as the compression algorithm creates noticable artefacts. It is, however, great for saving image data, e.g. heightmaps etc. Thus, for standard plots, it would be better to use [agg_png()], but for plots that includes a high degree of raster image rendering this device will result in smaller plots with very little quality degradation. } \note{ Smoothing is only applied if ragg has been compiled against a jpeg library that supports smoothing. } \examples{ file <- tempfile(fileext = '.jpeg') agg_jpeg(file, quality = 50) plot(sin, -pi, 2*pi) dev.off() } ragg/man/agg_tiff.Rd0000644000176200001440000000634714010207522014005 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/agg_dev.R \name{agg_tiff} \alias{agg_tiff} \title{Draw to a TIFF file} \usage{ agg_tiff( filename = "Rplot\%03d.tiff", width = 480, height = 480, units = "px", pointsize = 12, background = "white", res = 72, scaling = 1, compression = "none", bitsize = 8, bg ) } \arguments{ \item{filename}{The name of the file. Follows the same semantics as the file naming in [grDevices::png()], meaning that you can provide a [sprintf()] compliant string format to name multiple plots (such as the default value)} \item{width}{The dimensions of the device} \item{height}{The dimensions of the device} \item{units}{The unit `width` and `height` is measured in, in either pixels (`'px'`), inches (`'in'`), millimeters (`'mm'`), or centimeter (`'cm'`).} \item{pointsize}{The default pointsize of the device in pt. This will in general not have any effect on grid graphics (including ggplot2) as text size is always set explicitly there.} \item{background}{The background colour of the device} \item{res}{The resolution of the device. This setting will govern how device dimensions given in inches, centimeters, or millimeters will be converted to pixels. Further, it will be used to scale text sizes and linewidths} \item{scaling}{A scaling factor to apply to the rendered line width and text size. Useful for getting the right dimensions at the resolution that you need. If e.g. you need to render a plot at 4000x3000 pixels for it to fit into a layout, but you find that the result appears to small, you can increase the `scaling` argument to make everything appear bigger at the same resolution.} \item{compression}{The compression type to use for the image data. The standard options from the [grDevices::tiff()] function are available under the same name.} \item{bitsize}{Should the device record colour as 8 or 16bit} \item{bg}{Same as `background` for compatibility with old graphic device APIs} } \description{ The TIFF (Tagged Image File Format) format is a very versatile raster image storage format that supports 8 and 16bit colour mode, true transparency, as well as a range of other features not relevant to drawing from R (e.g. support for different colour spaces). The storage mode of the image data is not fixed and different compression modes are possible, in contrast to PNGs one-approach-fits-all. The default (uncompressed) will result in much larger files than PNG, and in general PNG is a better format for many of the graphic types produced in R. Still, TIFF has its purposes and sometimes this file format is explicetly requested. } \note{ `'jpeg'` compression is only available if ragg is compiled with a version of `libtiff` where jpeg support has been turned on. } \section{Transparency}{ TIFF have support for true transparency, meaning that the pixel colour is stored in pre-multiplied form. This is in contrast to pixels being stored in plain format, where the alpha values more function as a mask. The utility of this is not always that important, but it is one of the benefits of TIFF over PNG so it should be noted. } \examples{ file <- tempfile(fileext = '.tiff') # Use jpeg compression agg_tiff(file, compression = 'lzw+p') plot(sin, -pi, 2*pi) dev.off() } ragg/man/agg_png.Rd0000644000176200001440000000515414010207522013634 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/agg_dev.R \name{agg_png} \alias{agg_png} \title{Draw to a PNG file} \usage{ agg_png( filename = "Rplot\%03d.png", width = 480, height = 480, units = "px", pointsize = 12, background = "white", res = 72, scaling = 1, bitsize = 8, bg ) } \arguments{ \item{filename}{The name of the file. Follows the same semantics as the file naming in [grDevices::png()], meaning that you can provide a [sprintf()] compliant string format to name multiple plots (such as the default value)} \item{width}{The dimensions of the device} \item{height}{The dimensions of the device} \item{units}{The unit `width` and `height` is measured in, in either pixels (`'px'`), inches (`'in'`), millimeters (`'mm'`), or centimeter (`'cm'`).} \item{pointsize}{The default pointsize of the device in pt. This will in general not have any effect on grid graphics (including ggplot2) as text size is always set explicitly there.} \item{background}{The background colour of the device} \item{res}{The resolution of the device. This setting will govern how device dimensions given in inches, centimeters, or millimeters will be converted to pixels. Further, it will be used to scale text sizes and linewidths} \item{scaling}{A scaling factor to apply to the rendered line width and text size. Useful for getting the right dimensions at the resolution that you need. If e.g. you need to render a plot at 4000x3000 pixels for it to fit into a layout, but you find that the result appears to small, you can increase the `scaling` argument to make everything appear bigger at the same resolution.} \item{bitsize}{Should the device record colour as 8 or 16bit} \item{bg}{Same as `background` for compatibility with old graphic device APIs} } \description{ The PNG (Portable Network Graphic) format is one of the most ubiquitous today, due to its versatiliity and widespread support. It supports transparency as well as both 8 and 16 bit colour. The device uses default compression and filtering and will not use a colour palette as this is less useful for antialiased data. This means that it might be possible to compress the resulting image even more if size is of concern (though the defaults are often very good). In contrast to [grDevices::png()] the date and time will not be written to the file, meaning that similar plot code will produce identical files (a good feature if used with version control). It will, however, write in the dimensions of the image based on the `res` argument. } \examples{ file <- tempfile(fileext = '.png') agg_png(file) plot(sin, -pi, 2*pi) dev.off() } ragg/man/agg_supertransparent.Rd0000644000176200001440000000511614010207522016466 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/agg_dev.R \name{agg_supertransparent} \alias{agg_supertransparent} \title{Draw to a PNG file, modifying transparency on the fly} \usage{ agg_supertransparent( filename = "Rplot\%03d.png", width = 480, height = 480, units = "px", pointsize = 12, background = "white", res = 72, scaling = 1, alpha_mod = 1, bg ) } \arguments{ \item{filename}{The name of the file. Follows the same semantics as the file naming in [grDevices::png()], meaning that you can provide a [sprintf()] compliant string format to name multiple plots (such as the default value)} \item{width}{The dimensions of the device} \item{height}{The dimensions of the device} \item{units}{The unit `width` and `height` is measured in, in either pixels (`'px'`), inches (`'in'`), millimeters (`'mm'`), or centimeter (`'cm'`).} \item{pointsize}{The default pointsize of the device in pt. This will in general not have any effect on grid graphics (including ggplot2) as text size is always set explicitly there.} \item{background}{The background colour of the device} \item{res}{The resolution of the device. This setting will govern how device dimensions given in inches, centimeters, or millimeters will be converted to pixels. Further, it will be used to scale text sizes and linewidths} \item{scaling}{A scaling factor to apply to the rendered line width and text size. Useful for getting the right dimensions at the resolution that you need. If e.g. you need to render a plot at 4000x3000 pixels for it to fit into a layout, but you find that the result appears to small, you can increase the `scaling` argument to make everything appear bigger at the same resolution.} \item{alpha_mod}{A numeric between 0 and 1 that will be multiplied to the alpha channel of all transparent colours} \item{bg}{Same as `background` for compatibility with old graphic device APIs} } \description{ The graphic engine in R only supports 8bit colours. This is for the most part fine, as 8bit gives all the fidelity needed for most graphing needs. However, this may become a limitation if you need to plot thousands of very translucent shapes on top of each other. 8bit only afford a minimum of 1/255 alpha, which may end up accumulating to fully opaque at some point. This device allows you to create a 16bit device that modifies the alpha level of all incomming colours by a fixed multiplier, thus allowing for much more translucent colours. The device will only modify transparent colour, so if you pass in an opaque colour it will be left unchanged. } \keyword{internal} ragg/man/figures/0000755000176200001440000000000014153422062013410 5ustar liggesusersragg/man/figures/README-unnamed-chunk-3-1.png0000644000176200001440000007255114136434256020127 0ustar liggesusersPNG  IHDR!JzbKGD pHYs%%IR$ IDATxy\gg&w "PE(T[/ZjhW]ZmmZ֭^ZUDk@xrG $fc Iyd;;OyRJB-C$F @Z֭["H,O2A޽{':p1k֬9zիKJJy晄\.tPnKՎ;V()0t_.]bYB)eF\hh[w *ֺvڢE-Zgd}!!qk-[2~xpM&t <$`N: Hpm!qoV+tB_BCCñ}ZmHgTVV:lTWWo޼3w.~ႂ캡;RVV uffqqq#F8qb޽ }WnݺԻ&O޽V/9Ҷ}i7xӳm[f qoNKMM]vq.\~ׯ9sw k]SJ~mJJthVZVUU{~… Zv޽G 5{ ڼ5o>{#Gֶa__~DǗ0eUUU ?Cllqy\\^WW[oBRvg!C8rwN{Zʕ+#G={MqqqǏ>|iӾ{-Í78k1^d !$""ãm; :,8nƌ-2Ɛ6EDDEbC<ʑ#G iӦwy\6:::''ɓ/{em9tPnnn5E"!Ś`F*:tH-8zݻ^a0`@LL1ܹINvW__?z6lXAIIIzP޿[p0 7ߛyڵ/yG쳣F jM,K?""bsΝ;Ϝ9SXXhs]t1ҥKsԩS@@@ttO?Mh4ƍH$kMSO 6,22|Dmm}6l0cƌiӦ㏔Rë/_8p9CݻwΝkjjۯ_?~n={={7;|OZ޺u룏>kҥ;whG%|W S(QQQ ,(//oyx&E)MNNڵK/Ԫ7;^^^_ ;wLٽ{#d2٤IbT*]pmŋ_~͛7BTׯ/rtttppy+u DNog}vĈcƌ6AaYѸܐWTT{YYY%%%UUU7n& w4^3f̡Cu:^jiii%K *3HNG1n9#[׹sRSS׿İ,x⤤gyѣM^YY~Ca~r3gL*c9VIA}m %yTվN !;wfee=㆛:cZ6 СCm۶[߼u:݈#9Rh-$q 3 ܤ+00p„ _Gc}nnsigy_AAA*JT0EEE=44Ԥ|H3fHHHҬYTRc(i* # 3yL o߾m:AYY_oFFF:_P4444ABȧ~J)j{1w^///͜9sVhe^K.&%}9|pZ~Ϝ9_رL\DDgVV^7ijQK.~m 00x2b)))fͲ2#ܻw,I?l ii?q5.e'O"5kVS0陵`4WVVq]vtk׮+7ALf?'}qK.)Gj7y, Mp?gSOz}DD 5L1B1F𒯯B[ݻwoqL6!dĉ>>>M 1HJJƛ2dŚsQ*5:Ϥ~I.fG [#Bf"hŊe˖Jbcc/^lr߾}Yh4lPRmܸ?oMYnFoލj6A)z999eeeSSJ;֣G_ڵkZָaCeT`B?lfjQaoڔSfRrP(00ʕ+sOYYYTA.!oVơ6ux-IcҞ={*--p¹&ݼy3;;ҥKVZdInniy&M"<Ν !g6.lk?""0NSꌇ0=c]vMIIMeqDBH3-//eY r|+<ظY6u?h4o!$88V+33S$۷ϸ066V$W8NREEE5?%!dÆ % .$deev޽Umʔ)7+$X 0t?Aʖ-[ E"Q||!8/o9>|_lg?maǓ'O> [<1c?~5&&&66֤T*5e7uSFbi&BL5'N0`񭂯<`~JyL %êU ;6ڵkAAA'N4F8J j~~v!C\xѤիWMnoޔҢkbV.G}D"ь3Ν;g7 f16Cn޽{|MB?>bĈ 񊊊͛|'ƹԒ%Kl۶M*o۶mO=Դiӌ]x144tʔ)V2IywN;g _y͚5&uBT*{rq/3f̘f4hPSv5tPάY>yM:>~ر{8oo6MfҊo.\H$۶mk*$h3,&(ϻה i4&Zի"_RڵkԨQ& ~OnѲ2~5Oߪ̟bl'@.tsνݺu{g!lݺW^1y;0񹹹G/##3v~~Dr\.۾#teـh_~Xh\İEU| n>(.R7I>S$ <%҂w}׸P[)2+9 _uQҨ;>9anܸaRhjkkwb8!!:qqqv2.dDP(rFQնlǙyyyTbOOOJieeб\0L}}ЁBHx5J=Am{fYFsDUUUB^JL&ÅuRܸ}Nr!m D"1y=/_ĉ&pĝXX,yzEEŀc BBBK*++m%O)u18w=@Ͻ?A:vr& ,x*ecv%Hozt㈻n,']HgtenW߇ ݹ.gy8\IIIccqT*2dMj]vu:<!] !b+bY驔 8B.]!<Ё8;'M!C̙3$==pqʕ+.\hݚ:<<i=dq|фo=+EbbbЁ8;9'@ή8pK/RxxxLLV}E$[U"ۇʨT*BP[[kv>>>Ǖ K{Q* H{cY]'C^^^nDq!uu۽/*.21;1 3uhb IDATdȐG:`_IǸGGG7RnݾR(GQNh4I,icpr|֬YBGpsSչBG쐸x{A{ q^ڰԮNd;$ Ν;WVV>dȐ!"jPAӽkO83gW_-((0x@;z'Lp5k|w .4Thhhnjsɴu]|9'',&&&--M%wꫯnڴ /իWCCSO=zjCR%''_8p`fttwG}cy**$$ĸ,~焐+WkB8ärС%z̲Ŵm q >ܤD.oٲŸ$222""-p'#6'w^HqqIbbbuuŷgggGEEǷW|N;,$$$++ˤIII%7n,++3{mmŋwލwvRyCLJ.]a\rΝ \2&&Ct[o;vl&UUU޽X,p7(:p}SLꫯB0q:W0>,bzPQ_'߯Jń,z|B)X#>wcqoɹzGm(p3EFaw\}:8t@}ׁ~ľ wT7䅔*)A\+{"䪪縬e V[RRV[ꎐTXG,()sx8k? _p}5kxzz 00܄Zo{Fcc-K}5Z!"7ё'q'qѽmbNJEq8JB{@nޝfǰ +$$J;Ew,C<݅ !qapVij5v{lŤp1 0+ sd7|rCMW?:Xxc(/b%Ӈu`2 arü2pU֨OPڨ!a熆EuVپ"}wR|4S.1y7|{sbR!%Z==W>w!}C:Ј^DF]/C>wp(wvd@*oX3q <ؾ6QٸL)!0/%G)KNJ?M)@qI%IN?V@wp/])krF=%,C?=TjZ{k5 Ea 4RL&b $watv˲m;j!&3p6ުD??6Ֆ;d)9I`(q?C:GG{ݏRA>Ac;>;=S{g#6ERD"[7qL&Ja hm=,bmt θQkzkB%$C&ĉzFH@8!?V6l/R[[u֊FJΝ;r-u ;riH$"PJ-[uVDbV}JJJ铔rֱƸ`C~yyy bذa&o;wҥK! "%%EP̟? :6B;8?Vt?,Jǎ{i<==_~|Fcf&LX~ul㨴ĝR:o޼3g;vlǎW^%N2Ť>0cƌ0Ttjb//տݨҶmr1ƃM ږǸB t/_sNxxxfff``y}OOBBNk퐸`dPq Zxi)UMfp`Y UR !Աw6ksBVAB&%9D,:(W02,::Z*rW\\ܹiG~QQ?L0-ܜ?'|)}k Pꐹ *cz֬Y b3g4-[F퐸ZU]Ò{kzJO#: uꫯNKK~uO? bul2؅z%hfnż}"T`.MmK+M<0cpp֭[/_ؘiӦ.]5ulղ J,3$;@k8d{kvqŢ$¸߸q#00pРA&ZYHZM&3 c@L*RgY9SN7>6"B;tS 7 h /MwbT;Kd諒wHڈe{a[Mbn\wUK%"\*t nA"qpk~=ja"^zbC }PҖeM[w۝T|~-C˷.VB(E/.\p#|~\3gffnڴի:s/Rtty5zDz701gk"SEW92 ꩔ $;q3&{~ !'NO 'NXBV6졇kCcy5eɫB44?AmC)o-)\#-fqơ2,B(;w4_J瞞֭[~}xx믿gϞ0V%_WkJ=%eak2ܼS%LЁ9c;X&۸RjժYfyzzBRId2ٚ5kF%J`hTgLFc+4JөPH d-zܝ4q~ٳg{~M6{H>#1 3nܸC=:ʋRl~eY7C`F"_&~] ;2Jy|l7|E"0.}ߖ q!uu'Z tЅ]ugL)#}њO>_^fMPP֭[_y I5ux999 ,0v~~Rԍ !68!TP "C)yIw%JMxyy B…1 Z!/Jj{/!k#ǝ3&y>ӧWUUu)??ǼB(++#pTmeYa(X$8s SE}I]%HD>ݻ=ƒll$cank ð,:BܻBܻ éVrKBQWWhjkk-~e#!1ӧo\RYYYQQaK*JPaزg[SSĞ⽘}Re1fI 1N̲"K8R0L]]Ё???ekjjQ$XM):Dq{RBHGdVR,m]WWWwٓ'Ofdd?0$$D,SJ+++TTT{dk輞J2Hf@'FBL"v3,d"V߿BB{ꕓc j>عsgT:dȐ˗Tvԩ!Ě:uQr[?vbxZO+}Գ"w;p^Q~m)L!%''KRL&J7nhRAk4KZ߸qo[HHȏ?ȯKߧG|[N49sJJJ 8[r… ӽ[S"1COEx`8G8t:݁嗲޽{ܹӸ˗SSS닊Mf| ;wӧOOOOy"i툟^{xڵIpMM… ?3΃拊jjj %/RxxxLLV}EeM*++mqlhhL%}||8+//:AƸWUUw7n:wnqdr]_mG~@SJ !?pڵlذ͛7oٲСCfСC?~|/^ڰaCXXc=v%0**jǎFۡׯ7޺uk||sss7mԥKEw~>n8v%V\*|lHw]rT,bc:MBj+~8vRBIϰNjZmKKRRR$⋹stן?ƍ jElJAܹz'N[~Pzp0Lpw.|gïr!='rjdTkw^AQ0k%{Nd8M(qwoWXꫯZ##k۷8.117ܻwѣgpin=sǑ>:SV]G9חjj:~潍ju6lPѾH]C#G)gvN}ou־؆sO_Zj՛oiFۦՉ{JJJii)!ԩSyyy?^?{-[N:c_U3?Ssb+&e5'naG/Uכ_PUzP̹flK,iffwhu~ΝFB?c#<²lxx;*[圥oBnWw_9Dñ,[ؖ}VEE,[Xކ J/q]Ǹj4\nòlppN7TX՛=N Qs^J!yoڲmƪmމ;$q7nN:X YY0w@+}QB"ڲ@_9ѹ h/towB:q3gΙ3g!W\?=9wܹ ;!ʨ!~,{iX>*+Gh|Tٮ1iVwafX{#SqAΡՉӧ?;0Hƍ|I@@#2F&_ L{8aHi\2/<m2yAQ%Z8ypۣhY6-z2}K.H$-KRSS\e[}'|TlذǏUzgΟ?0dȐǏ}|'FZzqV'))iʕWQVN8.$$bfϲlnnp%B:,)7N)G\=0G6Nz)s]t!DP(Ϟ=[PXhHNN6)ߵkW``]bpE?_VUk|TBbL pzIU6(?eeʔ~ɸPdee+x ٣t:]ZZdhNr*tڵ7o/...--~znnnvv6!$--֭3 ~zÆ |RbٺA{RjaB;>hÆ aaa=إK¨;vBn|M6u҅b۹c1L߸q#00pРA&FXFH@8֍cy/ٌH$۷o߾}\H@@*p$ H@0ۭDS Cel.wk!q8ffwSCC)]8wuHw8wTk!qԪ6;v.;_zGuSOwA1CeeյKWm+3.thXըե,(#㸺ͫlU S۝jHIRPTqw](UG ?CeIY Y1I !"{-ABw2VCMT),^(^*7yݢ;4S3;B032txa E,ЧX1V%NzW r,Je2T*ݸq[zFۙhwhΫO?%wI6FT5j˩EEEӦM3 |Ν~~~r|?9wPhL*۬ 3 {CFw$tPF?ϔJCo36N !ZvSN-**/^|En ;,op'_7DrU6n8vX 8qܹs.]g "%%EP̟? ®3ݪ} ^t) @,H@@ޝGQI6$ 4AрG-hZU-V- h(V ($#A!ޝo]sB;3Wgw3Oy&0oڴ{˿_|d2 `Ǐ?qu\.ל9s[9$ЎAwbnP(=k/YtKdY4ioLwh׵[|Ξ1c^K.mX;fee͝;wСyyy+VHHHh͐c^TT+:ujرAQY-ʗ:w3Y_8q{rSLi<޷oߚ}?~<..n(Z].={^xᅢ?#fr/顪;͛W]]}u|}m>Tkڢ\!Μ93o޼'|/&oqpwt-lzh֭ Eǒ%K.]3Ϭ]R@sj`nN… }P?}ˠwo(0} .| V533f-^xĈV:qxGKnĽp ͜dwF&1c '^uuN#G2dHXX$++kPMŴ#GXǭw6~eX[>z&In}$p?M nAY}{nlZ(S qq!  i9ڲCwo⮪%KfϞ)eرcQQQ+2xgeey|ٶd|5E1$$D(˯ Aϋ S q! VճN?pxϟ8q[[]]]eeeK!CXǣCswIdddMMMK¶X,frDFHHH}}(Z$l6UUkkk_ )*b]]]V5OQ.ƅ4x.XPsI=zwlVUٳgjx$&&7.)//jIaaa7-|=Z555.K@l6q fX[[Sfb Bjt%/yA=@i2>ͩV1bDB՚>w,>^pst~򊊊“'O 0y䒒͛7˲쮯(g̘ K>q'Myl?„Yf =sӧ^GN/uq Tҥ˪U;VZZ _@{ˆV$IJNN𺍾3%(vc&,+whG xxP @CYh nNq@ۡr?_ٹsc=ָ\庺 ֗:-Dɩ˖-1bD'Ą{{7on\N q2~}kSt:~vo?|Zjw|[o)S+1x>sL>mڴ|nX1mwq}g͛ =sFiӦ~K.N+bHMA5u&I޵SãDj/TEqѻv..742A(vǎr5p8N:cEl*g{[ }4IF^fYgJRʭVmcwh(0}VVV `ZE)..n\覛nN"qvԀ-M6u]>~'6r̙cE;5>p6Gsعȹʚ5P`A]]]vv^{-??ɒ%N]"I~mt"dYYᶿg,+ Hx-N̰M8޸sAu.ADQwi?b R㞝=c ;vJKK;wСCVXKVD@;+h}QZ~)wK~thUU?غdə('Nxo۷f߾}Ǐң\ԿN`;=*454`į~[ 7$SU]ݞk$@[Wv$6q)E2G +ia ]yE&ǼeYII;wPZ[WŔM4]dn1053f>$Ov>6ȹι/Nך9ZAAU?կ|{r1@Hݗ~sgه dE X#ʗ~c{W]խ}\=t|R W6/.[GIT6 B|ȧѣ#fwVGMu%q ̒/ ;\Ȟǚu*@T_ұ]!*M./G ĝSB2^}MmG~DvGh3 |<lH}T6TEAueO:2U&ō4.cgO韚Sps)6Z( FVpB@jju[w>nM鿸6բu\tUe|Gv]^>G&IJA$Iaaa '$IA܂_#RUa{nU5=co:%t݈A|Sj/g(RTUťz뎽kszїONŢBmB󳴅~!^Hth0t7p\-?p- ao{AF(l*{7<|pK@JtõWp'P30Rc+]msW8].NGUUw |Sޝm6})KJhvPRB@FҘj閘m 4o;F$Bnk^D}׾<|F_7P2`xP$y/"[k%ż7Q: ķzUADQ16A;fS&wLNqM"q۬&f*˂ z ߹ơ1I XX] a@+0bM" *U)IFk][w$ ɻ$aTpiV }c6 ` Vy͓4dogӚ; JE8 &FB&&2*$@#qcl~ѓAAXw0'udQ #CEq:~/u:ŵknWB,}˖-gv8ޅn߾{|WsrrЗ:b=h(h_'Oۿ_RME9%K,]4))gYv|AiJh2}IDs|Cw0*@{.֭[ETU]p}׻woC-^:LRVx+ݛ&֌K4fh`ݻwgddINN9#1crrr>䓑#GXLĎK^^Y]S\Z1b1pI peOMMsc5 bZZZ^^;)[NNٳ ={lI$ `,2Lj_#IRttֱ,ZZ/p8,m)!!..F˅<[+;0v.,k go/))AcǎEEE5c|QWWw zEQl- $Y=zj=9u17lBEQNn7^IThqjnw=UUyw| P][7տV.|ͦCm;s|ls:9lTEHAwjDx]P媪F>e$~xIR^ѡ}۝'㋴>=\Sx=zݵa*J(Ę@tu[w/Tr>$v2wm2 EL2uG$7<_@FR]S‚o\QUUMS2 hwZb~{3F͂ ػG/]IZݒ$CUɉ(4sʘ.u+OO w}M=$hc<" bɽ' PUU_<||/9,`@CGfdnݒ:=DQ$)i\?kxMR?mr|l6(@z$ 䶛{t}ݵC:vёZǥwuNAojm]&!!H@@MrsjN6S<h2z֯gߞL?\LSŨ8&$zgWtE &$I(y*ut@o|ozg.GFk,[pZm0U0wH q 0wH q 0wDUUAGdYn;x(, k܎wEQUG}0B4W^9uرcFgԹ #QrrrVXqaաCӧw޽q5]郺ͩo˖-w9arUUw1o޼뮻o۷VA⢚lǂdQ+++I,oذn(**Z~ڵkg͚5tP:tFh;LQIAرcǂ z-]>hnG{9c0.]kNUU/,ݻwǎ[VV6w\ vܾ}EQEfi#IRJJl8p222<茆pv3( p_{Fqv SeZd֭ lOx}jffflŋ1jj).A;޽ke\(DQ0`ш#m6UW]]H4&ۑ>7ܜ"wl$''{ܢ(3fȐ!|' 7((({ǍO>}Zp M:A5hG:ɲkϞ=wq?.KsHIMMlfee7#bZZ@۱dV\WUUM4F ;rȐ!C<%tF#jЎtFSUuѢEӟ~C7)**胆\;uĽEnjϲ,;v,**q5^VVp 1..W^ l}K'O4@\K,3Qv3ԩSܣG ;w>h8M#}P"uuu;<0C lh؀HHHСCC'N^hD۱:5ev>h,͵cjA=`ĽEN駟6Lnݺ޽[Jk׮]~ٳg/[_6m /ҤI:w,ByyСC ?TŢ݇ ;7t{)Z1c\o˗7x+EQvZPPPQQҧO[vS<::_|'a (NOO.0`ȑ#7kkkNg㷒$iѢE 8pȑ#%B>}Z+xސmڴl6{4/322<,6VF$tݻWケwq-jt|*]_xol6frrr׮]{7EQL&W_ݮ]o9+++--̙3+V8tпoIb8xk&$$ĻdĈޛ'Ol:ɷoSRRҮ۷2;شiӄ @pc :t{s._xYfYd2 ?paÆM0!99?'N={ֻѣ՞Ѝ7zWݵkwӧg̘1=zP]]}UWu}̙dv0`L׮]ݣnSNU3ܹs +f㫪,XY$??ڼysddxcbbbbbv9sOq?*.. #w.Byy{%Go۶MUU|۬~zРA۷߿ƍN]EYreffM@:r駗cnذ0>>uch9#ϿreZ_~eAzAttdPZZ+\TAz4ͩ#Nr5̙3ݺuۿl/,,O~at$$$dԨQݽ{weejmWXo':9tdĉׯ/..nroMMѣ8nݺ{eY߹sglllFF@P"q2eŋeYdm۶Y&77]v 8}ի^0:w})4 gTTT8c T Yx1Y;1F`0wH q 0wH q 0wH q 0 +IENDB`ragg/man/figures/logo.png0000644000176200001440000033047113504650365015076 0ustar liggesusersPNG  IHDRfiCCPsRGB IEC61966-2.1(u+DQ?oFXHK 1jb̤i2̼f뽙$[e(k_VY+EdccMlsI==l6 G +NtUC(kwTXϪUܿ*T Zjo pTTW Zz$/'e x,$J8RjRO qS9p%XfvFbx|xPd/nM.eEi%WYc%$+jN$EHjo_+_'|-4C>G`]͢:]o@ۃÿR-h A54,{VkUW=rޱgd׸ pHYs   IDATxyUMgukE$^MC$I"(q쎠MERA%*IVx}79hҢIn*{%V[U<{݊;)S t~|+wN||B/N|.?j󞫼Hy|s?l_ĝD׿s{u;}.^xS<1&r̪{}?o~'N"??W#@Aep];4eO퓲1%bJ<ˏsa};wG~˔ ц3hyH x( RrϹ]xc?vowwo/Ǟzz38JKk4!ҙ%6khg !&VA+R5˦,~'~!NǝD~ŷ{?t02ƈ k ZebUZ g>09!%XZv _| w8㏼|k{|XMEa@ʠ3)!1@U9HIl2h J'J3R2?[P FI)M/|xu?;;I_cǞM!eBXCU8B)q7HӔ8 gޣ6@)8g@׏h|.9kʏ,7S{=;;J,hB)51ZT[F+rhQJ(hr"h%l >ڍ)^{λ7?1݉/TO|WocJic"J*b?)ZoG kZᬥtFk2_[9r:KFܭ2Z圧?_*2;[cu_9j~#cSI_V<~׵9%1"&*HLJ)RJ: M]h#J)BX08ˊB0FSji$儛Y+*9 kw.}<ַ1}˻?;yc0)g|25J+R)KuVJIr)IX) ˬq(% 6S&1`!H2)%5kMJrF7ŋ_xu>OSoC|>x~[$8 caI)&iB̯J$тfޣTS;sqK)鿉1%'/`A+BEY(29Tx,{Ĕ/_8nߧwo}Ky4 dd'bGʙ!gI3cH'4L9'm ; }Cd#8BN'3o&̝!(su!UeYm "x`Tw^8ڿ7'($' _n֛'PHt֢&DAg0AĔQ(RN( h5@Y8s}nFn쯰ƐRbp4!iĘE1E@S"#NAN) f-^޳]~κwo/z#_WoNi-R2sܮH i$Q'f|Y YřSK9pcӏzQ\yjnc D ޓ,5c r0MkL/WK6]R2\8}μ/Sԏ;q|k?Gn@i(2#(Cz!?d߫I ZpEwgVq~wI\G\u z֛fͺ  !h0BqΒS-c=Rt](Swٙ_C8ĝDwW.n:|o=r}ZѐsbaIjRՎE1%c)E$RJ$2FIRXͬrTm.[p\:l]!?~ \7:nCJ0j3i=0N3zG9K H 3yX<*>7?ַgwco}ݗ{wFdjmdQM؜elTJP1RJLb(pKgxf;l-`gY3X4dHV!rҠHFs7nnƎa aCBII1ƈ=J 72XZK;ѲwLOZQ8z}2/}ߏ̝cwc/ycvp1e-眧 XAiInaY$2)&+I;o ΝZr,)KʲdzQCʼn ՆB|ݘZspxњGc2DQ(2Fs18k@ Q:(ʂ4ϟzM?O]{r?>m1MVl|S* 늜&`I^a̟3y'q}oѺ@[}2$TfR"+EYwΑbb zuIa?{zpϸC=ƛ߽;rss:Oc %L YUiц™](j[gpb(,`{QSYy3i݅VM#x9t%ZI;"R'qDLYVh)ʒ"(HY*eU䘘pjkּ.4ȩ%Yż)4p ;CGIpГYI ,&a4O]Ѧ{W}g!Txk >t߹rmc!cbR M`:&S(d%7c頥i ,5;Y=;˼)?vU$ȔeIΉ)xDLQhm軎v:-ێiP4~ hJs[behō m77n!LBssE~ BDGcdnV(D+G™:?ow'/;wxG^* 'p3=a2eΐT<-PZ{{pݭgw9C[2z,HQ1HTX{G+2D?Q's*iWkOc8GY hpe) 4(c1=!8VG(rOe ~ !4 0v> 8k*`H.9t3?sG{nqķ u㽏O|B):βb9˪gqCOL(Cx(V䮳  ߻٭.XfmUhu<뒣Ց)c/u?B@bce(h 0b˂f0Zifp#ֺ)Ѵm0 8e9*yfuI]UÀ+K '\#:F)-{q)O(y}U;<_ο/P|ǝD[ů~#O{=f\k =ZR}1L2%6 Z^sy3˻l-UUUPTZƮ( wf[fZ1Ze+ ".qb74j3ull1+Jp֡*,`JX b1&FZ\N EHi"B!}$՛7}>ʯ;Zxk_]?yag c'rB Ƙ=Or낈"*( XʂP)=nآ$@̂\k%U1'gY)hAp~lGO \8*+ ,OL۶(eh]7PrIYUT9E{Fѵ--K>ufǯ#25m72ӄ9Q(ոHߣA[K~x=μܩk=wWn=y;{WiB|sO\;+8hb K` xږH_B8)\:Ο;-?utONo{+t=G>ى)sE'b&bg !$rh&bJN(Y]h=pgݽ# P WP0zVӷS,k:\QCo{3rT tCZHQ"Vk~pjlj8dP3(:6f1#)+-yS;\V=*Ӛ)fyZb,rR ΝY{_?w>}c|o}K_gW;x,9-#Ux]},y@jDk se98{ϻg7Mnj>CHb\nikEplRgt`є4cTǽvy8]h lV"Z~L_2}KY \%]?P5F102CSTh8R7K-XV,ft]'/#v)ܙV ]'N ڶE[GQU4 Tn* JkRƑt9Fd1 '-1F+J-U]C%B7yMMQݏD?'gE) We[8RT'Px/bYl͙kvڞ"ŌRrU蜑#j2]!%t.0%vsE7/l/9w{}%{%THq84)pN#BW,~cﹰ,9pg2bc(V)'WXBXguXKL^Bs,\Ewjji-a%*W^>g. Tq^n1%pvy:gf[K9ڍF Gҩ z}H􁪜Ѭ۵Hcfi N a%+>c7;ڭ>mױnG6}`b:Mp'BPbʌTen/^~͏W|J%%6&}[W"O Mj-mt7Jky" Bbx@-gG'Z`{^3-v<\8h01X\~0 V, 5WH"Ζ kVfÃH WZi{l6RfT)qTeC=> ԕr)R ,*ڮklYx4X‡Hu8PҶG"UU1T3$YIwjP$i# {Uٴ)A|W?W|7~ǯ=SƐ{ We‰KMuB²l7%;˂/lseASGe11vYK۞n EQ%MRͪ龱xnjfs"H1g>0ֱtC+ټzq$њi8K8g^gOm˟xZ_??p⩽SXI9d*#D1NZ(Y1)ޔڞqԜ>p..9]QZO\65ꪢKb8yrR'N 4I,~FaLjF}Ydɢ;+HۍX @B#9I(݆1|fQ5!v=#Jvs'b ġ 9(-xDYT8WPJpeH{FiO z0v>Z?zfM-tl/8QY|WvgOk!W6}hݾ+^Y|/]F%Q+ǯ'_89Hh+>xd$Q0톭9(dߩ51zAvL,qm.;݆ gDPLm5LY8(W#h(T1eUam#1 q=k|:ZDnh[]I64u3 a +G\Y`b:ʖ14rA/D;D{eIU7t݆•(lք'vDubsiAyQ8Sr(ٙZS愱't}7R+22C2"b6VpjzGd~tULFtLX(hvw7ݎ?';tgm >.@(ļ] 伊X阞&?Ί{rVxf<|?w[p~agQo c#D)40^XUDP$0D@)lYR5'"Slf{1@ҙ3ZCw)'h9Ge{ s<)QQ=}/̴0qV]?_̏9YiϞe>'15\ơP(cC!GbT\r KV.@ϰdbsPWUMUᜣgd\F68 HLAZ'GQu C&Hʲcec ~qJ)JOӻ!OkIŨXu22~l-lAFkRƹP93 3 <)rΌH]אk[Ʊ)%#CrC?^o&hJ7c-9eaoi7]ͺXI/e{™-RWuL-#9eВ'Rf#:Zm?\?E//~/_{_}'mk~鷾'Lۏy4ދTtHH2wTZeAYBVIMSl|vvݞvkU%+r0=7g%fd-- !SsPRfZ{ (V{ʊQT%0qjKʉzC߶XDlTuc( G`]AQjuaM}۲^- }>yb-c5ۋf;ۚ7:~ګa,Opl%A4{aL${iYZQԥxDWe{p>wg_pי%(;ߔ"9y|V)>P E\0m1Fh`GE?=$ 9Fl~BZS%G+m6'wSNlVk @2 )J7M++qD^k*$Ө!0Tu)/kq!x\QL'ǀGD cF.Y4B$,vMZb~1j6,Kqu-5 ?xOH0~Y*p^&)QbC? VxA|{_9__TtOD~k^rK7{V+>7O|LrBPX#ZQ:L_4 38OnTeзa w2M]ӵ=\WT}7U̞L4҄Bk+<@)ٌ*AXdnÖ%YliNPbeURĜh MI(E0 .eh7 c8~YnVXd#5|6c:"Hmc?Y)NhZ(C߱Yp2=}&@LBhk' 99Z跻$Z֫#ȁL"ƌVjM]­'$?8"9 1ƢYF~jU㙛{?|+~?ȗ?n{"~ƃ{?t'oJ))c섂]B x3whf5rWM]7LV! !PSb>o;ٌILK+QCX[aWMn׊v8H^xpX#MS9)rm C +4p1peHɛ .8& WhUXПә(h5QtuFYN9h#tbQS{;L/(?xBL4lT?zyiMYS0d{^rٚ@b 'TY5Jk Y٭7_<{~dmJ䷾楟g}7w1FDT&0[Gfes HhEU8fwg>eQk>lPQ>pծ;6 {CKMj; CGц(jE 75ZtVuU3zO,c"&EH MJ0Rf̚c MJST5ж=!GfŔ"7׮4iPbq獼p,&k`1.hj:CYW4 c @5l:1.teI"t) US:}r5Oԓ1-PZCKoc0tm+P)ҷJWq6q2(,&ט0?Eǯ<߼sU_WG}sZkpۧc<~+sNS Y59%% -̩UiٙvYVv0zʢ&),M3捛f )gZ3moݻyJV]tfrk S*xN0#U]+]X+~{QFs€68ShU\)RNh!R۬ :%+`F98x`j9SJB暱^`k7? eELAXvȧlڎh0V?8ncꥌ))m, ]յanjBJgr퀧nkܼuD Lb!6Vh%8XK~zwk#?!{ެW}cv~&:bPUHZj)"I+ ].pf=βX΀|rmۡ!Qlo-QZ?eUP8K 9 t#rr!U%j[rޭ[>E3I)+Jq_H)nlM+4epƢЄ,b(3'c )Kѷy e3Rΐ28 8v/Z8r&,MJ8?9Ow,4ɲC߬ք ]/&LLgC~tx@3f\1bm#iAP魝m|fns>ʇ\c=*VfRƠҸDE':5ahbsޞwwϏ{ko|髮n'U>pϼCOU;,'rG/ }#ȭ9TgN-9;9yNsvwfVRTtđ<$eUN$H? Đ$ޢSۍGMwe9L~ F,ίg*(FԵ cg"S'7ckݜ!Q(E* 1 3uu`z\QzZce,h2VஔYȚ0W(\JRdZ>r#(7'N+}d:Y)8ua4ݕ6TUEY5aتP u="P*m acq[[Ky] =:l(xrOg/<g~ /?1OoW̞;Z-\|b+sK{2a"EۉnK{oYϽ <ǹ#1DiGf:d)'gGʪhJf`GPၨxabmocι9uʮ'bG1!eBDcӀ HIxAFr̈)Bu6y*6Cc4}0w>?CH4a `tŰERW5Vtۇӿ=[_?3_׏?}Q)$i tT]8I L×?|o~}|WxvSL:&c ꜅ц2?òzYf yXhm`Dz2eЏ9.xhH1a?Cqۊ>TJtM&d9 DH!k&$jhe-\(' mAב} Z e@dn_mŖR+r3yEɹW j X*p>KV 3[nq>AbT7(Hc~D+hb[/H1T? R&D) XX7`'( Lǻ/x {Rۍ"zu\z]) B=Բ;/o~.w^ nA*Xz;vaf8O7a~BScz;1";iڇ+yZ3 ];+^^mySfԽPp#{g!QV.RH$q=a+e/j<7&AUJQ%g n#>ȢDM{LoCJ,?I?. FCwm3 J_Ska?韟ub*%J;W{|}w [vΘZk0NȚuuTƫn3C(߫jC 9GH@H!rȧ&BkN{^%B*(o떸nPV| [Km0ڡ5 eYxEDb?oK|/rʸXR2H?J2ǩlOM|yj-pؠT#N RkD K)6yAVYUa[<0a9=( {pc"] )Je$U W|{'?~?"G?xxZ~ ~q JLkeOQ8ӳvx;#~kK SDuE65@kr 6.PSFJ 6Tq>]D1dЪtҼ %$RH8_PR|ƲPhPȥaYbscE)>a5np*0/U֦|\G\!eP2$O)8MγGW0ZZgaY#PJ lIzsdTȥ8R˼!,羞Mt^:/h|zZKwwԺ"'h) 1DX-@(0c'x?Bkx]7X| Nk0;uEͩ -=9wh<.T{!j XF+OݝC|+)ovTV5B|Տ?}G_G#;~ϭ!Bn՜rzrJ0ײZ & VVWw{V٧/|tuE:/Re5a0 ^|ũ[@ ۲˗H1#iBJ0pӄ1R"%-UI$ZJ{Hݩ 6{ IDATbbC跣R35 ʇYJ -c-#>, RIp '5U5Bw}R(8ODv!x$S;¸OP)OOlv{Ue688; !hؖA 7 RrKț K 1M_NІXRa'OYBi !Tj&w[*V(  $/>~}~>tYr7§VUzv1n?_^?~oO<Ĵ2ZGߙ)}=/׉J6C@5ȍ%cww]=%lR>{?h(iD.qRt;{\&(%怭0xc^NP}%EOH[ưsqE\>' !ׂn]X ` Χc`ѡtz~ {:㖘8a_/1wӏ:K{as 8ޢK]5A* yPV%r$: e_d\m|yuJ@|~BI1ľhŭS7x,gwHhZ@)`0sҟߕPr=J`Dq[1M)!pxC᳷ ~;~g(pLʫ ]rꕘD _«K'/ki?x/绯<PJ6Dd+ɩV`~xF| wo|=FX`F 4_cDS*(9J)g~@Fw/iʤg;U eq9=a6R-@@ Rf߹<}V@ 4O }7"m n֟|=R 1$<~g4/؍p\Rx-cK9m ĺsr> W*{Heρ݄iGnauA ?x(mSKJ<sR&`- i?l@qkk`u:gE\0cc[\ϴj=P8=ἃםe_8f[Vic~WĔ3#r8RmR } ?>ȡ`POz5uw"i0NX U_!eE+p|Wiۖ 1\;L 5{XN He/# mݠ`,oV-xqE?WCJaec@f|y)EXkp>]u[k 54[@kkXIZawmSV??O,ǟ_YѵRS!_~ϔ[J*_W?x4>T&ִ2sRv_q6AIa%qbѦ'"JЊTJNIn`F{䜑s 0Mk k= %o m=RC >$U;y}8k-WTh0 BriThg, b h. '$R(ex{1ZH,Ϗo_tCAuG<ڻ=v)c̗bXziPrEkd`/!i9fhKGlwljFqɶDl[4Mg;|mn@ZWzMk E3,dA1 s_# j Zp@wA֫`(C/;|Pp(d!%b̝FÃjZijrJꧾ{/~_[ƔJqw amsJJ \ɕ9184_⇾>K8Fh8njm @-lLBi:F 8kru1gL,_PRt"h4RiD8<>u[6SS䘈%& &:W׉u̐?a5ۖ a ~k)`JR>]h8TMlRLKJ-܈|8&9~> ֦k3NOudQ h/8A*\wƠTy*%IZn.(BL2og%fƾ:ψJiĄV*űg<=|޹ǫm_5!)Vݻ;ra2 5Ek͵}/A 5'Q[< t٬왝0]5z?<#݃Y\4=!0y=~]hXC|%Xu@%V-]a52u%&_YĔ,q $:e>1SІ\/CPA㋤ bpfL?P2\n+ت\Brݯ mhLZmU M4Ώ à&rB2U+EjTSU]!m#L6MH㰮 "֙aR@Bđ89e@J ?xƀ&>~sƛҡؤ23BHUч˻ݿaVO~G9L ֧:FUJgl-}Wpo~;xutp`A{݁A)&44ʝS X9V eC,UcపeQSє}.CI%(ȹ 5g={7/{)E..ᚊI 6f._=*4iCX_wcU #=JRr˭< !sB$P5# 6s@e%r>Z&U6Tʱ2N_RwÄs-  <#mYkLr@WDNZP%=͗3NHd~[lk)Xmi2TRAk3v0Lpaw0Ntri`zm,x yugW?Ya@@zu g?[7ʿK &rٳ10XYἳЊw܏#K/}p} *Y#NO'8a Z1a9@!#)Hwƍ{cG5/ Z ?-nGM?l{Y 8g{i2/PZc<` ֕; fXyk~(VA߰UOMazb$9GJ{9ojNjz: }TiBYEBUzS9BUZ O I˅S3,ۺm@"H!ar9c[f~ :% :X?􇙕iF))G*AWsRH~ՁPWvMBjk7HP޻+ Y!1 kHۂ&FVq9ƒ, "y\sU H2f[o~Rn#eMN .9SfبR񸇳k_|wG_29X Ln0!b鶱  &0J޺NhpCGn7 @@$ihBJB # lGd#y\bvJ/Al2 ZჳD{_-Hivl!P+)A B$VB{К7;m r~F|Kn,amOt 2Z58?>4ќ(e&NB4Xrϸ% oX}mYJ`+w|W~8LelTQ-e i+Y Io3 r>C 5lȽLiM`1יyFqh ù$btbJ8ጹRf 0/@BIzOiv/V o޼3n<-O;>8B[RU8OL;{"mΏP !Hm6\UM#+DW_AfaZaT)}ٛ˂րnºlKġl-5'TQ 3Pb_ե~sࠨ"1Z@(Jr0>S0i>C@ D/ˊa@-I ؁ssA+|2ה. c)eĘs#}{aaDN[G6ZoX^|ݍRu%  ;|{|ݗ/;eŶΨ ~xZÀ4bY8p8ޡ5hH4øs۷g-Zklۆ/_qr^lu'nȥPhZޜ\L#]7 w`4ѡgR`\B15b; cfDB:-saR E?Hm r_shӧ%!pW釮^g6B"&8򃇲X#MrĮƈCy8m40am_HXca{ݿTV.v/ u#fX;G2ïE(ezY.aԊ91Ǖw<xBfrㆁ0N8 w*7&Lhvֹxq ?-Z10t(uR*{۴zQI (?~G>|BbYN{`[7`r'/Dekq>x>Hc%nq%,)KYƴVcRvd\Ru]FRiX H@K c ݞ{Ųm| B?zn>==ኋ͙4RJ ޢֆ˂+b8`<T/59KlLc?,wiv}%d(Q8kUrE+4x~x W2۶},rJnmP =qP[nw>e<^~#ut0L0r GHuC.Lݮw#NsHk\ r #L9[w!D4}6〰ny!E_?}`a8#xZՍӸ)-xtkLXQ9`-UT|cIJD$DS?t队03}T ~TgG6,RZaG.v#xg@ò.q)R?(iC68Ce>!rfֵR+'̧J j֊)&eE-|ƶ\#ܼۺuk$̇^kv;Ղ8":HH ~ѥQ|>D ~?}@ n=u 6?{Ҥ੖K&h 8;]_5vсuJKTT0~t0V9hּ`z>݋VM fS=쬵a @bTռ}tqa ֵj{ #KfՊ+tFwwuDCR;k=NVhm̔CÅPL1-q#%J\ !MX"$!iwn2H?Y^v#B`~)E8a|z5Lr܀d?( PJ<Nf(Md׆s6_;AJghm0&Dq-1ҟb28ݑ{-%J-@ sg(0pZ(RZJR ۼCܴR*Jcz7^z3J_99o;){b\k7Ë{N$u)~@c5P\V]}yM Ư|o/(Jk@]Dzm]؏uVws8L.YZBx[빧lvYc)$v4vJ LÄy`=Î/uhP/gG91;N![߯roJ458'r5UrYp0Rhak_|}l!pv0XOQDHja{ Jti+Øb,wHqC&p֣JsʨraQ*0a[(hp)3|QrgN݄儖KBAaqw<9>!y/ yqg=R{R6S}~kq;;B0UB: -C.h\u= lkD*u[ۆR k q}gHI!B)4iAvf7:$D`8C5Zj!aEgn8Up]jx" T -5J^ )m@uP_;΅u86xg%Cw[E8aE9qB\(AoFBE~xRnޙ08;#p]7{(aRl3'J{8kaɛ]#.^HGD)%F1]CݧƠi7"** ޡ)iGaJ9KpJ @".+LݷTɱ,I4D̂dcދ)BKdrjj&a'Z%hE(JGf NR# Zp9P3=trct}pDi'`'snEnh[ %b Z .+w_p:W8bN $ ztZ󂅤=5"Aըy=|P*P3KպhRpnH늵@ 991xjP*؟؇ 5Iu  JP"Tç)1Rm%JN܋"^RcVjAA>*@[V%eH`>{$(UTTvZbT\:\[Dm N!Ah+(5!{n@p?Tm'XNI+c2_ v;nj+n 3sIJ!i޸rRҠ0^[X-,4ѷz[F ~:iɖR6X@!s)1F[CH3'T%TX7.v&A*tBN_H)NkPO ~dC0 JrU849@\ QkΎXsRA+wBve J8==RJJ1Ga2J&|UL%jjl낐6G61 B[qkp:9  %岹$JT9i ;q+R!|L,]QI4wRܤJb,VkMhK)ŗF=#)Sac7T2k-{Ɛ\ O yɂ::m'[ 4S{br0W8_SR~p4vh՘eۆ"b(Pj|>S[IE1&r˺tOHZ׵ )R B0vTR[7R+#ŗ4iN>ȉKȰr}UIj|Ry+dY.4<Ĉh .jG;Y,uV E5igҝS~ 7vZmX9%8$n$skTq# -shCmF; ;)14ih-Ciya HƊy׈CZ8̀qF+Ԝ0 ;{8Zipg_ٶnq9>2_Oh%,/ڢz~{yxa@T]1NjKʸ׺ ?u0"oSe]t{|ta^.g;)? X֙m]5C4ˆL\+I(w{E#~(92 enGҴyƸ1eW21OgNt^ J:Zکq9n$'RJ໑yP y7P, GecQsu2h F5 DZm]V;aX*w;~wy߉*Uh-ڮ"[Eak El%3M4M(-tcdusNNw.,~c 7yP[g1b h( Jw1nɩEŞB !y=}Ҳօe>K(RLi-X"AX+ø<|q}B$lR'ဵyY2ݞRAV]8}r'ƒ)ܾ⛯0aL]*Ӹ[by-DO qUZ Clv|܊)s\& C/nfɰmtΡ;Ƞlꉕ%`J7a]d?~Uq( V&&ԊDIs>6dαߏ\1VQ*OxY 3ANud/ Vk||/- 0^nT7kls I/4X4oo'ee;Pf#0{ 2Y/@xޑv;(7d 5Q]eAt787$,AI*1b;RQݦ;j&y<[Z!T7R G/zIp?ҘQr޶֜'))/T*UU3*d Uv,r3 777rO gdϙs;J8@gwc(Kr2V~C-+[Ȭ)JX-p2 2:ݦ(me -?UZֱ<1V+nt_*,IF4iW  |FD-Y ?g-m3U*YE2/+!fQKcGKxOVFfѕ(=H&EBX$~yJ\ta[W3\.ö" ڱfflz݋-}o$P|}+5S)̳QsSF[˺,-H#+msJz EeHyc +=ϬkfA) kVѺIYZ(Ys)9|2 mZ'3λ*- i(ӽc2/3[v)ȤqM|*9 T76E!ej8LEЭ6g1\5yGJ$<,UDT>B30ܵ~mk%ءZXI(iu2rTk?n^Q9 Yfv7q8rKq1HHqzQ.}e;ʴ{h' E)@9t{~nڃ}U/Г7ƌN N,w)Y˖$wЉv#N y}ۯVaOLhtC5(iYh4=!%3 yf±̢QMxߖ5\@TtH*e0 qQH*T jn{}] v~ګ8ܕl&/3VPֵ$J,qαnzF=W |x83[X'w2ZוZ 5=)K{[ΡZúMg]WnPd"8?|4g<6Zapɥ,&bZѺkOA}Ui-ds+*cA40jPISXrTWյn5@YJrZ(rUjsL(EJmJ.AmC%4xw䔈9Q˟fr(m=$VJ'FYBdh'RTo)5 =$(BT-3!.{RVEc r-u= !n{$ h姈2;DnaAi:-g Lϼui.}o9_%kpR5Q xBw,Kxf'G\YX/jyKD=gAR) 7AT|O~_Qq\|j,hО)VR邷0*Jp0-;sv;bZq y&Q4S)u[(5 #a3ȶnmno)}DxV.kr]'=7;eQ[R% wT(%0JA1tY &Nao77ֆ`u8k",'qe]gvBfߏ |eur4-12m]$=jyö=sIQ1&L`\xF5Ĵ(MۆRZỡ\7&[M FFR_/rŭ76 "DmDS_jE#u%uy'O+=XEe} t_@%wu$Gmzn@)~3,c‚s ~ֺt}0 uy1\)S4TV$HIrYܲO(AH5v"8[ jص] blbu,69Y-0#VbrW]VH1JYaBj<-3yk<o.w"y+Ъۯ}ʯ~~׹FEG!B)(%ý3΋䌲Җ)q{jIX. IDATyE6JʶnQ["ˁոVX=FITy IxR{qx!H(qNq;JR6PJ3rgI7JnI=B$*W#zx]ONB 9O #*$ehe.伣A 1*%T$ LiY$6Iq"M\Jc{!X+oGsm Jh|tbZh$i㘣3);5Lp:GXl T'&k>oJRWCR)bSPGI B|.rYRh9*L U&Ev~MX?jG=+'c'}V1 ,ղQ N}g.3F ;e:FGmWjgQxuf^yf&UT)EW)E9q9#Rs6fF;E*Q p ~m37N 3pAW-ܽ qy"|!ĕ[la6GUۮseMc֍qc&OĒHQB|#rR7 (Ƒu[X煮qk;TIQ~n%yy7]SV\778/}mUbZq~%VJnA2B:4 ?./m()T毶Tִ=Ul1Vs(MfbiXW,zǁ+wAեu:/L~2>|  KwvM0A[3NGLg`Qp }Q>Y^*8X癘/_"ȺmMrp8 m[;q" = h4yWex{ 3QQWՒ:3RRkkzniRf9ܐFIOZqܵ BxE )3&ְz΃RƊݰ*=-9NVEi=q8fA@׏LZ.1 յ뺮8?7n C/x-~RT $_ !s0KHi#kkɵCS̲8q &j{0P,Jj%CލtFc`Vh3->$֤*kT<*ZMn6 +QEfFG rts,֣T:oPYadwM7h$H-:gޞ6]2'0v@9l@Q\䴐Kx)|"w׷gM(w נ+\.ta["tCq#,+/&ˋ݇X(p Z{iK _Tfݞe9K? V M9ɟFtgw pswVi4l6qdF708Nlv!e茢p#'41aXZ`lVVRF\iT-l"l+FRB&N@J<ۺ8/, _fa$g9KZznĕ3JbۑB)׫`e^^~R5$ *U}?b`f#R $הv\/WJ,P% Mȉ?~{ۋUӴ~4]9IF |׋zCA950k F.*t[Ӧ;MA{\׷7AwkIu;"#27{43FRVڊ?k]yt6VHw:~gi" Ƿt#eю5DmKrӎkU ֕%@L : b6ҊWI1p^Of;7X<(n_z2v6FIݵ5r. @{nE.b}(,=ES^x\U)^|D2#) s:+9~w̫ fb[_Y RI&P1n0ot]O_-o/|v<J ?ġm }qqjk f,+00M#ܾ|sF4RXEN77wP?NV0~D-x7; PW_EJo1+y~v/B (vF3i> %1;R [iۊ#}l% v9JƮ=>Fr~w|:2_.TxkXr8(oy=qdw؋]w~O zf=*+Rx"G_M΋*g;?~ʰ 1pZAghQI Cs9%6G+iz&(mJr5P2QeiPӼS8LR,$ymU^ FEI.ǯcN9YR3}z^ND%iav;|(qt eѫm g  _(2J)qAק҈N'S_dz/wxx9A2~pP-"qCUҞƱ'u^;M\RK7H 5UGB,Ԛn;erw&aU92t~:Ru$Y"x9=<0O"_Kq.8+R)wM N&4 @Y$Phe(s'i8`$*x8ai 0NKJH؍+U<]?JzMI;G0:]+*ZJK$Q**Y]ϧ&w@)\'fhh%'@ {X͙m1p\Z4pos,:S;FPq?ɇT1˟|Zk\ 1VFI6VUx!nTX݁u 'yEX6ơ'» clGQI?ԍ$ \/niXuFm}ۉ,H? 9T&ؒKxRaY#&16 bI:);K,}g#z%nL=9܂K4hm%0DvO-80#RbPZy&NX˥c2 ;yÝf⹬Ͽwuֱ9 $g;'+Wi8@1Tg`5tخ8K4yaJI0FҤnVl ƒbB,64wZ8G`^S@$H$o%:)!P+IthI] ZmhI)%nR݆BÇcN 9IƻVJuYz,?A4vrO>t57ahD*cDj%r.yY= x#?+|9Qc$´mxh_0 \zz0,:QeFܶkbTZ+יw΅5%^CFW)Z"~o>o~>S[FkGۉc"k`''5вu#a12WǵV;.Y 9g9zK)H44[r=%hk aKh,Zx¸r:ҨK%#;chcؖl{tlh#%?6^|ac[ ޷a5 RN`8o[.Gsf>tnGiI#1 6x\-\ j$(Am7o# k6-V ͠.\/Fr|/^p9xx|*ppFl{rRy ngQ=*(p>τmŋ"'Yp\Im hBҜUq`b\$in *Ӟ-zmBòXm99Ft\34qfj͜gvܟ_~8ՠ8Bz&oQJx»O?#?6,@`[#Du93 g4)% "YKYyjX)ᤂ̜jt1Yke5`4Sˊz!V4(Jm,5ҍ󅗜 2Fp|On^<,Q7膎$n_ r%"p9KRO1f7~NX?cHk']JIEzPX7ʩ$o"ؒj oeM7?$.+nbs#eޏ$+tzZ:*+H&I aJA@{tJA451N=*Ήou6{wz~ĸv+M'B&JW6pw U|'q sUI ݤmg`W)JTrYo|FqVrl̀U`(%am_V+~[ !Wyᘎ[cS\ s UO+g|<kBdzbNafM Vo|_ i]J&6+ʢjFi/ ^z Rk#xugJwxy8.lqISj,JTE W~6 =Xܲ ȨZU5OS2/k!c2vf2_ئv^8smڐIkOfDRF IDATIڶ!,6aJS+Q(9s0o-)H (i1ưPRhE8Vs c(]yeM/^G~?|KXQvlUnjsyտkLkrzv[y+n?yM5T0RKf *t١32Q ~N-1d?JCZZIph|~qZ 1"Ƌ .'~^ENN(#1j*CI0Jm)FA|9AڦøX^N/6-cDM}wC73.7̑%̜.=[2>t;jM=Q;R~w랗7i7H~&ion+44WU&⧜.R-9>|@Gu\aQ@(s 3xfޫd )~D wy߃Jc^a`T\UUƱ#lPJCdAXϰA,b,-2y4|wavqάq?[ [(JSd 9yT ؿVi,oSǕׯeB^l &Yh1ckbJ͉ay͞ W=?$a&-(ec`$6"$Y}6mb$#DV MyK/^膎nFYFSSe\ٖ뉹 \ %_+Xp<Ž"j.(YkUX5kAbDr͛ț[b |r!pn|.ˑO_xLg)UB<[_첵w=΍dVJ d }d)Fv%/8sZaE~Jro4u5KmNV-f I9Wg~VLquL5QjK}UT\NG1#5U\;KG*EHaA^NE,jR<|h-d+B(-:R`3%0츞d;MtgP+7N3yTg4KƉzy^nkBq3¾ӆ29咱44ĕbf^C YzUI AͶnԎ«NJ9&ƗFW!lׅ] b~d*Tdgs8+@3U>o`&o~1/J nF 04ba2$@.~[@jI5V$ɧy1YL%Fa㣖gIjkIrWFl/_I'Vrxg9)z_ ?yzs:Q- q+JC4NBh)bx&-&!ᴚ3(2WԼ?ޫY<|.3S(8 )RIm":f"j6EQ%D(sLfn\|@Tܹgy@EY(<$x +Ɖe|v4\7:hoq#,3؂oZI? ٽxo5oij5t(K*E<FFL3TeHkCjArM:B\Dn˲n<1M[ ق0Bsqy{F+*ZJk=[lo!$ebiv<9F^ ̲8׊1(DK(7%LB|8HRs{K~8O7XtVAg*>xaI^hڶ%d;IuVfF1˰yW4FWbІo'LF c/~ѭgMJ&Lm$4ۇeyN` u։ğusɚ߼ ϑR!Xlr+L^}Րyy)ڕ7+Bݾ;GM2x~Ze)Su$uCYqui)Ձ}C eyiH^2n4w'9&&WM"2InO ?pيvY!l(ReHɲFyJLIQHl˂wFu5H ?C fhGIJ Ӎ~4G:쳎>,trtl[̧߳FJۆ"/_}@!xwLJPF3~*Rhj;h:~[>~u8| 1`m%W6PY2JY!8 F5~~1a3LY k<׃ӫ'it-mY\Et|Yޏf+q#fy5n ~5#n@io[)0r(QJ )JIhhv R(`KjՎgTh7o$f&EmќXS2#޷2+r5s:I*^a$oq9L{^`~")neyxX8zm֪*J%klF#&!8goz.;^|IvH^֊tuވAӢ*t ␦A'u#1suy jr§6 I8 ;W UO_hNLJ( Mۊe?RcۈHr:YmQ5IJ|?eO?%pq4LbO3XzAiHƵXJ[zZJPrĘN7c#eKc )nhU//'ge-r[tM_!V?x{4ӃKT$|N%t78q:+|aJ#1/(/ܾDr^1T4R[}?串m#tX%9fdyD"hacD\JĘV蚖/^_XZqEU)<>c|9O\\%Z+_"M8tZb8Aq6hUʈcgLf‹♌,6Aʄ-8n=\,Yh1}C߱BY4.{:۶WⲐJ.Htط-5*@^)4/ƅDž='Mr||X~xO.CONi^$T8=/_dۑcm NxeJo[?sϼxu-MӋSi,|uxd0E)M^r$m'b(W)b9DZ{Z @i޳@Rz kp79ga3i9\\vw?l.$pJ1ʰlqc~o݉uĚW 1s$\w+$f<ٰL=<|nXVmmd`y>c'8Bsdȴ(}_wGE)OSxS=`x %+ڄ"C&rڪN/XHt`Ÿ~Ez}f[-;,O=[E&1q3 8qxX׉%x\ VtfH'ېF;yDP"urOnp (M?0'N´bVh#1-FRT5}gǚ?dr߈.>l5Ihmg!v0@ QD֌iE[KJlˋ5eր7O+*gq5dp[&GW溭1h^DP a ,gۊ:]Ou4m#̗BEc9Awt}o []^ >98;ܐb Ӎ]6J#$U;>`o9.df%R\x! "ps?5՗%DLb/.X^,<Ox\3ߎ3k}sGRDIDrMZµŊ1/u [іB c2}g*n/,ӕݻh;9bP29X!l !Qqh2ӄxKmFB̎YU%"drlaJɴ,{.hC EH!kǯBH c:r]+5Ӓӂv:+~ֳ=X RNl2V,fcSMbΐ[КuXE嚙=|X Ze($uQ\q;hz^Ca_;.;Bʆ dЍg) MVUЪp\cFc-mްe(U%m7Y2ox/oR\"WĨVŕQ)ᅪ\@p7^X~) :gDx.mIAXq[YKaIhӰZu[%ab̤y0sӓ IsC_pϋK*=FnGmYZ.K%}*VqOd) gkZ m%J(EiA:;=C V,(EԔ-m#n+˲C@ar,Kh?3ޙz&ֲ) IDATϪ+_]㘦t{Q^JkQay:]OZ&Ir U[ |pf$[YBFB+$.C蓅ǯ70EV4-1W&u ێ!G#RW T:d )VȜ8m;LR5)qQfE]FnIZe%E*I(LfG+(q٠$r(ߊsMSsOy;l|UViY1[*Y|>2LV+n/@䙔BC QJj8Lof>X6MB RYy%}}x>q4J8k$"g(%!{M)?Q֎k;VÈ-5*HuJ2YYFcjŢ%V39 B+R#DBX)є(~J]X,RQxhg ĐZ$h Ҷ ]6bov,c@Y#cBΨ;@7|c<DR ˺[/(=^{R.XaP+}>ה|fѵOoMJ0M3c b(%]Z塭q *& ?ވ S*9{ˇׂƛBH2()_K&%i*h!Rh%U1ԒWPݺ?hxS뺒B._HB 8ĴAiGіT[$Eᑮ=$YBk˲7#w+[ש$m,hZ|i,D ޳Vc boEmjx|i8*R-߶kYVƺBijd "B&b߱)MM$dIP]0J1ZE.:EYh%CUcS붲mQ(iaY7ulURXeZf~wtH p4F!aN# yM(#<ڊ>vn1of>݌FE}(y˲r}/Voۆ#t2bTW |&ōkI)ssx"GôeRHiĂuAQ}FBд9ZbڪvS =m$HOdMi8ΆSf >I%0@ E;]I3މ?E.dd9C9G :P8߳!Lj6 b{"0c>k-O凟w_} Y÷wKǵkN1iF2tj0IX]5(pQǍf> !eDzerδrۡ*¨*S44¡-e2E~)b'S c7l /fә5$'gdEi A>}_o okaIQ[j9PdaUֳD!RK񤺊|=2Fm\ U6(|ӂ5`1Y JV\0R4㡕-pib'v=1$QoXƑmP(8.pqY~`+Ab "^\⦔%'qGXGuŇt g?ky;Dٕ/Ů[\뽕䋌heyLǠYh{yAoNE†'?<no'u8N2F)bp(,/.?+Mg,-so Hs!61CRu5O4cEj3wSsd]7,h# 0 ]PHぶw >gZ7Ѝ oBDŮ\ ]A6ȁvR xNGn/4JG.-[}BXXBZMUOQKO.m ]Yb`guuZ𝄺y{=ֶvt|$@vmYLڶ!%18PXs6̺.t]t>{ufYf*^wZ..ytEZPpVs"ִ:$[`^ ɛqVNvVdIe ;̙k֭٫aOAs'Zo5„22ahӰ B4`b/2aՌcBQ/ b\?&C2mV1Zo$i21D~Ǻ>vw\4?,&ϞqX -142Uvɐ* ⋆O?سMXA7\i]Hqe"Sڔ6;%NS}~3o:a/BSm˰;fGbHh q;>_w?iϙ-_@N\=j7r0?LJB?R[H?;UM\_YUv"ȺIFQ7.Qm:ucGn iQ@iD4v@[ybYTO+FZ)A;M`$ Ek wxiV)pŞi91:1|~yMB`lVvڲ9p7i]q%T-o @۶ nQfcK-|R=9Y(Y܏_}5ыkn/x}mfdNh~GOGKS5ZYno0d!)T 79eQw ;W hprsK>Csg4O_͵b[\}q Hδnp8I)2ρ ʰl,pHizqLcݰ w1p2/_XVI1LѳAV&3R%2ALg(Z_0t-pA 0Zv|Ci\rڎiY*>r< J݀2-)#er'{7p:͠Z8\w=XE-=m9cegm/fR h V{n%yz>t-+Rbf٢o:?0ѕr*mSL6DYTMnh}e:|/!b-d y^(MoFPAh@+%Ec8E $iu _Gf'\FnQ>gG){6k9/_+wߝw=4zv ěo;Kx-lIDdZ֑2mgY#kؘĺ8AUeqN۴5fØG/v\_*I\Ģ}x|Z>ʻ{XQİ2/h [_hNgLQA%nivy~ %+:΁,Mv- JF@%NGJ4mC)u{b8 -ƴhJ^S@׶*Jp!ȼ8y:h"卜ĢYJTTӲgS^s5X̲ ~次sÎ-d>Z#>QG`mKI, yѦtI%;XƑiF&yE\=Y$~9C+MI wU)"_ChuG0n;O 4>$'L\!q0-’WžF{E,:dO7gq+FoLww#_~W?6zFRK>4-II䦾mXeDסJ*g1//_?2-e bm=I||[c6\1U8H)k/ ]&5MOɛL),k Lq~zR̄VhF[&S#x7-L*VO-r#1X#bra]$s}yBm$E0.+3qkH)+ʈ4νU( @Nβ,4ӵ^:¸uȶ6rUwAYm3oV+xj2,aE~f!lS0Zf~~bP95 [RJ60"Q` 9˅s=|pYG'2(1qBpÔ6XzI|J9RvNT:F?IF"?u;:Xn΁bfDzה$ɐ4+o߼d/FsU#?Dalˆۣe=]{źLrү5i8\\i$*r}}-^:뤸r mۻ(D d U-.WbC|wbI ,\?m0m *x>q7;O?HUB0n'%7mC 1IxYUIғn^ܐ3X;__)^vI(eˮI 8k** R5}۳l/v VM2#M?;kIɠmH3qZQ=wM\pjx{?;nÞ1JwQc MӉU)v3~GXxeWnRO|x?Sh%K6sx9 =aVa'\c9Y dBa]St>'bG%, iAxRctȶI8E%Cq,?%R6 ,C9UyYS>*t: Oɿ[,,PPօ)?"W6d.=6-W{1\E gy1Qrb]V|wcz5/>P\e^jU%eO:SUr$9'GXv(d0t]IJGt=۶8vr$T̙|3w-肜fr^DKus?5* o=9~'Hq{ $5;˟}pSy+Ҏ%"WѻT4\ زQr!$J. 1F9 Sh&LHAbkNBS2}3,鎩F r8qn,ӓ ?R"gŲ,#y$ ’zVPJ)hYN uae"jچF4j~z*3@UMkərL 6:  i:PWg>KVW=(\;W#V` bpNn3:cLoqqyI̖98R>Mdt#j?wv|a+PakE|md(Ϯ5裖yx N5]zEeb|w&B̑Gd7!{v{ !9 FH1-Q>-oznE-2K/{{*dV%ZrɣAW-&%VI-A]WX6wlQclK |n9S)Kq\ ˟ t?# Y|(΂?jzϖRhQF3m7[3JyqA)ux4-4ajo@B7 /S(ȫR^Vk JVf/kRbk;^dm+Zo^2OGa 3* !`,[B2B缽V||Z!#(-8\m!ZRViuߓ2O敡sA$bsWv»@N"Qg4۶}b%+" BXTI=1[XE('ZV1}/dg2mӈ#)(96дWWpT-Hɑs|tcAi#L tXkq՛BmP rLdMӓ%d3`jx<6m-=" #j$-Lô)jp^uZb/~ƚ"(C͸f \]:MpyˑohMjFe::] <&qw\qo 9yO^4c $r I8GM b@iJ+;<4@Rլd yu1Nӊj?޳ْ+{Os5U` 6fB!EH?I@&M3hhW(w=&3wnoV:: 8wwgềw ~ua?zJ^01v%%Oم@0W;ujOO}A^=U$/eN<1^=՛[re]ejIICmNtb^¥m3| Mj6J%'IrTZ(x2'bL;m:lYSgjZ$˰|RjT\G%1=Şϑ:֭Z :#q̚ 7Gey{hrǁJZY֕:R? tD++hy{Z szxx@;V e7';s>7>|2lonZ$\15I**ܑEූŽ\MIyM 5QrILpq7h ?OEF/R,3]7r{B#sswCCRIayȿ{(%я! ;#eJk|Bk-9ocX*/őo5?p)2#YWYhH56|ߑBH@R(_,ݠGqxQTU1b0z#jas-IU)M]UHҁRfΓfk%M3m4$j5MTZNyʛU)2:E^"R7( *(fc;"wÊя̻Z+=H9/2YY#lF[5?pFj)Բƛ7~3q׭WKب y4d8z?*’<ѪEXy(:TQXbn C ]0~, ~C0ö1ԦmuvNڶ.bd IDATRrI(a˴V~|!j%)$}-E0kiTmVĩdE*ym`ǎRP|I;t}gim5C;ꢮ6r솁9G_n{E )t}O7 (ݸ~$Fuۯ{yb?Deg&rʼ}zoVtۜiU- YMq% 5 ?qbr@D12 %P5`*1&,w1^i1x]-H?Cջły] /B)Ɓ=,{qM<&vg?41ero+3V~g}D[,Dw8בoZenFz@D3- aV<%7re[Sa؍\N (QL\߾V 9alUhGkD`ʊy+RQ튲%hoֈ gd{ 1; 33h$y]t'TJ)c"kEnۚn[_)JpVC_sZڤJt7ba͉"Jc tZWk|pssdY#qq~83 =iI1X1*Am:oXsÚ@2b0yйj8Ʒ^?&rgEN%i~&W?{̜gYUǛ=ԑzHiyNN Ybo#O'RaM5}' 3 "\ew{錶;ABY+|g?]!73xÃ^a2](G-iZ8s9_9u?F?%q]~i8v'Ɲc\^.@ғmgy TTv/]`7h}=שm[O+o9- 7 3.>=Ǟ'Ͽ>1@̐ %O|h+-qK5}UQMàh 41/(k@޼}Cp:)r,>r]/o_ރi+)xk%s\9nt- R*ƊΉuYNDd\(%Vwix?]I1v] ds 77^Y7, 28V*eRL\u6Ipi~z<ؒf\4vBB97r2<1NNҨVOXIʐc8Hɶ~:O< o4t]itY6{$@s Up# u`*c),s(%,u ,1\~r׏:x0Uq2ǝSFŋZeq"<Ɵ}/^I-:uf+1(T26vHPzTw֛/$(?2>Pkן^,grBQ黎:&DYWU\O\hὣ"393-c;h -c-|0g)5ozY ,8t70{.Ѱ&[12Q3 {Oj>[5xuA!Pv477wX]YRVyYAJY_~vkZ7䋨nѼ aZ㌓B”rVZf HKן:ZُÑe Ao2?r.ljwi6Cj)L/F*[}|Bte#4 *I0-d+|O ez2R1t=ᔉR |<^%o Cg3AiiyA! yjfNcuƘ8X?&}zN<;0-{;2Bse,3fN\` Zěw'356l9}X7YQT%ְ(yDVpz|֊.WjjܼxΚqYa y@F uViWaYf.=L]K9mcZRyFx6r#}WJLKLJHP95novb]8 s6"l!^hy9浪 Y'& 39vGRN' !m@xkX4kQ1Mr!兮/pwė=Xmh9Jc4rkiE,-Sd)(N7ЦXHk]HւY.9btn~nVx[ >gO :mvΔ5M2v}` pfhr zǷ_^أ3<;%#n7.u p^x!Dɉ8hԛy 3x9Jr3[EΆ$lEk qmsw[V3GsKsi x,Fŕ*F[LsWO]tEf.3p*þXs BF:RN$<=gۓҿރR8-?(-}ƭ._};ru^Q"")FJ嚈4kT1^)mªF)W+w (%}'ׅeLCH ׭mST .⌷[)xn~r%g閺uW]ie w,ݝFSJi~(uY Xn=qs™V+̋cuК,w OS6: ziLQ[r<9RJD;GFa /WaG-01aPi¨ӌqYh5#^x-8Eu#j \Yi*Lro2T ޿_c炶#nA U(#?3tV5F|?✤nsiZ4t= a/ӕyQIni%{Z9K4!w*mvgd@#+(Т4׊=bU2qYM̡~uMt@bѶL%׏{fiFz+=-nM6j:C0g߽gbG<3M3ݎ#lk|1Hƾ'Ɖ]ǒ `*]zi<>bdaqFֺ(|>cU-wm|~?)j3eWR2B@ǞC0c^~˧?s{(nGqxy"#wuA[Tt/J{JY+](5ɩ^6膑 AҭXsm8FR0P4k J5Mm܌'^E":e2K"?j<_?EA{Pʊje\*|f2Z{D|'2-4 b|)3tyҬ4HE@HXiCK+1-x?PP\1$V"LkO=3Yr⬑QZKul-RdBy||: FJq*)#WK[x'[.s!m7R|UEdm Isy ;2ƅ Rvk%.JjdAE3/ {QD+kqurWFn3w'U[m1ڰ̋DB1$ v9Q ㇀*+tz{)H:q(0MA|K]َct 5Fww Jԯzrc7(k{Kvк1vE}R|hp9`f;zA9G6nc&52Xg~EǛs~ٶzG3owa^/,o[ n *j("ώ͎;0^qjLb'+80lLkKi9ihZ+ysjm .펂gvEa(ZՏ7Jk]AILس:ÔfYZGML1bnu%5ȮA A2m/Gs&NJO EOV ;Jz~B>8r*tol fСmǙ9R(%q%pPqwGjB;~OE +>xJ<=: HStnJ$> MdZ*}1/L'7wFKJxZW^)<]'Y+ә{uh͸;BmKhM'G޽v\Mt~wWB I #QI6hyԤuRkjMe{FZ:2voU~3OαVY?3 IF3'mJ DŽnjBaݾֆ뻭{u#Sø'Z\wOY/JK^ )ªq3;qILi-\q'}uɂh0~q̓VMk!!ZcD ˎ_<ΔҼ{<q'>HmtVqh' jc Zbڨu]0ꬣn6ϋI)bGՆ%)~!!9x~Z.˖+V Hjw$1{iD79HJT4?z񲒶ޢ9(b㺲{*A+[Ө k37ANź&*H.့^drkhYLc˽^t@L'nn0Fq^GƘܠ[|_Uz6^ eE)-^yfy] ȩUK'umPUuw䋁{2q|8բiRm zߞqj hû˕TiJUVJV2Zo[RVrlNgO[0_N&Vqza(#9KFt{. Ze{\377whm$,q]I)1;jk5!i?>Lk|(<>>Ge:Q epc:O\H)84|َ_vAyf[עF^ȇZZc^h-ԄPs$Hͫ"6oRQ2 }JtJD8DM;Җu%.iNɏ,+l4JĹUPe<;Z͗Ғ`Z 4ߓbdFR B!wZ%UYCZkQۏ[*r}VD.+Տ\.Oʹ9\<,2t1-9|?^Ѿq{ lnت3-zkQX"tSJ㚀i8/Q|!Vڶq4ObcuakUt<^v7'w6VFblV]O?^qlt>-uR"U[%yr.Ͳh5-(0F4Ev :KN[bTdF͑.˄Qu+24xW˞GE8Z?PFhi%U:&y>(#Ql7tSheBB%ePR ʽʲa6e͠`Z~7J\<y Wq${mfy I!vΒ%0ù<Ȗ%NC=4N:J/W)^,rJi8YiYpf ([Qy#%gCHRۈ&x gZU8/OZof8kiJg5%JKThȁeS @ \]q\k<0։4^!0(Qy **~RY:KL=P;Gݗ'=*C8T@h3ȦaNˌ54E,˂1VR(EJ<?V(]ǸyEzrIVkb]u0ʒJeI9yͮWWh4dϿ[^==g:r!iXca/цyI5Ⱊgj.:Md9ĵ5UX5vP|Qϗ2Yw@WFRbTGu;)`γ@4X,^Tn᣶5I|FϰG`kJ{F)URӌ}E+(eg7GZWsK VJ9˿M*A?߾㉸6-JU$jSC+>~7Owp3V]4 gPkf'XhҪj(dM8FV;8Y%y1P%hP'xDUJ}g?r@i/"ƂcDm y޾zK5dawֹ-P&n V $.:J{]gYF\Q5FTT BIJ4,Bݼ<ӪfHq1 i4"\/Wv}C~O~:w{T͎nUn`pNb(%9+f3z*^|I`tߣݰ2 c',?8'f⟷0oZmywQqͷ=_,n8=JVufj9ĕZiv8EvS^+yN*)ImW7R +ԁBLJZ^V^St-C'ѩҰr}Qo0}E6;^Ry0):A!&~|R~m=Bt40li`pP^h#zZM,skZl:_Dm2ItL쉃g"ҙerfy) WvcI5w5+;6P['MJ QT*c41EáCV-Hy!*Z 4.qWNBe 8ǰ?UYS;n&!4d OhE1R'Eu"og`>0#oP7 jK^Wj.rdQXY4 j4*J^i(6uft[.[z_KA;9V(RAD\dڻy>f#&.HI"wGv{H,HjPb3woC 5+vJyfa܉B[1 R.btF|*U܍/![k}#pk43Mټ]OZWeX"_b J c.׉اE@iְnnFj/E(eܳIZ& OԒIqNl::0˝TJ*FZΣfYf(#ևɃ*{*MiZ:8} ˎ gk+8W*LaZY胒ĈQ*bdZW֔W\#<sƸpz|X1',LSdZJB߱ĕu^X63<]T|PxRk=w^ k%SJK;0 gh Β.ej+T*41Jqуw33ڋ8v?RKfWJLoZzY1Ph 1O鍽]J";6tq[$8þm-_&IqBEd|l pv@y92vS0p_VbEt˵R+.Nm0 'V^nG5 {B3@0lPb$CJ p-->̵i ޖ;.)ןV^)Ȗ"%ѩ(nRloh3p:4RЌ3F|O=qh-p=jbH1|>a$=]SfYwad>MҸg jm!㘘8]o!`4ĎyoNmxjqrֲ)7PZ5~<rO>_3ח'Q4R|!Hk{NM&uDZ%wc_wqyoԦS %lF. 4qF,+ϸ79yxfEyp5Bܰ||?݉R53ZKM4ؖFXRίadžRqqӭLm#:qbhƥI)fv-%Ji'ciRm eA'U3F o8gih8㍊pC`-Dz+|̺bw=Vq`"a񐻍s\Dw}$yZmpĺ|2m5FVkGطaRkphoӰ\ViNc?HGm޲ C.:W.iMqD9%00i3#4{$Q??Q8[Qʆyd 4RZDZ34OԚ_Ob{yy`*/@!ꮒE2hRs$8Dz r:]ǝ[y. 5oW;_̧r{aPᣈs2s ?S篌u8鏬r_ Gemz, x;i#>݈DCo$5p?"fmG֭4wTfQ7ZuVY-LX`Ue_o)=j mO]b*4խ"R1aJmh;&@BΑ F"N6@ct'YgGmHfx#,H$=Aӌ"80NwjIzW`^y{צѐI|j[XPX+nfM+#;seYƧd08J F Z35GXi]t3C<,,!WVn;H8xTM7)J߿~bPRmɹ\50}#Ն hhi Ώ`U%Wa {JcOx' <ӆmOLm%d]\+G}<??*Y n˂2J;rںta/La퍘 ijsh ρ*61*3 P)#pc`6DJ)*VJ^w6Fr0RiAw$,]gJQps:,DRL~Ki,yAQdzlawPZ71ZE Ȭ(T30xGa7J]#]ߦdTTB. ksYq.an?\?6WLcYƁb9ce4ɏLFV+e狤N1^k|1>Fգg [ϱ*)f+VwP"Io1mjľ^Q KyҖt$ZhV5֊{'I}'>3G:$A1S(xG .g dS~C~7N -*mɳ>iaw%Qf!TN`_~=||y|\+Z dPM.Oh]6FM g0=|IMAmF*6^#VkI-\H]:VӔHecT7g<7wrb݈)m@ ӆ6m'J^EmHZ-K`ՑrC krÆda߈8"9SZR61^mZa\\Z?;]ˉ?81oCՖy@v@ba 4ٰc+9CL۪<:zNt@+K6kFwV3MMVk3̓(Pӭj2;o8]$x\+?{F"%u$Vm%#UYcP; h\A3=GU-:X)KaݟvNpz%#h&ݸ)eXwξ-)GLn44ơrĊ|=!"z0z[#ͶK}7SQjMIb * +MMuvvA1ړ)ݨ߱+yNRP!A{ dqތL()Q!&dj::Ps*GL ж7ζv<$I5W̖UJI-UXr6clU֌g nҙM$HLf?||z7syڸL`Àў7Z=gZe)eq!TpJbw *bcw^CՃTw?RiÙ0zYHəRJMbH-瑔U4ݶ(PA9aK{Q8$go_|}ZYc+Z$jC!TЎV#DkU|Iq(iU^UEV>y^(vrR2&ĤP"뺡ԎgJ44G*#&4ͮ(\ADYt@l# tw8ɚ:PK|ii-C;ti`D[2J"yZ[k_{țD1n i,pe$'+GDZ$1e=$h+cCegh#vf4;xCIw/ Dޫ. UZfduWZ2ߓb( h1r:h$jq5\-ZZT0Zc]ԓKUvw'ऊVhq=5Ng+ c\$Xy6d+qVEw'ׄ A"j.Ǎ>HC>~05Ƌ7d.2| 2 "'A|˝u+0aroR߆Jugew(PGpͱ,\$2w IDAT3 z`x2F!: .5C <~_ϟ<--{(MCs~MwZF (Mp!AI:A7 "N$[8yNrruկ1: c;6z;XګE- YRdj;]1v:cfwl-2ؠ{P.@ KWu+2 Fu0t _Y1`TV'XӠp썤Vn//R%kr|X#0Sʀ847=0yfyqrOmD[QԸvtcF0h4%rAg!P4D* owo*Ǒa`L|:T"" ~`ݥzt)j&Œ4#(ѤT0@Bͥ`:÷-+1e㐓k8[2Gmzw0ୣ"Y=|͇# }_~,[fOEIs-V挸TUpdz{RJjSh-(7CrB++,0K nn;65Y-SKmE"Mrw[|cAJSr ξmB!NiIPݴHXC)&1fk1Ț Ee-g4x{py )Ɉ1"-w}"U0NUEaزb]wrdQ?|\7~lyw N3w2=HbJb=0H׷^fT%njIfQUj|y/eBL>6`MH5_7=:qG ķ@-/Z@r0]T R~" 0QUr)FR6Z0n AHˁ֗~w(hJwimɝHm$HD gjQZ D7+K^n30e0FT`sEΚ{hhrZjSZF1F>$\g?-O1 6q<hkN%JS[ő"F5Rq-6P}%T(, #{f+kP븦SÖO޽_;<==*8gh;LTHUfo-2I88xkrz]@x[NK"q}>~$DecqOqpTv8Z zOrRZ9hP@Z#B}VN+pNay= _(iqy0Lt~'UzQKsA**'4 |"\ķKhV%AUinJZ)몛Bٶ/_o|{^a#J5F-2 GBOBhuSNg|IhD̕V?G0({;ʂ-`v(7;4Tghhrip\ g]j- &1VZ@blw?JUIᜢFI@pUӅ[Q hGJS֡ly Voxk8DvyH)aTe8\ض x\H)cØY5 -^%ER,&wnk)ZErF޸ .) 0 je'RU썵 6 ߺ|y /rpk{zOi>(G }ɹp!Z+hE4qDYYRGM,-UC#kp+oiΑhs'(0#ۺb ttՙ%LCWkH5':*;J1J r-XxOu۹`d:axy?;f&#4 ע_>U]5D/E|uǸ mm)nҰ{mfu@[k2]5VnV6`Mug As=.&`4 D3j/ 0p9M֋RT2?fDI"?;Q헿 nZmX֕ཛྷZ'ZXxm"=AV#DU^=z48vP1ݯkE{bd$aӺ,`IQ&MIN*is_Ѻ$+8$.ضM64mxyyF+#x kMur!iEضav,+owoXXGJheϿTxy(%a \ ?#GO0Ih/E%j [xx8ʌ>ŝuYV9lÙR#K.8iJ8Owr8?$/o+] 0pӊ8z0[MXelh-%F7x_1z 1?\~BC鐬kћRf'4Jp'iLՄwߡ4LԖ?@Mc/sG2~~~B@BDjk1fWb|FNta$74_?a<*%%5Pq;TE:)yI%rĝA+L VYhұW+ھ7${!859i Qfx1&\e}cpr7ҊgcEebbe ]pk,)1(X݈&6@ \>Xi!`V+*1'R%IRracg}㹉U1,aK%@l0nYXW _wqg[y4 -zcq~BLBkYNceXыhEG=BW} ?Z G:N?R!g5 cߔ|\^RDY~iv[Qd'PSŹZV C80*UJŕUxy$ûW4>t@Z{bI \ CFZ hIjh.嶪>ަhrJCû@̷oqbbW m$=ᕟg>q0vHhi 鏉=7Z:16hRg4k+SP lyxpZ)V kSem쪒YCOh;$Q~LJs׼0 E?6ąm )fNR#)F hnc.wWo]g)!z_m$ՈiGC̝D;`]<\tz[ a`8NB J#LZCnϦg+e(]2FRԏZ<~tOWZ'sRʢpY8# $$Ulʲr+;ԫh %7v~ϼ<]jF(lk]! -y;Cew@yU 0IX%E791\מцGCDJBfRqZ]q Eqgn/Ѻag7քqj"WRrj983Ch6ED gc'JJ[@S&Q,%S5lB)&Zl%C0qE )j6TJs =m C+RJex)Y]m!IL(kX֥faPEUJ>a> 4eG܅ #i{Nm-=7rbD Sc4**4cAZRJj<_p^q>HT(h{l&3TwX`I:%wQǏ(J򊕒Kf%sKdT!H7k.Uh~e'DIuӌbLqlxpON9J?.s! 0*duIgH7.FƉ}0hciZbaHuWPZ%2Md҆0ޕ6VZZǽvl dӨnX̥+J21f9L!0 .scٷ~}7),%˗O 9^ԥk44 VXn #F̭3 By(˜YFT53M+pNbb(%fgդ#|)Y ¨6oxoZ*DV +бmo,3-GkfzU1ffa::R&"}N5"5dRzYh$&R{~{ ?)`=+k ­~5ٲf1c]':[آ'Xky4%4o_o=۾a$g*miG) 0d(9p^R>G"0x, !g(0N" Ci~ py|$}_/vsoH>xM4 mZc%T*%ETs8rbg N,=VIDu25Xﰶ__R\ A7ەOZTYYSP,.nӡ!ll :)T9@6q T/Ztfp@.add ɘ0JcA7BGFw/1Y y ұr"N4KûJI[)dsl+Q Mk fՋ)aŏb6@U,a@[g n"/jM^DAEgmi!>yF5PJ#r_A#sɻm4P@ɛQ MW~c<]06P!j%#|a\)FQSXzuRBJV/DAŸS) fD:@r(%8RE2FLC7"}Q2t*EbbX+0JȊ)D)aAcg]0;j퉊57~f'Z~M)aPWJg;QF|qVsXK<"OߞO3֙QQK#x׍FΙrVt"vyU V H*W-W?,1Z%|dȵ#9c먪Q޲o9 @H[*[) qRQ >7 ~b>BiJw93f5Tj(n`mOÇ.EVu!n2Z3|Pot:!p/ uwH„&k0DaXו\$It|y|y`]BЛ/t>ՈC1u|f`p~d>]˝Zw$vs3u ӈV$i9g(1Y(gY[a0<ȝ4ᇣTo\ 4{iM&v}a0_p~$i:Kg5ߡfYVҳs> ;b480V3LV,Mĉy 5 i}-5|k_Z4%f2Ǿk6#,Q9ZuNL}T52_NR9om23zsK"_)R܉)2 7k 7m䌷/}_y1W^Ԑyͥwf&tߣ K<9_.D  cC(ћX}[i-(a$RȪz"c IDAT%:rbׅaTjUBsguB ʎGZ[>|Z"iۄ>b JӀn;O|{r]9wo,k % 0D)=q^IFGtR) k4o>}ˍ֊ĥȑi>qĝ/?3RL5 ~7.IK>f((pA]8ı3.xXnWR! ۂiL`Ger_j|Jr{DYn ibe>^hRc6"[ ѐ[C5r!F(_k׼#Ox?=DZv7УEO,4/7'(wC3\ȱDq.EDQIP,&JHHlǑ H&Mk\h])(=lwRI^0 햾rsbw+ mќUr!tcV'\{ږ)JXU=-E (c])e!$eYIfat$w.WV? =vKWqLV~R}C2abRt@w$K>ۋg%GNǽ;qkJ%eza9VZ9#YיuYhl2̀X c3G͖3_= ~q sXH N]lQJ1Mu +F6 u}3FJ\\]֔)p1"x;NJ|)`hZ_geec`],eRrGRY2brfĆHyD kd<e*rhWɺFxz1I|=tIZ0+ '$F$i^Nö#-3̋V,TH*(G)\r9U9'}$#Μ"Vi ~;B[+تn7[D"m'Ͱ* Lera9,E WQ]{^T5~R(]*b 10/3]AZ!`Y׵tÜBɲۜغ,s!.Ҷ; f˶d!GH5HuX>кe Tb WWt: Pk k0DRZvƺJ>5s*+EvJB㽬fYWV5X+#L"ӵw/B$z'2RV^^Fz~hXtb|$ !8mχ浩7F)I\Jsy_b@kFD/2 !&QoIδxaKv,>p8XkO+U*@x)y6i%og-ݰ6wvrWum 7m'iI?Ezq|GM Zm1抐9ܮM"+x[6-F F7p<(L 16n!SOHd=.#ZJR*M mq-Z@9O5Q*rH1UY8TSP<ًZyr+%f+d&cH؊%5`L6Yn.N˝ºF.݉ 6䘉!ѴXK]'Pl/!+[e"'"2..Zc5u%mefmD;JV*T&mmP2 C4dwᗅBi'v;eJ[JIz\JMTtm8/unSL`Ʉ9u)Ů>p$ϪL ~4&SvMF Z|XYŠC[nJJ-EYھ% ږ g QWT>+0=1*Aqq:vUsEdyW-< Dr2Vv).^o ٣m:g l( RN2C3Z -ہ8T&B:Gu}<2d%J:]qN!DP+]Z&)aH4bkaZezU~@keZSDfwy-}?`m5}SƶՋ12mu ȴ(cdI$1:Wۜ:[yO%'ֵ,u tוVV˭P,~Ak' ESg",$1tJzipR/sC] ~^aJ6]HZޢ4eK\HmA1īz]cQz#{S!u^ t]JbS:ΆrR Cϰ}N) k]U%WCQ\\^J%NKӡM2U $0Fr慜 '$-ƂW3ɯh+y)1UgA*(m$:/]ǺFlw)-J,ٜVZ!QSR*-z [kIE][qYyᙋjZ ,T7TVw%{$4v4M䘘Ǒ2MM;ye<! 0`&4 zkd,ߤR8 |,LE ,|hq Ռ 8.j)dE.<3/+2,|iS :e]JBS9`i;Qqmsm%p-$&x9=:'J\IJN HQzk9q<{g*r-4-)DñxDb+蝈b8IPzN2+,aɥzd_ZS`]&2~{ŮB VвY%!GZ/+qD">raߣzdҊtdº(3 5xv/ˮgݠsL E~JߢaG.7Ѡ{aCMvۢ $uaiv If uXu=":kT }߂Q˪,GãݲA_MUi(2D`#D)i435iCl6e6ۍ fݡb i[G ~6ʖw>=bE"۫+kH0oaIDzM+p5׶XYec-V20/[_w b/hBbm1]Wr)\]]Ib" !GAq](buYɑ{I6r\YQƱ΋i'vvped-7tLT$&@Fv$۠ʹ<36N4&$Ę$ȶ 6 K,fO3ϰi٣J1C9DJ Vd]7ԵcjAPж-W~Hu%/͎#]7`A֙Wh4VUע5:<&}B\.uw_&~zkԼց76p{/?ÃY44dȗ_BdD PuYǑѶ|5ʰ tue6Cp Z=_8Ǥn5H.5Ӵ$mx|EEV'ac#5Xs9DbLDžxbYfyzµp=Τ!tnyW1a tw0N&>==7O\޿'WQ;0ϼ8t}nï 8Y@ v3Bھ*B8cyvj v++t>PpÔijNDbJ{9a:;M?N( _YSIAhہyRumY\5u,k?eLQELg,xx.um,YLE y7xg1vKO8~^Dʰ],x{ʹ&... 1~-<޽Xkymkwoٯ ]/21FkL 1 !c%*(cm-^I"Ql!I$dUuC)6TrPQLSդ/ 09-& MdjMck[ƩEnȾRiEԿW9F_a~qmEZkDΎu-(s 83X‡D٠ e Irw(R^hێy~;yf>biZ͎$wh4t݀:r =C6-(M!%4FQ1~ IDAT$8annnQII m$*I״t]O!0l7k q"41gFV{u!D p"xrD&}VYWϻ[ h4(\N4ޯ8@Iv{EBʤ칼z5Ru}+\/esc!u-ጣ2{|Do7)/~ܧFw$lxeaޞꛏx^}^sVyf])2.U5J*s2b^o}t^=Nߐ Ej]I)rZ\c.Ҵf/ mjKC74-ꃞk$y_1(Bj̩Hi.jsڱ,Yӊu 5l!eM#]ӵ!,uVoݰ7Qգ'/[kf'}8CvlӰxI6;nCӴhԶh*m=N6[' F[;{5m[,&Q [T$AGiZeV%*jOM)$1Դ# 9֖}Y߮kQJޗBui8~C?h^:p|Mme,:NG(GB\!ǺV̔,˿5yfe+suSjK޹^{:9or;?д#:fo\[ o=:D{n>I16%?_'?4ٯOOO|C^&%;\CЛ>RRxXB$}ht{ 1&<~R rHӉ9HJAJM7=o<,6IL\SkQb_E4Z2lSn't0U{1;+<{ ]W=}}_h "@ZH܌E!D/Vېb_U26JEW*Y Ęe#1 *V4ơ?)LDz[s!ү;# (|mm-˴p:B/IBUHbfB]/6R]$bh](bb։ 5k$fNKQF]X5<ÉM["C ߲c8>7˛q4Q} TTf]Wqw*0Ad(_Ư[? <ܫwq%]i7JyN$RȶiiFnD r5S GVJ=XM,m@v2坧J"-2TevV\H1`i,{+F[Gnh^Z (a';Z뚪bFeOi'1bPJNYnv$5X*W9 rT*s_񈱆\Y*Tz7չf^`ۋ i⸿$ D; jl:@C4P'JIp[ӵU!+NeYivNzjk!V0 r:77OK u(j):U8P2߉'6<ߡD*}G/{o`х~ooGQje+7%PRծh\.Ư~?o/³v^wRlKI-lw3FlSJ{%&J,=-x )keo6۬mZ9ݖVrNۡf-%+c$\?yVl?3k؈~࿸??7>Zgvy}Yk5"#%jδ܈193'kI}m4iޔ2'FO+>xA:&)9PX->eϐѼI"Jj55ԺL Ls*N'yf3ll/X U-rKoA6m}gWt{t>Zy9Dz.wu= PHf6 MΫjڅ&W\!這~[3F2ִ5YkH!C*klje)@*\۲Tze׉`#Y2#4D/є<Mik'q 4M,wO=̬^CEbfuM} q?OoWuV??Swط캬a|IJZWjVwh9; [8!rVNQv*wCqO3Fzp:S Na]㗙td&PD bXɛJ)'ƾThai_w}X0 =1\+TsN 94OEºnk9Q %4Z#LQ_l W:,O{iug#W(q_璒`Ne(Z*ez7 2FUG!cTC j:*]^ږ~;.TJA51n`|/oķ|-)Gr*<|r+o]ů>ᵇ7<9q?ɐ8*QճMj<_~ ?s?~ۏᣛeH]O!++o"g֊qogq=pqe g=2ͦ&PU@ۆasIuա4}B۵$y_^uhA$5׸VL6VR gQuQ_J ֶNŪmu]mlqگƺjZ׏1@H܋'j-H=mcd6𢛆{gZq) srVt %TWE}v_-Ic4@o41J42\]^R  ޡ^`kw5عb㺊2.@L`TƚAjHvؠ]#ۋ50l8Rx8h@ (p)H{RG|w9N+m5Pߕ?Mq34SˡPUߤb+ 잗)ynh:?+aq"wH)1=),e=Vk u" 9[o\*5RNL7 LǣLוL#MP*GZ_3˲ ֡i¹V(uG&*A䢤^n/w⻵VD3#Z`1)hc]|]55Zit:E|eX+J~`wuJ5BRFdx:Tnįs-l!tDP-p<0Na)[yMk4  (X7{i?_'>y|?=e>9i杇OW_}O<9rD#լ <;m nzM/G_{o_\ d_7_yO?9} /^uQcPr2%gɘaćHZB,‚9g:w=4h%d}O״?0D,+%v|'Y% q) 1YI11M㝳Zyͬaforʭk#:m!o|O[2ۑYvzO;lHE;_z1o>s{kB݊H.D#[( W~_2g_?㏼ӟۏ? "!UW*K{OG7Gly3{>AeaA4/77hmxs /k1!+\^-J(N9q [auǰ2l/$<aY&9!xo_Kk_359O~'9+kxUcPaՅS"Tw,qLjk".RZ+["i1FJe%b,,*)\!cԙlS(QR~ ehm:(b IyԚ\39TQV-V[c fTА]nTZ"evULs/2 S(1wT`%McX慶mE41 D|YrdҼnG)ż?;34KdBtUZUPێ 0ZƩnK"غY#~5kL|; Z^|Ⳛ^WN+o>f煘TmβQ{u%Q5&}g_˳5=/k?]|ӛνuGjYMs,8/O3LmۖT7hSg[*xTXc4PAQeA35ZJV\pM 7C]8{ZnBZVEƊص캗hl7;g!"0j8+S QZsʵjKE;Ykpcg8B3ZNTvgya) yey!zIr:uPqXi%nw]"clݢJ8,Ooy~ _e/;^|}ox-_oW;7<>v8̈́+Z!$"+N^ į|Kk}+zwo8;F~r' ĵMVyr{0sm׉ GQդl9OBpzK+(I7m5I&iM9 Ɖ*G@ +*Uk-a#]'m5R95@dmP&RkbZʯ) <2ICS,RD=OR2AJff])>/ FZ^wʴiR] &L)U q{)MUp9s%4i:=Hi\!k?NsՑ U<(ѭ緿2>!Gc5ya{/54Fnq <9۟{/.x952-т `#ߵ> [2Rg_3U_A>oo/<{iZ`ɕ;g r[\(I_y`ƚnV8) J oV:Q1cqۛkU\5;YVO"QŴL!9ݡd 2ZkƒBBaQd0tb49\l44]BG 1@bcLCL8'v\ ZVbF`XAiA‘!HBlV^-C#T1 \#H#쬇s&R>&PNFDu45L].st;m(m_ Ka 1%%G4`qbx[K}lonB qa}v^n Bst3m10X]K1.cE1ke558ST0PھM_co/wve!ꎻ7-/B?I4k5ވtGudv+Y@cnj>#K4AC$Y8 #V&`BZ-)IEWP>gM"u(xkaL,QV%8p{S0 MZ͛f a4FXFH2Z={sHE$H $I(lhN C5nB~^*E0X8I!#EFs)ib{; K؆ ^K)_u\;4Kp%}rI{8y$ű( ưą ַKoO5`$$J9C"fukb׿]+kWWso297Ԭba>8gP@0n'|^;BsmX>7F8X@JJhY6Fh(d"Ie|b!1#G#;p!p!0OIv )`ֺԔ< Lh꒜Z"څGftwl, Cdeu.DpBfhjQEd s8g]AB*][Hsu,Mrm ) ` T$v2i^rEQJɗ(Cq?E>c pųsnʱ>y~iWǸh[c2 bec3/c0*Pit#3?5]gUE Dty_o}W#f!'_|ήlRk6Ez `];$8~Ë;)~Iq!RyOQB4Z\^x8F>џ(c {gkC"/-C($52LcUI%1 )1Yd-&6%j(B6!y^"NxʒiR.XȎn)éԈ ICe4h 5v;!4$&DQ!b5l$A(yV("wt&p,k!Z3`w5g E1LXim3$Iw|^䕃c In0utP/ >ؒ8$i M$?uKk:׽탟7jWW}O"c!8$'3lb e*Fun5@;OC|o0%ʼiUuU@QB߱PQLXvh ӂaqFG{R!i@[#\tl)8^A ,(KIE!\*r=:PHD01 uM4} MRGYLaDs4cS c@SW'cKʢ`\7Ni&<ԀKjBs(NudVun4#˅)>m\Lid뻈O8/EN]}B% V#oM0T ʚ춦!W]fʙ{ρFMco7? ?߅Ugٻ}[I^Rh;evg@/[V0Ũh0T:-,)9Aw qnww@ZWa0؆2 .(f]qJTQxd OF!phAct,*y5OkRՑk4*+DDO+ Ӕ-"( YƐ^,Kd4 d|2AYIo"Q( YpBݥd4c[-q%8ƹu*$' WSSc<XL≙>8:ă79bרj]9R±`:3߼8׶e9YƖBD$Em0V-6R挚*Ia&9` WEu `ùf@Q,6d#"da4$MtMcB8n,dpFCEgKM;0TU8Vsc: *1ކF峩J6B"%aʂ^vQ 'iڂw _>[? praZ e]#/k4ά 5ŤlP7gd(q7\ 1V2ĩJ ΀^7+|݉_uoL=v䯬 Yc I.Y5%vJ gv4ƾ~} K]Zbi.ڝ>(S*NPS7 j.);10`zq䁆@uq 5;c4anhl#u`<ὅTuUA0NF# M"pd)EZQVlpG /,֤R1Fki._NYEvt ?C(BQ\Y u䲍Uy,v^|mOޝ# םh>:km1MK40 + @<tCv("CJQzR^u;ŷ}h?&Bn/~~ry3VlcA8vu)czT`}P`XV` B`<<'}{E>PUS5 iX63dI EN)*NCŸJ"HLH"td=hCwv!9T*u3"dJ;(RDIvF`Y:Yp`Qȁ-$N]/wclrUɔhbB ܔ`#Mo뵟/uGK{c,!ԐG{J氎b3j 888CʣKXD84^]ӛ#4N[ZB^.@T`u9(POr8xE>AY_\@Qh4͊%(I"(N*-0 AŘY&(?[ u*A(0 ȩ՛ށ{`u( ,ȋV $bvt 4֐CBNK9NL I!C066$E ICNq:#^ }.>_zL.Y˟37} Lbiw,A;riH lmslm(4,Eƨ ~ףe.Y{sM}i)d NgI8t}4"TU|:A%p1ntNv0-RYLq=BsʨbQSp #A"k!#r| (!PW5Ag,J>z}[Y')py[߃P&D`s h0PcR7xίlak0Al &̎gHt8~p?t|9Z];O[۟b0ёڑG񀯡u$3֢ ?W JmB=lsOdQ %s)(F"m o jMg^WSDpFl8I!U1]@&D+ʑF4˂ҁ3T+ʎBWx:, Q\6U ?#X0&R 8$6~φj`eɌ1#vFe0&O}ŋ?yGB_>Io&7u dY0>q(kQPJʐĊpXM(` 2XGDFPBS0[)OѸJllAyIS.spFHFBQ87)QbJ@@nFp ^GDXT@%ݠn^;Y8k{ʲ r09ßJo}B1vnl0(30!=qneϯびXY6%7xpbKS2e֞pJi'_7^sYn>{ߨz\,d;Os?(ROM ]5vƚpf` y(5)ֶ& $d$dRQHc5R yNJ3I9QL0ts $M\5hu{jsBP|0MC\9J 1Cx@)ZYC a NiBD2 EscwqmZS& OJyn]k7Ӽz6V͜OOb{`ԆY'C<@H:ɐ,uk/BmwyzLw?Kk[u !$lpXٌH)tFpj.XJ,-v<8:~'EѱK'DpaL͛Gt!#g xXuڰ8p&IMkXۄEOF%ܱyG1/e>FہImO&*Bj V tYB/6dD1ԔR*[_ŵ+tbJB/i)XQg\p;?{<*eg-䯨z7瓅h Ia.` w5T x. ,b6;+/#2(P%V!%*)tMjFBXsJt5!҈Fo5L kg PD0:@By2s(r2JcRR]AJrNtvdkjslN< /EtCVs1N:6u`RAb}c\…!yE`5EzQCF @0$8#pҋ_{;O#wwVo|ϟ~ M/Vo)F pA iTu8<P$٧ ֚vY8%NQTv_yF/bP濾()828`~? p|9u^B0t1ZTm㻵YB[I^V[4Vc{T.5*!85e*hʔ;QwW][Y;WO]MKڣq!HHBt<8n1vn80+  VrY&JAEԽRLwԝmڔ.)\un((I DJ>X}<8i c .^ƹmlMjo5ׇX]as8E^70΁ϰS3FGӪoحˋzG憯W'ݼ4.9θ,߹1 т09C8r`K ];k-"K] 0GC.Px(P@]VPRIb xh5(A> $)!BOIDATw8'Ils|sqB $>Y; 3v%v{'ЍK.]ƽ.`mka4ჇXkn!gF8Oу/>dg-g_ݧϭDXR3i,9%x#x<\KKdI 8Ź6?CK-\{q#215XPc-d2w35@$PXxOJ!Bap)"(t{@Z)߿};PPq-X^2qX9uO*: Ntp#)%5R<GS"p_ AZ{ X?ة +}9'gUU 4>rXٳ )R'.ኣo\JDQJN  p,.-( ZH6< \@ ~ӂ46kk[ sas6!XRpJJH!$֑|)i!:Ё`4fAd'Pxm5ƴ8u2_hZA7uc nQ>[ʡ[6-w}dD":mUF[ VXcem";8M4Z"8wACM 6)o?ҫ򞏼u?k-]Sz|PqP!̝1mhl Ȱk[ $G\^Vay}s-]PceuA1*M걙QJS6CN8R iB8C$j;Zy{] 絷!\X~; G=L^*EIAI4HI;N` kx&F is ; 8gpO{/OӼGK-GXW8[.]>A!Fq+$΃Ԧ5lRфem,lAݝi&3i)>A['!j-P(G 3k~s ,[%,-:t} }-+*&¿ gPG݅ج8"eŲ]A b ;l õWϙ2_E,(ۈ#Zsێ<5)"E6N#ӽEkۃO0}*rUt.iei #]r >cU{t7+ԙg߃xuWB_-%=^ t0uvW9 %/VBW'_tMۓP\>@y0`D i|[` hh)Tj0B#ЪhU# ~yhu fp#1I/I"0! 'Sdd:J5ǖ"sdy#R7wAgdJ7kʕn^:}nWFVst$gj-tԝr_װ_7Z ~V54V }o[G=Nd>-UlaY5V}xg[?k&>srq߀].r_r_qsGjy4k iQܟBZ-<(d=dKO a/zv7]ǰod}sn?TF'|3Nn#I?"mzv~K=گsl<b|_|4>?pߋQrib 2* (Ѧh{28oIyes8';Z9h6g>xRx'b8ՃWOϫ[xn%|^z}%x c8eXIfMM*iP8IDATx .떣 &w*Jt R$UnQI)B-ױ=f{.gy<|3̎|?7"1) @@"ʇl@@0|@@ u@@@  8*@(7! @@pTQn2C@ 3  d  @g@@QPG @@  r  (@@G@&3@@P>   :Mf  |@@ u@@@  8*@(7! @@pTQn2C@ 3  d  @g@@QPG @@  r  (@@G@&3@@P>   :Mf  |@@ u@@@  8*@(7! @@pTQn2C@ 3  d  @g@@QPG @@  r  (@@G@&3@@P>   :Mf  |@@ u@@@  8*@(7! @@pTQn2C@ 3  d  @g@@QPG @@  r  (@@G@&3@@P>   :Mf  |@@ u@@@  8*@(7! @@pTQn2C@ 3  d  @g@@QPG @@ dгgҚ  䴠^uVyw?ǏQQQR@k׮RlYe#  @"R𲿰L"=.\X+&\rɩSr9|;Vuvad. x7o,GL^n@@ ֕*UJʔ)tժUҢE ܹcѣ9d޽ұcGٿ_ejug@o&~++WB h_ѵk|ӦM~zy饗Yf~57s&a; xy*/*xw&CҺuk1bkCu6Ľ+ח?P-Z$]z9o޼fYۆ df`2P:랄 dU`ڵ]vLOϞ=eܸq&. @A.R6l3gΘ1:7}n3t@=y=%JB'9ZΥtg5]r4ok؁ 9~߾}v˗T9`V?~}V*! @W.\sns/ߗ}uѯjNM뤣[jYfU_  \K^QFk;v̜8pmL,8uhBBY\^gkұNL;ʓ  @F ?{lYdYRR/'^vmTRFo }DA*UD뽯Xg!AB@$iҤhY @UbŊҲeK4i+VQ02C@OTܰaC@y7  kƍH  v ]Ei@@@oB* %@jW{QZ@@zkǀZ/O@@ɓ'E vZ3jժf|y}= }mF@Y={_|E3gѣM{wU3@ 2DN8! ,H^ҥKy9rpq (ZV8%^ غu,[̜Ly"Eȸq; ޘ@@ $&&ʵ^ʕ=t`}mF@I%Kz[.]bcc%>>^bbbc}%F@ $.RY}:C@ ƌcNt1%JzK7p͚5r7'n.]dvv= ٳgO`TǿxOž馛tҢ޽y7N>#i4cǎ1y1 h޽{N:SxqVtF9rHdd >=ΝDT2(I&RbE4/kcLI 8!'?tÁe}H"7 X6mT&Mdzjŋ5]+WZjO?TbcceС~5׈2J:Δ SzAfZ׮]%o޼Yf2<@5zHyy7/^zI-[&mڴZt|i޼{ƀBc"d$O-Z0ʖ-kNL2E{9PBFog.U!CH۶mMYF 3ޥGf+QLj0g7kZ  E… 9 #G4+ɐ0al2Ge_T٪WnnB] mر# ݨQ̙3rq}d+~[4" @tt4gL¥.m h,B@\*@҆X  @ jR/@@.m 0jP/@O9r䈙%^re@ [@!S`˖-3ψ^Y)ҵ2ԩc,]t0F B.}$11Q"""f͚2ztcC̎#~V@w (QB>Cپ}޽[ʖ-+_| Ii@@@ @Eo$pc@. @YАmZ* SԝB@@t hllݻW8 O6)":лTR! C@@#3Յ{nj#'O;w˽bŊfMGyD/n?@@&53ݺuQx [p’#G9wW_ *lCp~:tHre]V<a 5+G/7M7䕡VZҺukWL8Q uب_s5yW]l2W8|РA?sL@VoV&M$7n4W jٲ[-jk(7X(uҖ-[$gΜ>OO=/rѮٳ)N2]=z}۔)Sd˵}2lذ @[^uyv2uT2d S TqIŔQA*:>J*,[}'h"0a\uUfx8Pm&+W4W>|ҥK54@'!_2~xy7ЪkV5k&Z5vX[B9@ FQM6u.={ҥKKttne˖k& ~1 8u<]weԀSCJdiwߕ?Ⱥu|Iꗹ&0 pUn-UQڣLHH0ߧ^@ ^ܹs_|QKs&1mŊ3 /`/ǏK{cO['L%K1ާh$@:ydј]yP7$C DZ7]Sg,xj'N(_%KK/qN:IO/,ZwyGF%7ٳe֭2r.O>>ߧg=uVƍ} .2ٰa߿?݄  yuS) Sg 4t5טzJz3xL23Ϙa:.Tϟo-Z\PuyRf3z/@rr^rٳg壏>2{N@ 2 @hsw7,__:qJLJM]:Jπ@%~'!% 2kĂe-AjҤ-U ^УGnl)q8Ld*[YNׯӤc=:!ANy!-:>3+] ^"7rbI9@? DԀN'dtOJ]#eO `~uưbjWL^DgD_b||TZ54u  @ x @K]'lڴɌ$@@C땐<Sc;=ys  ^πzW)  -aWu s  a)aU39f9/` `.ОU" ~RzusmxooӦu̙m7@k3dɒ% 7jHYӄ,44hPs綤.e֭YK.2&M3gຈ; @ {2 @ sҳ$@fr0`?ɓ'}'<9Լ#F+Vȶm=EN4욜 #@Z{JTTTX1.)_ $@ G )SFOW =;+n@.Le˖E+R%]wtK؎ZRJRfM8pL>ݬ޳g<ҤIP@@]t\RVZeRjUZxɗ/}lDlѣG˽+͚5Zjn_~E.r2d ՠ 5^jժ/m۶KK8S$@fŋg}&}h/zFcǎf|u Z"EH͘(OW Oy@ȕ+s=斝X |MESg  \@N. @@`8  Y /B@.8  Y /B@. '!eW&NԩSgr2_B ֭['?uѯZ[$o޼Pu !wTп۳C!^rwСҲeK/eӦMK@ ͛%66k%###e?ʒ%K̕LJ,)+Wz6"@fΜi>m4$::Z8 <\AHq'! з~[^}L֠AnݺԩS3}}$&&2JzF@?^~isLLR~}YvԮ]۳{@2.}g͘3 D֭+RJə3gDI?ey~3g@ϟ!~tTTPǎ4Hf6"`~O8!UTIWr BA{&@@uheذaҮ];0`2j(iҤbM ZBU|m&UV5WGDDeРAv ȓ'ѥ]iӧbŊs@| XzjRzu;w7-Z#FCˬs _zF'q9sn{:(P Spq꫓@ @b哧zJ5k&C 1E1g@3 pС/:[o5w/w}':>T@Ȫ@H,TF 5keVqxOp矛._}L4I>ln&@K3)k;wn3&wrɔx A4@W dPNR @@!NZJ  Mԛ @@&@0Z  Mԛ @@&@0Z  M f{$pB@/ND1JY\r#Epn @v f& [?S{9Yz*=*5ÇsTPq@_ta;Y;CbbbdѢExbСCr=ȱcDzx$^ @xG;S |RD y7L+W'ʮ]/ `@@k3J"D?tUSH"R~}7o^B:@ݺuMڽ{wٰaW^yY|/@BN4**J}ye5SȬYd׮]'Oy찀O0A ,([[oUZha&!}RZ5KDv  lPB< \dvm{L ',)RJu@׭[')SLJʗ/ JG@@i+PR\<bŊΆx\=+ n Mx@@@ߌw  !@oE@87  ~[@@_<ח/F@X K .Fll\?h.Kټys]8  ΀V^-M6m۶I^{wґ=  o#>}\~2m4ڵܹs@2l09{l @@@Jk֬}СCM׻(zÇvk< @% %w^/Z\9IHHGd dhf˗'NȺuҽ租~|I%c  `h[+իˀdϞ=%3/  @( S[122R^u۷ԫWOn&9sٶm[4hPKG  @`@p0O*Z̜9S͛' ,\rn簼@P@tq|…89r䐊+o3CHZ)x3/;㿊}Gk%P='orrܹٸ96Ib[n^r1++Dǵ^tEYy qDo*Ura(RV?7Jҥ`Yy qC+…HYЀS+W,JʖTOR&"A˝J@ޯ]c^Iv 萑{ Z:uꘋ]4k K̙#Ge˖YZz2Ү]a|X5wp+j4~z&߭Ǜ6oqoB>p!{>@ аhf* G=mAI@@ f  {@@ аhfTi JB;҆hKA;+kV%ЫvoC n;o6҇" ٵٯ*_~XSn Z`Ϟ=+5kLgBVK.Dn$;+۶mZjYJm]z\|Rdɰ! 榲  @ ~P@@ @ê,  |%@@J4"  ~P@@ @ê,  |%@@J4"  ~P@@ @ê,  |Aؔ ..N>,'N:rE-Ϟ=U ٺ9sF9"ǎ :zL=zTΝ; i]C=N:%cǎjժI"E+^xٖ rT`޼yR\9͗Xt4o-j[_XfmV/.J[6nXdSO=%OsHVL੫61:3&SZ=!t!tjovL ]#Rhl@E,yK]ǥCZK@>pi?2%%ݷ;w[ŮxOwk ?tR@L?iP&Hp  a&@@G{@@G@a&@@G{@@G@a&@@G{@@G@a&@@G{@@G@a&@@G{@@G@a&@@G{@@G@a&@@G{@@G@a&@@G{@@G@a&@@G{@@G@a&@@G{@@G@a&@@G{@@G@a&@@G{@@G@a&GٳgϫGcǎ|۽{}Ȟ={̮̘1C)[}޽={4xݺu۷˦M}:]9zyiSENJqjΎZE@ @îɩ08!)uoF ^=e赫]ߛ6Nƨ8Zf] &k;镶Ո".8s$ Description: Anti-Grain Geometry (AGG) is a high-quality and high-performance 2D drawing library. The 'ragg' package provides a set of graphic devices based on AGG to use as alternative to the raster devices provided through the 'grDevices' package. License: MIT + file LICENSE URL: https://ragg.r-lib.org, https://github.com/r-lib/ragg BugReports: https://github.com/r-lib/ragg/issues Encoding: UTF-8 RoxygenNote: 7.1.1 SystemRequirements: C++11, freetype2, libpng, libtiff, libjpeg Suggests: covr, testthat, grid, graphics Imports: systemfonts (>= 1.0.3), textshaping (>= 0.3.0) LinkingTo: systemfonts, textshaping NeedsCompilation: yes Packaged: 2021-12-06 14:54:42 UTC; thomas Author: Thomas Lin Pedersen [cre, aut] (), Maxim Shemanarev [aut, cph] (Author of AGG), Tony Juricic [ctb, cph] (Contributor to AGG), Milan Marusinec [ctb, cph] (Contributor to AGG), Spencer Garrett [ctb] (Contributor to AGG), RStudio [cph] Repository: CRAN Date/Publication: 2021-12-06 15:20:02 UTC ragg/tests/0000755000176200001440000000000014147724123012341 5ustar liggesusersragg/tests/testthat/0000755000176200001440000000000014153425042014174 5ustar liggesusersragg/tests/testthat/test-tiff.R0000644000176200001440000000061613654050521016230 0ustar liggesuserstest_that("agg_tiff 8bit generates file", { file <- tempfile(fileext = '.tiff') agg_tiff(file) plot(1:10, 1:10) dev.off() expect_gt(file.info(file)$size, 0) unlink(file) }) test_that("agg_tiff 16bit generates file", { file <- tempfile(fileext = '.tiff') agg_tiff(file, bitsize = 16) plot(1:10, 1:10) dev.off() expect_gt(file.info(file)$size, 0) unlink(file) }) ragg/tests/testthat/test-polyline.R0000644000176200001440000000232413652523720017135 0ustar liggesusersrender_polyline <- function(colour, linewidth, linetype, lineend, linejoin) { dev <- agg_capture() grid::grid.lines(x = c(0.1, 0.4, 0.8, 0.5, 0.9), y = c(0.9, 0.7, 0.1, 0.3, 0.8), gp = grid::gpar(col = colour, lwd = linewidth, lty = linetype, linewidth = linewidth, lineend = lineend)) out <- dev() dev.off() out } test_that("polyline stroke works", { polyline <- table(render_polyline('black', 14, 'solid', 'round', 'round')) expect_equal(polyline[['white']], 218850) expect_equal(polyline[['black']], 9298) polyline <- table(render_polyline('black', 14, 'dotdash', 'round', 'round')) expect_equal(polyline[['black']], 5497) polyline <- table(render_polyline('black', 14, 'solid', 'butt', 'round')) expect_equal(polyline[['black']], 9219) polyline <- table(render_polyline('black', 14, 'solid', 'round', 'bevel')) expect_equal(polyline[['black']], 9298) polyline <- table(render_polyline('blue', 14, 'solid', 'round', 'round')) expect_equal(polyline[['blue']], 9298) polyline <- table(render_polyline('#DE2D7633', 14, 'solid', 'round', 'round')) expect_equal(polyline[['#F8D5E4']], 9298) }) ragg/tests/testthat/test-png.R0000644000176200001440000000061013654050530016056 0ustar liggesuserstest_that("agg_png 8bit generates file", { file <- tempfile(fileext = '.png') agg_png(file) plot(1:10, 1:10) dev.off() expect_gt(file.info(file)$size, 0) unlink(file) }) test_that("agg_png 16bit generates file", { file <- tempfile(fileext = '.png') agg_png(file, bitsize = 16) plot(1:10, 1:10) dev.off() expect_gt(file.info(file)$size, 0) unlink(file) }) ragg/tests/testthat/test-ppm.R0000644000176200001440000000026713654064656016114 0ustar liggesuserstest_that("agg_ppm generates file", { file <- tempfile(fileext = '.ppm') agg_ppm(file) plot(1:10, 1:10) dev.off() expect_gt(file.info(file)$size, 0) unlink(file) }) ragg/tests/testthat/test-circle.R0000644000176200001440000000214313652236462016546 0ustar liggesusersrender_circle <- function(fill, colour, linewidth, linetype) { dev <- agg_capture() grid::grid.circle(r = 0.4, gp = grid::gpar(fill = fill, col = colour, lwd = linewidth, lty = linetype)) out <- dev() dev.off() out } test_that("circle stroke works", { circ <- table(render_circle(NA, 'black', 2, 'solid')) expect_equal(circ[['white']], 227079) expect_equal(circ[['black']], 402) circ <- table(render_circle(NA, 'black', 2, 'dotdash')) expect_equal(circ[['black']], 186) circ <- table(render_circle(NA, 'blue', 2, 'solid')) expect_equal(circ[['blue']], 402) circ <- table(render_circle(NA, '#DE2D7633', 2, 'solid')) expect_equal(circ[['#F8D5E4']], 472) }) test_that("circle fill works", { circ <- table(render_circle('black', NA, 2, 'solid')) expect_equal(circ[['white']], 113941) expect_equal(circ[['black']], 115014) circ <- table(render_circle('blue', NA, 2, 'solid')) expect_equal(circ[['blue']], 115014) circ <- table(render_circle('#DE2D7633', NA, 2, 'solid')) expect_equal(circ[['#F8D5E4']], 115044) }) ragg/tests/testthat/test-path.R0000644000176200001440000000262113652525300016232 0ustar liggesusersrender_path <- function(fill, colour, linewidth, linetype, linejoin) { dev <- agg_capture() grid::grid.path( x = c(0.5, 0.9, 0.5, 0.1, 0.4, 0.4, 0.6, 0.6), y = c(0.9, 0.5, 0.1, 0.5, 0.4, 0.6, 0.6, 0.4), id.lengths = c(4, 4), gp = grid::gpar(fill = fill, col = colour, lwd = linewidth, lty = linetype, linejoin = linejoin), rule = 'evenodd' ) out <- dev() dev.off() out } test_that("path stroke works", { path <- table(render_path(NA, 'black', 14, 'solid', 'round')) expect_equal(path[['white']], 212800) expect_equal(path[['black']], 13776) path <- table(render_path(NA, 'black', 14, 'dotdash', 'round')) expect_equal(path[['black']], 7896) path <- table(render_path(NA, 'black', 14, 'solid', 'mitre')) expect_equal(path[['black']], 13824) path <- table(render_path(NA, 'blue', 14, 'solid', 'round')) expect_equal(path[['blue']], 13776) path <- table(render_path(NA, '#DE2D7633', 14, 'solid', 'round')) expect_equal(path[['#F8D5E4']], 13776) }) test_that("path fill works", { path <- table(render_path('black', NA, 4, 'solid', 'round')) expect_equal(path[['white']], 165504) expect_equal(path[['black']], 64128) path <- table(render_path('blue', NA, 4, 'solid', 'round')) expect_equal(path[['blue']], 64128) path <- table(render_path('#DE2D7633', NA, 4, 'solid', 'round')) expect_equal(path[['#F8D5E4']], 64128) }) ragg/tests/testthat/test-line.R0000644000176200001440000000134514127510442016226 0ustar liggesusersrender_line <- function(colour, linewidth, linetype) { dev <- agg_capture() grid::grid.segments(x0 = 0.1, y0 = 0.1, x1 = 0.9, y1 = 0.9, gp = grid::gpar(col = colour, lwd = linewidth, lty = linetype)) out <- dev() dev.off() out } test_that("line stroke works", { line <- table(render_line('black', 14, 'solid')) expect_equal(line[['white']], 223760) expect_equal(line[['black']], 5060) line <- table(render_line('black', 14, 'dotdash')) expect_equal(line[['black']], 3062) line <- table(render_line('blue', 14, 'solid')) expect_equal(line[['blue']], 5060) line <- table(render_line('#DE2D7633', 14, 'solid')) expect_equal(line[['#F8D5E4']], 5060) }) ragg/tests/testthat/test-text.R0000644000176200001440000000062313777316074016300 0ustar liggesusersrender_text <- function() { dev <- agg_capture() grid::grid.text(label = 'this is a test') out <- dev() dev.off() out } # We cannot test exact across systems because fonts may differ. We simply test # if something is drawn test_that("text works", { skip_on_cran() # Solaris don't have any text support on CRAN text <- table(render_text()) expect_gt(length(text), 1) # Not only white }) ragg/tests/testthat/test-polygon.R0000644000176200001440000000307713674577325017015 0ustar liggesusersrender_polygon <- function(fill, colour, linewidth, linetype, linejoin) { dev <- agg_capture() grid::grid.polygon( x = c(0.5, 0.9, 0.5, 0.1), y = c(0.9, 0.5, 0.1, 0.5), gp = grid::gpar(fill = fill, col = colour, lwd = linewidth, lty = linetype, linejoin = linejoin) ) out <- dev() dev.off() out } is_4plus <- packageVersion('base') >= "4.1.0" test_that("polygon stroke works", { skip_on_cran() polygon <- table(render_polygon(NA, 'black', 14, 'solid', 'round')) expect_equal(polygon[['white']], 217376) expect_equal(polygon[['black']], if (is_4plus) 9968 else 9976) polygon <- table(render_polygon(NA, 'black', 14, 'dotdash', 'round')) expect_equal(polygon[['black']], 5762) polygon <- table(render_polygon(NA, 'black', 14, 'solid', 'mitre')) expect_equal(polygon[['black']], if (is_4plus) 9984 else 9988) polygon <- table(render_polygon(NA, 'blue', 14, 'solid', 'round')) expect_equal(polygon[['blue']], if (is_4plus) 9968 else 9976) polygon <- table(render_polygon(NA, '#DE2D7633', 14, 'solid', 'round')) expect_equal(polygon[['#F8D5E4']], if (is_4plus) 9968 else 9976) }) test_that("polygon fill works", { skip_on_cran() polygon <- table(render_polygon('black', NA, 4, 'solid', 'round')) expect_equal(polygon[['white']], 156288) expect_equal(polygon[['black']], 73344) polygon <- table(render_polygon('blue', NA, 4, 'solid', 'round')) expect_equal(polygon[['blue']], 73344) polygon <- table(render_polygon('#DE2D7633', NA, 4, 'solid', 'round')) expect_equal(polygon[['#F8D5E4']], 73344) }) ragg/tests/testthat/test-jpeg.R0000644000176200001440000000027213654064644016236 0ustar liggesuserstest_that("agg_jpeg generates file", { file <- tempfile(fileext = '.jpeg') agg_jpeg(file) plot(1:10, 1:10) dev.off() expect_gt(file.info(file)$size, 0) unlink(file) }) ragg/tests/testthat/test-rect.R0000644000176200001440000000214413652523375016245 0ustar liggesusersrender_rect <- function(fill, colour, linewidth, linetype) { dev <- agg_capture() grid::grid.rect(width = 0.8, height = 0.8, gp = grid::gpar(fill = fill, col = colour, lwd = linewidth, lty = linetype)) out <- dev() dev.off() out } test_that("rect stroke works", { rect <- table(render_rect(NA, 'black', 4, 'solid')) expect_equal(rect[['white']], 224256) expect_equal(rect[['black']], 3072) rect <- table(render_rect(NA, 'black', 4, 'dotdash')) expect_equal(rect[['black']], 1771) rect <- table(render_rect(NA, 'blue', 4, 'solid')) expect_equal(rect[['blue']], 3072) rect <- table(render_rect(NA, '#DE2D7633', 4, 'solid')) expect_equal(rect[['#F8D5E4']], 3072) }) test_that("rect fill works", { rect <- table(render_rect('black', NA, 4, 'solid')) expect_equal(rect[['white']], 82944) expect_equal(rect[['black']], 147456) rect <- table(render_rect('blue', NA, 4, 'solid')) expect_equal(rect[['blue']], 147456) rect <- table(render_rect('#DE2D7633', NA, 4, 'solid')) expect_equal(rect[['#F8D5E4']], 147456) }) ragg/tests/testthat/test-raster.R0000644000176200001440000000155613652526635016620 0ustar liggesusersrender_raster <- function(raster, interpolate, angle) { dev <- agg_capture() plot.new() graphics::rasterImage(raster, 0.25, 0.25, 0.75, 0.75, angle = angle, interpolate = interpolate) out <- dev() dev.off() out } test_that("raster works", { image <- matrix(grDevices::hcl(0, 80, seq(50, 80, 10)), nrow = 4, ncol = 5) raster <- table(render_raster(image, FALSE, 0)) expect_equal(raster[['#E16A86']], 7380) expect_equal(raster[['#FFA2BC']], 7200) raster <- table(render_raster(image, TRUE, 0)) expect_equal(raster[['#E16A86']], 180) expect_equal(raster[['#FFA2BC']], 3780) raster <- table(render_raster(image, FALSE, 30)) expect_equal(raster[['#E16A86']], 7227) expect_equal(raster[['#FFA2BC']], 7127) raster <- table(render_raster(image, TRUE, 30)) expect_equal(raster[['#E16A86']], 255) expect_equal(raster[['#FFA2BC']], 3628) }) ragg/tests/testthat.R0000644000176200001440000000006413652230356014324 0ustar liggesuserslibrary(testthat) library(ragg) test_check("ragg") ragg/src/0000755000176200001440000000000014153422061011757 5ustar liggesusersragg/src/rendering.h0000644000176200001440000000520514123065342014111 0ustar liggesusers#pragma once #include "ragg.h" #include "agg_pixfmt_gray.h" #include "agg_scanline_p.h" #include "agg_scanline_u.h" #include "agg_scanline_boolean_algebra.h" #include "util/agg_color_conv.h" #include "agg_image_accessors.h" #include "agg_span_image_filter_rgba.h" #include "agg_span_allocator.h" template void render(Raster &ras, RasterClip &ras_clip, Scanline &sl, Render &renderer, bool clip) { if (clip) { ScanlineRes sl_result; agg::scanline_p8 sl_clip; agg::sbool_intersect_shapes_aa(ras, ras_clip, sl, sl_clip, sl_result, renderer); } else { agg::render_scanlines(ras, sl, renderer); } } template void render_raster(agg::rendering_buffer &rbuf, unsigned w, unsigned h, Raster &ras, RasterClip &ras_clip, Scanline &sl, Interpolator interpolator, Render &renderer, bool interpolate, bool clip, bool scale_down) { unsigned char * buffer8 = new unsigned char[w * h * Target::pix_width]; agg::rendering_buffer rbuf8(buffer8, w, h, w * Target::pix_width); agg::convert(&rbuf8, &rbuf); typedef agg::image_accessor_clone img_source_type; Target img_pixf(rbuf8); img_source_type img_src(img_pixf); agg::span_allocator sa; if (interpolate) { typedef agg::span_image_filter_rgba_bilinear span_gen_type; span_gen_type sg(img_src, interpolator); agg::renderer_scanline_aa, span_gen_type> raster_renderer(renderer, sa, sg); render(ras, ras_clip, sl, raster_renderer, clip); } else if (scale_down) { typedef agg::span_image_resample_rgba_affine span_gen_type; agg::image_filter_bilinear filter_kernel; agg::image_filter_lut filter(filter_kernel, true); span_gen_type sg(img_src, interpolator, filter); sg.blur(1); agg::renderer_scanline_aa, span_gen_type> raster_renderer(renderer, sa, sg); render(ras, ras_clip, sl, raster_renderer, clip); } else { typedef agg::span_image_filter_rgba_nn span_gen_type; span_gen_type sg(img_src, interpolator); agg::renderer_scanline_aa, span_gen_type> raster_renderer(renderer, sa, sg); render(ras, ras_clip, sl, raster_renderer, clip); } delete [] buffer8; } ragg/src/AggDeviceJpeg.h0000644000176200001440000000412114131500433014546 0ustar liggesusers#pragma once #include "ragg.h" #include "AggDevice.h" #include "files.h" #define TRUE 1 #define FALSE 0 #include template class AggDeviceJpeg : public AggDevice { int quality; int smoothing; int method; public: AggDeviceJpeg(const char* fp, int w, int h, double ps, int bg, double res, double scaling, int qual, int smooth, int meth) : AggDevice(fp, w, h, ps, bg, res, scaling), quality(qual), smoothing(smooth), method(meth) { } // Behaviour bool savePage() { char buf[PATH_MAX+1]; snprintf(buf, PATH_MAX, this->file.c_str(), this->pageno); buf[PATH_MAX] = '\0'; FILE* fd = unicode_fopen(buf, "wb"); if(!fd) return false; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fd); cinfo.image_width = this->width; cinfo.image_height = this->height; cinfo.density_unit = 1; cinfo.X_density = this->res_real; cinfo.Y_density = this->res_real; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; cinfo.smoothing_factor = this->smoothing; switch (this->method) { case 0: cinfo.dct_method = JDCT_ISLOW; break; case 1: cinfo.dct_method = JDCT_IFAST; break; case 2: cinfo.dct_method = JDCT_FLOAT; break; } jpeg_set_defaults(&cinfo); jpeg_set_colorspace(&cinfo, JCS_RGB); jpeg_set_quality(&cinfo, this->quality, TRUE); jpeg_start_compress(&cinfo, TRUE); agg::row_ptr_cache buffer_rows( this->buffer, this->width, this->height, this->rbuf.stride_abs() ); JSAMPROW row_pointer; for (int row = 0; row < this->height; row++) { row_pointer = (JSAMPROW) buffer_rows.row_ptr(row); jpeg_write_scanlines(&cinfo, &row_pointer, 1); } jpeg_finish_compress(&cinfo); fclose(fd); jpeg_destroy_compress(&cinfo); return true; }; }; typedef AggDeviceJpeg AggDeviceJpegNoAlpha; ragg/src/ppm_dev.cpp0000644000176200001440000000117014127312027014115 0ustar liggesusers#include "ragg.h" #include "init_device.h" #include "AggDevicePpm.h" // [[export]] SEXP agg_ppm_c(SEXP file, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling) { int bgCol = RGBpar(bg, 0); if (R_TRANSPARENT(bgCol)) { bgCol = R_TRANWHITE; } BEGIN_CPP AggDevicePpmNoAlpha* device = new AggDevicePpmNoAlpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0] ); makeDevice(device, "agg_ppm"); END_CPP return R_NilValue; } ragg/src/AggDevice16.h0000644000176200001440000000252714127250561014130 0ustar liggesusers#pragma once #include "ragg.h" #include "AggDevice.h" #include "util/agg_color_conv.h" /* For htons */ #ifdef _WIN32 #include #else #include #endif // Functor for dimming alpha if needed struct AlphaDim { double alpha_mod; AlphaDim(double alpha_mod) : alpha_mod(alpha_mod) { } inline void operator () (agg::rgba16* p) { p->a *= alpha_mod; } }; template class AggDevice16 : public AggDevice { public: double alpha_mod; AggDevice16(const char* fp, int w, int h, double ps, int bg, double res, double scaling, double alpha_mod = 1.0) : AggDevice(fp, w, h, ps, bg, res, scaling), alpha_mod(alpha_mod) { this->background = convertColour(this->background_int); this->renderer.clear(this->background); } void to_bigend() { uint16_t * buf = reinterpret_cast(this->buffer); for (int i = 0; i < this->width * this->height * PIXFMT::num_components; i++) { buf[i] = htons(buf[i]); } } private: inline agg::rgba16 convertColour(unsigned int col) { agg::rgba16 new_col = agg::rgba8(R_RED(col), R_GREEN(col), R_BLUE(col), R_ALPHA(col)); if (alpha_mod != 1.0 && new_col.a != 65535) new_col.a *= alpha_mod; return new_col.premultiply(); } }; ragg/src/ragg.h0000644000176200001440000000556514127252400013062 0ustar liggesusers#pragma once #include #include #include #include #define R_NO_REMAP #include #include #include "agg_basics.h" #include "agg_pixfmt_rgb.h" #include "agg_pixfmt_rgba.h" #include "agg_renderer_base.h" #include "agg_renderer_scanline.h" // Define a C++ try-catch macro to guard C++ calls #define BEGIN_CPP try { #define END_CPP \ } \ catch (const std::bad_alloc&) { \ Rf_error("Memory allocation error. You are likely trying to create too large an image"); \ } \ catch (std::exception & e) { \ Rf_error("C++ exception: %s", e.what()); \ } \ #define R_USE_PROTOTYPES 1 typedef agg::pixfmt_rgb24_pre pixfmt_type_24; typedef agg::pixfmt_rgba32_pre pixfmt_type_32; typedef agg::pixfmt_rgb48_pre pixfmt_type_48; typedef agg::pixfmt_rgba64_pre pixfmt_type_64; typedef agg::pixfmt_bgra32_pre pixfmt_col_glyph; #ifdef WORDS_BIGENDIAN typedef agg::pixfmt_abgr32_plain pixfmt_r_raster; typedef agg::pixfmt_abgr32_pre pixfmt_r_capture; #else typedef agg::pixfmt_rgba32_plain pixfmt_r_raster; typedef agg::pixfmt_rgba32_pre pixfmt_r_capture; #endif // pixfmt agnosting demultiplying template inline void demultiply(PIXFMT* pixfmt) { return; } template<> inline void demultiply(pixfmt_type_32* pixfmt) { pixfmt->demultiply(); return; } template<> inline void demultiply(pixfmt_type_64* pixfmt) { pixfmt->demultiply(); return; } SEXP agg_ppm_c(SEXP file, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling); SEXP agg_png_c(SEXP file, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling, SEXP bit); SEXP agg_supertransparent_c(SEXP file, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling, SEXP alpha_mod); SEXP agg_tiff_c(SEXP file, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling, SEXP bit, SEXP compression, SEXP encoding); SEXP agg_jpeg_c(SEXP file, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling, SEXP quality, SEXP smoothing, SEXP method); SEXP agg_capture_c(SEXP name, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling); ragg/src/agg/0000755000176200001440000000000014153422062012516 5ustar liggesusersragg/src/agg/include/0000755000176200001440000000000014147727637014164 5ustar liggesusersragg/src/agg/include/agg_arc.h0000644000176200001440000000374013504406270015703 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Arc vertex generator // //---------------------------------------------------------------------------- #ifndef AGG_ARC_INCLUDED #define AGG_ARC_INCLUDED #include "agg_basics.h" namespace agg { //=====================================================================arc // // See Implementation agg_arc.cpp // class arc { public: arc() : m_scale(1.0), m_initialized(false) {} arc(double x, double y, double rx, double ry, double a1, double a2, bool ccw=true); void init(double x, double y, double rx, double ry, double a1, double a2, bool ccw=true); void approximation_scale(double s); double approximation_scale() const { return m_scale; } void rewind(unsigned); unsigned vertex(double* x, double* y); private: void normalize(double a1, double a2, bool ccw); double m_x; double m_y; double m_rx; double m_ry; double m_angle; double m_start; double m_end; double m_scale; double m_da; bool m_ccw; bool m_initialized; unsigned m_path_cmd; }; } #endif ragg/src/agg/include/agg_conv_adaptor_vpgen.h0000644000176200001440000001163713504406270021020 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_CONV_ADAPTOR_VPGEN_INCLUDED #define AGG_CONV_ADAPTOR_VPGEN_INCLUDED #include "agg_basics.h" namespace agg { //======================================================conv_adaptor_vpgen template class conv_adaptor_vpgen { public: explicit conv_adaptor_vpgen(VertexSource& source) : m_source(&source) {} void attach(VertexSource& source) { m_source = &source; } VPGen& vpgen() { return m_vpgen; } const VPGen& vpgen() const { return m_vpgen; } void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: conv_adaptor_vpgen(const conv_adaptor_vpgen&); const conv_adaptor_vpgen& operator = (const conv_adaptor_vpgen&); VertexSource* m_source; VPGen m_vpgen; double m_start_x; double m_start_y; unsigned m_poly_flags; int m_vertices; }; //------------------------------------------------------------------------ template void conv_adaptor_vpgen::rewind(unsigned path_id) { m_source->rewind(path_id); m_vpgen.reset(); m_start_x = 0; m_start_y = 0; m_poly_flags = 0; m_vertices = 0; } //------------------------------------------------------------------------ template unsigned conv_adaptor_vpgen::vertex(double* x, double* y) { unsigned cmd = path_cmd_stop; for(;;) { cmd = m_vpgen.vertex(x, y); if(!is_stop(cmd)) break; if(m_poly_flags && !m_vpgen.auto_unclose()) { *x = 0.0; *y = 0.0; cmd = m_poly_flags; m_poly_flags = 0; break; } if(m_vertices < 0) { if(m_vertices < -1) { m_vertices = 0; return path_cmd_stop; } m_vpgen.move_to(m_start_x, m_start_y); m_vertices = 1; continue; } double tx, ty; cmd = m_source->vertex(&tx, &ty); if(is_vertex(cmd)) { if(is_move_to(cmd)) { if(m_vpgen.auto_close() && m_vertices > 2) { m_vpgen.line_to(m_start_x, m_start_y); m_poly_flags = path_cmd_end_poly | path_flags_close; m_start_x = tx; m_start_y = ty; m_vertices = -1; continue; } m_vpgen.move_to(tx, ty); m_start_x = tx; m_start_y = ty; m_vertices = 1; } else { m_vpgen.line_to(tx, ty); ++m_vertices; } } else { if(is_end_poly(cmd)) { m_poly_flags = cmd; if(is_closed(cmd) || m_vpgen.auto_close()) { if(m_vpgen.auto_close()) m_poly_flags |= path_flags_close; if(m_vertices > 2) { m_vpgen.line_to(m_start_x, m_start_y); } m_vertices = 0; } } else { // path_cmd_stop if(m_vpgen.auto_close() && m_vertices > 2) { m_vpgen.line_to(m_start_x, m_start_y); m_poly_flags = path_cmd_end_poly | path_flags_close; m_vertices = -2; continue; } break; } } } return cmd; } } #endif ragg/src/agg/include/agg_span_gradient_alpha.h0000644000176200001440000001147613504406270021126 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_SPAN_GRADIENT_ALPHA_INCLUDED #define AGG_SPAN_GRADIENT_ALPHA_INCLUDED #include "agg_span_gradient.h" namespace agg { //======================================================span_gradient_alpha template class span_gradient_alpha { public: typedef Interpolator interpolator_type; typedef ColorT color_type; typedef typename color_type::value_type alpha_type; enum downscale_shift_e { downscale_shift = interpolator_type::subpixel_shift - gradient_subpixel_shift }; //-------------------------------------------------------------------- span_gradient_alpha() {} //-------------------------------------------------------------------- span_gradient_alpha(interpolator_type& inter, GradientF& gradient_function, AlphaF& alpha_function, double d1, double d2) : m_interpolator(&inter), m_gradient_function(&gradient_function), m_alpha_function(&alpha_function), m_d1(iround(d1 * gradient_subpixel_scale)), m_d2(iround(d2 * gradient_subpixel_scale)) {} //-------------------------------------------------------------------- interpolator_type& interpolator() { return *m_interpolator; } const GradientF& gradient_function() const { return *m_gradient_function; } const AlphaF& alpha_function() const { return *m_alpha_function; } double d1() const { return double(m_d1) / gradient_subpixel_scale; } double d2() const { return double(m_d2) / gradient_subpixel_scale; } //-------------------------------------------------------------------- void interpolator(interpolator_type& i) { m_interpolator = &i; } void gradient_function(const GradientF& gf) { m_gradient_function = &gf; } void alpha_function(const AlphaF& af) { m_alpha_function = ⁡ } void d1(double v) { m_d1 = iround(v * gradient_subpixel_scale); } void d2(double v) { m_d2 = iround(v * gradient_subpixel_scale); } //-------------------------------------------------------------------- void prepare() {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { int dd = m_d2 - m_d1; if(dd < 1) dd = 1; m_interpolator->begin(x+0.5, y+0.5, len); do { m_interpolator->coordinates(&x, &y); int d = m_gradient_function->calculate(x >> downscale_shift, y >> downscale_shift, m_d2); d = ((d - m_d1) * (int)m_alpha_function->size()) / dd; if(d < 0) d = 0; if(d >= (int)m_alpha_function->size()) d = m_alpha_function->size() - 1; span->a = (*m_alpha_function)[d]; ++span; ++(*m_interpolator); } while(--len); } private: interpolator_type* m_interpolator; GradientF* m_gradient_function; AlphaF* m_alpha_function; int m_d1; int m_d2; }; //=======================================================gradient_alpha_x template struct gradient_alpha_x { typedef typename ColorT::value_type alpha_type; alpha_type operator [] (alpha_type x) const { return x; } }; //====================================================gradient_alpha_x_u8 struct gradient_alpha_x_u8 { typedef int8u alpha_type; alpha_type operator [] (alpha_type x) const { return x; } }; //==========================================gradient_alpha_one_munus_x_u8 struct gradient_alpha_one_munus_x_u8 { typedef int8u alpha_type; alpha_type operator [] (alpha_type x) const { return 255-x; } }; } #endif ragg/src/agg/include/agg_path_length.h0000644000176200001440000000356013504406270017433 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_PATH_LENGTH_INCLUDED #define AGG_PATH_LENGTH_INCLUDED #include "agg_math.h" namespace agg { template double path_length(VertexSource& vs, unsigned path_id = 0) { double len = 0.0; double start_x = 0.0; double start_y = 0.0; double x1 = 0.0; double y1 = 0.0; double x2 = 0.0; double y2 = 0.0; bool first = true; unsigned cmd; vs.rewind(path_id); while(!is_stop(cmd = vs.vertex(&x2, &y2))) { if(is_vertex(cmd)) { if(first || is_move_to(cmd)) { start_x = x2; start_y = y2; } else { len += calc_distance(x1, y1, x2, y2); } x1 = x2; y1 = y2; first = false; } else { if(is_close(cmd) && !first) { len += calc_distance(x1, y1, start_x, start_y); } } } return len; } } #endif ragg/src/agg/include/agg_conv_shorten_path.h0000644000176200001440000000330413504406270020655 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_CONV_SHORTEN_PATH_INCLUDED #define AGG_CONV_SHORTEN_PATH_INCLUDED #include "agg_basics.h" #include "agg_conv_adaptor_vcgen.h" #include "agg_vcgen_vertex_sequence.h" namespace agg { //=======================================================conv_shorten_path template class conv_shorten_path : public conv_adaptor_vcgen { public: typedef conv_adaptor_vcgen base_type; conv_shorten_path(VertexSource& vs) : conv_adaptor_vcgen(vs) { } void shorten(double s) { base_type::generator().shorten(s); } double shorten() const { return base_type::generator().shorten(); } private: conv_shorten_path(const conv_shorten_path&); const conv_shorten_path& operator = (const conv_shorten_path&); }; } #endif ragg/src/agg/include/agg_dda_line.h0000644000176200001440000002042513504406270016674 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // classes dda_line_interpolator, dda2_line_interpolator // //---------------------------------------------------------------------------- #ifndef AGG_DDA_LINE_INCLUDED #define AGG_DDA_LINE_INCLUDED #include #include "agg_basics.h" namespace agg { //===================================================dda_line_interpolator template class dda_line_interpolator { public: //-------------------------------------------------------------------- dda_line_interpolator() {} //-------------------------------------------------------------------- dda_line_interpolator(int y1, int y2, unsigned count) : m_y(y1), m_inc(((y2 - y1) << FractionShift) / int(count)), m_dy(0) { } //-------------------------------------------------------------------- void operator ++ () { m_dy += m_inc; } //-------------------------------------------------------------------- void operator -- () { m_dy -= m_inc; } //-------------------------------------------------------------------- void operator += (unsigned n) { m_dy += m_inc * n; } //-------------------------------------------------------------------- void operator -= (unsigned n) { m_dy -= m_inc * n; } //-------------------------------------------------------------------- int y() const { return m_y + (m_dy >> (FractionShift-YShift)); } int dy() const { return m_dy; } private: int m_y; int m_inc; int m_dy; }; //=================================================dda2_line_interpolator class dda2_line_interpolator { public: typedef int save_data_type; enum save_size_e { save_size = 2 }; //-------------------------------------------------------------------- dda2_line_interpolator() {} //-------------------------------------------- Forward-adjusted line dda2_line_interpolator(int y1, int y2, int count) : m_cnt(count <= 0 ? 1 : count), m_lft((y2 - y1) / m_cnt), m_rem((y2 - y1) % m_cnt), m_mod(m_rem), m_y(y1) { if(m_mod <= 0) { m_mod += count; m_rem += count; m_lft--; } m_mod -= count; } //-------------------------------------------- Backward-adjusted line dda2_line_interpolator(int y1, int y2, int count, int) : m_cnt(count <= 0 ? 1 : count), m_lft((y2 - y1) / m_cnt), m_rem((y2 - y1) % m_cnt), m_mod(m_rem), m_y(y1) { if(m_mod <= 0) { m_mod += count; m_rem += count; m_lft--; } } //-------------------------------------------- Backward-adjusted line dda2_line_interpolator(int y, int count) : m_cnt(count <= 0 ? 1 : count), m_lft(y / m_cnt), m_rem(y % m_cnt), m_mod(m_rem), m_y(0) { if(m_mod <= 0) { m_mod += count; m_rem += count; m_lft--; } } //-------------------------------------------------------------------- void save(save_data_type* data) const { data[0] = m_mod; data[1] = m_y; } //-------------------------------------------------------------------- void load(const save_data_type* data) { m_mod = data[0]; m_y = data[1]; } //-------------------------------------------------------------------- void operator++() { m_mod += m_rem; m_y += m_lft; if(m_mod > 0) { m_mod -= m_cnt; m_y++; } } //-------------------------------------------------------------------- void operator--() { if(m_mod <= m_rem) { m_mod += m_cnt; m_y--; } m_mod -= m_rem; m_y -= m_lft; } //-------------------------------------------------------------------- void adjust_forward() { m_mod -= m_cnt; } //-------------------------------------------------------------------- void adjust_backward() { m_mod += m_cnt; } //-------------------------------------------------------------------- int mod() const { return m_mod; } int rem() const { return m_rem; } int lft() const { return m_lft; } //-------------------------------------------------------------------- int y() const { return m_y; } private: int m_cnt; int m_lft; int m_rem; int m_mod; int m_y; }; //---------------------------------------------line_bresenham_interpolator class line_bresenham_interpolator { public: enum subpixel_scale_e { subpixel_shift = 8, subpixel_scale = 1 << subpixel_shift, subpixel_mask = subpixel_scale - 1 }; //-------------------------------------------------------------------- static int line_lr(int v) { return v >> subpixel_shift; } //-------------------------------------------------------------------- line_bresenham_interpolator(int x1, int y1, int x2, int y2) : m_x1_lr(line_lr(x1)), m_y1_lr(line_lr(y1)), m_x2_lr(line_lr(x2)), m_y2_lr(line_lr(y2)), m_ver(std::abs(m_x2_lr - m_x1_lr) < std::abs(m_y2_lr - m_y1_lr)), m_len(m_ver ? std::abs(m_y2_lr - m_y1_lr) : std::abs(m_x2_lr - m_x1_lr)), m_inc(m_ver ? ((y2 > y1) ? 1 : -1) : ((x2 > x1) ? 1 : -1)), m_interpolator(m_ver ? x1 : y1, m_ver ? x2 : y2, m_len) { } //-------------------------------------------------------------------- bool is_ver() const { return m_ver; } unsigned len() const { return m_len; } int inc() const { return m_inc; } //-------------------------------------------------------------------- void hstep() { ++m_interpolator; m_x1_lr += m_inc; } //-------------------------------------------------------------------- void vstep() { ++m_interpolator; m_y1_lr += m_inc; } //-------------------------------------------------------------------- int x1() const { return m_x1_lr; } int y1() const { return m_y1_lr; } int x2() const { return line_lr(m_interpolator.y()); } int y2() const { return line_lr(m_interpolator.y()); } int x2_hr() const { return m_interpolator.y(); } int y2_hr() const { return m_interpolator.y(); } private: int m_x1_lr; int m_y1_lr; int m_x2_lr; int m_y2_lr; bool m_ver; unsigned m_len; int m_inc; dda2_line_interpolator m_interpolator; }; } #endif ragg/src/agg/include/agg_rendering_buffer.h0000644000176200001440000002354313504406270020447 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // class rendering_buffer // //---------------------------------------------------------------------------- #ifndef AGG_RENDERING_BUFFER_INCLUDED #define AGG_RENDERING_BUFFER_INCLUDED #include #include "agg_array.h" namespace agg { //===========================================================row_accessor template class row_accessor { public: typedef const_row_info row_data; //------------------------------------------------------------------- row_accessor() : m_buf(0), m_start(0), m_width(0), m_height(0), m_stride(0) { } //-------------------------------------------------------------------- row_accessor(T* buf, unsigned width, unsigned height, int stride) : m_buf(0), m_start(0), m_width(0), m_height(0), m_stride(0) { attach(buf, width, height, stride); } //-------------------------------------------------------------------- void attach(T* buf, unsigned width, unsigned height, int stride) { m_buf = m_start = buf; m_width = width; m_height = height; m_stride = stride; if(stride < 0) { m_start = m_buf - (AGG_INT64)(height - 1) * stride; } } //-------------------------------------------------------------------- AGG_INLINE T* buf() { return m_buf; } AGG_INLINE const T* buf() const { return m_buf; } AGG_INLINE unsigned width() const { return m_width; } AGG_INLINE unsigned height() const { return m_height; } AGG_INLINE int stride() const { return m_stride; } AGG_INLINE unsigned stride_abs() const { return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); } //-------------------------------------------------------------------- AGG_INLINE T* row_ptr(int, int y, unsigned) { return m_start + y * (AGG_INT64)m_stride; } AGG_INLINE T* row_ptr(int y) { return m_start + y * (AGG_INT64)m_stride; } AGG_INLINE const T* row_ptr(int y) const { return m_start + y * (AGG_INT64)m_stride; } AGG_INLINE row_data row (int y) const { return row_data(0, m_width-1, row_ptr(y)); } //-------------------------------------------------------------------- template void copy_from(const RenBuf& src) { unsigned h = height(); if(src.height() < h) h = src.height(); unsigned l = stride_abs(); if(src.stride_abs() < l) l = src.stride_abs(); l *= sizeof(T); unsigned y; unsigned w = width(); for (y = 0; y < h; y++) { std::memcpy(row_ptr(0, y, w), src.row_ptr(y), l); } } //-------------------------------------------------------------------- void clear(T value) { unsigned y; unsigned w = width(); unsigned stride = stride_abs(); for(y = 0; y < height(); y++) { T* p = row_ptr(0, y, w); unsigned x; for(x = 0; x < stride; x++) { *p++ = value; } } } private: //-------------------------------------------------------------------- T* m_buf; // Pointer to renrdering buffer T* m_start; // Pointer to first pixel depending on stride unsigned m_width; // Width in pixels unsigned m_height; // Height in pixels int m_stride; // Number of bytes per row. Can be < 0 }; //==========================================================row_ptr_cache template class row_ptr_cache { public: typedef const_row_info row_data; //------------------------------------------------------------------- row_ptr_cache() : m_buf(0), m_rows(), m_width(0), m_height(0), m_stride(0) { } //-------------------------------------------------------------------- row_ptr_cache(T* buf, unsigned width, unsigned height, int stride) : m_buf(0), m_rows(), m_width(0), m_height(0), m_stride(0) { attach(buf, width, height, stride); } //-------------------------------------------------------------------- void attach(T* buf, unsigned width, unsigned height, int stride) { m_buf = buf; m_width = width; m_height = height; m_stride = stride; if(height > m_rows.size()) { m_rows.resize(height); } T* row_ptr = m_buf; if(stride < 0) { row_ptr = m_buf - (AGG_INT64)(height - 1) * stride; } T** rows = &m_rows[0]; while(height--) { *rows++ = row_ptr; row_ptr += stride; } } //-------------------------------------------------------------------- AGG_INLINE T* buf() { return m_buf; } AGG_INLINE const T* buf() const { return m_buf; } AGG_INLINE unsigned width() const { return m_width; } AGG_INLINE unsigned height() const { return m_height; } AGG_INLINE int stride() const { return m_stride; } AGG_INLINE unsigned stride_abs() const { return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); } //-------------------------------------------------------------------- AGG_INLINE T* row_ptr(int, int y, unsigned) { return m_rows[y]; } AGG_INLINE T* row_ptr(int y) { return m_rows[y]; } AGG_INLINE const T* row_ptr(int y) const { return m_rows[y]; } AGG_INLINE row_data row (int y) const { return row_data(0, m_width-1, m_rows[y]); } //-------------------------------------------------------------------- T const* const* rows() const { return &m_rows[0]; } //-------------------------------------------------------------------- template void copy_from(const RenBuf& src) { unsigned h = height(); if(src.height() < h) h = src.height(); unsigned l = stride_abs(); if(src.stride_abs() < l) l = src.stride_abs(); l *= sizeof(T); unsigned y; unsigned w = width(); for (y = 0; y < h; y++) { std::memcpy(row_ptr(0, y, w), src.row_ptr(y), l); } } //-------------------------------------------------------------------- void clear(T value) { unsigned y; unsigned w = width(); unsigned stride = stride_abs(); for(y = 0; y < height(); y++) { T* p = row_ptr(0, y, w); unsigned x; for(x = 0; x < stride; x++) { *p++ = value; } } } private: //-------------------------------------------------------------------- T* m_buf; // Pointer to renrdering buffer pod_array m_rows; // Pointers to each row of the buffer unsigned m_width; // Width in pixels unsigned m_height; // Height in pixels int m_stride; // Number of bytes per row. Can be < 0 }; //========================================================rendering_buffer // // The definition of the main type for accessing the rows in the frame // buffer. It provides functionality to navigate to the rows in a // rectangular matrix, from top to bottom or from bottom to top depending // on stride. // // row_accessor is cheap to create/destroy, but performs one multiplication // when calling row_ptr(). // // row_ptr_cache creates an array of pointers to rows, so, the access // via row_ptr() may be faster. But it requires memory allocation // when creating. For example, on typical Intel Pentium hardware // row_ptr_cache speeds span_image_filter_rgb_nn up to 10% // // It's used only in short hand typedefs like pixfmt_rgba32 and can be // redefined in agg_config.h // In real applications you can use both, depending on your needs //------------------------------------------------------------------------ #ifdef AGG_RENDERING_BUFFER typedef AGG_RENDERING_BUFFER rendering_buffer; #else // typedef row_ptr_cache rendering_buffer; typedef row_accessor rendering_buffer; #endif } #endif ragg/src/agg/include/agg_conv_marker_adaptor.h0000644000176200001440000000350313504406270021153 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_CONV_MARKER_ADAPTOR_INCLUDED #define AGG_CONV_MARKER_ADAPTOR_INCLUDED #include "agg_basics.h" #include "agg_conv_adaptor_vcgen.h" #include "agg_vcgen_vertex_sequence.h" namespace agg { //=====================================================conv_marker_adaptor template struct conv_marker_adaptor : public conv_adaptor_vcgen { typedef Markers marker_type; typedef conv_adaptor_vcgen base_type; conv_marker_adaptor(VertexSource& vs) : conv_adaptor_vcgen(vs) { } void shorten(double s) { base_type::generator().shorten(s); } double shorten() const { return base_type::generator().shorten(); } private: conv_marker_adaptor(const conv_marker_adaptor&); const conv_marker_adaptor& operator = (const conv_marker_adaptor&); }; } #endif ragg/src/agg/include/agg_pixfmt_transposer.h0000644000176200001440000001411213504406270020720 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_PIXFMT_TRANSPOSER_INCLUDED #define AGG_PIXFMT_TRANSPOSER_INCLUDED #include "agg_basics.h" namespace agg { //=======================================================pixfmt_transposer template class pixfmt_transposer { public: typedef PixFmt pixfmt_type; typedef typename pixfmt_type::color_type color_type; typedef typename pixfmt_type::row_data row_data; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; //-------------------------------------------------------------------- pixfmt_transposer() : m_pixf(0) {} explicit pixfmt_transposer(pixfmt_type& pixf) : m_pixf(&pixf) {} void attach(pixfmt_type& pixf) { m_pixf = &pixf; } //-------------------------------------------------------------------- AGG_INLINE unsigned width() const { return m_pixf->height(); } AGG_INLINE unsigned height() const { return m_pixf->width(); } //-------------------------------------------------------------------- AGG_INLINE color_type pixel(int x, int y) const { return m_pixf->pixel(y, x); } //-------------------------------------------------------------------- AGG_INLINE void copy_pixel(int x, int y, const color_type& c) { m_pixf->copy_pixel(y, x, c); } //-------------------------------------------------------------------- AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) { m_pixf->blend_pixel(y, x, c, cover); } //-------------------------------------------------------------------- AGG_INLINE void copy_hline(int x, int y, unsigned len, const color_type& c) { m_pixf->copy_vline(y, x, len, c); } //-------------------------------------------------------------------- AGG_INLINE void copy_vline(int x, int y, unsigned len, const color_type& c) { m_pixf->copy_hline(y, x, len, c); } //-------------------------------------------------------------------- AGG_INLINE void blend_hline(int x, int y, unsigned len, const color_type& c, int8u cover) { m_pixf->blend_vline(y, x, len, c, cover); } //-------------------------------------------------------------------- AGG_INLINE void blend_vline(int x, int y, unsigned len, const color_type& c, int8u cover) { m_pixf->blend_hline(y, x, len, c, cover); } //-------------------------------------------------------------------- AGG_INLINE void blend_solid_hspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { m_pixf->blend_solid_vspan(y, x, len, c, covers); } //-------------------------------------------------------------------- AGG_INLINE void blend_solid_vspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { m_pixf->blend_solid_hspan(y, x, len, c, covers); } //-------------------------------------------------------------------- AGG_INLINE void copy_color_hspan(int x, int y, unsigned len, const color_type* colors) { m_pixf->copy_color_vspan(y, x, len, colors); } //-------------------------------------------------------------------- AGG_INLINE void copy_color_vspan(int x, int y, unsigned len, const color_type* colors) { m_pixf->copy_color_hspan(y, x, len, colors); } //-------------------------------------------------------------------- AGG_INLINE void blend_color_hspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { m_pixf->blend_color_vspan(y, x, len, colors, covers, cover); } //-------------------------------------------------------------------- AGG_INLINE void blend_color_vspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { m_pixf->blend_color_hspan(y, x, len, colors, covers, cover); } private: pixfmt_type* m_pixf; }; } #endif ragg/src/agg/include/agg_simul_eq.h0000644000176200001440000000764513504406270016764 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Solving simultaneous equations // //---------------------------------------------------------------------------- #ifndef AGG_SIMUL_EQ_INCLUDED #define AGG_SIMUL_EQ_INCLUDED #include #include "agg_basics.h" namespace agg { //=============================================================swap_arrays template void swap_arrays(T* a1, T* a2, unsigned n) { unsigned i; for(i = 0; i < n; i++) { T tmp = *a1; *a1++ = *a2; *a2++ = tmp; } } //============================================================matrix_pivot template struct matrix_pivot { static int pivot(double m[Rows][Cols], unsigned row) { int k = int(row); double max_val, tmp; max_val = -1.0; unsigned i; for(i = row; i < Rows; i++) { if((tmp = std::fabs(m[i][row])) > max_val && tmp != 0.0) { max_val = tmp; k = i; } } if(m[k][row] == 0.0) { return -1; } if(k != int(row)) { swap_arrays(m[k], m[row], Cols); return k; } return 0; } }; //===============================================================simul_eq template struct simul_eq { static bool solve(const double left[Size][Size], const double right[Size][RightCols], double result[Size][RightCols]) { unsigned i, j, k; double a1; double tmp[Size][Size + RightCols]; for(i = 0; i < Size; i++) { for(j = 0; j < Size; j++) { tmp[i][j] = left[i][j]; } for(j = 0; j < RightCols; j++) { tmp[i][Size + j] = right[i][j]; } } for(k = 0; k < Size; k++) { if(matrix_pivot::pivot(tmp, k) < 0) { return false; // Singularity.... } a1 = tmp[k][k]; for(j = k; j < Size + RightCols; j++) { tmp[k][j] /= a1; } for(i = k + 1; i < Size; i++) { a1 = tmp[i][k]; for (j = k; j < Size + RightCols; j++) { tmp[i][j] -= a1 * tmp[k][j]; } } } for(k = 0; k < RightCols; k++) { int m; for(m = int(Size - 1); m >= 0; m--) { result[m][k] = tmp[m][Size + k]; for(j = m + 1; j < Size; j++) { result[m][k] -= tmp[m][j] * result[j][k]; } } } return true; } }; } #endif ragg/src/agg/include/agg_math_stroke.h0000644000176200001440000004431113504406270017455 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Stroke math // //---------------------------------------------------------------------------- #ifndef AGG_STROKE_MATH_INCLUDED #define AGG_STROKE_MATH_INCLUDED #include "agg_math.h" #include "agg_vertex_sequence.h" namespace agg { //-------------------------------------------------------------line_cap_e enum line_cap_e { butt_cap, square_cap, round_cap }; //------------------------------------------------------------line_join_e enum line_join_e { miter_join = 0, miter_join_revert = 1, round_join = 2, bevel_join = 3, miter_join_round = 4 }; //-----------------------------------------------------------inner_join_e enum inner_join_e { inner_bevel, inner_miter, inner_jag, inner_round }; //------------------------------------------------------------math_stroke template class math_stroke { public: typedef typename VertexConsumer::value_type coord_type; math_stroke(); void line_cap(line_cap_e lc) { m_line_cap = lc; } void line_join(line_join_e lj) { m_line_join = lj; } void inner_join(inner_join_e ij) { m_inner_join = ij; } line_cap_e line_cap() const { return m_line_cap; } line_join_e line_join() const { return m_line_join; } inner_join_e inner_join() const { return m_inner_join; } void width(double w); void miter_limit(double ml) { m_miter_limit = ml; } void miter_limit_theta(double t); void inner_miter_limit(double ml) { m_inner_miter_limit = ml; } void approximation_scale(double as) { m_approx_scale = as; } double width() const { return m_width * 2.0; } double miter_limit() const { return m_miter_limit; } double inner_miter_limit() const { return m_inner_miter_limit; } double approximation_scale() const { return m_approx_scale; } void calc_cap(VertexConsumer& vc, const vertex_dist& v0, const vertex_dist& v1, double len); void calc_join(VertexConsumer& vc, const vertex_dist& v0, const vertex_dist& v1, const vertex_dist& v2, double len1, double len2); private: AGG_INLINE void add_vertex(VertexConsumer& vc, double x, double y) { vc.add(coord_type(x, y)); } void calc_arc(VertexConsumer& vc, double x, double y, double dx1, double dy1, double dx2, double dy2); void calc_miter(VertexConsumer& vc, const vertex_dist& v0, const vertex_dist& v1, const vertex_dist& v2, double dx1, double dy1, double dx2, double dy2, line_join_e lj, double mlimit, double dbevel); double m_width; double m_width_abs; double m_width_eps; int m_width_sign; double m_miter_limit; double m_inner_miter_limit; double m_approx_scale; line_cap_e m_line_cap; line_join_e m_line_join; inner_join_e m_inner_join; }; //----------------------------------------------------------------------- template math_stroke::math_stroke() : m_width(0.5), m_width_abs(0.5), m_width_eps(0.5/1024.0), m_width_sign(1), m_miter_limit(4.0), m_inner_miter_limit(1.01), m_approx_scale(1.0), m_line_cap(butt_cap), m_line_join(miter_join), m_inner_join(inner_miter) { } //----------------------------------------------------------------------- template void math_stroke::width(double w) { m_width = w * 0.5; if(m_width < 0) { m_width_abs = -m_width; m_width_sign = -1; } else { m_width_abs = m_width; m_width_sign = 1; } m_width_eps = m_width / 1024.0; } //----------------------------------------------------------------------- template void math_stroke::miter_limit_theta(double t) { m_miter_limit = 1.0 / std::sin(t * 0.5) ; } //----------------------------------------------------------------------- template void math_stroke::calc_arc(VC& vc, double x, double y, double dx1, double dy1, double dx2, double dy2) { double a1 = std::atan2(dy1 * m_width_sign, dx1 * m_width_sign); double a2 = std::atan2(dy2 * m_width_sign, dx2 * m_width_sign); double da = a1 - a2; int i, n; da = std::acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2; add_vertex(vc, x + dx1, y + dy1); if(m_width_sign > 0) { if(a1 > a2) a2 += 2 * pi; n = int((a2 - a1) / da); da = (a2 - a1) / (n + 1); a1 += da; for(i = 0; i < n; i++) { add_vertex(vc, x + std::cos(a1) * m_width, y + std::sin(a1) * m_width); a1 += da; } } else { if(a1 < a2) a2 -= 2 * pi; n = int((a1 - a2) / da); da = (a1 - a2) / (n + 1); a1 -= da; for(i = 0; i < n; i++) { add_vertex(vc, x + std::cos(a1) * m_width, y + std::sin(a1) * m_width); a1 -= da; } } add_vertex(vc, x + dx2, y + dy2); } //----------------------------------------------------------------------- template void math_stroke::calc_miter(VC& vc, const vertex_dist& v0, const vertex_dist& v1, const vertex_dist& v2, double dx1, double dy1, double dx2, double dy2, line_join_e lj, double mlimit, double dbevel) { double xi = v1.x; double yi = v1.y; double di = 1; double lim = m_width_abs * mlimit; bool miter_limit_exceeded = true; // Assume the worst bool intersection_failed = true; // Assume the worst if(calc_intersection(v0.x + dx1, v0.y - dy1, v1.x + dx1, v1.y - dy1, v1.x + dx2, v1.y - dy2, v2.x + dx2, v2.y - dy2, &xi, &yi)) { // Calculation of the intersection succeeded //--------------------- di = calc_distance(v1.x, v1.y, xi, yi); if(di <= lim) { // Inside the miter limit //--------------------- add_vertex(vc, xi, yi); miter_limit_exceeded = false; } intersection_failed = false; } else { // Calculation of the intersection failed, most probably // the three points lie one straight line. // First check if v0 and v2 lie on the opposite sides of vector: // (v1.x, v1.y) -> (v1.x+dx1, v1.y-dy1), that is, the perpendicular // to the line determined by vertices v0 and v1. // This condition determines whether the next line segments continues // the previous one or goes back. //---------------- double x2 = v1.x + dx1; double y2 = v1.y - dy1; if((cross_product(v0.x, v0.y, v1.x, v1.y, x2, y2) < 0.0) == (cross_product(v1.x, v1.y, v2.x, v2.y, x2, y2) < 0.0)) { // This case means that the next segment continues // the previous one (straight line) //----------------- add_vertex(vc, v1.x + dx1, v1.y - dy1); miter_limit_exceeded = false; } } if(miter_limit_exceeded) { // Miter limit exceeded //------------------------ switch(lj) { case miter_join_revert: // For the compatibility with SVG, PDF, etc, // we use a simple bevel join instead of // "smart" bevel //------------------- add_vertex(vc, v1.x + dx1, v1.y - dy1); add_vertex(vc, v1.x + dx2, v1.y - dy2); break; case miter_join_round: calc_arc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2); break; default: // If no miter-revert, calculate new dx1, dy1, dx2, dy2 //---------------- if(intersection_failed) { mlimit *= m_width_sign; add_vertex(vc, v1.x + dx1 + dy1 * mlimit, v1.y - dy1 + dx1 * mlimit); add_vertex(vc, v1.x + dx2 - dy2 * mlimit, v1.y - dy2 - dx2 * mlimit); } else { double x1 = v1.x + dx1; double y1 = v1.y - dy1; double x2 = v1.x + dx2; double y2 = v1.y - dy2; di = (lim - dbevel) / (di - dbevel); add_vertex(vc, x1 + (xi - x1) * di, y1 + (yi - y1) * di); add_vertex(vc, x2 + (xi - x2) * di, y2 + (yi - y2) * di); } break; } } } //--------------------------------------------------------stroke_calc_cap template void math_stroke::calc_cap(VC& vc, const vertex_dist& v0, const vertex_dist& v1, double len) { vc.remove_all(); double dx1 = (v1.y - v0.y) / len; double dy1 = (v1.x - v0.x) / len; double dx2 = 0; double dy2 = 0; dx1 *= m_width; dy1 *= m_width; if(m_line_cap != round_cap) { if(m_line_cap == square_cap) { dx2 = dy1 * m_width_sign; dy2 = dx1 * m_width_sign; } add_vertex(vc, v0.x - dx1 - dx2, v0.y + dy1 - dy2); add_vertex(vc, v0.x + dx1 - dx2, v0.y - dy1 - dy2); } else { double da = std::acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2; double a1; int i; int n = int(pi / da); da = pi / (n + 1); add_vertex(vc, v0.x - dx1, v0.y + dy1); if(m_width_sign > 0) { a1 = std::atan2(dy1, -dx1); a1 += da; for(i = 0; i < n; i++) { add_vertex(vc, v0.x + std::cos(a1) * m_width, v0.y + std::sin(a1) * m_width); a1 += da; } } else { a1 = std::atan2(-dy1, dx1); a1 -= da; for(i = 0; i < n; i++) { add_vertex(vc, v0.x + std::cos(a1) * m_width, v0.y + std::sin(a1) * m_width); a1 -= da; } } add_vertex(vc, v0.x + dx1, v0.y - dy1); } } //----------------------------------------------------------------------- template void math_stroke::calc_join(VC& vc, const vertex_dist& v0, const vertex_dist& v1, const vertex_dist& v2, double len1, double len2) { double dx1 = m_width * (v1.y - v0.y) / len1; double dy1 = m_width * (v1.x - v0.x) / len1; double dx2 = m_width * (v2.y - v1.y) / len2; double dy2 = m_width * (v2.x - v1.x) / len2; vc.remove_all(); double cp = cross_product(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y); if(cp != 0 && (cp > 0) == (m_width > 0)) { // Inner join //--------------- double limit = ((len1 < len2) ? len1 : len2) / m_width_abs; if(limit < m_inner_miter_limit) { limit = m_inner_miter_limit; } switch(m_inner_join) { default: // inner_bevel add_vertex(vc, v1.x + dx1, v1.y - dy1); add_vertex(vc, v1.x + dx2, v1.y - dy2); break; case inner_miter: calc_miter(vc, v0, v1, v2, dx1, dy1, dx2, dy2, miter_join_revert, limit, 0); break; case inner_jag: case inner_round: cp = (dx1-dx2) * (dx1-dx2) + (dy1-dy2) * (dy1-dy2); if(cp < len1 * len1 && cp < len2 * len2) { calc_miter(vc, v0, v1, v2, dx1, dy1, dx2, dy2, miter_join_revert, limit, 0); } else { if(m_inner_join == inner_jag) { add_vertex(vc, v1.x + dx1, v1.y - dy1); add_vertex(vc, v1.x, v1.y ); add_vertex(vc, v1.x + dx2, v1.y - dy2); } else { add_vertex(vc, v1.x + dx1, v1.y - dy1); add_vertex(vc, v1.x, v1.y ); calc_arc(vc, v1.x, v1.y, dx2, -dy2, dx1, -dy1); add_vertex(vc, v1.x, v1.y ); add_vertex(vc, v1.x + dx2, v1.y - dy2); } } break; } } else { // Outer join //--------------- // Calculate the distance between v1 and // the central point of the bevel line segment //--------------- double dx = (dx1 + dx2) / 2; double dy = (dy1 + dy2) / 2; double dbevel = std::sqrt(dx * dx + dy * dy); if(m_line_join == round_join || m_line_join == bevel_join) { // This is an optimization that reduces the number of points // in cases of almost collinear segments. If there's no // visible difference between bevel and miter joins we'd rather // use miter join because it adds only one point instead of two. // // Here we calculate the middle point between the bevel points // and then, the distance between v1 and this middle point. // At outer joins this distance always less than stroke width, // because it's actually the height of an isosceles triangle of // v1 and its two bevel points. If the difference between this // width and this value is small (no visible bevel) we can // add just one point. // // The constant in the expression makes the result approximately // the same as in round joins and caps. You can safely comment // out this entire "if". //------------------- if(m_approx_scale * (m_width_abs - dbevel) < m_width_eps) { if(calc_intersection(v0.x + dx1, v0.y - dy1, v1.x + dx1, v1.y - dy1, v1.x + dx2, v1.y - dy2, v2.x + dx2, v2.y - dy2, &dx, &dy)) { add_vertex(vc, dx, dy); } else { add_vertex(vc, v1.x + dx1, v1.y - dy1); } return; } } switch(m_line_join) { case miter_join: case miter_join_revert: case miter_join_round: calc_miter(vc, v0, v1, v2, dx1, dy1, dx2, dy2, m_line_join, m_miter_limit, dbevel); break; case round_join: calc_arc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2); break; default: // Bevel join add_vertex(vc, v1.x + dx1, v1.y - dy1); add_vertex(vc, v1.x + dx2, v1.y - dy2); break; } } } } #endif ragg/src/agg/include/agg_arrowhead.h0000644000176200001440000000442113504406270017107 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Simple arrowhead/arrowtail generator // //---------------------------------------------------------------------------- #ifndef AGG_ARROWHEAD_INCLUDED #define AGG_ARROWHEAD_INCLUDED #include "agg_basics.h" namespace agg { //===============================================================arrowhead // // See implementation agg_arrowhead.cpp // class arrowhead { public: arrowhead(); void head(double d1, double d2, double d3, double d4) { m_head_d1 = d1; m_head_d2 = d2; m_head_d3 = d3; m_head_d4 = d4; m_head_flag = true; } void head() { m_head_flag = true; } void no_head() { m_head_flag = false; } void tail(double d1, double d2, double d3, double d4) { m_tail_d1 = d1; m_tail_d2 = d2; m_tail_d3 = d3; m_tail_d4 = d4; m_tail_flag = true; } void tail() { m_tail_flag = true; } void no_tail() { m_tail_flag = false; } void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: double m_head_d1; double m_head_d2; double m_head_d3; double m_head_d4; double m_tail_d1; double m_tail_d2; double m_tail_d3; double m_tail_d4; bool m_head_flag; bool m_tail_flag; double m_coord[16]; unsigned m_cmd[8]; unsigned m_curr_id; unsigned m_curr_coord; }; } #endif ragg/src/agg/include/agg_conv_contour.h0000644000176200001440000000555013504406270017655 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // conv_stroke // //---------------------------------------------------------------------------- #ifndef AGG_CONV_CONTOUR_INCLUDED #define AGG_CONV_CONTOUR_INCLUDED #include "agg_basics.h" #include "agg_vcgen_contour.h" #include "agg_conv_adaptor_vcgen.h" namespace agg { //-----------------------------------------------------------conv_contour template struct conv_contour : public conv_adaptor_vcgen { typedef conv_adaptor_vcgen base_type; conv_contour(VertexSource& vs) : conv_adaptor_vcgen(vs) { } void line_join(line_join_e lj) { base_type::generator().line_join(lj); } void inner_join(inner_join_e ij) { base_type::generator().inner_join(ij); } void width(double w) { base_type::generator().width(w); } void miter_limit(double ml) { base_type::generator().miter_limit(ml); } void miter_limit_theta(double t) { base_type::generator().miter_limit_theta(t); } void inner_miter_limit(double ml) { base_type::generator().inner_miter_limit(ml); } void approximation_scale(double as) { base_type::generator().approximation_scale(as); } void auto_detect_orientation(bool v) { base_type::generator().auto_detect_orientation(v); } line_join_e line_join() const { return base_type::generator().line_join(); } inner_join_e inner_join() const { return base_type::generator().inner_join(); } double width() const { return base_type::generator().width(); } double miter_limit() const { return base_type::generator().miter_limit(); } double inner_miter_limit() const { return base_type::generator().inner_miter_limit(); } double approximation_scale() const { return base_type::generator().approximation_scale(); } bool auto_detect_orientation() const { return base_type::generator().auto_detect_orientation(); } private: conv_contour(const conv_contour&); const conv_contour& operator = (const conv_contour&); }; } #endif ragg/src/agg/include/agg_pixfmt_rgb_packed.h0000644000176200001440000014074313504406270020613 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_PIXFMT_RGB_PACKED_INCLUDED #define AGG_PIXFMT_RGB_PACKED_INCLUDED #include #include "agg_basics.h" #include "agg_color_rgba.h" #include "agg_rendering_buffer.h" namespace agg { //=========================================================blender_rgb555 struct blender_rgb555 { typedef rgba8 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int16u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type rgb = *p; calc_type r = (rgb >> 7) & 0xF8; calc_type g = (rgb >> 2) & 0xF8; calc_type b = (rgb << 3) & 0xF8; *p = (pixel_type) (((((cr - r) * alpha + (r << 8)) >> 1) & 0x7C00) | ((((cg - g) * alpha + (g << 8)) >> 6) & 0x03E0) | (((cb - b) * alpha + (b << 8)) >> 11) | 0x8000); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xF8) << 7) | ((g & 0xF8) << 2) | (b >> 3) | 0x8000); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 7) & 0xF8, (p >> 2) & 0xF8, (p << 3) & 0xF8); } }; //=====================================================blender_rgb555_pre struct blender_rgb555_pre { typedef rgba8 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int16u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned cover) { alpha = color_type::base_mask - alpha; pixel_type rgb = *p; calc_type r = (rgb >> 7) & 0xF8; calc_type g = (rgb >> 2) & 0xF8; calc_type b = (rgb << 3) & 0xF8; *p = (pixel_type) ((((r * alpha + cr * cover) >> 1) & 0x7C00) | (((g * alpha + cg * cover) >> 6) & 0x03E0) | ((b * alpha + cb * cover) >> 11) | 0x8000); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xF8) << 7) | ((g & 0xF8) << 2) | (b >> 3) | 0x8000); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 7) & 0xF8, (p >> 2) & 0xF8, (p << 3) & 0xF8); } }; //=====================================================blender_rgb555_gamma template class blender_rgb555_gamma { public: typedef rgba8 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int16u pixel_type; typedef Gamma gamma_type; blender_rgb555_gamma() : m_gamma(0) {} void gamma(const gamma_type& g) { m_gamma = &g; } AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type rgb = *p; calc_type r = m_gamma->dir((rgb >> 7) & 0xF8); calc_type g = m_gamma->dir((rgb >> 2) & 0xF8); calc_type b = m_gamma->dir((rgb << 3) & 0xF8); *p = (pixel_type) (((m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 8)) >> 8) << 7) & 0x7C00) | ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 8)) >> 8) << 2) & 0x03E0) | (m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 8)) >> 8) >> 3) | 0x8000); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xF8) << 7) | ((g & 0xF8) << 2) | (b >> 3) | 0x8000); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 7) & 0xF8, (p >> 2) & 0xF8, (p << 3) & 0xF8); } private: const Gamma* m_gamma; }; //=========================================================blender_rgb565 struct blender_rgb565 { typedef rgba8 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int16u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type rgb = *p; calc_type r = (rgb >> 8) & 0xF8; calc_type g = (rgb >> 3) & 0xFC; calc_type b = (rgb << 3) & 0xF8; *p = (pixel_type) (((((cr - r) * alpha + (r << 8)) ) & 0xF800) | ((((cg - g) * alpha + (g << 8)) >> 5) & 0x07E0) | (((cb - b) * alpha + (b << 8)) >> 11)); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 8) & 0xF8, (p >> 3) & 0xFC, (p << 3) & 0xF8); } }; //=====================================================blender_rgb565_pre struct blender_rgb565_pre { typedef rgba8 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int16u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned cover) { alpha = color_type::base_mask - alpha; pixel_type rgb = *p; calc_type r = (rgb >> 8) & 0xF8; calc_type g = (rgb >> 3) & 0xFC; calc_type b = (rgb << 3) & 0xF8; *p = (pixel_type) ((((r * alpha + cr * cover) ) & 0xF800) | (((g * alpha + cg * cover) >> 5 ) & 0x07E0) | ((b * alpha + cb * cover) >> 11)); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 8) & 0xF8, (p >> 3) & 0xFC, (p << 3) & 0xF8); } }; //=====================================================blender_rgb565_gamma template class blender_rgb565_gamma { public: typedef rgba8 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int16u pixel_type; typedef Gamma gamma_type; blender_rgb565_gamma() : m_gamma(0) {} void gamma(const gamma_type& g) { m_gamma = &g; } AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type rgb = *p; calc_type r = m_gamma->dir((rgb >> 8) & 0xF8); calc_type g = m_gamma->dir((rgb >> 3) & 0xFC); calc_type b = m_gamma->dir((rgb << 3) & 0xF8); *p = (pixel_type) (((m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 8)) >> 8) << 8) & 0xF800) | ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 8)) >> 8) << 3) & 0x07E0) | (m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 8)) >> 8) >> 3)); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 8) & 0xF8, (p >> 3) & 0xFC, (p << 3) & 0xF8); } private: const Gamma* m_gamma; }; //=====================================================blender_rgbAAA struct blender_rgbAAA { typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type rgb = *p; calc_type r = (rgb >> 14) & 0xFFC0; calc_type g = (rgb >> 4) & 0xFFC0; calc_type b = (rgb << 6) & 0xFFC0; *p = (pixel_type) (((((cr - r) * alpha + (r << 16)) >> 2) & 0x3FF00000) | ((((cg - g) * alpha + (g << 16)) >> 12) & 0x000FFC00) | (((cb - b) * alpha + (b << 16)) >> 22) | 0xC0000000); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xFFC0) << 14) | ((g & 0xFFC0) << 4) | (b >> 6) | 0xC0000000); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 14) & 0xFFC0, (p >> 4) & 0xFFC0, (p << 6) & 0xFFC0); } }; //==================================================blender_rgbAAA_pre struct blender_rgbAAA_pre { typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned cover) { alpha = color_type::base_mask - alpha; cover = (cover + 1) << (color_type::base_shift - 8); pixel_type rgb = *p; calc_type r = (rgb >> 14) & 0xFFC0; calc_type g = (rgb >> 4) & 0xFFC0; calc_type b = (rgb << 6) & 0xFFC0; *p = (pixel_type) ((((r * alpha + cr * cover) >> 2) & 0x3FF00000) | (((g * alpha + cg * cover) >> 12) & 0x000FFC00) | ((b * alpha + cb * cover) >> 22) | 0xC0000000); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xFFC0) << 14) | ((g & 0xFFC0) << 4) | (b >> 6) | 0xC0000000); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 14) & 0xFFC0, (p >> 4) & 0xFFC0, (p << 6) & 0xFFC0); } }; //=================================================blender_rgbAAA_gamma template class blender_rgbAAA_gamma { public: typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; typedef Gamma gamma_type; blender_rgbAAA_gamma() : m_gamma(0) {} void gamma(const gamma_type& g) { m_gamma = &g; } AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type rgb = *p; calc_type r = m_gamma->dir((rgb >> 14) & 0xFFC0); calc_type g = m_gamma->dir((rgb >> 4) & 0xFFC0); calc_type b = m_gamma->dir((rgb << 6) & 0xFFC0); *p = (pixel_type) (((m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 16)) >> 16) << 14) & 0x3FF00000) | ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 16)) >> 16) << 4 ) & 0x000FFC00) | (m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 16)) >> 16) >> 6 ) | 0xC0000000); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xFFC0) << 14) | ((g & 0xFFC0) << 4) | (b >> 6) | 0xC0000000); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 14) & 0xFFC0, (p >> 4) & 0xFFC0, (p << 6) & 0xFFC0); } private: const Gamma* m_gamma; }; //=====================================================blender_bgrAAA struct blender_bgrAAA { typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type bgr = *p; calc_type b = (bgr >> 14) & 0xFFC0; calc_type g = (bgr >> 4) & 0xFFC0; calc_type r = (bgr << 6) & 0xFFC0; *p = (pixel_type) (((((cb - b) * alpha + (b << 16)) >> 2) & 0x3FF00000) | ((((cg - g) * alpha + (g << 16)) >> 12) & 0x000FFC00) | (((cr - r) * alpha + (r << 16)) >> 22) | 0xC0000000); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((b & 0xFFC0) << 14) | ((g & 0xFFC0) << 4) | (r >> 6) | 0xC0000000); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p << 6) & 0xFFC0, (p >> 4) & 0xFFC0, (p >> 14) & 0xFFC0); } }; //=================================================blender_bgrAAA_pre struct blender_bgrAAA_pre { typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned cover) { alpha = color_type::base_mask - alpha; cover = (cover + 1) << (color_type::base_shift - 8); pixel_type bgr = *p; calc_type b = (bgr >> 14) & 0xFFC0; calc_type g = (bgr >> 4) & 0xFFC0; calc_type r = (bgr << 6) & 0xFFC0; *p = (pixel_type) ((((b * alpha + cb * cover) >> 2) & 0x3FF00000) | (((g * alpha + cg * cover) >> 12) & 0x000FFC00) | ((r * alpha + cr * cover) >> 22) | 0xC0000000); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((b & 0xFFC0) << 14) | ((g & 0xFFC0) << 4) | (r >> 6) | 0xC0000000); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p << 6) & 0xFFC0, (p >> 4) & 0xFFC0, (p >> 14) & 0xFFC0); } }; //=================================================blender_bgrAAA_gamma template class blender_bgrAAA_gamma { public: typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; typedef Gamma gamma_type; blender_bgrAAA_gamma() : m_gamma(0) {} void gamma(const gamma_type& g) { m_gamma = &g; } AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type bgr = *p; calc_type b = m_gamma->dir((bgr >> 14) & 0xFFC0); calc_type g = m_gamma->dir((bgr >> 4) & 0xFFC0); calc_type r = m_gamma->dir((bgr << 6) & 0xFFC0); *p = (pixel_type) (((m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 16)) >> 16) << 14) & 0x3FF00000) | ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 16)) >> 16) << 4 ) & 0x000FFC00) | (m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 16)) >> 16) >> 6 ) | 0xC0000000); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((b & 0xFFC0) << 14) | ((g & 0xFFC0) << 4) | (r >> 6) | 0xC0000000); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p << 6) & 0xFFC0, (p >> 4) & 0xFFC0, (p >> 14) & 0xFFC0); } private: const Gamma* m_gamma; }; //=====================================================blender_rgbBBA struct blender_rgbBBA { typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type rgb = *p; calc_type r = (rgb >> 16) & 0xFFE0; calc_type g = (rgb >> 5) & 0xFFE0; calc_type b = (rgb << 6) & 0xFFC0; *p = (pixel_type) (((((cr - r) * alpha + (r << 16)) ) & 0xFFE00000) | ((((cg - g) * alpha + (g << 16)) >> 11) & 0x001FFC00) | (((cb - b) * alpha + (b << 16)) >> 22)); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xFFE0) << 16) | ((g & 0xFFE0) << 5) | (b >> 6)); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 16) & 0xFFE0, (p >> 5) & 0xFFE0, (p << 6) & 0xFFC0); } }; //=================================================blender_rgbBBA_pre struct blender_rgbBBA_pre { typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned cover) { alpha = color_type::base_mask - alpha; cover = (cover + 1) << (color_type::base_shift - 8); pixel_type rgb = *p; calc_type r = (rgb >> 16) & 0xFFE0; calc_type g = (rgb >> 5) & 0xFFE0; calc_type b = (rgb << 6) & 0xFFC0; *p = (pixel_type) ((((r * alpha + cr * cover) ) & 0xFFE00000) | (((g * alpha + cg * cover) >> 11) & 0x001FFC00) | ((b * alpha + cb * cover) >> 22)); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xFFE0) << 16) | ((g & 0xFFE0) << 5) | (b >> 6)); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 16) & 0xFFE0, (p >> 5) & 0xFFE0, (p << 6) & 0xFFC0); } }; //=================================================blender_rgbBBA_gamma template class blender_rgbBBA_gamma { public: typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; typedef Gamma gamma_type; blender_rgbBBA_gamma() : m_gamma(0) {} void gamma(const gamma_type& g) { m_gamma = &g; } AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type rgb = *p; calc_type r = m_gamma->dir((rgb >> 16) & 0xFFE0); calc_type g = m_gamma->dir((rgb >> 5) & 0xFFE0); calc_type b = m_gamma->dir((rgb << 6) & 0xFFC0); *p = (pixel_type) (((m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 16)) >> 16) << 16) & 0xFFE00000) | ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 16)) >> 16) << 5 ) & 0x001FFC00) | (m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 16)) >> 16) >> 6 )); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((r & 0xFFE0) << 16) | ((g & 0xFFE0) << 5) | (b >> 6)); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p >> 16) & 0xFFE0, (p >> 5) & 0xFFE0, (p << 6) & 0xFFC0); } private: const Gamma* m_gamma; }; //=====================================================blender_bgrABB struct blender_bgrABB { typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type bgr = *p; calc_type b = (bgr >> 16) & 0xFFC0; calc_type g = (bgr >> 6) & 0xFFE0; calc_type r = (bgr << 5) & 0xFFE0; *p = (pixel_type) (((((cb - b) * alpha + (b << 16)) ) & 0xFFC00000) | ((((cg - g) * alpha + (g << 16)) >> 10) & 0x003FF800) | (((cr - r) * alpha + (r << 16)) >> 21)); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((b & 0xFFC0) << 16) | ((g & 0xFFE0) << 6) | (r >> 5)); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p << 5) & 0xFFE0, (p >> 6) & 0xFFE0, (p >> 16) & 0xFFC0); } }; //=================================================blender_bgrABB_pre struct blender_bgrABB_pre { typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; static AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned cover) { alpha = color_type::base_mask - alpha; cover = (cover + 1) << (color_type::base_shift - 8); pixel_type bgr = *p; calc_type b = (bgr >> 16) & 0xFFC0; calc_type g = (bgr >> 6) & 0xFFE0; calc_type r = (bgr << 5) & 0xFFE0; *p = (pixel_type) ((((b * alpha + cb * cover) ) & 0xFFC00000) | (((g * alpha + cg * cover) >> 10) & 0x003FF800) | ((r * alpha + cr * cover) >> 21)); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((b & 0xFFC0) << 16) | ((g & 0xFFE0) << 6) | (r >> 5)); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p << 5) & 0xFFE0, (p >> 6) & 0xFFE0, (p >> 16) & 0xFFC0); } }; //=================================================blender_bgrABB_gamma template class blender_bgrABB_gamma { public: typedef rgba16 color_type; typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; typedef int32u pixel_type; typedef Gamma gamma_type; blender_bgrABB_gamma() : m_gamma(0) {} void gamma(const gamma_type& g) { m_gamma = &g; } AGG_INLINE void blend_pix(pixel_type* p, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned) { pixel_type bgr = *p; calc_type b = m_gamma->dir((bgr >> 16) & 0xFFC0); calc_type g = m_gamma->dir((bgr >> 6) & 0xFFE0); calc_type r = m_gamma->dir((bgr << 5) & 0xFFE0); *p = (pixel_type) (((m_gamma->inv(((m_gamma->dir(cb) - b) * alpha + (b << 16)) >> 16) << 16) & 0xFFC00000) | ((m_gamma->inv(((m_gamma->dir(cg) - g) * alpha + (g << 16)) >> 16) << 6 ) & 0x003FF800) | (m_gamma->inv(((m_gamma->dir(cr) - r) * alpha + (r << 16)) >> 16) >> 5 )); } static AGG_INLINE pixel_type make_pix(unsigned r, unsigned g, unsigned b) { return (pixel_type)(((b & 0xFFC0) << 16) | ((g & 0xFFE0) << 6) | (r >> 5)); } static AGG_INLINE color_type make_color(pixel_type p) { return color_type((p << 5) & 0xFFE0, (p >> 6) & 0xFFE0, (p >> 16) & 0xFFC0); } private: const Gamma* m_gamma; }; //===========================================pixfmt_alpha_blend_rgb_packed template class pixfmt_alpha_blend_rgb_packed { public: typedef RenBuf rbuf_type; typedef typename rbuf_type::row_data row_data; typedef Blender blender_type; typedef typename blender_type::color_type color_type; typedef typename blender_type::pixel_type pixel_type; typedef int order_type; // A fake one typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; enum base_scale_e { base_shift = color_type::base_shift, base_scale = color_type::base_scale, base_mask = color_type::base_mask, pix_width = sizeof(pixel_type), }; private: //-------------------------------------------------------------------- AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover) { if (c.a) { calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; if(alpha == base_mask) { *p = m_blender.make_pix(c.r, c.g, c.b); } else { m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); } } } public: //-------------------------------------------------------------------- explicit pixfmt_alpha_blend_rgb_packed(rbuf_type& rb) : m_rbuf(&rb) {} void attach(rbuf_type& rb) { m_rbuf = &rb; } //-------------------------------------------------------------------- template bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) { rect_i r(x1, y1, x2, y2); if(r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) { int stride = pixf.stride(); m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), (r.x2 - r.x1) + 1, (r.y2 - r.y1) + 1, stride); return true; } return false; } Blender& blender() { return m_blender; } //-------------------------------------------------------------------- AGG_INLINE unsigned width() const { return m_rbuf->width(); } AGG_INLINE unsigned height() const { return m_rbuf->height(); } AGG_INLINE int stride() const { return m_rbuf->stride(); } //-------------------------------------------------------------------- AGG_INLINE int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } AGG_INLINE row_data row(int y) const { return m_rbuf->row(y); } //-------------------------------------------------------------------- AGG_INLINE int8u* pix_ptr(int x, int y) { return m_rbuf->row_ptr(y) + x * pix_width; } AGG_INLINE const int8u* pix_ptr(int x, int y) const { return m_rbuf->row_ptr(y) + x * pix_width; } //-------------------------------------------------------------------- AGG_INLINE void make_pix(int8u* p, const color_type& c) { *(pixel_type*)p = m_blender.make_pix(c.r, c.g, c.b); } //-------------------------------------------------------------------- AGG_INLINE color_type pixel(int x, int y) const { return m_blender.make_color(((pixel_type*)m_rbuf->row_ptr(y))[x]); } //-------------------------------------------------------------------- AGG_INLINE void copy_pixel(int x, int y, const color_type& c) { ((pixel_type*) m_rbuf->row_ptr(x, y, 1))[x] = m_blender.make_pix(c.r, c.g, c.b); } //-------------------------------------------------------------------- AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) { copy_or_blend_pix((pixel_type*)m_rbuf->row_ptr(x, y, 1) + x, c, cover); } //-------------------------------------------------------------------- AGG_INLINE void copy_hline(int x, int y, unsigned len, const color_type& c) { pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y, len) + x; pixel_type v = m_blender.make_pix(c.r, c.g, c.b); do { *p++ = v; } while(--len); } //-------------------------------------------------------------------- AGG_INLINE void copy_vline(int x, int y, unsigned len, const color_type& c) { pixel_type v = m_blender.make_pix(c.r, c.g, c.b); do { pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y++, 1) + x; *p = v; } while(--len); } //-------------------------------------------------------------------- void blend_hline(int x, int y, unsigned len, const color_type& c, int8u cover) { if (c.a) { pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y, len) + x; calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; if(alpha == base_mask) { pixel_type v = m_blender.make_pix(c.r, c.g, c.b); do { *p++ = v; } while(--len); } else { do { m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); ++p; } while(--len); } } } //-------------------------------------------------------------------- void blend_vline(int x, int y, unsigned len, const color_type& c, int8u cover) { if (c.a) { calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; if(alpha == base_mask) { pixel_type v = m_blender.make_pix(c.r, c.g, c.b); do { ((pixel_type*)m_rbuf->row_ptr(x, y++, 1))[x] = v; } while(--len); } else { do { m_blender.blend_pix( (pixel_type*)m_rbuf->row_ptr(x, y++, 1), c.r, c.g, c.b, alpha, cover); } while(--len); } } } //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y, len) + x; do { copy_or_blend_pix(p, c, *covers++); ++p; } while(--len); } //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { do { copy_or_blend_pix((pixel_type*)m_rbuf->row_ptr(x, y++, 1) + x, c, *covers++); } while(--len); } //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, unsigned len, const color_type* colors) { pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y, len) + x; do { *p++ = m_blender.make_pix(colors->r, colors->g, colors->b); ++colors; } while(--len); } //-------------------------------------------------------------------- void copy_color_vspan(int x, int y, unsigned len, const color_type* colors) { do { pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y++, 1) + x; *p = m_blender.make_pix(colors->r, colors->g, colors->b); ++colors; } while(--len); } //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y, len) + x; do { copy_or_blend_pix(p++, *colors++, covers ? *covers++ : cover); } while(--len); } //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { do { copy_or_blend_pix((pixel_type*)m_rbuf->row_ptr(x, y++, 1) + x, *colors++, covers ? *covers++ : cover); } while(--len); } //-------------------------------------------------------------------- template void copy_from(const RenBuf2& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len) { const int8u* p = from.row_ptr(ysrc); if(p) { std::memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, p + xsrc * pix_width, len * pix_width); } } //-------------------------------------------------------------------- template void blend_from(const SrcPixelFormatRenderer& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::order_type src_order; const value_type* psrc = (const value_type*)from.row_ptr(ysrc); if(psrc) { psrc += xsrc * 4; pixel_type* pdst = (pixel_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; do { value_type alpha = psrc[src_order::A]; if(alpha) { if(alpha == base_mask && cover == 255) { *pdst = m_blender.make_pix(psrc[src_order::R], psrc[src_order::G], psrc[src_order::B]); } else { m_blender.blend_pix(pdst, psrc[src_order::R], psrc[src_order::G], psrc[src_order::B], alpha, cover); } } psrc += 4; ++pdst; } while(--len); } } //-------------------------------------------------------------------- template void blend_from_color(const SrcPixelFormatRenderer& from, const color_type& color, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::value_type src_value_type; typedef typename SrcPixelFormatRenderer::color_type src_color_type; const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); if(psrc) { psrc += xsrc * SrcPixelFormatRenderer::pix_step + SrcPixelFormatRenderer::pix_offset; pixel_type* pdst = (pixel_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; do { m_blender.blend_pix(pdst, color.r, color.g, color.b, color.a, cover); psrc += SrcPixelFormatRenderer::pix_step; ++pdst; } while(--len); } } //-------------------------------------------------------------------- template void blend_from_lut(const SrcPixelFormatRenderer& from, const color_type* color_lut, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::value_type src_value_type; const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); if(psrc) { psrc += xsrc * SrcPixelFormatRenderer::pix_step + SrcPixelFormatRenderer::pix_offset; pixel_type* pdst = (pixel_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; do { const color_type& color = color_lut[*psrc]; m_blender.blend_pix(pdst, color.r, color.g, color.b, color.a, cover); psrc += SrcPixelFormatRenderer::pix_step; ++pdst; } while(--len); } } private: rbuf_type* m_rbuf; Blender m_blender; }; typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgb555; //----pixfmt_rgb555 typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgb565; //----pixfmt_rgb565 typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgb555_pre; //----pixfmt_rgb555_pre typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgb565_pre; //----pixfmt_rgb565_pre typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgbAAA; //----pixfmt_rgbAAA typedef pixfmt_alpha_blend_rgb_packed pixfmt_bgrAAA; //----pixfmt_bgrAAA typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgbBBA; //----pixfmt_rgbBBA typedef pixfmt_alpha_blend_rgb_packed pixfmt_bgrABB; //----pixfmt_bgrABB typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgbAAA_pre; //----pixfmt_rgbAAA_pre typedef pixfmt_alpha_blend_rgb_packed pixfmt_bgrAAA_pre; //----pixfmt_bgrAAA_pre typedef pixfmt_alpha_blend_rgb_packed pixfmt_rgbBBA_pre; //----pixfmt_rgbBBA_pre typedef pixfmt_alpha_blend_rgb_packed pixfmt_bgrABB_pre; //----pixfmt_bgrABB_pre //-----------------------------------------------------pixfmt_rgb555_gamma template class pixfmt_rgb555_gamma : public pixfmt_alpha_blend_rgb_packed, rendering_buffer> { public: pixfmt_rgb555_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb_packed, rendering_buffer>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_rgb565_gamma template class pixfmt_rgb565_gamma : public pixfmt_alpha_blend_rgb_packed, rendering_buffer> { public: pixfmt_rgb565_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb_packed, rendering_buffer>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_rgbAAA_gamma template class pixfmt_rgbAAA_gamma : public pixfmt_alpha_blend_rgb_packed, rendering_buffer> { public: pixfmt_rgbAAA_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb_packed, rendering_buffer>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_bgrAAA_gamma template class pixfmt_bgrAAA_gamma : public pixfmt_alpha_blend_rgb_packed, rendering_buffer> { public: pixfmt_bgrAAA_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb_packed, rendering_buffer>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_rgbBBA_gamma template class pixfmt_rgbBBA_gamma : public pixfmt_alpha_blend_rgb_packed, rendering_buffer> { public: pixfmt_rgbBBA_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb_packed, rendering_buffer>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_bgrABB_gamma template class pixfmt_bgrABB_gamma : public pixfmt_alpha_blend_rgb_packed, rendering_buffer> { public: pixfmt_bgrABB_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb_packed, rendering_buffer>(rb) { this->blender().gamma(g); } }; } #endif ragg/src/agg/include/agg_vpgen_clip_polygon.h0000644000176200001440000000455613504406270021041 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_VPGEN_CLIP_POLYGON_INCLUDED #define AGG_VPGEN_CLIP_POLYGON_INCLUDED #include "agg_basics.h" namespace agg { //======================================================vpgen_clip_polygon // // See Implementation agg_vpgen_clip_polygon.cpp // class vpgen_clip_polygon { public: vpgen_clip_polygon() : m_clip_box(0, 0, 1, 1), m_x1(0), m_y1(0), m_clip_flags(0), m_num_vertices(0), m_vertex(0), m_cmd(path_cmd_move_to) { } void clip_box(double x1, double y1, double x2, double y2) { m_clip_box.x1 = x1; m_clip_box.y1 = y1; m_clip_box.x2 = x2; m_clip_box.y2 = y2; m_clip_box.normalize(); } double x1() const { return m_clip_box.x1; } double y1() const { return m_clip_box.y1; } double x2() const { return m_clip_box.x2; } double y2() const { return m_clip_box.y2; } static bool auto_close() { return true; } static bool auto_unclose() { return false; } void reset(); void move_to(double x, double y); void line_to(double x, double y); unsigned vertex(double* x, double* y); private: unsigned clipping_flags(double x, double y); private: rect_d m_clip_box; double m_x1; double m_y1; unsigned m_clip_flags; double m_x[4]; double m_y[4]; unsigned m_num_vertices; unsigned m_vertex; unsigned m_cmd; }; } #endif ragg/src/agg/include/agg_scanline_u.h0000644000176200001440000004125414136003606017256 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for 32-bit screen coordinates (scanline32_u) 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_SCANLINE_U_INCLUDED #define AGG_SCANLINE_U_INCLUDED #include #include "agg_array.h" namespace agg { //=============================================================scanline_u8 // // Unpacked scanline container class // // This class is used to transfer data from a scanline rasterizer // to the rendering buffer. It's organized very simple. The class stores // information of horizontal spans to render it into a pixel-map buffer. // Each span has staring X, length, and an array of bytes that determine the // cover-values for each pixel. // Before using this class you should know the minimal and maximal pixel // coordinates of your scanline. The protocol of using is: // 1. reset(min_x, max_x) // 2. add_cell() / add_span() - accumulate scanline. // When forming one scanline the next X coordinate must be always greater // than the last stored one, i.e. it works only with ordered coordinates. // 3. Call finalize(y) and render the scanline. // 3. Call reset_spans() to prepare for the new scanline. // // 4. Rendering: // // Scanline provides an iterator class that allows you to extract // the spans and the cover values for each pixel. Be aware that clipping // has not been done yet, so you should perform it yourself. // Use scanline_u8::iterator to render spans: //------------------------------------------------------------------------- // // int y = sl.y(); // Y-coordinate of the scanline // // ************************************ // ...Perform vertical clipping here... // ************************************ // // scanline_u8::const_iterator span = sl.begin(); // // unsigned char* row = m_rbuf->row(y); // The address of the beginning // // of the current row // // unsigned num_spans = sl.num_spans(); // Number of spans. It's guaranteed that // // num_spans is always greater than 0. // // do // { // const scanline_u8::cover_type* covers = // span->covers; // The array of the cover values // // int num_pix = span->len; // Number of pixels of the span. // // Always greater than 0, still it's // // better to use "int" instead of // // "unsigned" because it's more // // convenient for clipping // int x = span->x; // // ************************************** // ...Perform horizontal clipping here... // ...you have x, covers, and pix_count.. // ************************************** // // unsigned char* dst = row + x; // Calculate the start address of the row. // // In this case we assume a simple // // grayscale image 1-byte per pixel. // do // { // *dst++ = *covers++; // Hypotetical rendering. // } // while(--num_pix); // // ++span; // } // while(--num_spans); // num_spans cannot be 0, so this loop is quite safe //------------------------------------------------------------------------ // // The question is: why should we accumulate the whole scanline when we // could render just separate spans when they're ready? // That's because using the scanline is generally faster. When is consists // of more than one span the conditions for the processor cash system // are better, because switching between two different areas of memory // (that can be very large) occurs less frequently. //------------------------------------------------------------------------ class scanline_u8 { public: typedef scanline_u8 self_type; typedef int8u cover_type; typedef int16 coord_type; //-------------------------------------------------------------------- struct span { coord_type x; coord_type len; cover_type* covers; }; typedef span* iterator; typedef const span* const_iterator; //-------------------------------------------------------------------- scanline_u8() : m_min_x(0), m_last_x(0x7FFFFFF0), m_cur_span(0) {} //-------------------------------------------------------------------- void reset(int min_x, int max_x) { unsigned max_len = max_x - min_x + 2; if(max_len > m_spans.size()) { m_spans.resize(max_len); m_covers.resize(max_len); } m_last_x = 0x7FFFFFF0; m_min_x = min_x; m_cur_span = &m_spans[0]; } //-------------------------------------------------------------------- void add_cell(int x, unsigned cover) { x -= m_min_x; m_covers[x] = (cover_type)cover; if(x == m_last_x+1) { m_cur_span->len++; } else { m_cur_span++; m_cur_span->x = (coord_type)(x + m_min_x); m_cur_span->len = 1; m_cur_span->covers = &m_covers[x]; } m_last_x = x; } //-------------------------------------------------------------------- void add_cells(int x, unsigned len, const cover_type* covers) { x -= m_min_x; std::memcpy(&m_covers[x], covers, len * sizeof(cover_type)); if(x == m_last_x+1) { m_cur_span->len += (coord_type)len; } else { m_cur_span++; m_cur_span->x = (coord_type)(x + m_min_x); m_cur_span->len = (coord_type)len; m_cur_span->covers = &m_covers[x]; } m_last_x = x + len - 1; } //-------------------------------------------------------------------- void add_span(int x, unsigned len, unsigned cover) { x -= m_min_x; std::memset(&m_covers[x], cover, len); if(x == m_last_x+1) { m_cur_span->len += (coord_type)len; } else { m_cur_span++; m_cur_span->x = (coord_type)(x + m_min_x); m_cur_span->len = (coord_type)len; m_cur_span->covers = &m_covers[x]; } m_last_x = x + len - 1; } //-------------------------------------------------------------------- void finalize(int y) { m_y = y; } //-------------------------------------------------------------------- void reset_spans() { m_last_x = 0x7FFFFFF0; m_cur_span = &m_spans[0]; } //-------------------------------------------------------------------- int y() const { return m_y; } unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); } const_iterator begin() const { return &m_spans[1]; } iterator begin() { return &m_spans[1]; } private: scanline_u8(const self_type&); const self_type& operator = (const self_type&); private: int m_min_x; int m_last_x; int m_y; pod_array m_covers; pod_array m_spans; span* m_cur_span; }; //==========================================================scanline_u8_am // // The scanline container with alpha-masking // //------------------------------------------------------------------------ template class scanline_u8_am : public scanline_u8 { public: typedef scanline_u8 base_type; typedef AlphaMask alpha_mask_type; typedef base_type::cover_type cover_type; typedef base_type::coord_type coord_type; scanline_u8_am() : base_type(), m_alpha_mask(0) {} scanline_u8_am(AlphaMask& am) : base_type(), m_alpha_mask(&am) {} //-------------------------------------------------------------------- void finalize(int span_y) { base_type::finalize(span_y); if(m_alpha_mask) { typename base_type::iterator span = base_type::begin(); unsigned count = base_type::num_spans(); do { m_alpha_mask->combine_hspan(span->x, base_type::y(), span->covers, span->len); ++span; } while(--count); } } private: AlphaMask* m_alpha_mask; }; //===========================================================scanline32_u8 class scanline32_u8 { public: typedef scanline32_u8 self_type; typedef int8u cover_type; typedef int32 coord_type; //-------------------------------------------------------------------- struct span { span() {} span(coord_type x_, coord_type len_, cover_type* covers_) : x(x_), len(len_), covers(covers_) {} coord_type x; coord_type len; cover_type* covers; }; typedef pod_bvector span_array_type; //-------------------------------------------------------------------- class const_iterator { public: const_iterator(const span_array_type& spans) : m_spans(spans), m_span_idx(0) {} const span& operator*() const { return m_spans[m_span_idx]; } const span* operator->() const { return &m_spans[m_span_idx]; } void operator ++ () { ++m_span_idx; } private: const span_array_type& m_spans; unsigned m_span_idx; }; //-------------------------------------------------------------------- class iterator { public: iterator(span_array_type& spans) : m_spans(spans), m_span_idx(0) {} span& operator*() { return m_spans[m_span_idx]; } span* operator->() { return &m_spans[m_span_idx]; } void operator ++ () { ++m_span_idx; } private: span_array_type& m_spans; unsigned m_span_idx; }; //-------------------------------------------------------------------- scanline32_u8() : m_min_x(0), m_last_x(0x7FFFFFF0), m_covers() {} //-------------------------------------------------------------------- void reset(int min_x, int max_x) { unsigned max_len = max_x - min_x + 2; if(max_len > m_covers.size()) { m_covers.resize(max_len); } m_last_x = 0x7FFFFFF0; m_min_x = min_x; m_spans.remove_all(); } //-------------------------------------------------------------------- void add_cell(int x, unsigned cover) { x -= m_min_x; m_covers[x] = cover_type(cover); if(x == m_last_x+1) { m_spans.last().len++; } else { m_spans.add(span(coord_type(x + m_min_x), 1, &m_covers[x])); } m_last_x = x; } //-------------------------------------------------------------------- void add_cells(int x, unsigned len, const cover_type* covers) { x -= m_min_x; std::memcpy(&m_covers[x], covers, len * sizeof(cover_type)); if(x == m_last_x+1) { m_spans.last().len += coord_type(len); } else { m_spans.add(span(coord_type(x + m_min_x), coord_type(len), &m_covers[x])); } m_last_x = x + len - 1; } //-------------------------------------------------------------------- void add_span(int x, unsigned len, unsigned cover) { x -= m_min_x; std::memset(&m_covers[x], cover, len); if(x == m_last_x+1) { m_spans.last().len += coord_type(len); } else { m_spans.add(span(coord_type(x + m_min_x), coord_type(len), &m_covers[x])); } m_last_x = x + len - 1; } //-------------------------------------------------------------------- void finalize(int y) { m_y = y; } //-------------------------------------------------------------------- void reset_spans() { m_last_x = 0x7FFFFFF0; m_spans.remove_all(); } //-------------------------------------------------------------------- int y() const { return m_y; } unsigned num_spans() const { return m_spans.size(); } const_iterator begin() const { return const_iterator(m_spans); } iterator begin() { return iterator(m_spans); } private: scanline32_u8(const self_type&); const self_type& operator = (const self_type&); private: int m_min_x; int m_last_x; int m_y; pod_array m_covers; span_array_type m_spans; }; //========================================================scanline32_u8_am // // The scanline container with alpha-masking // //------------------------------------------------------------------------ template class scanline32_u8_am : public scanline32_u8 { public: typedef scanline32_u8 base_type; typedef AlphaMask alpha_mask_type; typedef base_type::cover_type cover_type; typedef base_type::coord_type coord_type; scanline32_u8_am() : base_type(), m_alpha_mask(0) {} scanline32_u8_am(AlphaMask& am) : base_type(), m_alpha_mask(&am) {} //-------------------------------------------------------------------- void finalize(int span_y) { base_type::finalize(span_y); if(m_alpha_mask) { typename base_type::iterator span = base_type::begin(); unsigned count = base_type::num_spans(); do { m_alpha_mask->combine_hspan(span->x, base_type::y(), span->covers, span->len); ++span; } while(--count); } } private: AlphaMask* m_alpha_mask; }; } #endif ragg/src/agg/include/agg_trans_single_path.h0000644000176200001440000000564613504406270020651 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_TRANS_SINGLE_PATH_INCLUDED #define AGG_TRANS_SINGLE_PATH_INCLUDED #include "agg_basics.h" #include "agg_vertex_sequence.h" namespace agg { // See also: agg_trans_single_path.cpp // //-------------------------------------------------------trans_single_path class trans_single_path { enum status_e { initial, making_path, ready }; public: typedef vertex_sequence vertex_storage; trans_single_path(); //-------------------------------------------------------------------- void base_length(double v) { m_base_length = v; } double base_length() const { return m_base_length; } //-------------------------------------------------------------------- void preserve_x_scale(bool f) { m_preserve_x_scale = f; } bool preserve_x_scale() const { return m_preserve_x_scale; } //-------------------------------------------------------------------- void reset(); void move_to(double x, double y); void line_to(double x, double y); void finalize_path(); //-------------------------------------------------------------------- template void add_path(VertexSource& vs, unsigned path_id=0) { double x; double y; unsigned cmd; vs.rewind(path_id); while(!is_stop(cmd = vs.vertex(&x, &y))) { if(is_move_to(cmd)) { move_to(x, y); } else { if(is_vertex(cmd)) { line_to(x, y); } } } finalize_path(); } //-------------------------------------------------------------------- double total_length() const; void transform(double *x, double *y) const; private: vertex_storage m_src_vertices; double m_base_length; double m_kindex; status_e m_status; bool m_preserve_x_scale; }; } #endif ragg/src/agg/include/agg_conv_smooth_poly1.h0000644000176200001440000000521313504406270020615 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Smooth polygon generator // //---------------------------------------------------------------------------- #ifndef AGG_CONV_SMOOTH_POLY1_INCLUDED #define AGG_CONV_SMOOTH_POLY1_INCLUDED #include "agg_basics.h" #include "agg_vcgen_smooth_poly1.h" #include "agg_conv_adaptor_vcgen.h" #include "agg_conv_curve.h" namespace agg { //-------------------------------------------------------conv_smooth_poly1 template struct conv_smooth_poly1 : public conv_adaptor_vcgen { typedef conv_adaptor_vcgen base_type; conv_smooth_poly1(VertexSource& vs) : conv_adaptor_vcgen(vs) { } void smooth_value(double v) { base_type::generator().smooth_value(v); } double smooth_value() const { return base_type::generator().smooth_value(); } private: conv_smooth_poly1(const conv_smooth_poly1&); const conv_smooth_poly1& operator = (const conv_smooth_poly1&); }; //-------------------------------------------------conv_smooth_poly1_curve template struct conv_smooth_poly1_curve : public conv_curve > { conv_smooth_poly1_curve(VertexSource& vs) : conv_curve >(m_smooth), m_smooth(vs) { } void smooth_value(double v) { m_smooth.generator().smooth_value(v); } double smooth_value() const { return m_smooth.generator().smooth_value(); } private: conv_smooth_poly1_curve(const conv_smooth_poly1_curve&); const conv_smooth_poly1_curve& operator = (const conv_smooth_poly1_curve&); conv_smooth_poly1 m_smooth; }; } #endif ragg/src/agg/include/agg_span_interpolator_adaptor.h0000644000176200001440000000510013504406270022403 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_SPAN_INTERPOLATOR_ADAPTOR_INCLUDED #define AGG_SPAN_INTERPOLATOR_ADAPTOR_INCLUDED #include "agg_basics.h" namespace agg { //===============================================span_interpolator_adaptor template class span_interpolator_adaptor : public Interpolator { public: typedef Interpolator base_type; typedef typename base_type::trans_type trans_type; typedef Distortion distortion_type; //-------------------------------------------------------------------- span_interpolator_adaptor() {} span_interpolator_adaptor(trans_type& trans, distortion_type& dist) : base_type(trans), m_distortion(&dist) { } //-------------------------------------------------------------------- span_interpolator_adaptor(trans_type& trans, distortion_type& dist, double x, double y, unsigned len) : base_type(trans, x, y, len), m_distortion(&dist) { } //-------------------------------------------------------------------- distortion_type& distortion() const { return *m_distortion; } //-------------------------------------------------------------------- void distortion(distortion_type& dist) { m_distortion = dist; } //-------------------------------------------------------------------- void coordinates(int* x, int* y) const { base_type::coordinates(x, y); m_distortion->calculate(x, y); } private: //-------------------------------------------------------------------- distortion_type* m_distortion; }; } #endif ragg/src/agg/include/agg_span_subdiv_adaptor.h0000644000176200001440000001132413504406270021162 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_SPAN_SUBDIV_ADAPTOR_INCLUDED #define AGG_SPAN_SUBDIV_ADAPTOR_INCLUDED #include "agg_basics.h" namespace agg { //=================================================span_subdiv_adaptor template class span_subdiv_adaptor { public: typedef Interpolator interpolator_type; typedef typename interpolator_type::trans_type trans_type; enum sublixel_scale_e { subpixel_shift = SubpixelShift, subpixel_scale = 1 << subpixel_shift }; //---------------------------------------------------------------- span_subdiv_adaptor() : m_subdiv_shift(4), m_subdiv_size(1 << m_subdiv_shift), m_subdiv_mask(m_subdiv_size - 1) {} span_subdiv_adaptor(interpolator_type& interpolator, unsigned subdiv_shift = 4) : m_subdiv_shift(subdiv_shift), m_subdiv_size(1 << m_subdiv_shift), m_subdiv_mask(m_subdiv_size - 1), m_interpolator(&interpolator) {} span_subdiv_adaptor(interpolator_type& interpolator, double x, double y, unsigned len, unsigned subdiv_shift = 4) : m_subdiv_shift(subdiv_shift), m_subdiv_size(1 << m_subdiv_shift), m_subdiv_mask(m_subdiv_size - 1), m_interpolator(&interpolator) { begin(x, y, len); } //---------------------------------------------------------------- const interpolator_type& interpolator() const { return *m_interpolator; } void interpolator(interpolator_type& intr) { m_interpolator = &intr; } //---------------------------------------------------------------- const trans_type& transformer() const { return *m_interpolator->transformer(); } void transformer(const trans_type& trans) { m_interpolator->transformer(trans); } //---------------------------------------------------------------- unsigned subdiv_shift() const { return m_subdiv_shift; } void subdiv_shift(unsigned shift) { m_subdiv_shift = shift; m_subdiv_size = 1 << m_subdiv_shift; m_subdiv_mask = m_subdiv_size - 1; } //---------------------------------------------------------------- void begin(double x, double y, unsigned len) { m_pos = 1; m_src_x = iround(x * subpixel_scale) + subpixel_scale; m_src_y = y; m_len = len; if(len > m_subdiv_size) len = m_subdiv_size; m_interpolator->begin(x, y, len); } //---------------------------------------------------------------- void operator++() { ++(*m_interpolator); if(m_pos >= m_subdiv_size) { unsigned len = m_len; if(len > m_subdiv_size) len = m_subdiv_size; m_interpolator->resynchronize(double(m_src_x) / double(subpixel_scale) + len, m_src_y, len); m_pos = 0; } m_src_x += subpixel_scale; ++m_pos; --m_len; } //---------------------------------------------------------------- void coordinates(int* x, int* y) const { m_interpolator->coordinates(x, y); } //---------------------------------------------------------------- void local_scale(int* x, int* y) const { m_interpolator->local_scale(x, y); } private: unsigned m_subdiv_shift; unsigned m_subdiv_size; unsigned m_subdiv_mask; interpolator_type* m_interpolator; int m_src_x; double m_src_y; unsigned m_pos; unsigned m_len; }; } #endif ragg/src/agg/include/agg_conv_stroke.h0000644000176200001440000000611413504406270017470 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // conv_stroke // //---------------------------------------------------------------------------- #ifndef AGG_CONV_STROKE_INCLUDED #define AGG_CONV_STROKE_INCLUDED #include "agg_basics.h" #include "agg_vcgen_stroke.h" #include "agg_conv_adaptor_vcgen.h" namespace agg { //-------------------------------------------------------------conv_stroke template struct conv_stroke : public conv_adaptor_vcgen { typedef Markers marker_type; typedef conv_adaptor_vcgen base_type; conv_stroke(VertexSource& vs) : conv_adaptor_vcgen(vs) { } void line_cap(line_cap_e lc) { base_type::generator().line_cap(lc); } void line_join(line_join_e lj) { base_type::generator().line_join(lj); } void inner_join(inner_join_e ij) { base_type::generator().inner_join(ij); } line_cap_e line_cap() const { return base_type::generator().line_cap(); } line_join_e line_join() const { return base_type::generator().line_join(); } inner_join_e inner_join() const { return base_type::generator().inner_join(); } void width(double w) { base_type::generator().width(w); } void miter_limit(double ml) { base_type::generator().miter_limit(ml); } void miter_limit_theta(double t) { base_type::generator().miter_limit_theta(t); } void inner_miter_limit(double ml) { base_type::generator().inner_miter_limit(ml); } void approximation_scale(double as) { base_type::generator().approximation_scale(as); } double width() const { return base_type::generator().width(); } double miter_limit() const { return base_type::generator().miter_limit(); } double inner_miter_limit() const { return base_type::generator().inner_miter_limit(); } double approximation_scale() const { return base_type::generator().approximation_scale(); } void shorten(double s) { base_type::generator().shorten(s); } double shorten() const { return base_type::generator().shorten(); } private: conv_stroke(const conv_stroke&); const conv_stroke& operator = (const conv_stroke&); }; } #endif ragg/src/agg/include/agg_shorten_path.h0000644000176200001440000000376013504406270017636 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_SHORTEN_PATH_INCLUDED #define AGG_SHORTEN_PATH_INCLUDED #include "agg_basics.h" #include "agg_vertex_sequence.h" namespace agg { //===========================================================shorten_path template void shorten_path(VertexSequence& vs, double s, unsigned closed = 0) { typedef typename VertexSequence::value_type vertex_type; if(s > 0.0 && vs.size() > 1) { double d; int n = int(vs.size() - 2); while(n) { d = vs[n].dist; if(d > s) break; vs.remove_last(); s -= d; --n; } if(vs.size() < 2) { vs.remove_all(); } else { n = vs.size() - 1; vertex_type& prev = vs[n-1]; vertex_type& last = vs[n]; d = (prev.dist - s) / prev.dist; double x = prev.x + (last.x - prev.x) * d; double y = prev.y + (last.y - prev.y) * d; last.x = x; last.y = y; if(!prev(last)) vs.remove_last(); vs.close(closed != 0); } } } } #endif ragg/src/agg/include/agg_conv_bspline.h0000644000176200001440000000321313504406270017612 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_CONV_BSPLINE_INCLUDED #define AGG_CONV_BSPLINE_INCLUDED #include "agg_basics.h" #include "agg_vcgen_bspline.h" #include "agg_conv_adaptor_vcgen.h" namespace agg { //---------------------------------------------------------conv_bspline template struct conv_bspline : public conv_adaptor_vcgen { typedef conv_adaptor_vcgen base_type; conv_bspline(VertexSource& vs) : conv_adaptor_vcgen(vs) {} void interpolation_step(double v) { base_type::generator().interpolation_step(v); } double interpolation_step() const { return base_type::generator().interpolation_step(); } private: conv_bspline(const conv_bspline&); const conv_bspline& operator = (const conv_bspline&); }; } #endif ragg/src/agg/include/agg_conv_gpc.h0000644000176200001440000003074413504406270016740 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // General Polygon Clipper based on the GPC library by Alan Murta // Union, Intersection, XOR, A-B, B-A // Contact the author if you intend to use it in commercial applications! // http://www.cs.man.ac.uk/aig/staff/alan/software/ // Alan Murta (email: gpc@cs.man.ac.uk) // //---------------------------------------------------------------------------- #ifndef AGG_CONV_GPC_INCLUDED #define AGG_CONV_GPC_INCLUDED #include #include "agg_basics.h" #include "agg_array.h" extern "C" { #include "gpc.h" } namespace agg { enum gpc_op_e { gpc_or, gpc_and, gpc_xor, gpc_a_minus_b, gpc_b_minus_a }; //================================================================conv_gpc template class conv_gpc { enum status { status_move_to, status_line_to, status_stop }; struct contour_header_type { int num_vertices; int hole_flag; gpc_vertex* vertices; }; typedef pod_bvector vertex_array_type; typedef pod_bvector contour_header_array_type; public: typedef VSA source_a_type; typedef VSB source_b_type; typedef conv_gpc self_type; ~conv_gpc() { free_gpc_data(); } conv_gpc(source_a_type& a, source_b_type& b, gpc_op_e op = gpc_or) : m_src_a(&a), m_src_b(&b), m_status(status_move_to), m_vertex(-1), m_contour(-1), m_operation(op) { std::memset(&m_poly_a, 0, sizeof(m_poly_a)); std::memset(&m_poly_b, 0, sizeof(m_poly_b)); std::memset(&m_result, 0, sizeof(m_result)); } void attach1(VSA& source) { m_src_a = &source; } void attach2(VSB& source) { m_src_b = &source; } void operation(gpc_op_e v) { m_operation = v; } // Vertex Source Interface void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: conv_gpc(const conv_gpc&); const conv_gpc& operator = (const conv_gpc&); //-------------------------------------------------------------------- void free_polygon(gpc_polygon& p); void free_result(); void free_gpc_data(); void start_contour(); void add_vertex(double x, double y); void end_contour(unsigned orientation); void make_polygon(gpc_polygon& p); void start_extracting(); bool next_contour(); bool next_vertex(double* x, double* y); //-------------------------------------------------------------------- template void add(VS& src, gpc_polygon& p) { unsigned cmd; double x, y; double start_x = 0.0; double start_y = 0.0; bool line_to = false; unsigned orientation = 0; m_contour_accumulator.remove_all(); while(!is_stop(cmd = src.vertex(&x, &y))) { if(is_vertex(cmd)) { if(is_move_to(cmd)) { if(line_to) { end_contour(orientation); orientation = 0; } start_contour(); start_x = x; start_y = y; } add_vertex(x, y); line_to = true; } else { if(is_end_poly(cmd)) { orientation = get_orientation(cmd); if(line_to && is_closed(cmd)) { add_vertex(start_x, start_y); } } } } if(line_to) { end_contour(orientation); } make_polygon(p); } private: //-------------------------------------------------------------------- source_a_type* m_src_a; source_b_type* m_src_b; status m_status; int m_vertex; int m_contour; gpc_op_e m_operation; vertex_array_type m_vertex_accumulator; contour_header_array_type m_contour_accumulator; gpc_polygon m_poly_a; gpc_polygon m_poly_b; gpc_polygon m_result; }; //------------------------------------------------------------------------ template void conv_gpc::free_polygon(gpc_polygon& p) { int i; for(i = 0; i < p.num_contours; i++) { pod_allocator::deallocate(p.contour[i].vertex, p.contour[i].num_vertices); } pod_allocator::deallocate(p.contour, p.num_contours); std::memset(&p, 0, sizeof(gpc_polygon)); } //------------------------------------------------------------------------ template void conv_gpc::free_result() { if(m_result.contour) { gpc_free_polygon(&m_result); } std::memset(&m_result, 0, sizeof(m_result)); } //------------------------------------------------------------------------ template void conv_gpc::free_gpc_data() { free_polygon(m_poly_a); free_polygon(m_poly_b); free_result(); } //------------------------------------------------------------------------ template void conv_gpc::start_contour() { contour_header_type h; std::memset(&h, 0, sizeof(h)); m_contour_accumulator.add(h); m_vertex_accumulator.remove_all(); } //------------------------------------------------------------------------ template inline void conv_gpc::add_vertex(double x, double y) { gpc_vertex v; v.x = x; v.y = y; m_vertex_accumulator.add(v); } //------------------------------------------------------------------------ template void conv_gpc::end_contour(unsigned /*orientation*/) { if(m_contour_accumulator.size()) { if(m_vertex_accumulator.size() > 2) { contour_header_type& h = m_contour_accumulator[m_contour_accumulator.size() - 1]; h.num_vertices = m_vertex_accumulator.size(); h.hole_flag = 0; // TO DO: Clarify the "holes" //if(is_cw(orientation)) h.hole_flag = 1; h.vertices = pod_allocator::allocate(h.num_vertices); gpc_vertex* d = h.vertices; int i; for(i = 0; i < h.num_vertices; i++) { const gpc_vertex& s = m_vertex_accumulator[i]; d->x = s.x; d->y = s.y; ++d; } } else { m_vertex_accumulator.remove_last(); } } } //------------------------------------------------------------------------ template void conv_gpc::make_polygon(gpc_polygon& p) { free_polygon(p); if(m_contour_accumulator.size()) { p.num_contours = m_contour_accumulator.size(); p.hole = 0; p.contour = pod_allocator::allocate(p.num_contours); int i; gpc_vertex_list* pv = p.contour; for(i = 0; i < p.num_contours; i++) { const contour_header_type& h = m_contour_accumulator[i]; pv->num_vertices = h.num_vertices; pv->vertex = h.vertices; ++pv; } } } //------------------------------------------------------------------------ template void conv_gpc::start_extracting() { m_status = status_move_to; m_contour = -1; m_vertex = -1; } //------------------------------------------------------------------------ template bool conv_gpc::next_contour() { if(++m_contour < m_result.num_contours) { m_vertex = -1; return true; } return false; } //------------------------------------------------------------------------ template inline bool conv_gpc::next_vertex(double* x, double* y) { const gpc_vertex_list& vlist = m_result.contour[m_contour]; if(++m_vertex < vlist.num_vertices) { const gpc_vertex& v = vlist.vertex[m_vertex]; *x = v.x; *y = v.y; return true; } return false; } //------------------------------------------------------------------------ template void conv_gpc::rewind(unsigned path_id) { free_result(); m_src_a->rewind(path_id); m_src_b->rewind(path_id); add(*m_src_a, m_poly_a); add(*m_src_b, m_poly_b); switch(m_operation) { case gpc_or: gpc_polygon_clip(GPC_UNION, &m_poly_a, &m_poly_b, &m_result); break; case gpc_and: gpc_polygon_clip(GPC_INT, &m_poly_a, &m_poly_b, &m_result); break; case gpc_xor: gpc_polygon_clip(GPC_XOR, &m_poly_a, &m_poly_b, &m_result); break; case gpc_a_minus_b: gpc_polygon_clip(GPC_DIFF, &m_poly_a, &m_poly_b, &m_result); break; case gpc_b_minus_a: gpc_polygon_clip(GPC_DIFF, &m_poly_b, &m_poly_a, &m_result); break; } start_extracting(); } //------------------------------------------------------------------------ template unsigned conv_gpc::vertex(double* x, double* y) { if(m_status == status_move_to) { if(next_contour()) { if(next_vertex(x, y)) { m_status = status_line_to; return path_cmd_move_to; } m_status = status_stop; return path_cmd_end_poly | path_flags_close; } } else { if(next_vertex(x, y)) { return path_cmd_line_to; } else { m_status = status_move_to; } return path_cmd_end_poly | path_flags_close; } return path_cmd_stop; } } #endif ragg/src/agg/include/agg_basics.h0000644000176200001440000004254713504406270016412 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_BASICS_INCLUDED #define AGG_BASICS_INCLUDED #include #include "agg_config.h" //---------------------------------------------------------AGG_CUSTOM_ALLOCATOR #ifdef AGG_CUSTOM_ALLOCATOR #include "agg_allocator.h" #else namespace agg { // The policy of all AGG containers and memory allocation strategy // in general is that no allocated data requires explicit construction. // It means that the allocator can be really simple; you can even // replace new/delete to malloc/free. The constructors and destructors // won't be called in this case, however everything will remain working. // The second argument of deallocate() is the size of the allocated // block. You can use this information if you wish. //------------------------------------------------------------pod_allocator template struct pod_allocator { static T* allocate(unsigned num) { return new T [num]; } static void deallocate(T* ptr, unsigned) { delete [] ptr; } }; // Single object allocator. It's also can be replaced with your custom // allocator. The difference is that it can only allocate a single // object and the constructor and destructor must be called. // In AGG there is no need to allocate an array of objects with // calling their constructors (only single ones). So that, if you // replace these new/delete to malloc/free make sure that the in-place // new is called and take care of calling the destructor too. //------------------------------------------------------------obj_allocator template struct obj_allocator { static T* allocate() { return new T; } static void deallocate(T* ptr) { delete ptr; } }; } #endif //-------------------------------------------------------- Default basic types // // If the compiler has different capacity of the basic types you can redefine // them via the compiler command line or by generating agg_config.h that is // empty by default. // #ifndef AGG_INT8 #define AGG_INT8 signed char #endif #ifndef AGG_INT8U #define AGG_INT8U unsigned char #endif #ifndef AGG_INT16 #define AGG_INT16 short #endif #ifndef AGG_INT16U #define AGG_INT16U unsigned short #endif #ifndef AGG_INT32 #define AGG_INT32 int #endif #ifndef AGG_INT32U #define AGG_INT32U unsigned #endif #ifndef AGG_INT64 #if defined(_MSC_VER) || defined(__BORLANDC__) #define AGG_INT64 signed __int64 #else #define AGG_INT64 signed long long #endif #endif #ifndef AGG_INT64U #if defined(_MSC_VER) || defined(__BORLANDC__) #define AGG_INT64U unsigned __int64 #else #define AGG_INT64U unsigned long long #endif #endif //------------------------------------------------ Some fixes for MS Visual C++ #if defined(_MSC_VER) #pragma warning(disable:4786) // Identifier was truncated... #endif #if defined(_MSC_VER) #define AGG_INLINE __forceinline #else #define AGG_INLINE inline #endif namespace agg { //------------------------------------------------------------------------- typedef AGG_INT8 int8; //----int8 typedef AGG_INT8U int8u; //----int8u typedef AGG_INT16 int16; //----int16 typedef AGG_INT16U int16u; //----int16u typedef AGG_INT32 int32; //----int32 typedef AGG_INT32U int32u; //----int32u typedef AGG_INT64 int64; //----int64 typedef AGG_INT64U int64u; //----int64u #if defined(AGG_FISTP) #pragma warning(push) #pragma warning(disable : 4035) //Disable warning "no return value" AGG_INLINE int iround(double v) //-------iround { int t; __asm fld qword ptr [v] __asm fistp dword ptr [t] __asm mov eax, dword ptr [t] } AGG_INLINE unsigned uround(double v) //-------uround { unsigned t; __asm fld qword ptr [v] __asm fistp dword ptr [t] __asm mov eax, dword ptr [t] } #pragma warning(pop) AGG_INLINE int ifloor(double v) { return int(floor(v)); } AGG_INLINE unsigned ufloor(double v) //-------ufloor { return unsigned(floor(v)); } AGG_INLINE int iceil(double v) { return int(ceil(v)); } AGG_INLINE unsigned uceil(double v) //--------uceil { return unsigned(ceil(v)); } #elif defined(AGG_QIFIST) AGG_INLINE int iround(double v) { return int(v); } AGG_INLINE int uround(double v) { return unsigned(v); } AGG_INLINE int ifloor(double v) { return int(std::floor(v)); } AGG_INLINE unsigned ufloor(double v) { return unsigned(std::floor(v)); } AGG_INLINE int iceil(double v) { return int(std::ceil(v)); } AGG_INLINE unsigned uceil(double v) { return unsigned(std::ceil(v)); } #else AGG_INLINE int iround(double v) { return int((v < 0.0) ? v - 0.5 : v + 0.5); } AGG_INLINE int uround(double v) { return unsigned(v + 0.5); } AGG_INLINE int ifloor(double v) { int i = int(v); return i - (i > v); } AGG_INLINE unsigned ufloor(double v) { return unsigned(v); } AGG_INLINE int iceil(double v) { return int(std::ceil(v)); } AGG_INLINE unsigned uceil(double v) { return unsigned(std::ceil(v)); } #endif //---------------------------------------------------------------saturation template struct saturation { AGG_INLINE static int iround(double v) { if(v < double(-Limit)) return -Limit; if(v > double( Limit)) return Limit; return agg::iround(v); } }; //------------------------------------------------------------------mul_one template struct mul_one { AGG_INLINE static unsigned mul(unsigned a, unsigned b) { unsigned q = a * b + (1 << (Shift-1)); return (q + (q >> Shift)) >> Shift; } }; //------------------------------------------------------------------------- typedef unsigned char cover_type; //----cover_type enum cover_scale_e { cover_shift = 8, //----cover_shift cover_size = 1 << cover_shift, //----cover_size cover_mask = cover_size - 1, //----cover_mask cover_none = 0, //----cover_none cover_full = cover_mask //----cover_full }; //----------------------------------------------------poly_subpixel_scale_e // These constants determine the subpixel accuracy, to be more precise, // the number of bits of the fractional part of the coordinates. // The possible coordinate capacity in bits can be calculated by formula: // sizeof(int) * 8 - poly_subpixel_shift, i.e, for 32-bit integers and // 8-bits fractional part the capacity is 24 bits. enum poly_subpixel_scale_e { poly_subpixel_shift = 8, //----poly_subpixel_shift poly_subpixel_scale = 1< struct rect_base { typedef T value_type; typedef rect_base self_type; T x1, y1, x2, y2; rect_base() {} rect_base(T x1_, T y1_, T x2_, T y2_) : x1(x1_), y1(y1_), x2(x2_), y2(y2_) {} void init(T x1_, T y1_, T x2_, T y2_) { x1 = x1_; y1 = y1_; x2 = x2_; y2 = y2_; } const self_type& normalize() { T t; if(x1 > x2) { t = x1; x1 = x2; x2 = t; } if(y1 > y2) { t = y1; y1 = y2; y2 = t; } return *this; } bool clip(const self_type& r) { if(x2 > r.x2) x2 = r.x2; if(y2 > r.y2) y2 = r.y2; if(x1 < r.x1) x1 = r.x1; if(y1 < r.y1) y1 = r.y1; return x1 <= x2 && y1 <= y2; } bool is_valid() const { return x1 <= x2 && y1 <= y2; } bool hit_test(T x, T y) const { return (x >= x1 && x <= x2 && y >= y1 && y <= y2); } bool overlaps(const self_type& r) const { return !(r.x1 > x2 || r.x2 < x1 || r.y1 > y2 || r.y2 < y1); } }; //-----------------------------------------------------intersect_rectangles template inline Rect intersect_rectangles(const Rect& r1, const Rect& r2) { Rect r = r1; // First process x2,y2 because the other order // results in Internal Compiler Error under // Microsoft Visual C++ .NET 2003 69462-335-0000007-18038 in // case of "Maximize Speed" optimization option. //----------------- if(r.x2 > r2.x2) r.x2 = r2.x2; if(r.y2 > r2.y2) r.y2 = r2.y2; if(r.x1 < r2.x1) r.x1 = r2.x1; if(r.y1 < r2.y1) r.y1 = r2.y1; return r; } //---------------------------------------------------------unite_rectangles template inline Rect unite_rectangles(const Rect& r1, const Rect& r2) { Rect r = r1; if(r.x2 < r2.x2) r.x2 = r2.x2; if(r.y2 < r2.y2) r.y2 = r2.y2; if(r.x1 > r2.x1) r.x1 = r2.x1; if(r.y1 > r2.y1) r.y1 = r2.y1; return r; } typedef rect_base rect_i; //----rect_i typedef rect_base rect_f; //----rect_f typedef rect_base rect_d; //----rect_d //---------------------------------------------------------path_commands_e enum path_commands_e { path_cmd_stop = 0, //----path_cmd_stop path_cmd_move_to = 1, //----path_cmd_move_to path_cmd_line_to = 2, //----path_cmd_line_to path_cmd_curve3 = 3, //----path_cmd_curve3 path_cmd_curve4 = 4, //----path_cmd_curve4 path_cmd_curveN = 5, //----path_cmd_curveN path_cmd_catrom = 6, //----path_cmd_catrom path_cmd_ubspline = 7, //----path_cmd_ubspline path_cmd_end_poly = 0x0F, //----path_cmd_end_poly path_cmd_mask = 0x0F //----path_cmd_mask }; //------------------------------------------------------------path_flags_e enum path_flags_e { path_flags_none = 0, //----path_flags_none path_flags_ccw = 0x10, //----path_flags_ccw path_flags_cw = 0x20, //----path_flags_cw path_flags_close = 0x40, //----path_flags_close path_flags_mask = 0xF0 //----path_flags_mask }; //---------------------------------------------------------------is_vertex inline bool is_vertex(unsigned c) { return c >= path_cmd_move_to && c < path_cmd_end_poly; } //--------------------------------------------------------------is_drawing inline bool is_drawing(unsigned c) { return c >= path_cmd_line_to && c < path_cmd_end_poly; } //-----------------------------------------------------------------is_stop inline bool is_stop(unsigned c) { return c == path_cmd_stop; } //--------------------------------------------------------------is_move_to inline bool is_move_to(unsigned c) { return c == path_cmd_move_to; } //--------------------------------------------------------------is_line_to inline bool is_line_to(unsigned c) { return c == path_cmd_line_to; } //----------------------------------------------------------------is_curve inline bool is_curve(unsigned c) { return c == path_cmd_curve3 || c == path_cmd_curve4; } //---------------------------------------------------------------is_curve3 inline bool is_curve3(unsigned c) { return c == path_cmd_curve3; } //---------------------------------------------------------------is_curve4 inline bool is_curve4(unsigned c) { return c == path_cmd_curve4; } //-------------------------------------------------------------is_end_poly inline bool is_end_poly(unsigned c) { return (c & path_cmd_mask) == path_cmd_end_poly; } //----------------------------------------------------------------is_close inline bool is_close(unsigned c) { return (c & ~(path_flags_cw | path_flags_ccw)) == (path_cmd_end_poly | path_flags_close); } //------------------------------------------------------------is_next_poly inline bool is_next_poly(unsigned c) { return is_stop(c) || is_move_to(c) || is_end_poly(c); } //-------------------------------------------------------------------is_cw inline bool is_cw(unsigned c) { return (c & path_flags_cw) != 0; } //------------------------------------------------------------------is_ccw inline bool is_ccw(unsigned c) { return (c & path_flags_ccw) != 0; } //-------------------------------------------------------------is_oriented inline bool is_oriented(unsigned c) { return (c & (path_flags_cw | path_flags_ccw)) != 0; } //---------------------------------------------------------------is_closed inline bool is_closed(unsigned c) { return (c & path_flags_close) != 0; } //----------------------------------------------------------get_close_flag inline unsigned get_close_flag(unsigned c) { return c & path_flags_close; } //-------------------------------------------------------clear_orientation inline unsigned clear_orientation(unsigned c) { return c & ~(path_flags_cw | path_flags_ccw); } //---------------------------------------------------------get_orientation inline unsigned get_orientation(unsigned c) { return c & (path_flags_cw | path_flags_ccw); } //---------------------------------------------------------set_orientation inline unsigned set_orientation(unsigned c, unsigned o) { return clear_orientation(c) | o; } //--------------------------------------------------------------point_base template struct point_base { typedef T value_type; T x,y; point_base() {} point_base(T x_, T y_) : x(x_), y(y_) {} }; typedef point_base point_i; //-----point_i typedef point_base point_f; //-----point_f typedef point_base point_d; //-----point_d //-------------------------------------------------------------vertex_base template struct vertex_base { typedef T value_type; T x,y; unsigned cmd; vertex_base() {} vertex_base(T x_, T y_, unsigned cmd_) : x(x_), y(y_), cmd(cmd_) {} }; typedef vertex_base vertex_i; //-----vertex_i typedef vertex_base vertex_f; //-----vertex_f typedef vertex_base vertex_d; //-----vertex_d //----------------------------------------------------------------row_info template struct row_info { int x1, x2; T* ptr; row_info() {} row_info(int x1_, int x2_, T* ptr_) : x1(x1_), x2(x2_), ptr(ptr_) {} }; //----------------------------------------------------------const_row_info template struct const_row_info { int x1, x2; const T* ptr; const_row_info() {} const_row_info(int x1_, int x2_, const T* ptr_) : x1(x1_), x2(x2_), ptr(ptr_) {} }; //------------------------------------------------------------is_equal_eps template inline bool is_equal_eps(T v1, T v2, T epsilon) { bool neg1 = v1 < 0.0; bool neg2 = v2 < 0.0; if (neg1 != neg2) return std::fabs(v1) < epsilon && std::fabs(v2) < epsilon; int int1, int2; std::frexp(v1, &int1); std::frexp(v2, &int2); int min12 = int1 < int2 ? int1 : int2; v1 = std::ldexp(v1, -min12); v2 = std::ldexp(v2, -min12); return std::fabs(v1 - v2) < epsilon; } } #endif ragg/src/agg/include/agg_renderer_raster_text.h0000644000176200001440000002102313504406270021362 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_RENDERER_RASTER_TEXT_INCLUDED #define AGG_RENDERER_RASTER_TEXT_INCLUDED #include "agg_basics.h" namespace agg { //==============================================renderer_raster_htext_solid template class renderer_raster_htext_solid { public: typedef BaseRenderer ren_type; typedef GlyphGenerator glyph_gen_type; typedef typename glyph_gen_type::glyph_rect glyph_rect; typedef typename ren_type::color_type color_type; renderer_raster_htext_solid(ren_type& ren, glyph_gen_type& glyph) : m_ren(&ren), m_glyph(&glyph) {} void attach(ren_type& ren) { m_ren = &ren; } //-------------------------------------------------------------------- void color(const color_type& c) { m_color = c; } const color_type& color() const { return m_color; } //-------------------------------------------------------------------- template void render_text(double x, double y, const CharT* str, bool flip=false) { glyph_rect r; while(*str) { m_glyph->prepare(&r, x, y, *str, flip); if(r.x2 >= r.x1) { int i; if(flip) { for(i = r.y1; i <= r.y2; i++) { m_ren->blend_solid_hspan(r.x1, i, (r.x2 - r.x1 + 1), m_color, m_glyph->span(r.y2 - i)); } } else { for(i = r.y1; i <= r.y2; i++) { m_ren->blend_solid_hspan(r.x1, i, (r.x2 - r.x1 + 1), m_color, m_glyph->span(i - r.y1)); } } } x += r.dx; y += r.dy; ++str; } } private: ren_type* m_ren; glyph_gen_type* m_glyph; color_type m_color; }; //=============================================renderer_raster_vtext_solid template class renderer_raster_vtext_solid { public: typedef BaseRenderer ren_type; typedef GlyphGenerator glyph_gen_type; typedef typename glyph_gen_type::glyph_rect glyph_rect; typedef typename ren_type::color_type color_type; renderer_raster_vtext_solid(ren_type& ren, glyph_gen_type& glyph) : m_ren(&ren), m_glyph(&glyph) { } //-------------------------------------------------------------------- void color(const color_type& c) { m_color = c; } const color_type& color() const { return m_color; } //-------------------------------------------------------------------- template void render_text(double x, double y, const CharT* str, bool flip=false) { glyph_rect r; while(*str) { m_glyph->prepare(&r, x, y, *str, !flip); if(r.x2 >= r.x1) { int i; if(flip) { for(i = r.y1; i <= r.y2; i++) { m_ren->blend_solid_vspan(i, r.x1, (r.x2 - r.x1 + 1), m_color, m_glyph->span(i - r.y1)); } } else { for(i = r.y1; i <= r.y2; i++) { m_ren->blend_solid_vspan(i, r.x1, (r.x2 - r.x1 + 1), m_color, m_glyph->span(r.y2 - i)); } } } x += r.dx; y += r.dy; ++str; } } private: ren_type* m_ren; glyph_gen_type* m_glyph; color_type m_color; }; //===================================================renderer_raster_htext template class renderer_raster_htext { public: typedef ScanlineRenderer ren_type; typedef GlyphGenerator glyph_gen_type; typedef typename glyph_gen_type::glyph_rect glyph_rect; class scanline_single_span { public: typedef agg::cover_type cover_type; //---------------------------------------------------------------- struct const_span { int x; unsigned len; const cover_type* covers; const_span() {} const_span(int x_, unsigned len_, const cover_type* covers_) : x(x_), len(len_), covers(covers_) {} }; typedef const const_span* const_iterator; //---------------------------------------------------------------- scanline_single_span(int x, int y, unsigned len, const cover_type* covers) : m_y(y), m_span(x, len, covers) {} //---------------------------------------------------------------- int y() const { return m_y; } unsigned num_spans() const { return 1; } const_iterator begin() const { return &m_span; } private: //---------------------------------------------------------------- int m_y; const_span m_span; }; //-------------------------------------------------------------------- renderer_raster_htext(ren_type& ren, glyph_gen_type& glyph) : m_ren(&ren), m_glyph(&glyph) { } //-------------------------------------------------------------------- template void render_text(double x, double y, const CharT* str, bool flip=false) { glyph_rect r; while(*str) { m_glyph->prepare(&r, x, y, *str, flip); if(r.x2 >= r.x1) { m_ren->prepare(); int i; if(flip) { for(i = r.y1; i <= r.y2; i++) { m_ren->render( scanline_single_span(r.x1, i, (r.x2 - r.x1 + 1), m_glyph->span(r.y2 - i))); } } else { for(i = r.y1; i <= r.y2; i++) { m_ren->render( scanline_single_span(r.x1, i, (r.x2 - r.x1 + 1), m_glyph->span(i - r.y1))); } } } x += r.dx; y += r.dy; ++str; } } private: ren_type* m_ren; glyph_gen_type* m_glyph; }; } #endif ragg/src/agg/include/agg_rasterizer_outline_aa.h0000644000176200001440000005041613504406270021532 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_RASTERIZER_OUTLINE_AA_INCLUDED #define AGG_RASTERIZER_OUTLINE_AA_INCLUDED #include #include "agg_basics.h" #include "agg_line_aa_basics.h" #include "agg_vertex_sequence.h" namespace agg { //------------------------------------------------------------------------- inline bool cmp_dist_start(int d) { return d > 0; } inline bool cmp_dist_end(int d) { return d <= 0; } //-----------------------------------------------------------line_aa_vertex // Vertex (x, y) with the distance to the next one. The last vertex has // the distance between the last and the first points struct line_aa_vertex { int x; int y; int len; line_aa_vertex() {} line_aa_vertex(int x_, int y_) : x(x_), y(y_), len(0) { } bool operator () (const line_aa_vertex& val) { double dx = val.x - x; double dy = val.y - y; return (len = uround(std::sqrt(dx * dx + dy * dy))) > (line_subpixel_scale + line_subpixel_scale / 2); } }; //----------------------------------------------------------outline_aa_join_e enum outline_aa_join_e { outline_no_join, //-----outline_no_join outline_miter_join, //-----outline_miter_join outline_round_join, //-----outline_round_join outline_miter_accurate_join //-----outline_accurate_join }; //=======================================================rasterizer_outline_aa template class rasterizer_outline_aa { private: //------------------------------------------------------------------------ struct draw_vars { unsigned idx; int x1, y1, x2, y2; line_parameters curr, next; int lcurr, lnext; int xb1, yb1, xb2, yb2; unsigned flags; }; void draw(draw_vars& dv, unsigned start, unsigned end); public: typedef line_aa_vertex vertex_type; typedef vertex_sequence vertex_storage_type; explicit rasterizer_outline_aa(Renderer& ren) : m_ren(&ren), m_line_join(ren.accurate_join_only() ? outline_miter_accurate_join : outline_round_join), m_round_cap(false), m_start_x(0), m_start_y(0) {} void attach(Renderer& ren) { m_ren = &ren; } //------------------------------------------------------------------------ void line_join(outline_aa_join_e join) { m_line_join = m_ren->accurate_join_only() ? outline_miter_accurate_join : join; } bool line_join() const { return m_line_join; } //------------------------------------------------------------------------ void round_cap(bool v) { m_round_cap = v; } bool round_cap() const { return m_round_cap; } //------------------------------------------------------------------------ void move_to(int x, int y) { m_src_vertices.modify_last(vertex_type(m_start_x = x, m_start_y = y)); } //------------------------------------------------------------------------ void line_to(int x, int y) { m_src_vertices.add(vertex_type(x, y)); } //------------------------------------------------------------------------ void move_to_d(double x, double y) { move_to(Coord::conv(x), Coord::conv(y)); } //------------------------------------------------------------------------ void line_to_d(double x, double y) { line_to(Coord::conv(x), Coord::conv(y)); } //------------------------------------------------------------------------ void render(bool close_polygon); //------------------------------------------------------------------------ void add_vertex(double x, double y, unsigned cmd) { if(is_move_to(cmd)) { render(false); move_to_d(x, y); } else { if(is_end_poly(cmd)) { render(is_closed(cmd)); if(is_closed(cmd)) { move_to(m_start_x, m_start_y); } } else { line_to_d(x, y); } } } //------------------------------------------------------------------------ template void add_path(VertexSource& vs, unsigned path_id=0) { double x; double y; unsigned cmd; vs.rewind(path_id); while(!is_stop(cmd = vs.vertex(&x, &y))) { add_vertex(x, y, cmd); } render(false); } //------------------------------------------------------------------------ template void render_all_paths(VertexSource& vs, const ColorStorage& colors, const PathId& path_id, unsigned num_paths) { for(unsigned i = 0; i < num_paths; i++) { m_ren->color(colors[i]); add_path(vs, path_id[i]); } } //------------------------------------------------------------------------ template void render_ctrl(Ctrl& c) { unsigned i; for(i = 0; i < c.num_paths(); i++) { m_ren->color(c.color(i)); add_path(c, i); } } private: rasterizer_outline_aa(const rasterizer_outline_aa&); const rasterizer_outline_aa& operator = (const rasterizer_outline_aa&); Renderer* m_ren; vertex_storage_type m_src_vertices; outline_aa_join_e m_line_join; bool m_round_cap; int m_start_x; int m_start_y; }; //---------------------------------------------------------------------------- template void rasterizer_outline_aa::draw(draw_vars& dv, unsigned start, unsigned end) { unsigned i; const vertex_storage_type::value_type* v; for(i = start; i < end; i++) { if(m_line_join == outline_round_join) { dv.xb1 = dv.curr.x1 + (dv.curr.y2 - dv.curr.y1); dv.yb1 = dv.curr.y1 - (dv.curr.x2 - dv.curr.x1); dv.xb2 = dv.curr.x2 + (dv.curr.y2 - dv.curr.y1); dv.yb2 = dv.curr.y2 - (dv.curr.x2 - dv.curr.x1); } switch(dv.flags) { case 0: m_ren->line3(dv.curr, dv.xb1, dv.yb1, dv.xb2, dv.yb2); break; case 1: m_ren->line2(dv.curr, dv.xb2, dv.yb2); break; case 2: m_ren->line1(dv.curr, dv.xb1, dv.yb1); break; case 3: m_ren->line0(dv.curr); break; } if(m_line_join == outline_round_join && (dv.flags & 2) == 0) { m_ren->pie(dv.curr.x2, dv.curr.y2, dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), dv.curr.y2 - (dv.curr.x2 - dv.curr.x1), dv.curr.x2 + (dv.next.y2 - dv.next.y1), dv.curr.y2 - (dv.next.x2 - dv.next.x1)); } dv.x1 = dv.x2; dv.y1 = dv.y2; dv.lcurr = dv.lnext; dv.lnext = m_src_vertices[dv.idx].len; ++dv.idx; if(dv.idx >= m_src_vertices.size()) dv.idx = 0; v = &m_src_vertices[dv.idx]; dv.x2 = v->x; dv.y2 = v->y; dv.curr = dv.next; dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); dv.xb1 = dv.xb2; dv.yb1 = dv.yb2; switch(m_line_join) { case outline_no_join: dv.flags = 3; break; case outline_miter_join: dv.flags >>= 1; dv.flags |= ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1); if((dv.flags & 2) == 0) { bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); } break; case outline_round_join: dv.flags >>= 1; dv.flags |= ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1); break; case outline_miter_accurate_join: dv.flags = 0; bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); break; } } } //---------------------------------------------------------------------------- template void rasterizer_outline_aa::render(bool close_polygon) { m_src_vertices.close(close_polygon); draw_vars dv; const vertex_storage_type::value_type* v; int x1; int y1; int x2; int y2; int lprev; if(close_polygon) { if(m_src_vertices.size() >= 3) { dv.idx = 2; v = &m_src_vertices[m_src_vertices.size() - 1]; x1 = v->x; y1 = v->y; lprev = v->len; v = &m_src_vertices[0]; x2 = v->x; y2 = v->y; dv.lcurr = v->len; line_parameters prev(x1, y1, x2, y2, lprev); v = &m_src_vertices[1]; dv.x1 = v->x; dv.y1 = v->y; dv.lnext = v->len; dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr); v = &m_src_vertices[dv.idx]; dv.x2 = v->x; dv.y2 = v->y; dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); dv.xb1 = 0; dv.yb1 = 0; dv.xb2 = 0; dv.yb2 = 0; switch(m_line_join) { case outline_no_join: dv.flags = 3; break; case outline_miter_join: case outline_round_join: dv.flags = (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) | ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1); break; case outline_miter_accurate_join: dv.flags = 0; break; } if((dv.flags & 1) == 0 && m_line_join != outline_round_join) { bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1); } if((dv.flags & 2) == 0 && m_line_join != outline_round_join) { bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); } draw(dv, 0, m_src_vertices.size()); } } else { switch(m_src_vertices.size()) { case 0: case 1: break; case 2: { v = &m_src_vertices[0]; x1 = v->x; y1 = v->y; lprev = v->len; v = &m_src_vertices[1]; x2 = v->x; y2 = v->y; line_parameters lp(x1, y1, x2, y2, lprev); if(m_round_cap) { m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); } m_ren->line3(lp, x1 + (y2 - y1), y1 - (x2 - x1), x2 + (y2 - y1), y2 - (x2 - x1)); if(m_round_cap) { m_ren->semidot(cmp_dist_end, x2, y2, x2 + (y2 - y1), y2 - (x2 - x1)); } } break; case 3: { int x3, y3; int lnext; v = &m_src_vertices[0]; x1 = v->x; y1 = v->y; lprev = v->len; v = &m_src_vertices[1]; x2 = v->x; y2 = v->y; lnext = v->len; v = &m_src_vertices[2]; x3 = v->x; y3 = v->y; line_parameters lp1(x1, y1, x2, y2, lprev); line_parameters lp2(x2, y2, x3, y3, lnext); if(m_round_cap) { m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); } if(m_line_join == outline_round_join) { m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1), x2 + (y2 - y1), y2 - (x2 - x1)); m_ren->pie(x2, y2, x2 + (y2 - y1), y2 - (x2 - x1), x2 + (y3 - y2), y2 - (x3 - x2)); m_ren->line3(lp2, x2 + (y3 - y2), y2 - (x3 - x2), x3 + (y3 - y2), y3 - (x3 - x2)); } else { bisectrix(lp1, lp2, &dv.xb1, &dv.yb1); m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1), dv.xb1, dv.yb1); m_ren->line3(lp2, dv.xb1, dv.yb1, x3 + (y3 - y2), y3 - (x3 - x2)); } if(m_round_cap) { m_ren->semidot(cmp_dist_end, x3, y3, x3 + (y3 - y2), y3 - (x3 - x2)); } } break; default: { dv.idx = 3; v = &m_src_vertices[0]; x1 = v->x; y1 = v->y; lprev = v->len; v = &m_src_vertices[1]; x2 = v->x; y2 = v->y; dv.lcurr = v->len; line_parameters prev(x1, y1, x2, y2, lprev); v = &m_src_vertices[2]; dv.x1 = v->x; dv.y1 = v->y; dv.lnext = v->len; dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr); v = &m_src_vertices[dv.idx]; dv.x2 = v->x; dv.y2 = v->y; dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext); dv.xb1 = 0; dv.yb1 = 0; dv.xb2 = 0; dv.yb2 = 0; switch(m_line_join) { case outline_no_join: dv.flags = 3; break; case outline_miter_join: case outline_round_join: dv.flags = (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) | ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1); break; case outline_miter_accurate_join: dv.flags = 0; break; } if(m_round_cap) { m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1)); } if((dv.flags & 1) == 0) { if(m_line_join == outline_round_join) { m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1), x2 + (y2 - y1), y2 - (x2 - x1)); m_ren->pie(prev.x2, prev.y2, x2 + (y2 - y1), y2 - (x2 - x1), dv.curr.x1 + (dv.curr.y2 - dv.curr.y1), dv.curr.y1 - (dv.curr.x2 - dv.curr.x1)); } else { bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1); m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1), dv.xb1, dv.yb1); } } else { m_ren->line1(prev, x1 + (y2 - y1), y1 - (x2 - x1)); } if((dv.flags & 2) == 0 && m_line_join != outline_round_join) { bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2); } draw(dv, 1, m_src_vertices.size() - 2); if((dv.flags & 1) == 0) { if(m_line_join == outline_round_join) { m_ren->line3(dv.curr, dv.curr.x1 + (dv.curr.y2 - dv.curr.y1), dv.curr.y1 - (dv.curr.x2 - dv.curr.x1), dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); } else { m_ren->line3(dv.curr, dv.xb1, dv.yb1, dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); } } else { m_ren->line2(dv.curr, dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); } if(m_round_cap) { m_ren->semidot(cmp_dist_end, dv.curr.x2, dv.curr.y2, dv.curr.x2 + (dv.curr.y2 - dv.curr.y1), dv.curr.y2 - (dv.curr.x2 - dv.curr.x1)); } } break; } } m_src_vertices.remove_all(); } } #endif ragg/src/agg/include/agg_ellipse_bresenham.h0000644000176200001440000000542313504406270020617 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Simple Bresenham interpolator for ellipsees // //---------------------------------------------------------------------------- #ifndef AGG_ELLIPSE_BRESENHAM_INCLUDED #define AGG_ELLIPSE_BRESENHAM_INCLUDED #include "agg_basics.h" namespace agg { //------------------------------------------ellipse_bresenham_interpolator class ellipse_bresenham_interpolator { public: ellipse_bresenham_interpolator(int rx, int ry) : m_rx2(rx * rx), m_ry2(ry * ry), m_two_rx2(m_rx2 << 1), m_two_ry2(m_ry2 << 1), m_dx(0), m_dy(0), m_inc_x(0), m_inc_y(-ry * m_two_rx2), m_cur_f(0) {} int dx() const { return m_dx; } int dy() const { return m_dy; } void operator++ () { int mx, my, mxy, min_m; int fx, fy, fxy; mx = fx = m_cur_f + m_inc_x + m_ry2; if(mx < 0) mx = -mx; my = fy = m_cur_f + m_inc_y + m_rx2; if(my < 0) my = -my; mxy = fxy = m_cur_f + m_inc_x + m_ry2 + m_inc_y + m_rx2; if(mxy < 0) mxy = -mxy; min_m = mx; bool flag = true; if(min_m > my) { min_m = my; flag = false; } m_dx = m_dy = 0; if(min_m > mxy) { m_inc_x += m_two_ry2; m_inc_y += m_two_rx2; m_cur_f = fxy; m_dx = 1; m_dy = 1; return; } if(flag) { m_inc_x += m_two_ry2; m_cur_f = fx; m_dx = 1; return; } m_inc_y += m_two_rx2; m_cur_f = fy; m_dy = 1; } private: int m_rx2; int m_ry2; int m_two_rx2; int m_two_ry2; int m_dx; int m_dy; int m_inc_x; int m_inc_y; int m_cur_f; }; } #endif ragg/src/agg/include/agg_trans_warp_magnifier.h0000644000176200001440000000333713504406270021341 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_WARP_MAGNIFIER_INCLUDED #define AGG_WARP_MAGNIFIER_INCLUDED namespace agg { //----------------------------------------------------trans_warp_magnifier // // See Inmplementation agg_trans_warp_magnifier.cpp // class trans_warp_magnifier { public: trans_warp_magnifier() : m_xc(0.0), m_yc(0.0), m_magn(1.0), m_radius(1.0) {} void center(double x, double y) { m_xc = x; m_yc = y; } void magnification(double m) { m_magn = m; } void radius(double r) { m_radius = r; } double xc() const { return m_xc; } double yc() const { return m_yc; } double magnification() const { return m_magn; } double radius() const { return m_radius; } void transform(double* x, double* y) const; void inverse_transform(double* x, double* y) const; private: double m_xc; double m_yc; double m_magn; double m_radius; }; } #endif ragg/src/agg/include/agg_span_gradient.h0000644000176200001440000003033714131767200017756 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_SPAN_GRADIENT_INCLUDED #define AGG_SPAN_GRADIENT_INCLUDED #include #include #include "agg_basics.h" #include "agg_math.h" #include "agg_array.h" namespace agg { enum gradient_subpixel_scale_e { gradient_subpixel_shift = 4, //-----gradient_subpixel_shift gradient_subpixel_scale = 1 << gradient_subpixel_shift, //-----gradient_subpixel_scale gradient_subpixel_mask = gradient_subpixel_scale - 1 //-----gradient_subpixel_mask }; //==========================================================span_gradient template class span_gradient { public: typedef Interpolator interpolator_type; typedef ColorT color_type; enum downscale_shift_e { downscale_shift = interpolator_type::subpixel_shift - gradient_subpixel_shift }; //-------------------------------------------------------------------- span_gradient() {} //-------------------------------------------------------------------- span_gradient(interpolator_type& inter, GradientF& gradient_function, ColorF& color_function, double d1, double d2, bool pad = true) : m_interpolator(&inter), m_gradient_function(&gradient_function), m_color_function(&color_function), m_d1(iround(d1 * gradient_subpixel_scale)), m_d2(iround(d2 * gradient_subpixel_scale)), m_pad(pad) {} //-------------------------------------------------------------------- interpolator_type& interpolator() { return *m_interpolator; } const GradientF& gradient_function() const { return *m_gradient_function; } const ColorF& color_function() const { return *m_color_function; } double d1() const { return double(m_d1) / gradient_subpixel_scale; } double d2() const { return double(m_d2) / gradient_subpixel_scale; } //-------------------------------------------------------------------- void interpolator(interpolator_type& i) { m_interpolator = &i; } void gradient_function(GradientF& gf) { m_gradient_function = &gf; } void color_function(ColorF& cf) { m_color_function = &cf; } void d1(double v) { m_d1 = iround(v * gradient_subpixel_scale); } void d2(double v) { m_d2 = iround(v * gradient_subpixel_scale); } //-------------------------------------------------------------------- void prepare() {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { int dd = m_d2 - m_d1; if(dd < 1) dd = 1; m_interpolator->begin(x+0.5, y+0.5, len); do { m_interpolator->coordinates(&x, &y); int d = m_gradient_function->calculate(x >> downscale_shift, y >> downscale_shift, m_d2); bool outside = false; d = ((d - m_d1) * (int)m_color_function->size()) / dd; if(d < 0) { d = 0; outside = true; } else if(d >= (int)m_color_function->size()) { d = m_color_function->size() - 1; outside = true; } *span++ = m_pad || !outside ? (*m_color_function)[d] : color_type(0, 0, 0, 0); ++(*m_interpolator); } while(--len); } private: interpolator_type* m_interpolator; GradientF* m_gradient_function; ColorF* m_color_function; int m_d1; int m_d2; bool m_pad; }; //=====================================================gradient_linear_color template struct gradient_linear_color { typedef ColorT color_type; gradient_linear_color() {} gradient_linear_color(const color_type& c1, const color_type& c2, unsigned size = 256) : m_c1(c1), m_c2(c2), m_size(size) // VFALCO 4/28/09 ,m_mult(1/(double(size)-1)) // VFALCO {} unsigned size() const { return m_size; } color_type operator [] (unsigned v) const { // VFALCO 4/28/09 //return m_c1.gradient(m_c2, double(v) / double(m_size - 1)); return m_c1.gradient(m_c2, double(v) * m_mult ); // VFALCO } void colors(const color_type& c1, const color_type& c2, unsigned size = 256) { m_c1 = c1; m_c2 = c2; m_size = size; // VFALCO 4/28/09 m_mult=1/(double(size)-1); // VFALCO } color_type m_c1; color_type m_c2; unsigned m_size; // VFALCO 4/28/09 double m_mult; // VFALCO }; //==========================================================gradient_circle class gradient_circle { // Actually the same as radial. Just for compatibility public: static AGG_INLINE int calculate(int x, int y, int) { return int(fast_sqrt(x*x + y*y)); } }; //==========================================================gradient_radial class gradient_radial { public: static AGG_INLINE int calculate(int x, int y, int) { return int(fast_sqrt(x*x + y*y)); } }; //========================================================gradient_radial_d class gradient_radial_d { public: static AGG_INLINE int calculate(int x, int y, int) { return uround(std::sqrt(double(x)*double(x) + double(y)*double(y))); } }; //====================================================gradient_radial_focus class gradient_radial_focus { public: //--------------------------------------------------------------------- gradient_radial_focus() : m_r(100 * gradient_subpixel_scale), m_fx(0), m_fy(0) { update_values(); } //--------------------------------------------------------------------- gradient_radial_focus(double r, double fx, double fy) : m_r (iround(r * gradient_subpixel_scale)), m_fx(iround(fx * gradient_subpixel_scale)), m_fy(iround(fy * gradient_subpixel_scale)) { update_values(); } //--------------------------------------------------------------------- void init(double r, double fx, double fy) { m_r = iround(r * gradient_subpixel_scale); m_fx = iround(fx * gradient_subpixel_scale); m_fy = iround(fy * gradient_subpixel_scale); update_values(); } //--------------------------------------------------------------------- double radius() const { return double(m_r) / gradient_subpixel_scale; } double focus_x() const { return double(m_fx) / gradient_subpixel_scale; } double focus_y() const { return double(m_fy) / gradient_subpixel_scale; } //--------------------------------------------------------------------- int calculate(int x, int y, int) const { double dx = x - m_fx; double dy = y - m_fy; double d2 = dx * m_fy - dy * m_fx; double d3 = m_r2 * (dx * dx + dy * dy) - d2 * d2; return iround((dx * m_fx + dy * m_fy + std::sqrt(std::fabs(d3))) * m_mul); } private: //--------------------------------------------------------------------- void update_values() { // Calculate the invariant values. In case the focal center // lies exactly on the gradient circle the divisor degenerates // into zero. In this case we just move the focal center by // one subpixel unit possibly in the direction to the origin (0,0) // and calculate the values again. //------------------------- m_r2 = double(m_r) * double(m_r); m_fx2 = double(m_fx) * double(m_fx); m_fy2 = double(m_fy) * double(m_fy); double d = (m_r2 - (m_fx2 + m_fy2)); if(d == 0) { if(m_fx) { if(m_fx < 0) ++m_fx; else --m_fx; } if(m_fy) { if(m_fy < 0) ++m_fy; else --m_fy; } m_fx2 = double(m_fx) * double(m_fx); m_fy2 = double(m_fy) * double(m_fy); d = (m_r2 - (m_fx2 + m_fy2)); } m_mul = m_r / d; } int m_r; int m_fx; int m_fy; double m_r2; double m_fx2; double m_fy2; double m_mul; }; //==============================================================gradient_x class gradient_x { public: static int calculate(int x, int, int) { return x; } }; //==============================================================gradient_y class gradient_y { public: static int calculate(int, int y, int) { return y; } }; //========================================================gradient_diamond class gradient_diamond { public: static AGG_INLINE int calculate(int x, int y, int) { int ax = std::abs(x); int ay = std::abs(y); return ax > ay ? ax : ay; } }; //=============================================================gradient_xy class gradient_xy { public: static AGG_INLINE int calculate(int x, int y, int d) { return std::abs(x) * std::abs(y) / d; } }; //========================================================gradient_sqrt_xy class gradient_sqrt_xy { public: static AGG_INLINE int calculate(int x, int y, int) { return fast_sqrt(std::abs(x) * std::abs(y)); } }; //==========================================================gradient_conic class gradient_conic { public: static AGG_INLINE int calculate(int x, int y, int d) { return uround(std::fabs(std::atan2(double(y), double(x))) * double(d) / pi); } }; //=================================================gradient_repeat_adaptor template class gradient_repeat_adaptor { public: gradient_repeat_adaptor(const GradientF& gradient) : m_gradient(&gradient) {} AGG_INLINE int calculate(int x, int y, int d) const { int ret = m_gradient->calculate(x, y, d) % d; if(ret < 0) ret += d; return ret; } private: const GradientF* m_gradient; }; //================================================gradient_reflect_adaptor template class gradient_reflect_adaptor { public: gradient_reflect_adaptor(const GradientF& gradient) : m_gradient(&gradient) {} AGG_INLINE int calculate(int x, int y, int d) const { int d2 = d << 1; int ret = m_gradient->calculate(x, y, d) % d2; if(ret < 0) ret += d2; if(ret >= d) ret = d2 - ret; return ret; } private: const GradientF* m_gradient; }; } #endif ragg/src/agg/include/agg_scanline_boolean_algebra.h0000644000176200001440000015221213504406270022105 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED #define AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED #include #include "agg_basics.h" namespace agg { //-----------------------------------------------sbool_combine_spans_bin // Functor. // Combine two binary encoded spans, i.e., when we don't have any // anti-aliasing information, but only X and Length. The function // is compatible with any type of scanlines. //---------------- template struct sbool_combine_spans_bin { void operator () (const typename Scanline1::const_iterator&, const typename Scanline2::const_iterator&, int x, unsigned len, Scanline& sl) const { sl.add_span(x, len, cover_full); } }; //---------------------------------------------sbool_combine_spans_empty // Functor. // Combine two spans as empty ones. The functor does nothing // and is used to XOR binary spans. //---------------- template struct sbool_combine_spans_empty { void operator () (const typename Scanline1::const_iterator&, const typename Scanline2::const_iterator&, int, unsigned, Scanline&) const {} }; //--------------------------------------------------sbool_add_span_empty // Functor. // Add nothing. Used in conbine_shapes_sub //---------------- template struct sbool_add_span_empty { void operator () (const typename Scanline1::const_iterator&, int, unsigned, Scanline&) const {} }; //----------------------------------------------------sbool_add_span_bin // Functor. // Add a binary span //---------------- template struct sbool_add_span_bin { void operator () (const typename Scanline1::const_iterator&, int x, unsigned len, Scanline& sl) const { sl.add_span(x, len, cover_full); } }; //-----------------------------------------------------sbool_add_span_aa // Functor. // Add an anti-aliased span // anti-aliasing information, but only X and Length. The function // is compatible with any type of scanlines. //---------------- template struct sbool_add_span_aa { void operator () (const typename Scanline1::const_iterator& span, int x, unsigned len, Scanline& sl) const { if(span->len < 0) { sl.add_span(x, len, *span->covers); } else if(span->len > 0) { const typename Scanline1::cover_type* covers = span->covers; if(span->x < x) covers += x - span->x; sl.add_cells(x, len, covers); } } }; //----------------------------------------------sbool_intersect_spans_aa // Functor. // Intersect two spans preserving the anti-aliasing information. // The result is added to the "sl" scanline. //------------------ template struct sbool_intersect_spans_aa { enum cover_scale_e { cover_shift = CoverShift, cover_size = 1 << cover_shift, cover_mask = cover_size - 1, cover_full = cover_mask }; void operator () (const typename Scanline1::const_iterator& span1, const typename Scanline2::const_iterator& span2, int x, unsigned len, Scanline& sl) const { unsigned cover; const typename Scanline1::cover_type* covers1; const typename Scanline2::cover_type* covers2; // Calculate the operation code and choose the // proper combination algorithm. // 0 = Both spans are of AA type // 1 = span1 is solid, span2 is AA // 2 = span1 is AA, span2 is solid // 3 = Both spans are of solid type //----------------- switch((span1->len < 0) | ((span2->len < 0) << 1)) { case 0: // Both are AA spans covers1 = span1->covers; covers2 = span2->covers; if(span1->x < x) covers1 += x - span1->x; if(span2->x < x) covers2 += x - span2->x; do { cover = *covers1++ * *covers2++; sl.add_cell(x++, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); } while(--len); break; case 1: // span1 is solid, span2 is AA covers2 = span2->covers; if(span2->x < x) covers2 += x - span2->x; if(*(span1->covers) == cover_full) { sl.add_cells(x, len, covers2); } else { do { cover = *(span1->covers) * *covers2++; sl.add_cell(x++, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); } while(--len); } break; case 2: // span1 is AA, span2 is solid covers1 = span1->covers; if(span1->x < x) covers1 += x - span1->x; if(*(span2->covers) == cover_full) { sl.add_cells(x, len, covers1); } else { do { cover = *covers1++ * *(span2->covers); sl.add_cell(x++, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); } while(--len); } break; case 3: // Both are solid spans cover = *(span1->covers) * *(span2->covers); sl.add_span(x, len, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); break; } } }; //--------------------------------------------------sbool_unite_spans_aa // Functor. // Unite two spans preserving the anti-aliasing information. // The result is added to the "sl" scanline. //------------------ template struct sbool_unite_spans_aa { enum cover_scale_e { cover_shift = CoverShift, cover_size = 1 << cover_shift, cover_mask = cover_size - 1, cover_full = cover_mask }; void operator () (const typename Scanline1::const_iterator& span1, const typename Scanline2::const_iterator& span2, int x, unsigned len, Scanline& sl) const { unsigned cover; const typename Scanline1::cover_type* covers1; const typename Scanline2::cover_type* covers2; // Calculate the operation code and choose the // proper combination algorithm. // 0 = Both spans are of AA type // 1 = span1 is solid, span2 is AA // 2 = span1 is AA, span2 is solid // 3 = Both spans are of solid type //----------------- switch((span1->len < 0) | ((span2->len < 0) << 1)) { case 0: // Both are AA spans covers1 = span1->covers; covers2 = span2->covers; if(span1->x < x) covers1 += x - span1->x; if(span2->x < x) covers2 += x - span2->x; do { cover = cover_mask * cover_mask - (cover_mask - *covers1++) * (cover_mask - *covers2++); sl.add_cell(x++, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); } while(--len); break; case 1: // span1 is solid, span2 is AA covers2 = span2->covers; if(span2->x < x) covers2 += x - span2->x; if(*(span1->covers) == cover_full) { sl.add_span(x, len, cover_full); } else { do { cover = cover_mask * cover_mask - (cover_mask - *(span1->covers)) * (cover_mask - *covers2++); sl.add_cell(x++, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); } while(--len); } break; case 2: // span1 is AA, span2 is solid covers1 = span1->covers; if(span1->x < x) covers1 += x - span1->x; if(*(span2->covers) == cover_full) { sl.add_span(x, len, cover_full); } else { do { cover = cover_mask * cover_mask - (cover_mask - *covers1++) * (cover_mask - *(span2->covers)); sl.add_cell(x++, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); } while(--len); } break; case 3: // Both are solid spans cover = cover_mask * cover_mask - (cover_mask - *(span1->covers)) * (cover_mask - *(span2->covers)); sl.add_span(x, len, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); break; } } }; //---------------------------------------------sbool_xor_formula_linear template struct sbool_xor_formula_linear { enum cover_scale_e { cover_shift = CoverShift, cover_size = 1 << cover_shift, cover_mask = cover_size - 1 }; static AGG_INLINE unsigned calculate(unsigned a, unsigned b) { unsigned cover = a + b; if(cover > cover_mask) cover = cover_mask + cover_mask - cover; return cover; } }; //---------------------------------------------sbool_xor_formula_saddle template struct sbool_xor_formula_saddle { enum cover_scale_e { cover_shift = CoverShift, cover_size = 1 << cover_shift, cover_mask = cover_size - 1 }; static AGG_INLINE unsigned calculate(unsigned a, unsigned b) { unsigned k = a * b; if(k == cover_mask * cover_mask) return 0; a = (cover_mask * cover_mask - (a << cover_shift) + k) >> cover_shift; b = (cover_mask * cover_mask - (b << cover_shift) + k) >> cover_shift; return cover_mask - ((a * b) >> cover_shift); } }; //-------------------------------------------sbool_xor_formula_abs_diff struct sbool_xor_formula_abs_diff { static AGG_INLINE unsigned calculate(unsigned a, unsigned b) { return unsigned(std::abs(int(a) - int(b))); } }; //----------------------------------------------------sbool_xor_spans_aa // Functor. // XOR two spans preserving the anti-aliasing information. // The result is added to the "sl" scanline. //------------------ template struct sbool_xor_spans_aa { enum cover_scale_e { cover_shift = CoverShift, cover_size = 1 << cover_shift, cover_mask = cover_size - 1, cover_full = cover_mask }; void operator () (const typename Scanline1::const_iterator& span1, const typename Scanline2::const_iterator& span2, int x, unsigned len, Scanline& sl) const { unsigned cover; const typename Scanline1::cover_type* covers1; const typename Scanline2::cover_type* covers2; // Calculate the operation code and choose the // proper combination algorithm. // 0 = Both spans are of AA type // 1 = span1 is solid, span2 is AA // 2 = span1 is AA, span2 is solid // 3 = Both spans are of solid type //----------------- switch((span1->len < 0) | ((span2->len < 0) << 1)) { case 0: // Both are AA spans covers1 = span1->covers; covers2 = span2->covers; if(span1->x < x) covers1 += x - span1->x; if(span2->x < x) covers2 += x - span2->x; do { cover = XorFormula::calculate(*covers1++, *covers2++); if(cover) sl.add_cell(x, cover); ++x; } while(--len); break; case 1: // span1 is solid, span2 is AA covers2 = span2->covers; if(span2->x < x) covers2 += x - span2->x; do { cover = XorFormula::calculate(*(span1->covers), *covers2++); if(cover) sl.add_cell(x, cover); ++x; } while(--len); break; case 2: // span1 is AA, span2 is solid covers1 = span1->covers; if(span1->x < x) covers1 += x - span1->x; do { cover = XorFormula::calculate(*covers1++, *(span2->covers)); if(cover) sl.add_cell(x, cover); ++x; } while(--len); break; case 3: // Both are solid spans cover = XorFormula::calculate(*(span1->covers), *(span2->covers)); if(cover) sl.add_span(x, len, cover); break; } } }; //-----------------------------------------------sbool_subtract_spans_aa // Functor. // Unite two spans preserving the anti-aliasing information. // The result is added to the "sl" scanline. //------------------ template struct sbool_subtract_spans_aa { enum cover_scale_e { cover_shift = CoverShift, cover_size = 1 << cover_shift, cover_mask = cover_size - 1, cover_full = cover_mask }; void operator () (const typename Scanline1::const_iterator& span1, const typename Scanline2::const_iterator& span2, int x, unsigned len, Scanline& sl) const { unsigned cover; const typename Scanline1::cover_type* covers1; const typename Scanline2::cover_type* covers2; // Calculate the operation code and choose the // proper combination algorithm. // 0 = Both spans are of AA type // 1 = span1 is solid, span2 is AA // 2 = span1 is AA, span2 is solid // 3 = Both spans are of solid type //----------------- switch((span1->len < 0) | ((span2->len < 0) << 1)) { case 0: // Both are AA spans covers1 = span1->covers; covers2 = span2->covers; if(span1->x < x) covers1 += x - span1->x; if(span2->x < x) covers2 += x - span2->x; do { cover = *covers1++ * (cover_mask - *covers2++); if(cover) { sl.add_cell(x, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); } ++x; } while(--len); break; case 1: // span1 is solid, span2 is AA covers2 = span2->covers; if(span2->x < x) covers2 += x - span2->x; do { cover = *(span1->covers) * (cover_mask - *covers2++); if(cover) { sl.add_cell(x, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); } ++x; } while(--len); break; case 2: // span1 is AA, span2 is solid covers1 = span1->covers; if(span1->x < x) covers1 += x - span1->x; if(*(span2->covers) != cover_full) { do { cover = *covers1++ * (cover_mask - *(span2->covers)); if(cover) { sl.add_cell(x, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); } ++x; } while(--len); } break; case 3: // Both are solid spans cover = *(span1->covers) * (cover_mask - *(span2->covers)); if(cover) { sl.add_span(x, len, (cover == cover_full * cover_full) ? cover_full : (cover >> cover_shift)); } break; } } }; //--------------------------------------------sbool_add_spans_and_render template void sbool_add_spans_and_render(const Scanline1& sl1, Scanline& sl, Renderer& ren, AddSpanFunctor add_span) { sl.reset_spans(); typename Scanline1::const_iterator span = sl1.begin(); unsigned num_spans = sl1.num_spans(); for(;;) { add_span(span, span->x, std::abs((int)span->len), sl); if(--num_spans == 0) break; ++span; } sl.finalize(sl1.y()); ren.render(sl); } //---------------------------------------------sbool_intersect_scanlines // Intersect two scanlines, "sl1" and "sl2" and generate a new "sl" one. // The combine_spans functor can be of type sbool_combine_spans_bin or // sbool_intersect_spans_aa. First is a general functor to combine // two spans without Anti-Aliasing, the second preserves the AA // information, but works slower // template void sbool_intersect_scanlines(const Scanline1& sl1, const Scanline2& sl2, Scanline& sl, CombineSpansFunctor combine_spans) { sl.reset_spans(); unsigned num1 = sl1.num_spans(); if(num1 == 0) return; unsigned num2 = sl2.num_spans(); if(num2 == 0) return; typename Scanline1::const_iterator span1 = sl1.begin(); typename Scanline2::const_iterator span2 = sl2.begin(); while(num1 && num2) { int xb1 = span1->x; int xb2 = span2->x; int xe1 = xb1 + std::abs((int)span1->len) - 1; int xe2 = xb2 + std::abs((int)span2->len) - 1; // Determine what spans we should advance in the next step // The span with the least ending X should be advanced // advance_both is just an optimization when we ending // coordinates are the same and we can advance both //-------------- bool advance_span1 = xe1 < xe2; bool advance_both = xe1 == xe2; // Find the intersection of the spans // and check if they intersect //-------------- if(xb1 < xb2) xb1 = xb2; if(xe1 > xe2) xe1 = xe2; if(xb1 <= xe1) { combine_spans(span1, span2, xb1, xe1 - xb1 + 1, sl); } // Advance the spans //-------------- if(advance_both) { --num1; --num2; if(num1) ++span1; if(num2) ++span2; } else { if(advance_span1) { --num1; if(num1) ++span1; } else { --num2; if(num2) ++span2; } } } } //------------------------------------------------sbool_intersect_shapes // Intersect the scanline shapes. Here the "Scanline Generator" // abstraction is used. ScanlineGen1 and ScanlineGen2 are // the generators, and can be of type rasterizer_scanline_aa<>. // There function requires three scanline containers that can be of // different types. // "sl1" and "sl2" are used to retrieve scanlines from the generators, // "sl" is ised as the resulting scanline to render it. // The external "sl1" and "sl2" are used only for the sake of // optimization and reusing of the scanline objects. // the function calls sbool_intersect_scanlines with CombineSpansFunctor // as the last argument. See sbool_intersect_scanlines for details. //---------- template void sbool_intersect_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren, CombineSpansFunctor combine_spans) { // Prepare the scanline generators. // If anyone of them doesn't contain // any scanlines, then return. //----------------- if(!sg1.rewind_scanlines()) return; if(!sg2.rewind_scanlines()) return; // Get the bounding boxes //---------------- rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y()); rect_i r2(sg2.min_x(), sg2.min_y(), sg2.max_x(), sg2.max_y()); // Calculate the intersection of the bounding // boxes and return if they don't intersect. //----------------- rect_i ir = intersect_rectangles(r1, r2); if(!ir.is_valid()) return; // Reset the scanlines and get two first ones //----------------- sl.reset(ir.x1, ir.x2); sl1.reset(sg1.min_x(), sg1.max_x()); sl2.reset(sg2.min_x(), sg2.max_x()); if(!sg1.sweep_scanline(sl1)) return; if(!sg2.sweep_scanline(sl2)) return; ren.prepare(); // The main loop // Here we synchronize the scanlines with // the same Y coordinate, ignoring all other ones. // Only scanlines having the same Y-coordinate // are to be combined. //----------------- for(;;) { while(sl1.y() < sl2.y()) { if(!sg1.sweep_scanline(sl1)) return; } while(sl2.y() < sl1.y()) { if(!sg2.sweep_scanline(sl2)) return; } if(sl1.y() == sl2.y()) { // The Y coordinates are the same. // Combine the scanlines, render if they contain any spans, // and advance both generators to the next scanlines //---------------------- sbool_intersect_scanlines(sl1, sl2, sl, combine_spans); if(sl.num_spans()) { sl.finalize(sl1.y()); ren.render(sl); } if(!sg1.sweep_scanline(sl1)) return; if(!sg2.sweep_scanline(sl2)) return; } } } //-------------------------------------------------sbool_unite_scanlines // Unite two scanlines, "sl1" and "sl2" and generate a new "sl" one. // The combine_spans functor can be of type sbool_combine_spans_bin or // sbool_intersect_spans_aa. First is a general functor to combine // two spans without Anti-Aliasing, the second preserves the AA // information, but works slower // template void sbool_unite_scanlines(const Scanline1& sl1, const Scanline2& sl2, Scanline& sl, AddSpanFunctor1 add_span1, AddSpanFunctor2 add_span2, CombineSpansFunctor combine_spans) { sl.reset_spans(); unsigned num1 = sl1.num_spans(); unsigned num2 = sl2.num_spans(); typename Scanline1::const_iterator span1;// = sl1.begin(); typename Scanline2::const_iterator span2;// = sl2.begin(); enum invalidation_e { invalid_b = 0xFFFFFFF, invalid_e = invalid_b - 1 }; // Initialize the spans as invalid //--------------- int xb1 = invalid_b; int xb2 = invalid_b; int xe1 = invalid_e; int xe2 = invalid_e; // Initialize span1 if there are spans //--------------- if(num1) { span1 = sl1.begin(); xb1 = span1->x; xe1 = xb1 + std::abs((int)span1->len) - 1; --num1; } // Initialize span2 if there are spans //--------------- if(num2) { span2 = sl2.begin(); xb2 = span2->x; xe2 = xb2 + std::abs((int)span2->len) - 1; --num2; } for(;;) { // Retrieve a new span1 if it's invalid //---------------- if(num1 && xb1 > xe1) { --num1; ++span1; xb1 = span1->x; xe1 = xb1 + std::abs((int)span1->len) - 1; } // Retrieve a new span2 if it's invalid //---------------- if(num2 && xb2 > xe2) { --num2; ++span2; xb2 = span2->x; xe2 = xb2 + std::abs((int)span2->len) - 1; } if(xb1 > xe1 && xb2 > xe2) break; // Calculate the intersection //---------------- int xb = xb1; int xe = xe1; if(xb < xb2) xb = xb2; if(xe > xe2) xe = xe2; int len = xe - xb + 1; // The length of the intersection if(len > 0) { // The spans intersect, // add the beginning of the span //---------------- if(xb1 < xb2) { add_span1(span1, xb1, xb2 - xb1, sl); xb1 = xb2; } else if(xb2 < xb1) { add_span2(span2, xb2, xb1 - xb2, sl); xb2 = xb1; } // Add the combination part of the spans //---------------- combine_spans(span1, span2, xb, len, sl); // Invalidate the fully processed span or both //---------------- if(xe1 < xe2) { // Invalidate span1 and eat // the processed part of span2 //-------------- xb1 = invalid_b; xe1 = invalid_e; xb2 += len; } else if(xe2 < xe1) { // Invalidate span2 and eat // the processed part of span1 //-------------- xb2 = invalid_b; xe2 = invalid_e; xb1 += len; } else { xb1 = invalid_b; // Invalidate both xb2 = invalid_b; xe1 = invalid_e; xe2 = invalid_e; } } else { // The spans do not intersect //-------------- if(xb1 < xb2) { // Advance span1 //--------------- if(xb1 <= xe1) { add_span1(span1, xb1, xe1 - xb1 + 1, sl); } xb1 = invalid_b; // Invalidate xe1 = invalid_e; } else { // Advance span2 //--------------- if(xb2 <= xe2) { add_span2(span2, xb2, xe2 - xb2 + 1, sl); } xb2 = invalid_b; // Invalidate xe2 = invalid_e; } } } } //----------------------------------------------------sbool_unite_shapes // Unite the scanline shapes. Here the "Scanline Generator" // abstraction is used. ScanlineGen1 and ScanlineGen2 are // the generators, and can be of type rasterizer_scanline_aa<>. // There function requires three scanline containers that can be // of different type. // "sl1" and "sl2" are used to retrieve scanlines from the generators, // "sl" is ised as the resulting scanline to render it. // The external "sl1" and "sl2" are used only for the sake of // optimization and reusing of the scanline objects. // the function calls sbool_unite_scanlines with CombineSpansFunctor // as the last argument. See sbool_unite_scanlines for details. //---------- template void sbool_unite_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren, AddSpanFunctor1 add_span1, AddSpanFunctor2 add_span2, CombineSpansFunctor combine_spans) { // Prepare the scanline generators. // If anyone of them doesn't contain // any scanlines, then return. //----------------- bool flag1 = sg1.rewind_scanlines(); bool flag2 = sg2.rewind_scanlines(); if(!flag1 && !flag2) return; // Get the bounding boxes //---------------- rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y()); rect_i r2(sg2.min_x(), sg2.min_y(), sg2.max_x(), sg2.max_y()); // Calculate the union of the bounding boxes //----------------- rect_i ur(1,1,0,0); if(flag1 && flag2) ur = unite_rectangles(r1, r2); else if(flag1) ur = r1; else if(flag2) ur = r2; if(!ur.is_valid()) return; ren.prepare(); // Reset the scanlines and get two first ones //----------------- sl.reset(ur.x1, ur.x2); if(flag1) { sl1.reset(sg1.min_x(), sg1.max_x()); flag1 = sg1.sweep_scanline(sl1); } if(flag2) { sl2.reset(sg2.min_x(), sg2.max_x()); flag2 = sg2.sweep_scanline(sl2); } // The main loop // Here we synchronize the scanlines with // the same Y coordinate. //----------------- while(flag1 || flag2) { if(flag1 && flag2) { if(sl1.y() == sl2.y()) { // The Y coordinates are the same. // Combine the scanlines, render if they contain any spans, // and advance both generators to the next scanlines //---------------------- sbool_unite_scanlines(sl1, sl2, sl, add_span1, add_span2, combine_spans); if(sl.num_spans()) { sl.finalize(sl1.y()); ren.render(sl); } flag1 = sg1.sweep_scanline(sl1); flag2 = sg2.sweep_scanline(sl2); } else { if(sl1.y() < sl2.y()) { sbool_add_spans_and_render(sl1, sl, ren, add_span1); flag1 = sg1.sweep_scanline(sl1); } else { sbool_add_spans_and_render(sl2, sl, ren, add_span2); flag2 = sg2.sweep_scanline(sl2); } } } else { if(flag1) { sbool_add_spans_and_render(sl1, sl, ren, add_span1); flag1 = sg1.sweep_scanline(sl1); } if(flag2) { sbool_add_spans_and_render(sl2, sl, ren, add_span2); flag2 = sg2.sweep_scanline(sl2); } } } } //-------------------------------------------------sbool_subtract_shapes // Subtract the scanline shapes, "sg1-sg2". Here the "Scanline Generator" // abstraction is used. ScanlineGen1 and ScanlineGen2 are // the generators, and can be of type rasterizer_scanline_aa<>. // There function requires three scanline containers that can be of // different types. // "sl1" and "sl2" are used to retrieve scanlines from the generators, // "sl" is ised as the resulting scanline to render it. // The external "sl1" and "sl2" are used only for the sake of // optimization and reusing of the scanline objects. // the function calls sbool_intersect_scanlines with CombineSpansFunctor // as the last argument. See combine_scanlines_sub for details. //---------- template void sbool_subtract_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren, AddSpanFunctor1 add_span1, CombineSpansFunctor combine_spans) { // Prepare the scanline generators. // Here "sg1" is master, "sg2" is slave. //----------------- if(!sg1.rewind_scanlines()) return; bool flag2 = sg2.rewind_scanlines(); // Get the bounding box //---------------- rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y()); // Reset the scanlines and get two first ones //----------------- sl.reset(sg1.min_x(), sg1.max_x()); sl1.reset(sg1.min_x(), sg1.max_x()); sl2.reset(sg2.min_x(), sg2.max_x()); if(!sg1.sweep_scanline(sl1)) return; if(flag2) flag2 = sg2.sweep_scanline(sl2); ren.prepare(); // A fake span2 processor sbool_add_span_empty add_span2; // The main loop // Here we synchronize the scanlines with // the same Y coordinate, ignoring all other ones. // Only scanlines having the same Y-coordinate // are to be combined. //----------------- bool flag1 = true; do { // Synchronize "slave" with "master" //----------------- while(flag2 && sl2.y() < sl1.y()) { flag2 = sg2.sweep_scanline(sl2); } if(flag2 && sl2.y() == sl1.y()) { // The Y coordinates are the same. // Combine the scanlines and render if they contain any spans. //---------------------- sbool_unite_scanlines(sl1, sl2, sl, add_span1, add_span2, combine_spans); if(sl.num_spans()) { sl.finalize(sl1.y()); ren.render(sl); } } else { sbool_add_spans_and_render(sl1, sl, ren, add_span1); } // Advance the "master" flag1 = sg1.sweep_scanline(sl1); } while(flag1); } //---------------------------------------------sbool_intersect_shapes_aa // Intersect two anti-aliased scanline shapes. // Here the "Scanline Generator" abstraction is used. // ScanlineGen1 and ScanlineGen2 are the generators, and can be of // type rasterizer_scanline_aa<>. There function requires three // scanline containers that can be of different types. // "sl1" and "sl2" are used to retrieve scanlines from the generators, // "sl" is ised as the resulting scanline to render it. // The external "sl1" and "sl2" are used only for the sake of // optimization and reusing of the scanline objects. //---------- template void sbool_intersect_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { sbool_intersect_spans_aa combine_functor; sbool_intersect_shapes(sg1, sg2, sl1, sl2, sl, ren, combine_functor); } //--------------------------------------------sbool_intersect_shapes_bin // Intersect two binary scanline shapes (without anti-aliasing). // See intersect_shapes_aa for more comments //---------- template void sbool_intersect_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { sbool_combine_spans_bin combine_functor; sbool_intersect_shapes(sg1, sg2, sl1, sl2, sl, ren, combine_functor); } //-------------------------------------------------sbool_unite_shapes_aa // Unite two anti-aliased scanline shapes // See intersect_shapes_aa for more comments //---------- template void sbool_unite_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { sbool_add_span_aa add_functor1; sbool_add_span_aa add_functor2; sbool_unite_spans_aa combine_functor; sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, add_functor1, add_functor2, combine_functor); } //------------------------------------------------sbool_unite_shapes_bin // Unite two binary scanline shapes (without anti-aliasing). // See intersect_shapes_aa for more comments //---------- template void sbool_unite_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { sbool_add_span_bin add_functor1; sbool_add_span_bin add_functor2; sbool_combine_spans_bin combine_functor; sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, add_functor1, add_functor2, combine_functor); } //---------------------------------------------------sbool_xor_shapes_aa // Apply eXclusive OR to two anti-aliased scanline shapes. There's // a modified "Linear" XOR used instead of classical "Saddle" one. // The reason is to have the result absolutely conststent with what // the scanline rasterizer produces. // See intersect_shapes_aa for more comments //---------- template void sbool_xor_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { sbool_add_span_aa add_functor1; sbool_add_span_aa add_functor2; sbool_xor_spans_aa > combine_functor; sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, add_functor1, add_functor2, combine_functor); } //------------------------------------------sbool_xor_shapes_saddle_aa // Apply eXclusive OR to two anti-aliased scanline shapes. // There's the classical "Saddle" used to calculate the // Anti-Aliasing values, that is: // a XOR b : 1-((1-a+a*b)*(1-b+a*b)) // See intersect_shapes_aa for more comments //---------- template void sbool_xor_shapes_saddle_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { sbool_add_span_aa add_functor1; sbool_add_span_aa add_functor2; sbool_xor_spans_aa > combine_functor; sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, add_functor1, add_functor2, combine_functor); } //--------------------------------------sbool_xor_shapes_abs_diff_aa // Apply eXclusive OR to two anti-aliased scanline shapes. // There's the absolute difference used to calculate // Anti-Aliasing values, that is: // a XOR b : abs(a-b) // See intersect_shapes_aa for more comments //---------- template void sbool_xor_shapes_abs_diff_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { sbool_add_span_aa add_functor1; sbool_add_span_aa add_functor2; sbool_xor_spans_aa combine_functor; sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, add_functor1, add_functor2, combine_functor); } //--------------------------------------------------sbool_xor_shapes_bin // Apply eXclusive OR to two binary scanline shapes (without anti-aliasing). // See intersect_shapes_aa for more comments //---------- template void sbool_xor_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { sbool_add_span_bin add_functor1; sbool_add_span_bin add_functor2; sbool_combine_spans_empty combine_functor; sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren, add_functor1, add_functor2, combine_functor); } //----------------------------------------------sbool_subtract_shapes_aa // Subtract shapes "sg1-sg2" with anti-aliasing // See intersect_shapes_aa for more comments //---------- template void sbool_subtract_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { sbool_add_span_aa add_functor; sbool_subtract_spans_aa combine_functor; sbool_subtract_shapes(sg1, sg2, sl1, sl2, sl, ren, add_functor, combine_functor); } //---------------------------------------------sbool_subtract_shapes_bin // Subtract binary shapes "sg1-sg2" without anti-aliasing // See intersect_shapes_aa for more comments //---------- template void sbool_subtract_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { sbool_add_span_bin add_functor; sbool_combine_spans_empty combine_functor; sbool_subtract_shapes(sg1, sg2, sl1, sl2, sl, ren, add_functor, combine_functor); } //------------------------------------------------------------sbool_op_e enum sbool_op_e { sbool_or, //----sbool_or sbool_and, //----sbool_and sbool_xor, //----sbool_xor sbool_xor_saddle, //----sbool_xor_saddle sbool_xor_abs_diff, //----sbool_xor_abs_diff sbool_a_minus_b, //----sbool_a_minus_b sbool_b_minus_a //----sbool_b_minus_a }; //----------------------------------------------sbool_combine_shapes_bin template void sbool_combine_shapes_bin(sbool_op_e op, ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { switch(op) { case sbool_or : sbool_unite_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break; case sbool_and : sbool_intersect_shapes_bin(sg1, sg2, sl1, sl2, sl, ren); break; case sbool_xor : case sbool_xor_saddle : case sbool_xor_abs_diff: sbool_xor_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break; case sbool_a_minus_b : sbool_subtract_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break; case sbool_b_minus_a : sbool_subtract_shapes_bin (sg2, sg1, sl2, sl1, sl, ren); break; } } //-----------------------------------------------sbool_combine_shapes_aa template void sbool_combine_shapes_aa(sbool_op_e op, ScanlineGen1& sg1, ScanlineGen2& sg2, Scanline1& sl1, Scanline2& sl2, Scanline& sl, Renderer& ren) { switch(op) { case sbool_or : sbool_unite_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break; case sbool_and : sbool_intersect_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break; case sbool_xor : sbool_xor_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break; case sbool_xor_saddle : sbool_xor_shapes_saddle_aa (sg1, sg2, sl1, sl2, sl, ren); break; case sbool_xor_abs_diff: sbool_xor_shapes_abs_diff_aa(sg1, sg2, sl1, sl2, sl, ren); break; case sbool_a_minus_b : sbool_subtract_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break; case sbool_b_minus_a : sbool_subtract_shapes_aa (sg2, sg1, sl2, sl1, sl, ren); break; } } } #endif ragg/src/agg/include/agg_span_pattern_rgba.h0000644000176200001440000000646213504406270020633 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_SPAN_PATTERN_RGBA_INCLUDED #define AGG_SPAN_PATTERN_RGBA_INCLUDED #include "agg_basics.h" namespace agg { //======================================================span_pattern_rgba template class span_pattern_rgba { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; //-------------------------------------------------------------------- span_pattern_rgba() {} span_pattern_rgba(source_type& src, unsigned offset_x, unsigned offset_y) : m_src(&src), m_offset_x(offset_x), m_offset_y(offset_y) {} //-------------------------------------------------------------------- void attach(source_type& v) { m_src = &v; } source_type& source() { return *m_src; } const source_type& source() const { return *m_src; } //-------------------------------------------------------------------- void offset_x(unsigned v) { m_offset_x = v; } void offset_y(unsigned v) { m_offset_y = v; } unsigned offset_x() const { return m_offset_x; } unsigned offset_y() const { return m_offset_y; } void alpha(value_type) {} value_type alpha() const { return 0; } //-------------------------------------------------------------------- void prepare() {} void generate(color_type* span, int x, int y, unsigned len) { x += m_offset_x; y += m_offset_y; const value_type* p = (const value_type*)m_src->span(x, y, len); do { span->r = p[order_type::R]; span->g = p[order_type::G]; span->b = p[order_type::B]; span->a = p[order_type::A]; p = (const value_type*)m_src->next_x(); ++span; } while(--len); } private: source_type* m_src; unsigned m_offset_x; unsigned m_offset_y; }; } #endif ragg/src/agg/include/agg_rasterizer_cells_aa.h0000644000176200001440000005206413506444162021162 0ustar liggesusers//---------------------------------------------------------------------------- // 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 #include #include #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 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 }; struct sorted_y { unsigned start; unsigned num; }; public: typedef Cell cell_type; typedef rasterizer_cells_aa self_type; ~rasterizer_cells_aa(); rasterizer_cells_aa(unsigned cell_block_limit=1024); 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; unsigned m_cell_block_limit; cell_type** m_cells; cell_type* m_curr_cell_ptr; pod_vector m_sorted_cells; pod_vector 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 rasterizer_cells_aa::~rasterizer_cells_aa() { if(m_num_blocks) { cell_type** ptr = m_cells + m_num_blocks - 1; while(m_num_blocks--) { pod_allocator::deallocate(*ptr, cell_block_size); ptr--; } pod_allocator::deallocate(m_cells, m_max_blocks); } } //------------------------------------------------------------------------ template rasterizer_cells_aa::rasterizer_cells_aa(unsigned cell_block_limit) : m_num_blocks(0), m_max_blocks(0), m_curr_block(0), m_num_cells(0), m_cell_block_limit(cell_block_limit), m_cells(0), m_curr_cell_ptr(0), m_sorted_cells(), m_sorted_y(), m_min_x(std::numeric_limits::max()), m_min_y(std::numeric_limits::max()), m_max_x(std::numeric_limits::min()), m_max_y(std::numeric_limits::min()), m_sorted(false) { m_style_cell.initial(); m_curr_cell.initial(); } //------------------------------------------------------------------------ template void rasterizer_cells_aa::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::max(); m_min_y = std::numeric_limits::max(); m_max_x = std::numeric_limits::min(); m_max_y = std::numeric_limits::min(); } //------------------------------------------------------------------------ template AGG_INLINE void rasterizer_cells_aa::add_curr_cell() { if(m_curr_cell.area | m_curr_cell.cover) { if((m_num_cells & cell_block_mask) == 0) { if(m_num_blocks >= m_cell_block_limit) return; allocate_block(); } *m_curr_cell_ptr++ = m_curr_cell; ++m_num_cells; } } //------------------------------------------------------------------------ template AGG_INLINE void rasterizer_cells_aa::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 AGG_INLINE void rasterizer_cells_aa::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 += 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 += 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 AGG_INLINE void rasterizer_cells_aa::style(const cell_type& style_cell) { m_style_cell.style(style_cell); } //------------------------------------------------------------------------ template void rasterizer_cells_aa::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 - ( (unsigned int) 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 += 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 += 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 void rasterizer_cells_aa::allocate_block() { if(m_curr_block >= m_num_blocks) { if(m_num_blocks >= m_max_blocks) { cell_type** new_cells = pod_allocator::allocate(m_max_blocks + cell_block_pool); if(m_cells) { std::memcpy(new_cells, m_cells, m_max_blocks * sizeof(cell_type*)); pod_allocator::deallocate(m_cells, m_max_blocks); } m_cells = new_cells; m_max_blocks += cell_block_pool; } m_cells[m_num_blocks++] = pod_allocator::allocate(cell_block_size); } m_curr_cell_ptr = m_cells[m_curr_block++]; } //------------------------------------------------------------------------ template static AGG_INLINE void swap_cells(T* a, T* b) { T temp = *a; *a = *b; *b = temp; } //------------------------------------------------------------------------ enum { qsort_threshold = 9 }; //------------------------------------------------------------------------ template 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 void rasterizer_cells_aa::sort_cells() { if(m_sorted) return; //Perform sort only the first time. add_curr_cell(); m_curr_cell.x = std::numeric_limits::max(); m_curr_cell.y = std::numeric_limits::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 ragg/src/agg/include/agg_bspline.h0000644000176200001440000000512013504406270016564 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // class bspline // //---------------------------------------------------------------------------- #ifndef AGG_BSPLINE_INCLUDED #define AGG_BSPLINE_INCLUDED #include "agg_array.h" namespace agg { //----------------------------------------------------------------bspline // A very simple class of Bi-cubic Spline interpolation. // First call init(num, x[], y[]) where num - number of source points, // x, y - arrays of X and Y values respectively. Here Y must be a function // of X. It means that all the X-coordinates must be arranged in the ascending // order. // Then call get(x) that calculates a value Y for the respective X. // The class supports extrapolation, i.e. you can call get(x) where x is // outside the given with init() X-range. Extrapolation is a simple linear // function. // // See Implementation agg_bspline.cpp //------------------------------------------------------------------------ class bspline { public: bspline(); bspline(int num); bspline(int num, const double* x, const double* y); void init(int num); void add_point(double x, double y); void prepare(); void init(int num, const double* x, const double* y); double get(double x) const; double get_stateful(double x) const; private: bspline(const bspline&); const bspline& operator = (const bspline&); static void bsearch(int n, const double *x, double x0, int *i); double extrapolation_left(double x) const; double extrapolation_right(double x) const; double interpolation(double x, int i) const; int m_max; int m_num; double* m_x; double* m_y; pod_array m_am; mutable int m_last_idx; }; } #endif ragg/src/agg/include/agg_span_converter.h0000644000176200001440000000363613504406270020172 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_SPAN_CONVERTER_INCLUDED #define AGG_SPAN_CONVERTER_INCLUDED #include "agg_basics.h" namespace agg { //----------------------------------------------------------span_converter template class span_converter { public: typedef typename SpanGenerator::color_type color_type; span_converter(SpanGenerator& span_gen, SpanConverter& span_cnv) : m_span_gen(&span_gen), m_span_cnv(&span_cnv) {} void attach_generator(SpanGenerator& span_gen) { m_span_gen = &span_gen; } void attach_converter(SpanConverter& span_cnv) { m_span_cnv = &span_cnv; } //-------------------------------------------------------------------- void prepare() { m_span_gen->prepare(); m_span_cnv->prepare(); } //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { m_span_gen->generate(span, x, y, len); m_span_cnv->generate(span, x, y, len); } private: SpanGenerator* m_span_gen; SpanConverter* m_span_cnv; }; } #endif ragg/src/agg/include/agg_math.h0000644000176200001440000003504413504406270016071 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // Bessel function (besj) was adapted for use in AGG library by Andy Wilk // Contact: castor.vulgaris@gmail.com //---------------------------------------------------------------------------- #ifndef AGG_MATH_INCLUDED #define AGG_MATH_INCLUDED #include #include "agg_basics.h" namespace agg { //------------------------------------------------------vertex_dist_epsilon // Coinciding points maximal distance (Epsilon) const double vertex_dist_epsilon = 1e-14; //-----------------------------------------------------intersection_epsilon // See calc_intersection const double intersection_epsilon = 1.0e-30; //------------------------------------------------------------cross_product AGG_INLINE double cross_product(double x1, double y1, double x2, double y2, double x, double y) { return (x - x2) * (y2 - y1) - (y - y2) * (x2 - x1); } //--------------------------------------------------------point_in_triangle AGG_INLINE bool point_in_triangle(double x1, double y1, double x2, double y2, double x3, double y3, double x, double y) { bool cp1 = cross_product(x1, y1, x2, y2, x, y) < 0.0; bool cp2 = cross_product(x2, y2, x3, y3, x, y) < 0.0; bool cp3 = cross_product(x3, y3, x1, y1, x, y) < 0.0; return cp1 == cp2 && cp2 == cp3 && cp3 == cp1; } //-----------------------------------------------------------calc_distance AGG_INLINE double calc_distance(double x1, double y1, double x2, double y2) { double dx = x2-x1; double dy = y2-y1; return std::sqrt(dx * dx + dy * dy); } //--------------------------------------------------------calc_sq_distance AGG_INLINE double calc_sq_distance(double x1, double y1, double x2, double y2) { double dx = x2-x1; double dy = y2-y1; return dx * dx + dy * dy; } //------------------------------------------------calc_line_point_distance AGG_INLINE double calc_line_point_distance(double x1, double y1, double x2, double y2, double x, double y) { double dx = x2-x1; double dy = y2-y1; double d = std::sqrt(dx * dx + dy * dy); if(d < vertex_dist_epsilon) { return calc_distance(x1, y1, x, y); } return ((x - x2) * dy - (y - y2) * dx) / d; } //-------------------------------------------------------calc_line_point_u AGG_INLINE double calc_segment_point_u(double x1, double y1, double x2, double y2, double x, double y) { double dx = x2 - x1; double dy = y2 - y1; if(dx == 0 && dy == 0) { return 0; } double pdx = x - x1; double pdy = y - y1; return (pdx * dx + pdy * dy) / (dx * dx + dy * dy); } //---------------------------------------------calc_line_point_sq_distance AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1, double x2, double y2, double x, double y, double u) { if(u <= 0) { return calc_sq_distance(x, y, x1, y1); } else if(u >= 1) { return calc_sq_distance(x, y, x2, y2); } return calc_sq_distance(x, y, x1 + u * (x2 - x1), y1 + u * (y2 - y1)); } //---------------------------------------------calc_line_point_sq_distance AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1, double x2, double y2, double x, double y) { return calc_segment_point_sq_distance( x1, y1, x2, y2, x, y, calc_segment_point_u(x1, y1, x2, y2, x, y)); } //-------------------------------------------------------calc_intersection AGG_INLINE bool calc_intersection(double ax, double ay, double bx, double by, double cx, double cy, double dx, double dy, double* x, double* y) { double num = (ay-cy) * (dx-cx) - (ax-cx) * (dy-cy); double den = (bx-ax) * (dy-cy) - (by-ay) * (dx-cx); if(std::fabs(den) < intersection_epsilon) return false; double r = num / den; *x = ax + r * (bx-ax); *y = ay + r * (by-ay); return true; } //-----------------------------------------------------intersection_exists AGG_INLINE bool intersection_exists(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { // It's less expensive but you can't control the // boundary conditions: Less or LessEqual double dx1 = x2 - x1; double dy1 = y2 - y1; double dx2 = x4 - x3; double dy2 = y4 - y3; return ((x3 - x2) * dy1 - (y3 - y2) * dx1 < 0.0) != ((x4 - x2) * dy1 - (y4 - y2) * dx1 < 0.0) && ((x1 - x4) * dy2 - (y1 - y4) * dx2 < 0.0) != ((x2 - x4) * dy2 - (y2 - y4) * dx2 < 0.0); // It's is more expensive but more flexible // in terms of boundary conditions. //-------------------- //double den = (x2-x1) * (y4-y3) - (y2-y1) * (x4-x3); //if(fabs(den) < intersection_epsilon) return false; //double nom1 = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3); //double nom2 = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3); //double ua = nom1 / den; //double ub = nom2 / den; //return ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0; } //--------------------------------------------------------calc_orthogonal AGG_INLINE void calc_orthogonal(double thickness, double x1, double y1, double x2, double y2, double* x, double* y) { double dx = x2 - x1; double dy = y2 - y1; double d = std::sqrt(dx*dx + dy*dy); *x = thickness * dy / d; *y = -thickness * dx / d; } //--------------------------------------------------------dilate_triangle AGG_INLINE void dilate_triangle(double x1, double y1, double x2, double y2, double x3, double y3, double *x, double* y, double d) { double dx1=0.0; double dy1=0.0; double dx2=0.0; double dy2=0.0; double dx3=0.0; double dy3=0.0; double loc = cross_product(x1, y1, x2, y2, x3, y3); if(std::fabs(loc) > intersection_epsilon) { if(cross_product(x1, y1, x2, y2, x3, y3) > 0.0) { d = -d; } calc_orthogonal(d, x1, y1, x2, y2, &dx1, &dy1); calc_orthogonal(d, x2, y2, x3, y3, &dx2, &dy2); calc_orthogonal(d, x3, y3, x1, y1, &dx3, &dy3); } *x++ = x1 + dx1; *y++ = y1 + dy1; *x++ = x2 + dx1; *y++ = y2 + dy1; *x++ = x2 + dx2; *y++ = y2 + dy2; *x++ = x3 + dx2; *y++ = y3 + dy2; *x++ = x3 + dx3; *y++ = y3 + dy3; *x++ = x1 + dx3; *y++ = y1 + dy3; } //------------------------------------------------------calc_triangle_area AGG_INLINE double calc_triangle_area(double x1, double y1, double x2, double y2, double x3, double y3) { return (x1*y2 - x2*y1 + x2*y3 - x3*y2 + x3*y1 - x1*y3) * 0.5; } //-------------------------------------------------------calc_polygon_area template double calc_polygon_area(const Storage& st) { unsigned i; double sum = 0.0; double x = st[0].x; double y = st[0].y; double xs = x; double ys = y; for(i = 1; i < st.size(); i++) { const typename Storage::value_type& v = st[i]; sum += x * v.y - y * v.x; x = v.x; y = v.y; } return (sum + x * ys - y * xs) * 0.5; } //------------------------------------------------------------------------ // Tables for fast sqrt extern int16u g_sqrt_table[1024]; extern int8 g_elder_bit_table[256]; //---------------------------------------------------------------fast_sqrt //Fast integer Sqrt - really fast: no cycles, divisions or multiplications #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4035) //Disable warning "no return value" #endif AGG_INLINE unsigned fast_sqrt(unsigned val) { #if defined(_M_IX86) && defined(_MSC_VER) && !defined(AGG_NO_ASM) //For Ix86 family processors this assembler code is used. //The key command here is bsr - determination the number of the most //significant bit of the value. For other processors //(and maybe compilers) the pure C "#else" section is used. __asm { mov ebx, val mov edx, 11 bsr ecx, ebx sub ecx, 9 jle less_than_9_bits shr ecx, 1 adc ecx, 0 sub edx, ecx shl ecx, 1 shr ebx, cl less_than_9_bits: xor eax, eax mov ax, g_sqrt_table[ebx*2] mov ecx, edx shr eax, cl } #else //This code is actually pure C and portable to most //arcitectures including 64bit ones. unsigned t = val; int bit=0; unsigned shift = 11; //The following piece of code is just an emulation of the //Ix86 assembler command "bsr" (see above). However on old //Intels (like Intel MMX 233MHz) this code is about twice //faster (sic!) then just one "bsr". On PIII and PIV the //bsr is optimized quite well. bit = t >> 24; if(bit) { bit = g_elder_bit_table[bit] + 24; } else { bit = (t >> 16) & 0xFF; if(bit) { bit = g_elder_bit_table[bit] + 16; } else { bit = (t >> 8) & 0xFF; if(bit) { bit = g_elder_bit_table[bit] + 8; } else { bit = g_elder_bit_table[t]; } } } //This code calculates the sqrt. bit -= 9; if(bit > 0) { bit = (bit >> 1) + (bit & 1); shift -= bit; val >>= (bit << 1); } return g_sqrt_table[val] >> shift; #endif } #if defined(_MSC_VER) #pragma warning(pop) #endif //--------------------------------------------------------------------besj // Function BESJ calculates Bessel function of first kind of order n // Arguments: // n - an integer (>=0), the order // x - value at which the Bessel function is required //-------------------- // C++ Mathematical Library // Convereted from equivalent FORTRAN library // Converetd by Gareth Walker for use by course 392 computational project // All functions tested and yield the same results as the corresponding // FORTRAN versions. // // If you have any problems using these functions please report them to // M.Muldoon@UMIST.ac.uk // // Documentation available on the web // http://www.ma.umist.ac.uk/mrm/Teaching/392/libs/392.html // Version 1.0 8/98 // 29 October, 1999 //-------------------- // Adapted for use in AGG library by Andy Wilk (castor.vulgaris@gmail.com) //------------------------------------------------------------------------ inline double besj(double x, int n) { if(n < 0) { return 0; } double d = 1E-6; double b = 0; if(std::fabs(x) <= d) { if(n != 0) return 0; return 1; } double b1 = 0; // b1 is the value from the previous iteration // Set up a starting order for recurrence int m1 = (int)std::fabs(x) + 6; if(std::fabs(x) > 5) { m1 = (int)(std::fabs(1.4 * x + 60 / x)); } int m2 = (int)(n + 2 + std::fabs(x) / 4); if (m1 > m2) { m2 = m1; } // Apply recurrence down from curent max order for(;;) { double c3 = 0; double c2 = 1E-30; double c4 = 0; int m8 = 1; if (m2 / 2 * 2 == m2) { m8 = -1; } int imax = m2 - 2; for (int i = 1; i <= imax; i++) { double c6 = 2 * (m2 - i) * c2 / x - c3; c3 = c2; c2 = c6; if(m2 - i - 1 == n) { b = c6; } m8 = -1 * m8; if (m8 > 0) { c4 = c4 + 2 * c6; } } double c6 = 2 * c2 / x - c3; if(n == 0) { b = c6; } c4 += c6; b /= c4; if(std::fabs(b - b1) < d) { return b; } b1 = b; m2 += 3; } } } #endif ragg/src/agg/include/agg_trans_viewport.h0000644000176200001440000002266013504406270020226 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Viewport transformer - simple orthogonal conversions from world coordinates // to screen (device) ones. // //---------------------------------------------------------------------------- #ifndef AGG_TRANS_VIEWPORT_INCLUDED #define AGG_TRANS_VIEWPORT_INCLUDED #include #include #include "agg_trans_affine.h" namespace agg { enum aspect_ratio_e { aspect_ratio_stretch, aspect_ratio_meet, aspect_ratio_slice }; //----------------------------------------------------------trans_viewport class trans_viewport { public: //------------------------------------------------------------------- trans_viewport() : m_world_x1(0.0), m_world_y1(0.0), m_world_x2(1.0), m_world_y2(1.0), m_device_x1(0.0), m_device_y1(0.0), m_device_x2(1.0), m_device_y2(1.0), m_aspect(aspect_ratio_stretch), m_is_valid(true), m_align_x(0.5), m_align_y(0.5), m_wx1(0.0), m_wy1(0.0), m_wx2(1.0), m_wy2(1.0), m_dx1(0.0), m_dy1(0.0), m_kx(1.0), m_ky(1.0) {} //------------------------------------------------------------------- void preserve_aspect_ratio(double alignx, double aligny, aspect_ratio_e aspect) { m_align_x = alignx; m_align_y = aligny; m_aspect = aspect; update(); } //------------------------------------------------------------------- void device_viewport(double x1, double y1, double x2, double y2) { m_device_x1 = x1; m_device_y1 = y1; m_device_x2 = x2; m_device_y2 = y2; update(); } //------------------------------------------------------------------- void world_viewport(double x1, double y1, double x2, double y2) { m_world_x1 = x1; m_world_y1 = y1; m_world_x2 = x2; m_world_y2 = y2; update(); } //------------------------------------------------------------------- void device_viewport(double* x1, double* y1, double* x2, double* y2) const { *x1 = m_device_x1; *y1 = m_device_y1; *x2 = m_device_x2; *y2 = m_device_y2; } //------------------------------------------------------------------- void world_viewport(double* x1, double* y1, double* x2, double* y2) const { *x1 = m_world_x1; *y1 = m_world_y1; *x2 = m_world_x2; *y2 = m_world_y2; } //------------------------------------------------------------------- void world_viewport_actual(double* x1, double* y1, double* x2, double* y2) const { *x1 = m_wx1; *y1 = m_wy1; *x2 = m_wx2; *y2 = m_wy2; } //------------------------------------------------------------------- bool is_valid() const { return m_is_valid; } double align_x() const { return m_align_x; } double align_y() const { return m_align_y; } aspect_ratio_e aspect_ratio() const { return m_aspect; } //------------------------------------------------------------------- void transform(double* x, double* y) const { *x = (*x - m_wx1) * m_kx + m_dx1; *y = (*y - m_wy1) * m_ky + m_dy1; } //------------------------------------------------------------------- void transform_scale_only(double* x, double* y) const { *x *= m_kx; *y *= m_ky; } //------------------------------------------------------------------- void inverse_transform(double* x, double* y) const { *x = (*x - m_dx1) / m_kx + m_wx1; *y = (*y - m_dy1) / m_ky + m_wy1; } //------------------------------------------------------------------- void inverse_transform_scale_only(double* x, double* y) const { *x /= m_kx; *y /= m_ky; } //------------------------------------------------------------------- double device_dx() const { return m_dx1 - m_wx1 * m_kx; } double device_dy() const { return m_dy1 - m_wy1 * m_ky; } //------------------------------------------------------------------- double scale_x() const { return m_kx; } //------------------------------------------------------------------- double scale_y() const { return m_ky; } //------------------------------------------------------------------- double scale() const { return (m_kx + m_ky) * 0.5; } //------------------------------------------------------------------- trans_affine to_affine() const { trans_affine mtx = trans_affine_translation(-m_wx1, -m_wy1); mtx *= trans_affine_scaling(m_kx, m_ky); mtx *= trans_affine_translation(m_dx1, m_dy1); return mtx; } //------------------------------------------------------------------- trans_affine to_affine_scale_only() const { return trans_affine_scaling(m_kx, m_ky); } //------------------------------------------------------------------- unsigned byte_size() const { return sizeof(*this); } void serialize(int8u* ptr) const { std::memcpy(ptr, this, sizeof(*this)); } void deserialize(const int8u* ptr) { std::memcpy(this, ptr, sizeof(*this)); } private: void update(); double m_world_x1; double m_world_y1; double m_world_x2; double m_world_y2; double m_device_x1; double m_device_y1; double m_device_x2; double m_device_y2; aspect_ratio_e m_aspect; bool m_is_valid; double m_align_x; double m_align_y; double m_wx1; double m_wy1; double m_wx2; double m_wy2; double m_dx1; double m_dy1; double m_kx; double m_ky; }; //----------------------------------------------------------------------- inline void trans_viewport::update() { const double epsilon = 1e-30; if(std::fabs(m_world_x1 - m_world_x2) < epsilon || std::fabs(m_world_y1 - m_world_y2) < epsilon || std::fabs(m_device_x1 - m_device_x2) < epsilon || std::fabs(m_device_y1 - m_device_y2) < epsilon) { m_wx1 = m_world_x1; m_wy1 = m_world_y1; m_wx2 = m_world_x1 + 1.0; m_wy2 = m_world_y2 + 1.0; m_dx1 = m_device_x1; m_dy1 = m_device_y1; m_kx = 1.0; m_ky = 1.0; m_is_valid = false; return; } double world_x1 = m_world_x1; double world_y1 = m_world_y1; double world_x2 = m_world_x2; double world_y2 = m_world_y2; double device_x1 = m_device_x1; double device_y1 = m_device_y1; double device_x2 = m_device_x2; double device_y2 = m_device_y2; if(m_aspect != aspect_ratio_stretch) { double d; m_kx = (device_x2 - device_x1) / (world_x2 - world_x1); m_ky = (device_y2 - device_y1) / (world_y2 - world_y1); if((m_aspect == aspect_ratio_meet) == (m_kx < m_ky)) { d = (world_y2 - world_y1) * m_ky / m_kx; world_y1 += (world_y2 - world_y1 - d) * m_align_y; world_y2 = world_y1 + d; } else { d = (world_x2 - world_x1) * m_kx / m_ky; world_x1 += (world_x2 - world_x1 - d) * m_align_x; world_x2 = world_x1 + d; } } m_wx1 = world_x1; m_wy1 = world_y1; m_wx2 = world_x2; m_wy2 = world_y2; m_dx1 = device_x1; m_dy1 = device_y1; m_kx = (device_x2 - device_x1) / (world_x2 - world_x1); m_ky = (device_y2 - device_y1) / (world_y2 - world_y1); m_is_valid = true; } } #endif ragg/src/agg/include/agg_scanline_storage_aa.h0000644000176200001440000006433513515401165021126 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // 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_SCANLINE_STORAGE_AA_INCLUDED #define AGG_SCANLINE_STORAGE_AA_INCLUDED #include #include #include #include "agg_array.h" namespace agg { //----------------------------------------------scanline_cell_storage template class scanline_cell_storage { struct extra_span { unsigned len; T* ptr; }; public: typedef T value_type; //--------------------------------------------------------------- ~scanline_cell_storage() { remove_all(); } //--------------------------------------------------------------- scanline_cell_storage() : m_cells(128-2), m_extra_storage() {} // Copying //--------------------------------------------------------------- scanline_cell_storage(const scanline_cell_storage& v) : m_cells(v.m_cells), m_extra_storage() { copy_extra_storage(v); } //--------------------------------------------------------------- const scanline_cell_storage& operator = (const scanline_cell_storage& v) { remove_all(); m_cells = v.m_cells; copy_extra_storage(v); return *this; } //--------------------------------------------------------------- void remove_all() { int i; for(i = m_extra_storage.size()-1; i >= 0; --i) { pod_allocator::deallocate(m_extra_storage[i].ptr, m_extra_storage[i].len); } m_extra_storage.remove_all(); m_cells.remove_all(); } //--------------------------------------------------------------- int add_cells(const T* cells, unsigned num_cells) { int idx = m_cells.allocate_continuous_block(num_cells); if(idx >= 0) { T* ptr = &m_cells[idx]; std::memcpy(ptr, cells, sizeof(T) * num_cells); return idx; } extra_span s; s.len = num_cells; s.ptr = pod_allocator::allocate(num_cells); std::memcpy(s.ptr, cells, sizeof(T) * num_cells); m_extra_storage.add(s); return -int(m_extra_storage.size()); } //--------------------------------------------------------------- const T* operator [] (int idx) const { if(idx >= 0) { if((unsigned)idx >= m_cells.size()) return 0; return &m_cells[(unsigned)idx]; } unsigned i = unsigned(-idx - 1); if(i >= m_extra_storage.size()) return 0; return m_extra_storage[i].ptr; } //--------------------------------------------------------------- T* operator [] (int idx) { if(idx >= 0) { if((unsigned)idx >= m_cells.size()) return 0; return &m_cells[(unsigned)idx]; } unsigned i = unsigned(-idx - 1); if(i >= m_extra_storage.size()) return 0; return m_extra_storage[i].ptr; } private: void copy_extra_storage(const scanline_cell_storage& v) { unsigned i; for(i = 0; i < v.m_extra_storage.size(); ++i) { const extra_span& src = v.m_extra_storage[i]; extra_span dst; dst.len = src.len; dst.ptr = pod_allocator::allocate(dst.len); std::memcpy(dst.ptr, src.ptr, dst.len * sizeof(T)); m_extra_storage.add(dst); } } pod_bvector m_cells; pod_bvector m_extra_storage; }; //-----------------------------------------------scanline_storage_aa template class scanline_storage_aa { public: typedef T cover_type; //--------------------------------------------------------------- struct span_data { int32 x; int32 len; // If negative, it's a solid span, covers is valid int covers_id; // The index of the cells in the scanline_cell_storage }; //--------------------------------------------------------------- struct scanline_data { int y; unsigned num_spans; unsigned start_span; }; //--------------------------------------------------------------- class embedded_scanline { public: //----------------------------------------------------------- class const_iterator { public: struct span { int32 x; int32 len; // If negative, it's a solid span, covers is valid const T* covers; }; const_iterator() : m_storage(0) {} const_iterator(embedded_scanline& sl) : m_storage(sl.m_storage), m_span_idx(sl.m_scanline.start_span) { init_span(); } const span& operator*() const { return m_span; } const span* operator->() const { return &m_span; } void operator ++ () { ++m_span_idx; init_span(); } private: void init_span() { const span_data& s = m_storage->span_by_index(m_span_idx); m_span.x = s.x; m_span.len = s.len; m_span.covers = m_storage->covers_by_index(s.covers_id); } scanline_storage_aa* m_storage; unsigned m_span_idx; span m_span; }; friend class const_iterator; //----------------------------------------------------------- embedded_scanline(const scanline_storage_aa& storage) : m_storage(&storage) { init(0); } //----------------------------------------------------------- void reset(int, int) {} unsigned num_spans() const { return m_scanline.num_spans; } int y() const { return m_scanline.y; } const_iterator begin() const { return const_iterator(*this); } //----------------------------------------------------------- void init(unsigned scanline_idx) { m_scanline_idx = scanline_idx; m_scanline = m_storage->scanline_by_index(m_scanline_idx); } private: const scanline_storage_aa* m_storage; scanline_data m_scanline; unsigned m_scanline_idx; }; //--------------------------------------------------------------- scanline_storage_aa() : m_covers(), m_spans(256-2), // Block increment size m_scanlines(), m_min_x(std::numeric_limits::max()), m_min_y(std::numeric_limits::max()), m_max_x(std::numeric_limits::min()), m_max_y(std::numeric_limits::min()), m_cur_scanline(0) { m_fake_scanline.y = 0; m_fake_scanline.num_spans = 0; m_fake_scanline.start_span = 0; m_fake_span.x = 0; m_fake_span.len = 0; m_fake_span.covers_id = 0; } // Renderer Interface //--------------------------------------------------------------- void prepare() { m_covers.remove_all(); m_scanlines.remove_all(); m_spans.remove_all(); m_min_x = std::numeric_limits::max(); m_min_y = std::numeric_limits::max(); m_max_x = std::numeric_limits::min(); m_max_y = std::numeric_limits::min(); m_cur_scanline = 0; } //--------------------------------------------------------------- template void render(const Scanline& sl) { scanline_data sl_this; int y = sl.y(); if(y < m_min_y) m_min_y = y; if(y > m_max_y) m_max_y = y; sl_this.y = y; sl_this.num_spans = sl.num_spans(); sl_this.start_span = m_spans.size(); typename Scanline::const_iterator span_iterator = sl.begin(); unsigned num_spans = sl_this.num_spans; for(;;) { span_data sp; sp.x = span_iterator->x; sp.len = span_iterator->len; int len = std::abs(int(sp.len)); sp.covers_id = m_covers.add_cells(span_iterator->covers, unsigned(len)); m_spans.add(sp); int x1 = sp.x; int x2 = sp.x + len - 1; if(x1 < m_min_x) m_min_x = x1; if(x2 > m_max_x) m_max_x = x2; if(--num_spans == 0) break; ++span_iterator; } m_scanlines.add(sl_this); } //--------------------------------------------------------------- // Iterate scanlines interface long min_x() const { return m_min_x; } long min_y() const { return m_min_y; } long max_x() const { return m_max_x; } long max_y() const { return m_max_y; } //--------------------------------------------------------------- bool rewind_scanlines() { m_cur_scanline = 0; return m_scanlines.size() > 0; } //--------------------------------------------------------------- template bool sweep_scanline(Scanline& sl) { sl.reset_spans(); for(;;) { if(m_cur_scanline >= m_scanlines.size()) return false; const scanline_data& sl_this = m_scanlines[m_cur_scanline]; unsigned num_spans = sl_this.num_spans; unsigned span_idx = sl_this.start_span; do { const span_data& sp = m_spans[span_idx++]; const T* covers = covers_by_index(sp.covers_id); if(sp.len < 0) { sl.add_span(sp.x, unsigned(-sp.len), *covers); } else { sl.add_cells(sp.x, sp.len, covers); } } while(--num_spans); ++m_cur_scanline; if(sl.num_spans()) { sl.finalize(sl_this.y); break; } } return true; } //--------------------------------------------------------------- // Specialization for embedded_scanline bool sweep_scanline(embedded_scanline& sl) { do { if(m_cur_scanline >= m_scanlines.size()) return false; sl.init(m_cur_scanline); ++m_cur_scanline; } while(sl.num_spans() == 0); return true; } //--------------------------------------------------------------- unsigned byte_size() const { unsigned i; unsigned size = sizeof(int32) * 4; // min_x, min_y, max_x, max_y for(i = 0; i < m_scanlines.size(); ++i) { size += sizeof(int32) * 3; // scanline size in bytes, Y, num_spans const scanline_data& sl_this = m_scanlines[i]; unsigned num_spans = sl_this.num_spans; unsigned span_idx = sl_this.start_span; do { const span_data& sp = m_spans[span_idx++]; size += sizeof(int32) * 2; // X, span_len if(sp.len < 0) { size += sizeof(T); // cover } else { size += sizeof(T) * unsigned(sp.len); // covers } } while(--num_spans); } return size; } //--------------------------------------------------------------- static void write_int32(int8u* dst, int32 val) { dst[0] = ((const int8u*)&val)[0]; dst[1] = ((const int8u*)&val)[1]; dst[2] = ((const int8u*)&val)[2]; dst[3] = ((const int8u*)&val)[3]; } //--------------------------------------------------------------- void serialize(int8u* data) const { unsigned i; write_int32(data, min_x()); // min_x data += sizeof(int32); write_int32(data, min_y()); // min_y data += sizeof(int32); write_int32(data, max_x()); // max_x data += sizeof(int32); write_int32(data, max_y()); // max_y data += sizeof(int32); for(i = 0; i < m_scanlines.size(); ++i) { const scanline_data& sl_this = m_scanlines[i]; int8u* size_ptr = data; data += sizeof(int32); // Reserve space for scanline size in bytes write_int32(data, sl_this.y); // Y data += sizeof(int32); write_int32(data, sl_this.num_spans); // num_spans data += sizeof(int32); unsigned num_spans = sl_this.num_spans; unsigned span_idx = sl_this.start_span; do { const span_data& sp = m_spans[span_idx++]; const T* covers = covers_by_index(sp.covers_id); write_int32(data, sp.x); // X data += sizeof(int32); write_int32(data, sp.len); // span_len data += sizeof(int32); if(sp.len < 0) { std::memcpy(data, covers, sizeof(T)); data += sizeof(T); } else { std::memcpy(data, covers, unsigned(sp.len) * sizeof(T)); data += sizeof(T) * unsigned(sp.len); } } while(--num_spans); write_int32(size_ptr, int32(unsigned(data - size_ptr))); } } //--------------------------------------------------------------- const scanline_data& scanline_by_index(unsigned i) const { return (i < m_scanlines.size()) ? m_scanlines[i] : m_fake_scanline; } //--------------------------------------------------------------- const span_data& span_by_index(unsigned i) const { return (i < m_spans.size()) ? m_spans[i] : m_fake_span; } //--------------------------------------------------------------- const T* covers_by_index(int i) const { return m_covers[i]; } private: scanline_cell_storage m_covers; pod_bvector m_spans; pod_bvector m_scanlines; span_data m_fake_span; scanline_data m_fake_scanline; long m_min_x; long m_min_y; long m_max_x; long m_max_y; unsigned m_cur_scanline; }; typedef scanline_storage_aa scanline_storage_aa8; //--------scanline_storage_aa8 typedef scanline_storage_aa scanline_storage_aa16; //--------scanline_storage_aa16 typedef scanline_storage_aa scanline_storage_aa32; //--------scanline_storage_aa32 //------------------------------------------serialized_scanlines_adaptor_aa template class serialized_scanlines_adaptor_aa { public: typedef T cover_type; //--------------------------------------------------------------------- class embedded_scanline { public: typedef T cover_type; //----------------------------------------------------------------- class const_iterator { public: struct span { int32 x; int32 len; // If negative, it's a solid span, "covers" is valid const T* covers; }; const_iterator() : m_ptr(0) {} const_iterator(const embedded_scanline* sl) : m_ptr(sl->m_ptr), m_dx(sl->m_dx) { init_span(); } const span& operator*() const { return m_span; } const span* operator->() const { return &m_span; } void operator ++ () { if(m_span.len < 0) { m_ptr += sizeof(T); } else { m_ptr += m_span.len * sizeof(T); } init_span(); } private: int read_int32() { int32 val; ((int8u*)&val)[0] = *m_ptr++; ((int8u*)&val)[1] = *m_ptr++; ((int8u*)&val)[2] = *m_ptr++; ((int8u*)&val)[3] = *m_ptr++; return val; } void init_span() { m_span.x = read_int32() + m_dx; m_span.len = read_int32(); m_span.covers = m_ptr; } const int8u* m_ptr; span m_span; int m_dx; }; friend class const_iterator; //----------------------------------------------------------------- embedded_scanline() : m_ptr(0), m_y(0), m_num_spans(0) {} //----------------------------------------------------------------- void reset(int, int) {} unsigned num_spans() const { return m_num_spans; } int y() const { return m_y; } const_iterator begin() const { return const_iterator(this); } private: //----------------------------------------------------------------- int read_int32() { int32 val; ((int8u*)&val)[0] = *m_ptr++; ((int8u*)&val)[1] = *m_ptr++; ((int8u*)&val)[2] = *m_ptr++; ((int8u*)&val)[3] = *m_ptr++; return val; } public: //----------------------------------------------------------------- void init(const int8u* ptr, int dx, int dy) { m_ptr = ptr; m_y = read_int32() + dy; m_num_spans = unsigned(read_int32()); m_dx = dx; } private: const int8u* m_ptr; int m_y; unsigned m_num_spans; int m_dx; }; public: //-------------------------------------------------------------------- serialized_scanlines_adaptor_aa() : m_data(0), m_end(0), m_ptr(0), m_dx(0), m_dy(0), m_min_x(std::numeric_limits::max()), m_min_y(std::numeric_limits::max()), m_max_x(std::numeric_limits::min()), m_max_y(std::numeric_limits::min()) {} //-------------------------------------------------------------------- serialized_scanlines_adaptor_aa(const int8u* data, unsigned size, double dx, double dy) : m_data(data), m_end(data + size), m_ptr(data), m_dx(iround(dx)), m_dy(iround(dy)), m_min_x(std::numeric_limits::max()), m_min_y(std::numeric_limits::max()), m_max_x(std::numeric_limits::min()), m_max_y(std::numeric_limits::min()) {} //-------------------------------------------------------------------- void init(const int8u* data, unsigned size, double dx, double dy) { m_data = data; m_end = data + size; m_ptr = data; m_dx = iround(dx); m_dy = iround(dy); m_min_x = std::numeric_limits::max(); m_min_y = std::numeric_limits::max(); m_max_x = std::numeric_limits::min(); m_max_y = std::numeric_limits::min(); } private: //-------------------------------------------------------------------- int read_int32() { int32 val; ((int8u*)&val)[0] = *m_ptr++; ((int8u*)&val)[1] = *m_ptr++; ((int8u*)&val)[2] = *m_ptr++; ((int8u*)&val)[3] = *m_ptr++; return val; } //-------------------------------------------------------------------- unsigned read_int32u() { int32u val; ((int8u*)&val)[0] = *m_ptr++; ((int8u*)&val)[1] = *m_ptr++; ((int8u*)&val)[2] = *m_ptr++; ((int8u*)&val)[3] = *m_ptr++; return val; } public: // Iterate scanlines interface //-------------------------------------------------------------------- bool rewind_scanlines() { m_ptr = m_data; if(m_ptr < m_end) { m_min_x = read_int32() + m_dx; m_min_y = read_int32() + m_dy; m_max_x = read_int32() + m_dx; m_max_y = read_int32() + m_dy; } return m_ptr < m_end; } //-------------------------------------------------------------------- long min_x() const { return m_min_x; } long min_y() const { return m_min_y; } long max_x() const { return m_max_x; } long max_y() const { return m_max_y; } //-------------------------------------------------------------------- template bool sweep_scanline(Scanline& sl) { sl.reset_spans(); for(;;) { if(m_ptr >= m_end) return false; read_int32(); // Skip scanline size in bytes int y = read_int32() + m_dy; unsigned num_spans = read_int32(); do { int x = read_int32() + m_dx; int len = read_int32(); if(len < 0) { sl.add_span(x, unsigned(-len), *m_ptr); m_ptr += sizeof(T); } else { sl.add_cells(x, len, m_ptr); m_ptr += len * sizeof(T); } } while(--num_spans); if(sl.num_spans()) { sl.finalize(y); break; } } return true; } //-------------------------------------------------------------------- // Specialization for embedded_scanline bool sweep_scanline(embedded_scanline& sl) { do { if(m_ptr >= m_end) return false; unsigned byte_size = read_int32u(); sl.init(m_ptr, m_dx, m_dy); m_ptr += byte_size - sizeof(int32); } while(sl.num_spans() == 0); return true; } private: const int8u* m_data; const int8u* m_end; const int8u* m_ptr; int m_dx; int m_dy; long m_min_x; long m_min_y; long m_max_x; long m_max_y; }; typedef serialized_scanlines_adaptor_aa serialized_scanlines_adaptor_aa8; //----serialized_scanlines_adaptor_aa8 typedef serialized_scanlines_adaptor_aa serialized_scanlines_adaptor_aa16; //----serialized_scanlines_adaptor_aa16 typedef serialized_scanlines_adaptor_aa serialized_scanlines_adaptor_aa32; //----serialized_scanlines_adaptor_aa32 } #endif ragg/src/agg/include/agg_span_image_filter_rgba.h0000644000176200001440000011036013504406270021576 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_SPAN_IMAGE_FILTER_RGBA_INCLUDED #define AGG_SPAN_IMAGE_FILTER_RGBA_INCLUDED #include "agg_basics.h" #include "agg_color_rgba.h" #include "agg_span_image_filter.h" namespace agg { //==============================================span_image_filter_rgba_nn template class span_image_filter_rgba_nn : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgba_nn() {} span_image_filter_rgba_nn(source_type& src, interpolator_type& inter) : base_type(src, inter, 0) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); do { base_type::interpolator().coordinates(&x, &y); const value_type* fg_ptr = (const value_type*) base_type::source().span(x >> image_subpixel_shift, y >> image_subpixel_shift, 1); span->r = fg_ptr[order_type::R]; span->g = fg_ptr[order_type::G]; span->b = fg_ptr[order_type::B]; span->a = fg_ptr[order_type::A]; ++span; ++base_type::interpolator(); } while(--len); } }; //=========================================span_image_filter_rgba_bilinear template class span_image_filter_rgba_bilinear : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgba_bilinear() {} span_image_filter_rgba_bilinear(source_type& src, interpolator_type& inter) : base_type(src, inter, 0) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[4]; const value_type *fg_ptr; do { int x_hr; int y_hr; base_type::interpolator().coordinates(&x_hr, &y_hr); x_hr -= base_type::filter_dx_int(); y_hr -= base_type::filter_dy_int(); int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; unsigned weight; fg[0] = fg[1] = fg[2] = fg[3] = image_subpixel_scale * image_subpixel_scale / 2; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); weight = (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_x(); weight = x_hr * (image_subpixel_scale - y_hr); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_y(); weight = (image_subpixel_scale - x_hr) * y_hr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_x(); weight = x_hr * y_hr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr; span->r = value_type(color_type::downshift(fg[order_type::R], image_subpixel_shift * 2)); span->g = value_type(color_type::downshift(fg[order_type::G], image_subpixel_shift * 2)); span->b = value_type(color_type::downshift(fg[order_type::B], image_subpixel_shift * 2)); span->a = value_type(color_type::downshift(fg[order_type::A], image_subpixel_shift * 2)); ++span; ++base_type::interpolator(); } while(--len); } }; //====================================span_image_filter_rgba_bilinear_clip template class span_image_filter_rgba_bilinear_clip : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgba_bilinear_clip() {} span_image_filter_rgba_bilinear_clip(source_type& src, const color_type& back_color, interpolator_type& inter) : base_type(src, inter, 0), m_back_color(back_color) {} const color_type& background_color() const { return m_back_color; } void background_color(const color_type& v) { m_back_color = v; } //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[4]; value_type back_r = m_back_color.r; value_type back_g = m_back_color.g; value_type back_b = m_back_color.b; value_type back_a = m_back_color.a; const value_type *fg_ptr; int maxx = base_type::source().width() - 1; int maxy = base_type::source().height() - 1; do { int x_hr; int y_hr; base_type::interpolator().coordinates(&x_hr, &y_hr); x_hr -= base_type::filter_dx_int(); y_hr -= base_type::filter_dy_int(); int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; unsigned weight; if(x_lr >= 0 && y_lr >= 0 && x_lr < maxx && y_lr < maxy) { fg[0] = fg[1] = fg[2] = fg[3] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + (x_lr << 2); weight = (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr++; weight = x_hr * (image_subpixel_scale - y_hr); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr++; ++y_lr; fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + (x_lr << 2); weight = (image_subpixel_scale - x_hr) * y_hr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr++; weight = x_hr * y_hr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr++; fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2); fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2); fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2); fg[3] = color_type::downshift(fg[3], image_subpixel_shift * 2); } else { if(x_lr < -1 || y_lr < -1 || x_lr > maxx || y_lr > maxy) { fg[order_type::R] = back_r; fg[order_type::G] = back_g; fg[order_type::B] = back_b; fg[order_type::A] = back_a; } else { fg[0] = fg[1] = fg[2] = fg[3] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; weight = (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr); if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + (x_lr << 2); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr++; } else { fg[order_type::R] += back_r * weight; fg[order_type::G] += back_g * weight; fg[order_type::B] += back_b * weight; fg[order_type::A] += back_a * weight; } x_lr++; weight = x_hr * (image_subpixel_scale - y_hr); if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + (x_lr << 2); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr++; } else { fg[order_type::R] += back_r * weight; fg[order_type::G] += back_g * weight; fg[order_type::B] += back_b * weight; fg[order_type::A] += back_a * weight; } x_lr--; y_lr++; weight = (image_subpixel_scale - x_hr) * y_hr; if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + (x_lr << 2); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr++; } else { fg[order_type::R] += back_r * weight; fg[order_type::G] += back_g * weight; fg[order_type::B] += back_b * weight; fg[order_type::A] += back_a * weight; } x_lr++; weight = x_hr * y_hr; if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + (x_lr << 2); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr++; } else { fg[order_type::R] += back_r * weight; fg[order_type::G] += back_g * weight; fg[order_type::B] += back_b * weight; fg[order_type::A] += back_a * weight; } fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2); fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2); fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2); fg[3] = color_type::downshift(fg[3], image_subpixel_shift * 2); } } span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; span->a = (value_type)fg[order_type::A]; ++span; ++base_type::interpolator(); } while(--len); } private: color_type m_back_color; }; //==============================================span_image_filter_rgba_2x2 template class span_image_filter_rgba_2x2 : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgba_2x2() {} span_image_filter_rgba_2x2(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, &filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[4]; const value_type *fg_ptr; const int16* weight_array = base_type::filter().weight_array() + ((base_type::filter().diameter()/2 - 1) << image_subpixel_shift); do { int x_hr; int y_hr; base_type::interpolator().coordinates(&x_hr, &y_hr); x_hr -= base_type::filter_dx_int(); y_hr -= base_type::filter_dy_int(); int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; unsigned weight; fg[0] = fg[1] = fg[2] = fg[3] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); weight = (weight_array[x_hr + image_subpixel_scale] * weight_array[y_hr + image_subpixel_scale] + image_filter_scale / 2) >> image_filter_shift; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_x(); weight = (weight_array[x_hr] * weight_array[y_hr + image_subpixel_scale] + image_filter_scale / 2) >> image_filter_shift; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_y(); weight = (weight_array[x_hr + image_subpixel_scale] * weight_array[y_hr] + image_filter_scale / 2) >> image_filter_shift; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_x(); weight = (weight_array[x_hr] * weight_array[y_hr] + image_filter_scale / 2) >> image_filter_shift; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr; fg[0] = color_type::downshift(fg[0], image_filter_shift); fg[1] = color_type::downshift(fg[1], image_filter_shift); fg[2] = color_type::downshift(fg[2], image_filter_shift); fg[3] = color_type::downshift(fg[3], image_filter_shift); if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value(); if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A]; if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A]; if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A]; span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; span->a = (value_type)fg[order_type::A]; ++span; ++base_type::interpolator(); } while(--len); } }; //==================================================span_image_filter_rgba template class span_image_filter_rgba : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgba() {} span_image_filter_rgba(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, &filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[4]; const value_type *fg_ptr; unsigned diameter = base_type::filter().diameter(); int start = base_type::filter().start(); const int16* weight_array = base_type::filter().weight_array(); int x_count; int weight_y; do { base_type::interpolator().coordinates(&x, &y); x -= base_type::filter_dx_int(); y -= base_type::filter_dy_int(); int x_hr = x; int y_hr = y; int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; fg[0] = fg[1] = fg[2] = fg[3] = 0; int x_fract = x_hr & image_subpixel_mask; unsigned y_count = diameter; y_hr = image_subpixel_mask - (y_hr & image_subpixel_mask); fg_ptr = (const value_type*)base_type::source().span(x_lr + start, y_lr + start, diameter); for(;;) { x_count = diameter; weight_y = weight_array[y_hr]; x_hr = image_subpixel_mask - x_fract; for(;;) { int weight = (weight_y * weight_array[x_hr] + image_filter_scale / 2) >> image_filter_shift; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr; if(--x_count == 0) break; x_hr += image_subpixel_scale; fg_ptr = (const value_type*)base_type::source().next_x(); } if(--y_count == 0) break; y_hr += image_subpixel_scale; fg_ptr = (const value_type*)base_type::source().next_y(); } fg[0] = color_type::downshift(fg[0], image_filter_shift); fg[1] = color_type::downshift(fg[1], image_filter_shift); fg[2] = color_type::downshift(fg[2], image_filter_shift); fg[3] = color_type::downshift(fg[3], image_filter_shift); if(fg[0] < 0) fg[0] = 0; if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; if(fg[3] < 0) fg[3] = 0; if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value(); if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A]; if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A]; if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A]; span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; span->a = (value_type)fg[order_type::A]; ++span; ++base_type::interpolator(); } while(--len); } }; //========================================span_image_resample_rgba_affine template class span_image_resample_rgba_affine : public span_image_resample_affine { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef span_image_resample_affine base_type; typedef typename base_type::interpolator_type interpolator_type; typedef typename color_type::value_type value_type; typedef typename color_type::long_type long_type; enum base_scale_e { downscale_shift = image_filter_shift }; //-------------------------------------------------------------------- span_image_resample_rgba_affine() {} span_image_resample_rgba_affine(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[4]; int diameter = base_type::filter().diameter(); int filter_scale = diameter << image_subpixel_shift; int radius_x = (diameter * base_type::m_rx) >> 1; int radius_y = (diameter * base_type::m_ry) >> 1; int len_x_lr = (diameter * base_type::m_rx + image_subpixel_mask) >> image_subpixel_shift; const int16* weight_array = base_type::filter().weight_array(); do { base_type::interpolator().coordinates(&x, &y); x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; fg[0] = fg[1] = fg[2] = fg[3] = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * base_type::m_ry_inv) >> image_subpixel_shift; int total_weight = 0; int x_lr = x >> image_subpixel_shift; int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * base_type::m_rx_inv) >> image_subpixel_shift; int x_hr2 = x_hr; const value_type* fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); for(;;) { int weight_y = weight_array[y_hr]; x_hr = x_hr2; for(;;) { int weight = (weight_y * weight_array[x_hr] + image_filter_scale / 2) >> downscale_shift; fg[0] += *fg_ptr++ * weight; fg[1] += *fg_ptr++ * weight; fg[2] += *fg_ptr++ * weight; fg[3] += *fg_ptr++ * weight; total_weight += weight; x_hr += base_type::m_rx_inv; if(x_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_x(); } y_hr += base_type::m_ry_inv; if(y_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_y(); } fg[0] /= total_weight; fg[1] /= total_weight; fg[2] /= total_weight; fg[3] /= total_weight; if(fg[0] < 0) fg[0] = 0; if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; if(fg[3] < 0) fg[3] = 0; if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value(); if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A]; if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A]; if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A]; span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; span->a = (value_type)fg[order_type::A]; ++span; ++base_type::interpolator(); } while(--len); } }; //==============================================span_image_resample_rgba template class span_image_resample_rgba : public span_image_resample { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_resample base_type; typedef typename color_type::value_type value_type; typedef typename color_type::long_type long_type; enum base_scale_e { downscale_shift = image_filter_shift }; //-------------------------------------------------------------------- span_image_resample_rgba() {} span_image_resample_rgba(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[4]; int diameter = base_type::filter().diameter(); int filter_scale = diameter << image_subpixel_shift; const int16* weight_array = base_type::filter().weight_array(); do { int rx; int ry; int rx_inv = image_subpixel_scale; int ry_inv = image_subpixel_scale; base_type::interpolator().coordinates(&x, &y); base_type::interpolator().local_scale(&rx, &ry); base_type::adjust_scale(&rx, &ry); rx_inv = image_subpixel_scale * image_subpixel_scale / rx; ry_inv = image_subpixel_scale * image_subpixel_scale / ry; int radius_x = (diameter * rx) >> 1; int radius_y = (diameter * ry) >> 1; int len_x_lr = (diameter * rx + image_subpixel_mask) >> image_subpixel_shift; x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; fg[0] = fg[1] = fg[2] = fg[3] = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * ry_inv) >> image_subpixel_shift; int total_weight = 0; int x_lr = x >> image_subpixel_shift; int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * rx_inv) >> image_subpixel_shift; int x_hr2 = x_hr; const value_type* fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); for(;;) { int weight_y = weight_array[y_hr]; x_hr = x_hr2; for(;;) { int weight = (weight_y * weight_array[x_hr] + image_filter_scale / 2) >> downscale_shift; fg[0] += *fg_ptr++ * weight; fg[1] += *fg_ptr++ * weight; fg[2] += *fg_ptr++ * weight; fg[3] += *fg_ptr++ * weight; total_weight += weight; x_hr += rx_inv; if(x_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_x(); } y_hr += ry_inv; if(y_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_y(); } fg[0] /= total_weight; fg[1] /= total_weight; fg[2] /= total_weight; fg[3] /= total_weight; if(fg[0] < 0) fg[0] = 0; if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; if(fg[3] < 0) fg[3] = 0; if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value(); if(fg[order_type::R] > fg[order_type::R]) fg[order_type::R] = fg[order_type::R]; if(fg[order_type::G] > fg[order_type::G]) fg[order_type::G] = fg[order_type::G]; if(fg[order_type::B] > fg[order_type::B]) fg[order_type::B] = fg[order_type::B]; span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; span->a = (value_type)fg[order_type::A]; ++span; ++base_type::interpolator(); } while(--len); } }; } #endif ragg/src/agg/include/agg_vcgen_bspline.h0000644000176200001440000000410213504406270017745 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_VCGEN_BSPLINE_INCLUDED #define AGG_VCGEN_BSPLINE_INCLUDED #include "agg_basics.h" #include "agg_array.h" #include "agg_bspline.h" namespace agg { //==========================================================vcgen_bspline class vcgen_bspline { enum status_e { initial, ready, polygon, end_poly, stop }; public: typedef pod_bvector vertex_storage; vcgen_bspline(); void interpolation_step(double v) { m_interpolation_step = v; } double interpolation_step() const { return m_interpolation_step; } // Vertex Generator Interface void remove_all(); void add_vertex(double x, double y, unsigned cmd); // Vertex Source Interface void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: vcgen_bspline(const vcgen_bspline&); const vcgen_bspline& operator = (const vcgen_bspline&); vertex_storage m_src_vertices; bspline m_spline_x; bspline m_spline_y; double m_interpolation_step; unsigned m_closed; status_e m_status; unsigned m_src_vertex; double m_cur_abscissa; double m_max_abscissa; }; } #endif ragg/src/agg/include/agg_curves.h0000644000176200001440000004666513506714016016464 0ustar liggesusers//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // Copyright (C) 2005 Tony Juricic (tonygeek@yahoo.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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_CURVES_INCLUDED #define AGG_CURVES_INCLUDED #include "agg_array.h" namespace agg { // See Implementation agg_curves.cpp //--------------------------------------------curve_approximation_method_e enum curve_approximation_method_e { curve_inc, curve_div }; //--------------------------------------------------------------curve3_inc class curve3_inc { public: curve3_inc() : m_num_steps(0), m_step(0), m_scale(1.0) { } curve3_inc(double x1, double y1, double x2, double y2, double x3, double y3) : m_num_steps(0), m_step(0), m_scale(1.0) { init(x1, y1, x2, y2, x3, y3); } void reset() { m_num_steps = 0; m_step = -1; } void init(double x1, double y1, double x2, double y2, double x3, double y3); void approximation_method(curve_approximation_method_e) {} curve_approximation_method_e approximation_method() const { return curve_inc; } void approximation_scale(double s); double approximation_scale() const; void angle_tolerance(double) {} double angle_tolerance() const { return 0.0; } void cusp_limit(double) {} double cusp_limit() const { return 0.0; } void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: int m_num_steps; int m_step; double m_scale; double m_start_x; double m_start_y; double m_end_x; double m_end_y; double m_fx; double m_fy; double m_dfx; double m_dfy; double m_ddfx; double m_ddfy; double m_saved_fx; double m_saved_fy; double m_saved_dfx; double m_saved_dfy; }; //-------------------------------------------------------------curve3_div class curve3_div { public: curve3_div() : m_approximation_scale(1.0), m_angle_tolerance(0.0), m_count(0) {} curve3_div(double x1, double y1, double x2, double y2, double x3, double y3) : m_approximation_scale(1.0), m_angle_tolerance(0.0), m_count(0) { init(x1, y1, x2, y2, x3, y3); } void reset() { m_points.remove_all(); m_count = 0; } void init(double x1, double y1, double x2, double y2, double x3, double y3); void approximation_method(curve_approximation_method_e) {} curve_approximation_method_e approximation_method() const { return curve_div; } void approximation_scale(double s) { m_approximation_scale = s; } double approximation_scale() const { return m_approximation_scale; } void angle_tolerance(double a) { m_angle_tolerance = a; } double angle_tolerance() const { return m_angle_tolerance; } void cusp_limit(double) {} double cusp_limit() const { return 0.0; } void rewind(unsigned) { m_count = 0; } unsigned vertex(double* x, double* y) { if(m_count >= m_points.size()) return path_cmd_stop; const point_d& p = m_points[m_count++]; *x = p.x; *y = p.y; return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to; } private: void bezier(double x1, double y1, double x2, double y2, double x3, double y3); void recursive_bezier(double x1, double y1, double x2, double y2, double x3, double y3, unsigned level); double m_approximation_scale; double m_distance_tolerance_square; double m_angle_tolerance; unsigned m_count; pod_bvector m_points; }; //-------------------------------------------------------------curve4_points struct curve4_points { double cp[8]; curve4_points() {} curve4_points(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2; cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4; } void init(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2; cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4; } double operator [] (unsigned i) const { return cp[i]; } double& operator [] (unsigned i) { return cp[i]; } }; //-------------------------------------------------------------curve4_inc class curve4_inc { public: curve4_inc() : m_num_steps(0), m_step(0), m_scale(1.0) { } curve4_inc(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) : m_num_steps(0), m_step(0), m_scale(1.0) { init(x1, y1, x2, y2, x3, y3, x4, y4); } curve4_inc(const curve4_points& cp) : m_num_steps(0), m_step(0), m_scale(1.0) { init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); } void reset() { m_num_steps = 0; m_step = -1; } void init(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4); void init(const curve4_points& cp) { init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); } void approximation_method(curve_approximation_method_e) {} curve_approximation_method_e approximation_method() const { return curve_inc; } void approximation_scale(double s); double approximation_scale() const; void angle_tolerance(double) {} double angle_tolerance() const { return 0.0; } void cusp_limit(double) {} double cusp_limit() const { return 0.0; } void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: int m_num_steps; int m_step; double m_scale; double m_start_x; double m_start_y; double m_end_x; double m_end_y; double m_fx; double m_fy; double m_dfx; double m_dfy; double m_ddfx; double m_ddfy; double m_dddfx; double m_dddfy; double m_saved_fx; double m_saved_fy; double m_saved_dfx; double m_saved_dfy; double m_saved_ddfx; double m_saved_ddfy; }; //-------------------------------------------------------catrom_to_bezier inline curve4_points catrom_to_bezier(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { // Trans. matrix Catmull-Rom to Bezier // // 0 1 0 0 // -1/6 1 1/6 0 // 0 1/6 1 -1/6 // 0 0 1 0 // return curve4_points( x2, y2, (-x1 + 6*x2 + x3) / 6, (-y1 + 6*y2 + y3) / 6, ( x2 + 6*x3 - x4) / 6, ( y2 + 6*y3 - y4) / 6, x3, y3); } //----------------------------------------------------------------------- inline curve4_points catrom_to_bezier(const curve4_points& cp) { return catrom_to_bezier(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); } //-----------------------------------------------------ubspline_to_bezier inline curve4_points ubspline_to_bezier(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { // Trans. matrix Uniform BSpline to Bezier // // 1/6 4/6 1/6 0 // 0 4/6 2/6 0 // 0 2/6 4/6 0 // 0 1/6 4/6 1/6 // return curve4_points( (x1 + 4*x2 + x3) / 6, (y1 + 4*y2 + y3) / 6, (4*x2 + 2*x3) / 6, (4*y2 + 2*y3) / 6, (2*x2 + 4*x3) / 6, (2*y2 + 4*y3) / 6, (x2 + 4*x3 + x4) / 6, (y2 + 4*y3 + y4) / 6); } //----------------------------------------------------------------------- inline curve4_points ubspline_to_bezier(const curve4_points& cp) { return ubspline_to_bezier(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); } //------------------------------------------------------hermite_to_bezier inline curve4_points hermite_to_bezier(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { // Trans. matrix Hermite to Bezier // // 1 0 0 0 // 1 0 1/3 0 // 0 1 0 -1/3 // 0 1 0 0 // return curve4_points( x1, y1, (3*x1 + x3) / 3, (3*y1 + y3) / 3, (3*x2 - x4) / 3, (3*y2 - y4) / 3, x2, y2); } //----------------------------------------------------------------------- inline curve4_points hermite_to_bezier(const curve4_points& cp) { return hermite_to_bezier(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); } //-------------------------------------------------------------curve4_div class curve4_div { public: curve4_div() : m_approximation_scale(1.0), m_angle_tolerance(0.0), m_cusp_limit(0.0), m_count(0) {} curve4_div(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) : m_approximation_scale(1.0), m_angle_tolerance(0.0), m_cusp_limit(0.0), m_count(0) { init(x1, y1, x2, y2, x3, y3, x4, y4); } curve4_div(const curve4_points& cp) : m_approximation_scale(1.0), m_angle_tolerance(0.0), m_count(0) { init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); } void reset() { m_points.remove_all(); m_count = 0; } void init(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4); void init(const curve4_points& cp) { init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); } void approximation_method(curve_approximation_method_e) {} curve_approximation_method_e approximation_method() const { return curve_div; } void approximation_scale(double s) { m_approximation_scale = s; } double approximation_scale() const { return m_approximation_scale; } void angle_tolerance(double a) { m_angle_tolerance = a; } double angle_tolerance() const { return m_angle_tolerance; } void cusp_limit(double v) { m_cusp_limit = (v == 0.0) ? 0.0 : pi - v; } double cusp_limit() const { return (m_cusp_limit == 0.0) ? 0.0 : pi - m_cusp_limit; } void rewind(unsigned) { m_count = 0; } unsigned vertex(double* x, double* y) { if(m_count >= m_points.size()) return path_cmd_stop; const point_d& p = m_points[m_count++]; *x = p.x; *y = p.y; return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to; } private: void bezier(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4); void recursive_bezier(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, unsigned level); double m_approximation_scale; double m_distance_tolerance_square; double m_angle_tolerance; double m_cusp_limit; unsigned m_count; pod_bvector m_points; }; //-----------------------------------------------------------------curve3 class curve3 { public: curve3() : m_approximation_method(curve_div) {} curve3(double x1, double y1, double x2, double y2, double x3, double y3) : m_approximation_method(curve_div) { init(x1, y1, x2, y2, x3, y3); } void reset() { m_curve_inc.reset(); m_curve_div.reset(); } void init(double x1, double y1, double x2, double y2, double x3, double y3) { if(m_approximation_method == curve_inc) { m_curve_inc.init(x1, y1, x2, y2, x3, y3); } else { m_curve_div.init(x1, y1, x2, y2, x3, y3); } } void approximation_method(curve_approximation_method_e v) { m_approximation_method = v; } curve_approximation_method_e approximation_method() const { return m_approximation_method; } void approximation_scale(double s) { m_curve_inc.approximation_scale(s); m_curve_div.approximation_scale(s); } double approximation_scale() const { return m_curve_inc.approximation_scale(); } void angle_tolerance(double a) { m_curve_div.angle_tolerance(a); } double angle_tolerance() const { return m_curve_div.angle_tolerance(); } void cusp_limit(double v) { m_curve_div.cusp_limit(v); } double cusp_limit() const { return m_curve_div.cusp_limit(); } void rewind(unsigned path_id) { if(m_approximation_method == curve_inc) { m_curve_inc.rewind(path_id); } else { m_curve_div.rewind(path_id); } } unsigned vertex(double* x, double* y) { if(m_approximation_method == curve_inc) { return m_curve_inc.vertex(x, y); } return m_curve_div.vertex(x, y); } private: curve3_inc m_curve_inc; curve3_div m_curve_div; curve_approximation_method_e m_approximation_method; }; //-----------------------------------------------------------------curve4 class curve4 { public: curve4() : m_approximation_method(curve_div) {} curve4(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) : m_approximation_method(curve_div) { init(x1, y1, x2, y2, x3, y3, x4, y4); } curve4(const curve4_points& cp) : m_approximation_method(curve_div) { init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); } void reset() { m_curve_inc.reset(); m_curve_div.reset(); } void init(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { if(m_approximation_method == curve_inc) { m_curve_inc.init(x1, y1, x2, y2, x3, y3, x4, y4); } else { m_curve_div.init(x1, y1, x2, y2, x3, y3, x4, y4); } } void init(const curve4_points& cp) { init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); } void approximation_method(curve_approximation_method_e v) { m_approximation_method = v; } curve_approximation_method_e approximation_method() const { return m_approximation_method; } void approximation_scale(double s) { m_curve_inc.approximation_scale(s); m_curve_div.approximation_scale(s); } double approximation_scale() const { return m_curve_inc.approximation_scale(); } void angle_tolerance(double v) { m_curve_div.angle_tolerance(v); } double angle_tolerance() const { return m_curve_div.angle_tolerance(); } void cusp_limit(double v) { m_curve_div.cusp_limit(v); } double cusp_limit() const { return m_curve_div.cusp_limit(); } void rewind(unsigned path_id) { if(m_approximation_method == curve_inc) { m_curve_inc.rewind(path_id); } else { m_curve_div.rewind(path_id); } } unsigned vertex(double* x, double* y) { if(m_approximation_method == curve_inc) { return m_curve_inc.vertex(x, y); } return m_curve_div.vertex(x, y); } private: curve4_inc m_curve_inc; curve4_div m_curve_div; curve_approximation_method_e m_approximation_method; }; } #endif ragg/src/agg/include/agg_renderer_mclip.h0000644000176200001440000002700313504406270020126 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // class renderer_mclip // //---------------------------------------------------------------------------- #ifndef AGG_RENDERER_MCLIP_INCLUDED #define AGG_RENDERER_MCLIP_INCLUDED #include "agg_basics.h" #include "agg_array.h" #include "agg_renderer_base.h" namespace agg { //----------------------------------------------------------renderer_mclip template class renderer_mclip { public: typedef PixelFormat pixfmt_type; typedef typename pixfmt_type::color_type color_type; typedef typename pixfmt_type::row_data row_data; typedef renderer_base base_ren_type; //-------------------------------------------------------------------- explicit renderer_mclip(pixfmt_type& pixf) : m_ren(pixf), m_curr_cb(0), m_bounds(m_ren.xmin(), m_ren.ymin(), m_ren.xmax(), m_ren.ymax()) {} void attach(pixfmt_type& pixf) { m_ren.attach(pixf); reset_clipping(true); } //-------------------------------------------------------------------- const pixfmt_type& ren() const { return m_ren.ren(); } pixfmt_type& ren() { return m_ren.ren(); } //-------------------------------------------------------------------- unsigned width() const { return m_ren.width(); } unsigned height() const { return m_ren.height(); } //-------------------------------------------------------------------- const rect_i& clip_box() const { return m_ren.clip_box(); } int xmin() const { return m_ren.xmin(); } int ymin() const { return m_ren.ymin(); } int xmax() const { return m_ren.xmax(); } int ymax() const { return m_ren.ymax(); } //-------------------------------------------------------------------- const rect_i& bounding_clip_box() const { return m_bounds; } int bounding_xmin() const { return m_bounds.x1; } int bounding_ymin() const { return m_bounds.y1; } int bounding_xmax() const { return m_bounds.x2; } int bounding_ymax() const { return m_bounds.y2; } //-------------------------------------------------------------------- void first_clip_box() { m_curr_cb = 0; if(m_clip.size()) { const rect_i& cb = m_clip[0]; m_ren.clip_box_naked(cb.x1, cb.y1, cb.x2, cb.y2); } } //-------------------------------------------------------------------- bool next_clip_box() { if(++m_curr_cb < m_clip.size()) { const rect_i& cb = m_clip[m_curr_cb]; m_ren.clip_box_naked(cb.x1, cb.y1, cb.x2, cb.y2); return true; } return false; } //-------------------------------------------------------------------- void reset_clipping(bool visibility) { m_ren.reset_clipping(visibility); m_clip.remove_all(); m_curr_cb = 0; m_bounds = m_ren.clip_box(); } //-------------------------------------------------------------------- void add_clip_box(int x1, int y1, int x2, int y2) { rect_i cb(x1, y1, x2, y2); cb.normalize(); if(cb.clip(rect_i(0, 0, width() - 1, height() - 1))) { m_clip.add(cb); if(cb.x1 < m_bounds.x1) m_bounds.x1 = cb.x1; if(cb.y1 < m_bounds.y1) m_bounds.y1 = cb.y1; if(cb.x2 > m_bounds.x2) m_bounds.x2 = cb.x2; if(cb.y2 > m_bounds.y2) m_bounds.y2 = cb.y2; } } //-------------------------------------------------------------------- void clear(const color_type& c) { m_ren.clear(c); } //-------------------------------------------------------------------- void copy_pixel(int x, int y, const color_type& c) { first_clip_box(); do { if(m_ren.inbox(x, y)) { m_ren.ren().copy_pixel(x, y, c); break; } } while(next_clip_box()); } //-------------------------------------------------------------------- void blend_pixel(int x, int y, const color_type& c, cover_type cover) { first_clip_box(); do { if(m_ren.inbox(x, y)) { m_ren.ren().blend_pixel(x, y, c, cover); break; } } while(next_clip_box()); } //-------------------------------------------------------------------- color_type pixel(int x, int y) const { first_clip_box(); do { if(m_ren.inbox(x, y)) { return m_ren.ren().pixel(x, y); } } while(next_clip_box()); return color_type::no_color(); } //-------------------------------------------------------------------- void copy_hline(int x1, int y, int x2, const color_type& c) { first_clip_box(); do { m_ren.copy_hline(x1, y, x2, c); } while(next_clip_box()); } //-------------------------------------------------------------------- void copy_vline(int x, int y1, int y2, const color_type& c) { first_clip_box(); do { m_ren.copy_vline(x, y1, y2, c); } while(next_clip_box()); } //-------------------------------------------------------------------- void blend_hline(int x1, int y, int x2, const color_type& c, cover_type cover) { first_clip_box(); do { m_ren.blend_hline(x1, y, x2, c, cover); } while(next_clip_box()); } //-------------------------------------------------------------------- void blend_vline(int x, int y1, int y2, const color_type& c, cover_type cover) { first_clip_box(); do { m_ren.blend_vline(x, y1, y2, c, cover); } while(next_clip_box()); } //-------------------------------------------------------------------- void copy_bar(int x1, int y1, int x2, int y2, const color_type& c) { first_clip_box(); do { m_ren.copy_bar(x1, y1, x2, y2, c); } while(next_clip_box()); } //-------------------------------------------------------------------- void blend_bar(int x1, int y1, int x2, int y2, const color_type& c, cover_type cover) { first_clip_box(); do { m_ren.blend_bar(x1, y1, x2, y2, c, cover); } while(next_clip_box()); } //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, int len, const color_type& c, const cover_type* covers) { first_clip_box(); do { m_ren.blend_solid_hspan(x, y, len, c, covers); } while(next_clip_box()); } //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, int len, const color_type& c, const cover_type* covers) { first_clip_box(); do { m_ren.blend_solid_vspan(x, y, len, c, covers); } while(next_clip_box()); } //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, int len, const color_type* colors) { first_clip_box(); do { m_ren.copy_color_hspan(x, y, len, colors); } while(next_clip_box()); } //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, int len, const color_type* colors, const cover_type* covers, cover_type cover = cover_full) { first_clip_box(); do { m_ren.blend_color_hspan(x, y, len, colors, covers, cover); } while(next_clip_box()); } //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, int len, const color_type* colors, const cover_type* covers, cover_type cover = cover_full) { first_clip_box(); do { m_ren.blend_color_vspan(x, y, len, colors, covers, cover); } while(next_clip_box()); } //-------------------------------------------------------------------- void copy_from(const rendering_buffer& from, const rect_i* rc=0, int x_to=0, int y_to=0) { first_clip_box(); do { m_ren.copy_from(from, rc, x_to, y_to); } while(next_clip_box()); } //-------------------------------------------------------------------- template void blend_from(const SrcPixelFormatRenderer& src, const rect_i* rect_src_ptr = 0, int dx = 0, int dy = 0, cover_type cover = cover_full) { first_clip_box(); do { m_ren.blend_from(src, rect_src_ptr, dx, dy, cover); } while(next_clip_box()); } private: renderer_mclip(const renderer_mclip&); const renderer_mclip& operator = (const renderer_mclip&); base_ren_type m_ren; pod_bvector m_clip; unsigned m_curr_cb; rect_i m_bounds; }; } #endif ragg/src/agg/include/agg_span_image_filter_gray.h0000644000176200001440000006747513504406270021647 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_SPAN_IMAGE_FILTER_GRAY_INCLUDED #define AGG_SPAN_IMAGE_FILTER_GRAY_INCLUDED #include "agg_basics.h" #include "agg_color_gray.h" #include "agg_span_image_filter.h" namespace agg { //==============================================span_image_filter_gray_nn template class span_image_filter_gray_nn : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_gray_nn() {} span_image_filter_gray_nn(source_type& src, interpolator_type& inter) : base_type(src, inter, 0) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); do { base_type::interpolator().coordinates(&x, &y); span->v = *(const value_type*) base_type::source().span(x >> image_subpixel_shift, y >> image_subpixel_shift, 1); span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; //=========================================span_image_filter_gray_bilinear template class span_image_filter_gray_bilinear : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_gray_bilinear() {} span_image_filter_gray_bilinear(source_type& src, interpolator_type& inter) : base_type(src, inter, 0) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg; const value_type *fg_ptr; do { int x_hr; int y_hr; base_type::interpolator().coordinates(&x_hr, &y_hr); x_hr -= base_type::filter_dx_int(); y_hr -= base_type::filter_dy_int(); int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; fg = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); fg += *fg_ptr * (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr); fg_ptr = (const value_type*)base_type::source().next_x(); fg += *fg_ptr * x_hr * (image_subpixel_scale - y_hr); fg_ptr = (const value_type*)base_type::source().next_y(); fg += *fg_ptr * (image_subpixel_scale - x_hr) * y_hr; fg_ptr = (const value_type*)base_type::source().next_x(); fg += *fg_ptr * x_hr * y_hr; span->v = color_type::downshift(fg, image_subpixel_shift * 2); span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; //====================================span_image_filter_gray_bilinear_clip template class span_image_filter_gray_bilinear_clip : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_gray_bilinear_clip() {} span_image_filter_gray_bilinear_clip(source_type& src, const color_type& back_color, interpolator_type& inter) : base_type(src, inter, 0), m_back_color(back_color) {} const color_type& background_color() const { return m_back_color; } void background_color(const color_type& v) { m_back_color = v; } //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg; long_type src_alpha; value_type back_v = m_back_color.v; value_type back_a = m_back_color.a; const value_type *fg_ptr; int maxx = base_type::source().width() - 1; int maxy = base_type::source().height() - 1; do { int x_hr; int y_hr; base_type::interpolator().coordinates(&x_hr, &y_hr); x_hr -= base_type::filter_dx_int(); y_hr -= base_type::filter_dy_int(); int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; if(x_lr >= 0 && y_lr >= 0 && x_lr < maxx && y_lr < maxy) { fg = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; fg_ptr = (const value_type*)base_type::source().row_ptr(y_lr) + x_lr; fg += *fg_ptr++ * (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr); fg += *fg_ptr++ * (image_subpixel_scale - y_hr) * x_hr; ++y_lr; fg_ptr = (const value_type*)base_type::source().row_ptr(y_lr) + x_lr; fg += *fg_ptr++ * (image_subpixel_scale - x_hr) * y_hr; fg += *fg_ptr++ * x_hr * y_hr; fg = color_type::downshift(fg, image_subpixel_shift * 2); src_alpha = color_type::full_value(); } else { unsigned weight; if(x_lr < -1 || y_lr < -1 || x_lr > maxx || y_lr > maxy) { fg = back_v; src_alpha = back_a; } else { fg = src_alpha = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; weight = (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr); if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg += weight * *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); src_alpha += weight * color_type::full_value(); } else { fg += back_v * weight; src_alpha += back_a * weight; } x_lr++; weight = x_hr * (image_subpixel_scale - y_hr); if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg += weight * *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); src_alpha += weight * color_type::full_value(); } else { fg += back_v * weight; src_alpha += back_a * weight; } x_lr--; y_lr++; weight = (image_subpixel_scale - x_hr) * y_hr; if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg += weight * *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); src_alpha += weight * color_type::full_value(); } else { fg += back_v * weight; src_alpha += back_a * weight; } x_lr++; weight = x_hr * y_hr; if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg += weight * *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); src_alpha += weight * color_type::full_value(); } else { fg += back_v * weight; src_alpha += back_a * weight; } fg = color_type::downshift(fg, image_subpixel_shift * 2); src_alpha = color_type::downshift(src_alpha, image_subpixel_shift * 2); } } span->v = (value_type)fg; span->a = (value_type)src_alpha; ++span; ++base_type::interpolator(); } while(--len); } private: color_type m_back_color; }; //==============================================span_image_filter_gray_2x2 template class span_image_filter_gray_2x2 : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_gray_2x2() {} span_image_filter_gray_2x2(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, &filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg; const value_type *fg_ptr; const int16* weight_array = base_type::filter().weight_array() + ((base_type::filter().diameter()/2 - 1) << image_subpixel_shift); do { int x_hr; int y_hr; base_type::interpolator().coordinates(&x_hr, &y_hr); x_hr -= base_type::filter_dx_int(); y_hr -= base_type::filter_dy_int(); int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; unsigned weight; fg = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); weight = (weight_array[x_hr + image_subpixel_scale] * weight_array[y_hr + image_subpixel_scale] + image_filter_scale / 2) >> image_filter_shift; fg += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_x(); weight = (weight_array[x_hr] * weight_array[y_hr + image_subpixel_scale] + image_filter_scale / 2) >> image_filter_shift; fg += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_y(); weight = (weight_array[x_hr + image_subpixel_scale] * weight_array[y_hr] + image_filter_scale / 2) >> image_filter_shift; fg += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_x(); weight = (weight_array[x_hr] * weight_array[y_hr] + image_filter_scale / 2) >> image_filter_shift; fg += weight * *fg_ptr; fg >>= image_filter_shift; if(fg > color_type::full_value()) fg = color_type::full_value(); span->v = (value_type)fg; span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; //==================================================span_image_filter_gray template class span_image_filter_gray : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_gray() {} span_image_filter_gray(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, &filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg; const value_type *fg_ptr; unsigned diameter = base_type::filter().diameter(); int start = base_type::filter().start(); const int16* weight_array = base_type::filter().weight_array(); int x_count; int weight_y; do { base_type::interpolator().coordinates(&x, &y); x -= base_type::filter_dx_int(); y -= base_type::filter_dy_int(); int x_hr = x; int y_hr = y; int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; fg = 0; int x_fract = x_hr & image_subpixel_mask; unsigned y_count = diameter; y_hr = image_subpixel_mask - (y_hr & image_subpixel_mask); fg_ptr = (const value_type*)base_type::source().span(x_lr + start, y_lr + start, diameter); for(;;) { x_count = diameter; weight_y = weight_array[y_hr]; x_hr = image_subpixel_mask - x_fract; for(;;) { fg += *fg_ptr * ((weight_y * weight_array[x_hr] + image_filter_scale / 2) >> image_filter_shift); if(--x_count == 0) break; x_hr += image_subpixel_scale; fg_ptr = (const value_type*)base_type::source().next_x(); } if(--y_count == 0) break; y_hr += image_subpixel_scale; fg_ptr = (const value_type*)base_type::source().next_y(); } fg = color_type::downshift(fg, image_filter_shift); if(fg < 0) fg = 0; if(fg > color_type::full_value()) fg = color_type::full_value(); span->v = (value_type)fg; span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; //=========================================span_image_resample_gray_affine template class span_image_resample_gray_affine : public span_image_resample_affine { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef span_image_resample_affine base_type; typedef typename base_type::interpolator_type interpolator_type; typedef typename color_type::value_type value_type; typedef typename color_type::long_type long_type; enum base_scale_e { downscale_shift = image_filter_shift }; //-------------------------------------------------------------------- span_image_resample_gray_affine() {} span_image_resample_gray_affine(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg; int diameter = base_type::filter().diameter(); int filter_scale = diameter << image_subpixel_shift; int radius_x = (diameter * base_type::m_rx) >> 1; int radius_y = (diameter * base_type::m_ry) >> 1; int len_x_lr = (diameter * base_type::m_rx + image_subpixel_mask) >> image_subpixel_shift; const int16* weight_array = base_type::filter().weight_array(); do { base_type::interpolator().coordinates(&x, &y); x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; fg = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * base_type::m_ry_inv) >> image_subpixel_shift; int total_weight = 0; int x_lr = x >> image_subpixel_shift; int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * base_type::m_rx_inv) >> image_subpixel_shift; int x_hr2 = x_hr; const value_type* fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); for(;;) { int weight_y = weight_array[y_hr]; x_hr = x_hr2; for(;;) { int weight = (weight_y * weight_array[x_hr] + image_filter_scale / 2) >> downscale_shift; fg += *fg_ptr * weight; total_weight += weight; x_hr += base_type::m_rx_inv; if(x_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_x(); } y_hr += base_type::m_ry_inv; if(y_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_y(); } fg /= total_weight; if(fg < 0) fg = 0; if(fg > color_type::full_value()) fg = color_type::full_value(); span->v = (value_type)fg; span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; //================================================span_image_resample_gray template class span_image_resample_gray : public span_image_resample { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef Interpolator interpolator_type; typedef span_image_resample base_type; typedef typename color_type::value_type value_type; typedef typename color_type::long_type long_type; enum base_scale_e { downscale_shift = image_filter_shift }; //-------------------------------------------------------------------- span_image_resample_gray() {} span_image_resample_gray(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg; int diameter = base_type::filter().diameter(); int filter_scale = diameter << image_subpixel_shift; const int16* weight_array = base_type::filter().weight_array(); do { int rx; int ry; int rx_inv = image_subpixel_scale; int ry_inv = image_subpixel_scale; base_type::interpolator().coordinates(&x, &y); base_type::interpolator().local_scale(&rx, &ry); base_type::adjust_scale(&rx, &ry); rx_inv = image_subpixel_scale * image_subpixel_scale / rx; ry_inv = image_subpixel_scale * image_subpixel_scale / ry; int radius_x = (diameter * rx) >> 1; int radius_y = (diameter * ry) >> 1; int len_x_lr = (diameter * rx + image_subpixel_mask) >> image_subpixel_shift; x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; fg = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * ry_inv) >> image_subpixel_shift; int total_weight = 0; int x_lr = x >> image_subpixel_shift; int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * rx_inv) >> image_subpixel_shift; int x_hr2 = x_hr; const value_type* fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); for(;;) { int weight_y = weight_array[y_hr]; x_hr = x_hr2; for(;;) { int weight = (weight_y * weight_array[x_hr] + image_filter_scale / 2) >> downscale_shift; fg += *fg_ptr * weight; total_weight += weight; x_hr += rx_inv; if(x_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_x(); } y_hr += ry_inv; if(y_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_y(); } fg /= total_weight; if(fg < 0) fg = 0; if(fg > color_type::full_value()) fg = color_type::full_value(); span->v = (value_type)fg; span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; } #endif ragg/src/agg/include/agg_bounding_rect.h0000644000176200001440000000700213504406270017753 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // bounding_rect function template // //---------------------------------------------------------------------------- #ifndef AGG_BOUNDING_RECT_INCLUDED #define AGG_BOUNDING_RECT_INCLUDED #include "agg_basics.h" namespace agg { //-----------------------------------------------------------bounding_rect template bool bounding_rect(VertexSource& vs, GetId& gi, unsigned start, unsigned num, CoordT* x1, CoordT* y1, CoordT* x2, CoordT* y2) { unsigned i; double x; double y; bool first = true; *x1 = CoordT(1); *y1 = CoordT(1); *x2 = CoordT(0); *y2 = CoordT(0); for(i = 0; i < num; i++) { vs.rewind(gi[start + i]); unsigned cmd; while(!is_stop(cmd = vs.vertex(&x, &y))) { if(is_vertex(cmd)) { if(first) { *x1 = CoordT(x); *y1 = CoordT(y); *x2 = CoordT(x); *y2 = CoordT(y); first = false; } else { if(CoordT(x) < *x1) *x1 = CoordT(x); if(CoordT(y) < *y1) *y1 = CoordT(y); if(CoordT(x) > *x2) *x2 = CoordT(x); if(CoordT(y) > *y2) *y2 = CoordT(y); } } } } return *x1 <= *x2 && *y1 <= *y2; } //-----------------------------------------------------bounding_rect_single template bool bounding_rect_single(VertexSource& vs, unsigned path_id, CoordT* x1, CoordT* y1, CoordT* x2, CoordT* y2) { double x; double y; bool first = true; *x1 = CoordT(1); *y1 = CoordT(1); *x2 = CoordT(0); *y2 = CoordT(0); vs.rewind(path_id); unsigned cmd; while(!is_stop(cmd = vs.vertex(&x, &y))) { if(is_vertex(cmd)) { if(first) { *x1 = CoordT(x); *y1 = CoordT(y); *x2 = CoordT(x); *y2 = CoordT(y); first = false; } else { if(CoordT(x) < *x1) *x1 = CoordT(x); if(CoordT(y) < *y1) *y1 = CoordT(y); if(CoordT(x) > *x2) *x2 = CoordT(x); if(CoordT(y) > *y2) *y2 = CoordT(y); } } } return *x1 <= *x2 && *y1 <= *y2; } } #endif ragg/src/agg/include/agg_font_freetype.h0000644000176200001440000002145614015466715020023 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // See implementation agg_font_freetype.cpp // //---------------------------------------------------------------------------- #ifndef AGG_FONT_FREETYPE_INCLUDED #define AGG_FONT_FREETYPE_INCLUDED #include #include FT_FREETYPE_H #include "agg_scanline_storage_aa.h" #include "agg_scanline_storage_bin.h" #include "agg_scanline_u.h" #include "agg_scanline_bin.h" #include "agg_path_storage_integer.h" #include "agg_rasterizer_scanline_aa.h" #include "agg_conv_curve.h" #include "agg_font_cache_manager.h" #include "agg_trans_affine.h" namespace agg { //-----------------------------------------------font_engine_freetype_base class font_engine_freetype_base { public: //-------------------------------------------------------------------- typedef serialized_scanlines_adaptor_aa gray8_adaptor_type; typedef serialized_scanlines_adaptor_bin mono_adaptor_type; typedef scanline_storage_aa8 scanlines_aa_type; typedef scanline_storage_bin scanlines_bin_type; //-------------------------------------------------------------------- ~font_engine_freetype_base(); font_engine_freetype_base(bool flag32, unsigned max_faces = 32); // Set font parameters //-------------------------------------------------------------------- void resolution(unsigned dpi); bool load_font(const char* font_name, unsigned face_index, glyph_rendering ren_type, const char* font_mem = 0, const long font_mem_size = 0); bool attach(const char* file_name); bool char_map(FT_Encoding map); bool height(double h); bool width(double w); void hinting(bool h); void flip_y(bool f); void transform(const trans_affine& affine); void id(unsigned id) { m_cur_id = id; } // Set Gamma //-------------------------------------------------------------------- template void gamma(const GammaF& f) { m_rasterizer.gamma(f); } // Accessors //-------------------------------------------------------------------- int last_error() const { return m_last_error; } unsigned resolution() const { return m_resolution; } const char* name() const { return m_name; } const char* family() const { return m_cur_face->family_name; } unsigned num_faces() const; FT_Encoding char_map() const { return m_char_map; } double height() const { return double(m_height) / 64.0; } double width() const { return double(m_width) / 64.0; } double ascender() const; double descender() const; bool hinting() const { return m_hinting; } bool flip_y() const { return m_flip_y; } unsigned id() const { return m_cur_id; } // Interface mandatory to implement for font_cache_manager //-------------------------------------------------------------------- const char* font_signature() const { return m_signature; } int change_stamp() const { return m_change_stamp; } unsigned get_glyph_index(unsigned glyph_code); bool prepare_glyph(unsigned glyph_index); unsigned glyph_index() const { return m_glyph_index; } unsigned data_size() const { return m_data_size; } glyph_data_type data_type() const { return m_data_type; } const rect_i& bounds() const { return m_bounds; } double ascent() const { return double(m_cur_face->size->metrics.ascender) / 64;} double descent() const { return double(m_cur_face->size->metrics.descender) / 64;} double max_advance() const { return double(m_cur_face->size->metrics.max_advance) / 64;} double advance_x() const { return m_advance_x; } double advance_y() const { return m_advance_y; } void write_glyph_to(int8u* data) const; bool add_kerning(unsigned first, unsigned second, double* x, double* y); private: font_engine_freetype_base(const font_engine_freetype_base&); const font_engine_freetype_base& operator = (const font_engine_freetype_base&); void update_char_size(); void update_signature(); int find_face(const char* face_name, unsigned face_index) const; bool m_flag32; int m_change_stamp; int m_last_error; unsigned m_cur_id; char* m_name; unsigned m_name_len; unsigned m_face_index; FT_Encoding m_char_map; char* m_signature; unsigned m_height; unsigned m_width; bool m_hinting; bool m_flip_y; bool m_library_initialized; FT_Library m_library; // handle to library FT_Face* m_faces; // A pool of font faces char** m_face_names; unsigned* m_face_indices; unsigned m_num_faces; unsigned m_max_faces; FT_Face m_cur_face; // handle to the current face object int m_resolution; glyph_rendering m_glyph_rendering; unsigned m_glyph_index; unsigned m_data_size; glyph_data_type m_data_type; rect_i m_bounds; double m_advance_x; double m_advance_y; trans_affine m_affine; path_storage_integer m_path16; path_storage_integer m_path32; conv_curve > m_curves16; conv_curve > m_curves32; scanline_u8 m_scanline_aa; scanline_bin m_scanline_bin; scanlines_aa_type m_scanlines_aa; scanlines_bin_type m_scanlines_bin; rasterizer_scanline_aa<> m_rasterizer; }; //------------------------------------------------font_engine_freetype_int16 // This class uses values of type int16 (10.6 format) for the vector cache. // The vector cache is compact, but when rendering glyphs of height // more that 200 there integer overflow can occur. // class font_engine_freetype_int16 : public font_engine_freetype_base { public: typedef serialized_integer_path_adaptor path_adaptor_type; typedef font_engine_freetype_base::gray8_adaptor_type gray8_adaptor_type; typedef font_engine_freetype_base::mono_adaptor_type mono_adaptor_type; typedef font_engine_freetype_base::scanlines_aa_type scanlines_aa_type; typedef font_engine_freetype_base::scanlines_bin_type scanlines_bin_type; font_engine_freetype_int16(unsigned max_faces = 32) : font_engine_freetype_base(false, max_faces) {} }; //------------------------------------------------font_engine_freetype_int32 // This class uses values of type int32 (26.6 format) for the vector cache. // The vector cache is twice larger than in font_engine_freetype_int16, // but it allows you to render glyphs of very large sizes. // class font_engine_freetype_int32 : public font_engine_freetype_base { public: typedef serialized_integer_path_adaptor path_adaptor_type; typedef font_engine_freetype_base::gray8_adaptor_type gray8_adaptor_type; typedef font_engine_freetype_base::mono_adaptor_type mono_adaptor_type; typedef font_engine_freetype_base::scanlines_aa_type scanlines_aa_type; typedef font_engine_freetype_base::scanlines_bin_type scanlines_bin_type; font_engine_freetype_int32(unsigned max_faces = 32) : font_engine_freetype_base(true, max_faces) {} }; } #endif ragg/src/agg/include/agg_gamma_lut.h0000644000176200001440000002004513504406270017101 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_GAMMA_LUT_INCLUDED #define AGG_GAMMA_LUT_INCLUDED #include #include "agg_basics.h" #include "agg_gamma_functions.h" namespace agg { template class gamma_lut { public: typedef gamma_lut self_type; enum gamma_scale_e { gamma_shift = GammaShift, gamma_size = 1 << gamma_shift, gamma_mask = gamma_size - 1 }; enum hi_res_scale_e { hi_res_shift = HiResShift, hi_res_size = 1 << hi_res_shift, hi_res_mask = hi_res_size - 1 }; ~gamma_lut() { pod_allocator::deallocate(m_inv_gamma, hi_res_size); pod_allocator::deallocate(m_dir_gamma, gamma_size); } gamma_lut() : m_gamma(1.0), m_dir_gamma(pod_allocator::allocate(gamma_size)), m_inv_gamma(pod_allocator::allocate(hi_res_size)) { unsigned i; for(i = 0; i < gamma_size; i++) { m_dir_gamma[i] = HiResT(i << (hi_res_shift - gamma_shift)); } for(i = 0; i < hi_res_size; i++) { m_inv_gamma[i] = LoResT(i >> (hi_res_shift - gamma_shift)); } } gamma_lut(double g) : m_gamma(1.0), m_dir_gamma(pod_allocator::allocate(gamma_size)), m_inv_gamma(pod_allocator::allocate(hi_res_size)) { gamma(g); } void gamma(double g) { m_gamma = g; unsigned i; for(i = 0; i < gamma_size; i++) { m_dir_gamma[i] = (HiResT) uround(std::pow(i / double(gamma_mask), m_gamma) * double(hi_res_mask)); } double inv_g = 1.0 / g; for(i = 0; i < hi_res_size; i++) { m_inv_gamma[i] = (LoResT) uround(std::pow(i / double(hi_res_mask), inv_g) * double(gamma_mask)); } } double gamma() const { return m_gamma; } HiResT dir(LoResT v) const { return m_dir_gamma[unsigned(v)]; } LoResT inv(HiResT v) const { return m_inv_gamma[unsigned(v)]; } private: gamma_lut(const self_type&); const self_type& operator = (const self_type&); double m_gamma; HiResT* m_dir_gamma; LoResT* m_inv_gamma; }; // // sRGB support classes // // Optimized sRGB lookup table. The direct conversion (sRGB to linear) // is a straightforward lookup. The inverse conversion (linear to sRGB) // is implemented using binary search. template class sRGB_lut_base { public: LinearType dir(int8u v) const { return m_dir_table[v]; } int8u inv(LinearType v) const { // Unrolled binary search. int8u x = 0; if (v > m_inv_table[128]) x = 128; if (v > m_inv_table[x + 64]) x += 64; if (v > m_inv_table[x + 32]) x += 32; if (v > m_inv_table[x + 16]) x += 16; if (v > m_inv_table[x + 8]) x += 8; if (v > m_inv_table[x + 4]) x += 4; if (v > m_inv_table[x + 2]) x += 2; if (v > m_inv_table[x + 1]) x += 1; return x; } protected: LinearType m_dir_table[256]; LinearType m_inv_table[256]; // Only derived classes may instantiate. sRGB_lut_base() { } }; // sRGB_lut - implements sRGB conversion for the various types. // Base template is undefined, specializations are provided below. template class sRGB_lut; template<> class sRGB_lut : public sRGB_lut_base { public: sRGB_lut() { // Generate lookup tables. m_dir_table[0] = 0; m_inv_table[0] = 0; for (unsigned i = 1; i <= 255; ++i) { // Floating-point RGB is in range [0,1]. m_dir_table[i] = float(sRGB_to_linear(i / 255.0)); m_inv_table[i] = float(sRGB_to_linear((i - 0.5) / 255.0)); } } }; template<> class sRGB_lut : public sRGB_lut_base { public: sRGB_lut() { // Generate lookup tables. m_dir_table[0] = 0; m_inv_table[0] = 0; for (int i = 1; i <= 255; ++i) { // 16-bit RGB is in range [0,65535]. m_dir_table[i] = uround(65535.0 * sRGB_to_linear(i / 255.0)); m_inv_table[i] = uround(65535.0 * sRGB_to_linear((i - 0.5) / 255.0)); } } }; template<> class sRGB_lut : public sRGB_lut_base { public: sRGB_lut() { // Generate lookup tables. m_dir_table[0] = 0; m_inv_table[0] = 0; for (int i = 1; i <= 255; ++i) { // 8-bit RGB is handled with simple bidirectional lookup tables. m_dir_table[i] = uround(255.0 * sRGB_to_linear(i / 255.0)); m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 255.0)); } } int8u inv(int8u v) const { // In this case, the inverse transform is a simple lookup. return m_inv_table[v]; } }; // Common base class for sRGB_conv objects. Defines an internal // sRGB_lut object so that users don't have to. template class sRGB_conv_base { public: static T rgb_from_sRGB(int8u x) { return lut.dir(x); } static int8u rgb_to_sRGB(T x) { return lut.inv(x); } private: static sRGB_lut lut; }; // Definition of sRGB_conv_base::lut. Due to the fact that this a template, // we don't need to place the definition in a cpp file. Hurrah. template sRGB_lut sRGB_conv_base::lut; // Wrapper for sRGB-linear conversion. // Base template is undefined, specializations are provided below. template class sRGB_conv; template<> class sRGB_conv : public sRGB_conv_base { public: static float alpha_from_sRGB(int8u x) { static const double y = 1 / 255.0; return float(x * y); } static int8u alpha_to_sRGB(float x) { if (x < 0) return 0; if (x > 1) return 255; return int8u(0.5 + x * 255); } }; template<> class sRGB_conv : public sRGB_conv_base { public: static int16u alpha_from_sRGB(int8u x) { return (x << 8) | x; } static int8u alpha_to_sRGB(int16u x) { return x >> 8; } }; template<> class sRGB_conv : public sRGB_conv_base { public: static int8u alpha_from_sRGB(int8u x) { return x; } static int8u alpha_to_sRGB(int8u x) { return x; } }; } #endif ragg/src/agg/include/agg_vcgen_vertex_sequence.h0000644000176200001440000000737013504406270021530 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_VCGEN_VERTEX_SEQUENCE_INCLUDED #define AGG_VCGEN_VERTEX_SEQUENCE_INCLUDED #include "agg_basics.h" #include "agg_vertex_sequence.h" #include "agg_shorten_path.h" namespace agg { //===================================================vcgen_vertex_sequence class vcgen_vertex_sequence { public: typedef vertex_dist_cmd vertex_type; typedef vertex_sequence vertex_storage; vcgen_vertex_sequence() : m_flags(0), m_cur_vertex(0), m_shorten(0.0), m_ready(false) { } // Vertex Generator Interface void remove_all(); void add_vertex(double x, double y, unsigned cmd); // Vertex Source Interface void rewind(unsigned path_id); unsigned vertex(double* x, double* y); void shorten(double s) { m_shorten = s; } double shorten() const { return m_shorten; } private: vcgen_vertex_sequence(const vcgen_vertex_sequence&); const vcgen_vertex_sequence& operator = (const vcgen_vertex_sequence&); vertex_storage m_src_vertices; unsigned m_flags; unsigned m_cur_vertex; double m_shorten; bool m_ready; }; //------------------------------------------------------------------------ inline void vcgen_vertex_sequence::remove_all() { m_ready = false; m_src_vertices.remove_all(); m_cur_vertex = 0; m_flags = 0; } //------------------------------------------------------------------------ inline void vcgen_vertex_sequence::add_vertex(double x, double y, unsigned cmd) { m_ready = false; if(is_move_to(cmd)) { m_src_vertices.modify_last(vertex_dist_cmd(x, y, cmd)); } else { if(is_vertex(cmd)) { m_src_vertices.add(vertex_dist_cmd(x, y, cmd)); } else { m_flags = cmd & path_flags_mask; } } } //------------------------------------------------------------------------ inline void vcgen_vertex_sequence::rewind(unsigned) { if(!m_ready) { m_src_vertices.close(is_closed(m_flags)); shorten_path(m_src_vertices, m_shorten, get_close_flag(m_flags)); } m_ready = true; m_cur_vertex = 0; } //------------------------------------------------------------------------ inline unsigned vcgen_vertex_sequence::vertex(double* x, double* y) { if(!m_ready) { rewind(0); } if(m_cur_vertex == m_src_vertices.size()) { ++m_cur_vertex; return path_cmd_end_poly | m_flags; } if(m_cur_vertex > m_src_vertices.size()) { return path_cmd_stop; } vertex_type& v = m_src_vertices[m_cur_vertex++]; *x = v.x; *y = v.y; return v.cmd; } } #endif ragg/src/agg/include/agg_trans_bilinear.h0000644000176200001440000001250213504406270020126 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Bilinear 2D transformations // //---------------------------------------------------------------------------- #ifndef AGG_TRANS_BILINEAR_INCLUDED #define AGG_TRANS_BILINEAR_INCLUDED #include "agg_basics.h" #include "agg_simul_eq.h" namespace agg { //==========================================================trans_bilinear class trans_bilinear { public: //-------------------------------------------------------------------- trans_bilinear() : m_valid(false) {} //-------------------------------------------------------------------- // Arbitrary quadrangle transformations trans_bilinear(const double* src, const double* dst) { quad_to_quad(src, dst); } //-------------------------------------------------------------------- // Direct transformations trans_bilinear(double x1, double y1, double x2, double y2, const double* quad) { rect_to_quad(x1, y1, x2, y2, quad); } //-------------------------------------------------------------------- // Reverse transformations trans_bilinear(const double* quad, double x1, double y1, double x2, double y2) { quad_to_rect(quad, x1, y1, x2, y2); } //-------------------------------------------------------------------- // Set the transformations using two arbitrary quadrangles. void quad_to_quad(const double* src, const double* dst) { double left[4][4]; double right[4][2]; unsigned i; for(i = 0; i < 4; i++) { unsigned ix = i * 2; unsigned iy = ix + 1; left[i][0] = 1.0; left[i][1] = src[ix] * src[iy]; left[i][2] = src[ix]; left[i][3] = src[iy]; right[i][0] = dst[ix]; right[i][1] = dst[iy]; } m_valid = simul_eq<4, 2>::solve(left, right, m_mtx); } //-------------------------------------------------------------------- // Set the direct transformations, i.e., rectangle -> quadrangle void rect_to_quad(double x1, double y1, double x2, double y2, const double* quad) { double src[8]; src[0] = src[6] = x1; src[2] = src[4] = x2; src[1] = src[3] = y1; src[5] = src[7] = y2; quad_to_quad(src, quad); } //-------------------------------------------------------------------- // Set the reverse transformations, i.e., quadrangle -> rectangle void quad_to_rect(const double* quad, double x1, double y1, double x2, double y2) { double dst[8]; dst[0] = dst[6] = x1; dst[2] = dst[4] = x2; dst[1] = dst[3] = y1; dst[5] = dst[7] = y2; quad_to_quad(quad, dst); } //-------------------------------------------------------------------- // Check if the equations were solved successfully bool is_valid() const { return m_valid; } //-------------------------------------------------------------------- // Transform a point (x, y) void transform(double* x, double* y) const { double tx = *x; double ty = *y; double xy = tx * ty; *x = m_mtx[0][0] + m_mtx[1][0] * xy + m_mtx[2][0] * tx + m_mtx[3][0] * ty; *y = m_mtx[0][1] + m_mtx[1][1] * xy + m_mtx[2][1] * tx + m_mtx[3][1] * ty; } //-------------------------------------------------------------------- class iterator_x { double inc_x; double inc_y; public: double x; double y; iterator_x() {} iterator_x(double tx, double ty, double step, const double m[4][2]) : inc_x(m[1][0] * step * ty + m[2][0] * step), inc_y(m[1][1] * step * ty + m[2][1] * step), x(m[0][0] + m[1][0] * tx * ty + m[2][0] * tx + m[3][0] * ty), y(m[0][1] + m[1][1] * tx * ty + m[2][1] * tx + m[3][1] * ty) { } void operator ++ () { x += inc_x; y += inc_y; } }; iterator_x begin(double x, double y, double step) const { return iterator_x(x, y, step, m_mtx); } private: double m_mtx[4][2]; bool m_valid; }; } #endif ragg/src/agg/include/agg_pixfmt_rgb.h0000644000176200001440000011254313504406270017301 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_PIXFMT_RGB_INCLUDED #define AGG_PIXFMT_RGB_INCLUDED #include #include "agg_pixfmt_base.h" #include "agg_rendering_buffer.h" namespace agg { //=====================================================apply_gamma_dir_rgb template class apply_gamma_dir_rgb { public: typedef typename ColorT::value_type value_type; apply_gamma_dir_rgb(const GammaLut& gamma) : m_gamma(gamma) {} AGG_INLINE void operator () (value_type* p) { p[Order::R] = m_gamma.dir(p[Order::R]); p[Order::G] = m_gamma.dir(p[Order::G]); p[Order::B] = m_gamma.dir(p[Order::B]); } private: const GammaLut& m_gamma; }; //=====================================================apply_gamma_inv_rgb template class apply_gamma_inv_rgb { public: typedef typename ColorT::value_type value_type; apply_gamma_inv_rgb(const GammaLut& gamma) : m_gamma(gamma) {} AGG_INLINE void operator () (value_type* p) { p[Order::R] = m_gamma.inv(p[Order::R]); p[Order::G] = m_gamma.inv(p[Order::G]); p[Order::B] = m_gamma.inv(p[Order::B]); } private: const GammaLut& m_gamma; }; //=========================================================blender_rgb template struct blender_rgb { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; // Blend pixels using the non-premultiplied form of Alvy-Ray Smith's // compositing function. Since the render buffer is opaque we skip the // initial premultiply and final demultiply. //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) { blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover)); } //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha) { p[Order::R] = color_type::lerp(p[Order::R], cr, alpha); p[Order::G] = color_type::lerp(p[Order::G], cg, alpha); p[Order::B] = color_type::lerp(p[Order::B], cb, alpha); } }; //======================================================blender_rgb_pre template struct blender_rgb_pre { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; // Blend pixels using the premultiplied form of Alvy-Ray Smith's // compositing function. //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) { blend_pix(p, color_type::mult_cover(cr, cover), color_type::mult_cover(cg, cover), color_type::mult_cover(cb, cover), color_type::mult_cover(alpha, cover)); } //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha) { p[Order::R] = color_type::prelerp(p[Order::R], cr, alpha); p[Order::G] = color_type::prelerp(p[Order::G], cg, alpha); p[Order::B] = color_type::prelerp(p[Order::B], cb, alpha); } }; //===================================================blender_rgb_gamma template class blender_rgb_gamma : public blender_base { public: typedef ColorT color_type; typedef Order order_type; typedef Gamma gamma_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- blender_rgb_gamma() : m_gamma(0) {} void gamma(const gamma_type& g) { m_gamma = &g; } //-------------------------------------------------------------------- AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) { blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover)); } //-------------------------------------------------------------------- AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha) { calc_type r = m_gamma->dir(p[Order::R]); calc_type g = m_gamma->dir(p[Order::G]); calc_type b = m_gamma->dir(p[Order::B]); p[Order::R] = m_gamma->inv(color_type::downscale((m_gamma->dir(cr) - r) * alpha) + r); p[Order::G] = m_gamma->inv(color_type::downscale((m_gamma->dir(cg) - g) * alpha) + g); p[Order::B] = m_gamma->inv(color_type::downscale((m_gamma->dir(cb) - b) * alpha) + b); } private: const gamma_type* m_gamma; }; //==================================================pixfmt_alpha_blend_rgb template class pixfmt_alpha_blend_rgb { public: typedef pixfmt_rgb_tag pixfmt_category; typedef RenBuf rbuf_type; typedef Blender blender_type; typedef typename rbuf_type::row_data row_data; typedef typename blender_type::color_type color_type; typedef typename blender_type::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; enum { num_components = 3, pix_step = Step, pix_offset = Offset, pix_width = sizeof(value_type) * pix_step }; struct pixel_type { value_type c[num_components]; void set(value_type r, value_type g, value_type b) { c[order_type::R] = r; c[order_type::G] = g; c[order_type::B] = b; } void set(const color_type& color) { set(color.r, color.g, color.b); } void get(value_type& r, value_type& g, value_type& b) const { r = c[order_type::R]; g = c[order_type::G]; b = c[order_type::B]; } color_type get() const { return color_type( c[order_type::R], c[order_type::G], c[order_type::B]); } pixel_type* next() { return (pixel_type*)(c + pix_step); } const pixel_type* next() const { return (const pixel_type*)(c + pix_step); } pixel_type* advance(int n) { return (pixel_type*)(c + n * pix_step); } const pixel_type* advance(int n) const { return (const pixel_type*)(c + n * pix_step); } }; private: //-------------------------------------------------------------------- AGG_INLINE void blend_pix(pixel_type* p, value_type r, value_type g, value_type b, value_type a, unsigned cover) { m_blender.blend_pix(p->c, r, g, b, a, cover); } //-------------------------------------------------------------------- AGG_INLINE void blend_pix(pixel_type* p, value_type r, value_type g, value_type b, value_type a) { m_blender.blend_pix(p->c, r, g, b, a); } //-------------------------------------------------------------------- AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover) { m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a, cover); } //-------------------------------------------------------------------- AGG_INLINE void blend_pix(pixel_type* p, const color_type& c) { m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a); } //-------------------------------------------------------------------- AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover) { if (!c.is_transparent()) { if (c.is_opaque() && cover == cover_mask) { p->set(c); } else { blend_pix(p, c, cover); } } } //-------------------------------------------------------------------- AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c) { if (!c.is_transparent()) { if (c.is_opaque()) { p->set(c); } else { blend_pix(p, c); } } } public: //-------------------------------------------------------------------- explicit pixfmt_alpha_blend_rgb(rbuf_type& rb) : m_rbuf(&rb) {} void attach(rbuf_type& rb) { m_rbuf = &rb; } //-------------------------------------------------------------------- template bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) { rect_i r(x1, y1, x2, y2); if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) { int stride = pixf.stride(); m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), (r.x2 - r.x1) + 1, (r.y2 - r.y1) + 1, stride); return true; } return false; } //-------------------------------------------------------------------- Blender& blender() { return m_blender; } //-------------------------------------------------------------------- AGG_INLINE unsigned width() const { return m_rbuf->width(); } AGG_INLINE unsigned height() const { return m_rbuf->height(); } AGG_INLINE int stride() const { return m_rbuf->stride(); } //-------------------------------------------------------------------- AGG_INLINE int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } AGG_INLINE row_data row(int y) const { return m_rbuf->row(y); } //-------------------------------------------------------------------- AGG_INLINE int8u* pix_ptr(int x, int y) { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); } AGG_INLINE const int8u* pix_ptr(int x, int y) const { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); } // Return pointer to pixel value, forcing row to be allocated. AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len) { return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset)); } // Return pointer to pixel value, or null if row not allocated. AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const { int8u* p = m_rbuf->row_ptr(y); return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step + pix_offset)) : 0; } // Get pixel pointer from raw buffer pointer. AGG_INLINE static pixel_type* pix_value_ptr(void* p) { return (pixel_type*)((value_type*)p + pix_offset); } // Get pixel pointer from raw buffer pointer. AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) { return (const pixel_type*)((const value_type*)p + pix_offset); } //-------------------------------------------------------------------- AGG_INLINE static void write_plain_color(void* p, color_type c) { // RGB formats are implicitly premultiplied. c.premultiply(); pix_value_ptr(p)->set(c); } //-------------------------------------------------------------------- AGG_INLINE static color_type read_plain_color(const void* p) { return pix_value_ptr(p)->get(); } //-------------------------------------------------------------------- AGG_INLINE static void make_pix(int8u* p, const color_type& c) { ((pixel_type*)p)->set(c); } //-------------------------------------------------------------------- AGG_INLINE color_type pixel(int x, int y) const { if (const pixel_type* p = pix_value_ptr(x, y)) { return p->get(); } return color_type::no_color(); } //-------------------------------------------------------------------- AGG_INLINE void copy_pixel(int x, int y, const color_type& c) { pix_value_ptr(x, y, 1)->set(c); } //-------------------------------------------------------------------- AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) { copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover); } //-------------------------------------------------------------------- AGG_INLINE void copy_hline(int x, int y, unsigned len, const color_type& c) { pixel_type* p = pix_value_ptr(x, y, len); do { p->set(c); p = p->next(); } while(--len); } //-------------------------------------------------------------------- AGG_INLINE void copy_vline(int x, int y, unsigned len, const color_type& c) { do { pix_value_ptr(x, y++, 1)->set(c); } while (--len); } //-------------------------------------------------------------------- void blend_hline(int x, int y, unsigned len, const color_type& c, int8u cover) { if (!c.is_transparent()) { pixel_type* p = pix_value_ptr(x, y, len); if (c.is_opaque() && cover == cover_mask) { do { p->set(c); p = p->next(); } while (--len); } else { do { blend_pix(p, c, cover); p = p->next(); } while (--len); } } } //-------------------------------------------------------------------- void blend_vline(int x, int y, unsigned len, const color_type& c, int8u cover) { if (!c.is_transparent()) { if (c.is_opaque() && cover == cover_mask) { do { pix_value_ptr(x, y++, 1)->set(c); } while (--len); } else { do { blend_pix(pix_value_ptr(x, y++, 1), c, cover); } while (--len); } } } //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { if (!c.is_transparent()) { pixel_type* p = pix_value_ptr(x, y, len); do { if (c.is_opaque() && *covers == cover_mask) { p->set(c); } else { blend_pix(p, c, *covers); } p = p->next(); ++covers; } while (--len); } } //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { if (!c.is_transparent()) { do { pixel_type* p = pix_value_ptr(x, y++, 1); if (c.is_opaque() && *covers == cover_mask) { p->set(c); } else { blend_pix(p, c, *covers); } ++covers; } while (--len); } } //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, unsigned len, const color_type* colors) { pixel_type* p = pix_value_ptr(x, y, len); do { p->set(*colors++); p = p->next(); } while (--len); } //-------------------------------------------------------------------- void copy_color_vspan(int x, int y, unsigned len, const color_type* colors) { do { pix_value_ptr(x, y++, 1)->set(*colors++); } while (--len); } //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { pixel_type* p = pix_value_ptr(x, y, len); if (covers) { do { copy_or_blend_pix(p, *colors++, *covers++); p = p->next(); } while (--len); } else { if (cover == cover_mask) { do { copy_or_blend_pix(p, *colors++); p = p->next(); } while (--len); } else { do { copy_or_blend_pix(p, *colors++, cover); p = p->next(); } while (--len); } } } //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { if (covers) { do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); } while (--len); } else { if (cover == cover_mask) { do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); } while (--len); } else { do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); } while (--len); } } } //-------------------------------------------------------------------- template void for_each_pixel(Function f) { for (unsigned y = 0; y < height(); ++y) { row_data r = m_rbuf->row(y); if (r.ptr) { unsigned len = r.x2 - r.x1 + 1; pixel_type* p = pix_value_ptr(r.x1, y, len); do { f(p->c); p = p->next(); } while (--len); } } } //-------------------------------------------------------------------- template void apply_gamma_dir(const GammaLut& g) { for_each_pixel(apply_gamma_dir_rgb(g)); } //-------------------------------------------------------------------- template void apply_gamma_inv(const GammaLut& g) { for_each_pixel(apply_gamma_inv_rgb(g)); } //-------------------------------------------------------------------- template void copy_from(const RenBuf2& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len) { if (const int8u* p = from.row_ptr(ysrc)) { std::memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, p + xsrc * pix_width, len * pix_width); } } //-------------------------------------------------------------------- // Blend from an RGBA surface. template void blend_from(const SrcPixelFormatRenderer& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; typedef typename SrcPixelFormatRenderer::order_type src_order; if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); if (cover == cover_mask) { do { value_type alpha = psrc->c[src_order::A]; if (alpha <= color_type::empty_value()) { if (alpha >= color_type::full_value()) { pdst->c[order_type::R] = psrc->c[src_order::R]; pdst->c[order_type::G] = psrc->c[src_order::G]; pdst->c[order_type::B] = psrc->c[src_order::B]; } else { blend_pix(pdst, psrc->c[src_order::R], psrc->c[src_order::G], psrc->c[src_order::B], alpha); } } psrc = psrc->next(); pdst = pdst->next(); } while(--len); } else { do { copy_or_blend_pix(pdst, psrc->get(), cover); psrc = psrc->next(); pdst = pdst->next(); } while (--len); } } } //-------------------------------------------------------------------- // Blend from single color, using grayscale surface as alpha channel. template void blend_from_color(const SrcPixelFormatRenderer& from, const color_type& color, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; typedef typename SrcPixelFormatRenderer::color_type src_color_type; if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); do { copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); psrc = psrc->next(); pdst = pdst->next(); } while (--len); } } //-------------------------------------------------------------------- // Blend from color table, using grayscale surface as indexes into table. // Obviously, this only works for integer value types. template void blend_from_lut(const SrcPixelFormatRenderer& from, const color_type* color_lut, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); if (cover == cover_mask) { do { const color_type& color = color_lut[psrc->c[0]]; blend_pix(pdst, color); psrc = psrc->next(); pdst = pdst->next(); } while(--len); } else { do { copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); psrc = psrc->next(); pdst = pdst->next(); } while(--len); } } } private: rbuf_type* m_rbuf; Blender m_blender; }; //----------------------------------------------------------------------- typedef blender_rgb blender_rgb24; typedef blender_rgb blender_bgr24; typedef blender_rgb blender_srgb24; typedef blender_rgb blender_sbgr24; typedef blender_rgb blender_rgb48; typedef blender_rgb blender_bgr48; typedef blender_rgb blender_rgb96; typedef blender_rgb blender_bgr96; typedef blender_rgb_pre blender_rgb24_pre; typedef blender_rgb_pre blender_bgr24_pre; typedef blender_rgb_pre blender_srgb24_pre; typedef blender_rgb_pre blender_sbgr24_pre; typedef blender_rgb_pre blender_rgb48_pre; typedef blender_rgb_pre blender_bgr48_pre; typedef blender_rgb_pre blender_rgb96_pre; typedef blender_rgb_pre blender_bgr96_pre; typedef pixfmt_alpha_blend_rgb pixfmt_rgb24; typedef pixfmt_alpha_blend_rgb pixfmt_bgr24; typedef pixfmt_alpha_blend_rgb pixfmt_srgb24; typedef pixfmt_alpha_blend_rgb pixfmt_sbgr24; typedef pixfmt_alpha_blend_rgb pixfmt_rgb48; typedef pixfmt_alpha_blend_rgb pixfmt_bgr48; typedef pixfmt_alpha_blend_rgb pixfmt_rgb96; typedef pixfmt_alpha_blend_rgb pixfmt_bgr96; typedef pixfmt_alpha_blend_rgb pixfmt_rgb24_pre; typedef pixfmt_alpha_blend_rgb pixfmt_bgr24_pre; typedef pixfmt_alpha_blend_rgb pixfmt_srgb24_pre; typedef pixfmt_alpha_blend_rgb pixfmt_sbgr24_pre; typedef pixfmt_alpha_blend_rgb pixfmt_rgb48_pre; typedef pixfmt_alpha_blend_rgb pixfmt_bgr48_pre; typedef pixfmt_alpha_blend_rgb pixfmt_rgb96_pre; typedef pixfmt_alpha_blend_rgb pixfmt_bgr96_pre; typedef pixfmt_alpha_blend_rgb pixfmt_rgbx32; typedef pixfmt_alpha_blend_rgb pixfmt_xrgb32; typedef pixfmt_alpha_blend_rgb pixfmt_xbgr32; typedef pixfmt_alpha_blend_rgb pixfmt_bgrx32; typedef pixfmt_alpha_blend_rgb pixfmt_srgbx32; typedef pixfmt_alpha_blend_rgb pixfmt_sxrgb32; typedef pixfmt_alpha_blend_rgb pixfmt_sxbgr32; typedef pixfmt_alpha_blend_rgb pixfmt_sbgrx32; typedef pixfmt_alpha_blend_rgb pixfmt_rgbx64; typedef pixfmt_alpha_blend_rgb pixfmt_xrgb64; typedef pixfmt_alpha_blend_rgb pixfmt_xbgr64; typedef pixfmt_alpha_blend_rgb pixfmt_bgrx64; typedef pixfmt_alpha_blend_rgb pixfmt_rgbx128; typedef pixfmt_alpha_blend_rgb pixfmt_xrgb128; typedef pixfmt_alpha_blend_rgb pixfmt_xbgr128; typedef pixfmt_alpha_blend_rgb pixfmt_bgrx128; typedef pixfmt_alpha_blend_rgb pixfmt_rgbx32_pre; typedef pixfmt_alpha_blend_rgb pixfmt_xrgb32_pre; typedef pixfmt_alpha_blend_rgb pixfmt_xbgr32_pre; typedef pixfmt_alpha_blend_rgb pixfmt_bgrx32_pre; typedef pixfmt_alpha_blend_rgb pixfmt_srgbx32_pre; typedef pixfmt_alpha_blend_rgb pixfmt_sxrgb32_pre; typedef pixfmt_alpha_blend_rgb pixfmt_sxbgr32_pre; typedef pixfmt_alpha_blend_rgb pixfmt_sbgrx32_pre; typedef pixfmt_alpha_blend_rgb pixfmt_rgbx64_pre; typedef pixfmt_alpha_blend_rgb pixfmt_xrgb64_pre; typedef pixfmt_alpha_blend_rgb pixfmt_xbgr64_pre; typedef pixfmt_alpha_blend_rgb pixfmt_bgrx64_pre; typedef pixfmt_alpha_blend_rgb pixfmt_rgbx128_pre; typedef pixfmt_alpha_blend_rgb pixfmt_xrgb128_pre; typedef pixfmt_alpha_blend_rgb pixfmt_xbgr128_pre; typedef pixfmt_alpha_blend_rgb pixfmt_bgrx128_pre; //-----------------------------------------------------pixfmt_rgb24_gamma template class pixfmt_rgb24_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_rgb24_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_srgb24_gamma template class pixfmt_srgb24_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_srgb24_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_bgr24_gamma template class pixfmt_bgr24_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_bgr24_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_sbgr24_gamma template class pixfmt_sbgr24_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_sbgr24_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_rgb48_gamma template class pixfmt_rgb48_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_rgb48_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; //-----------------------------------------------------pixfmt_bgr48_gamma template class pixfmt_bgr48_gamma : public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_bgr48_gamma(rendering_buffer& rb, const Gamma& g) : pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; } #endif ragg/src/agg/include/agg_span_gradient_image.h0000644000176200001440000000713713504406270021122 0ustar liggesusers//---------------------------------------------------------------------------- // AGG Contribution Pack - Gradients 1 (AGG CP - Gradients 1) // http://milan.marusinec.sk/aggcp // // For Anti-Grain Geometry - Version 2.4 // http://www.antigrain.org // // Contribution Created By: // Milan Marusinec alias Milano // milan@marusinec.sk // Copyright (c) 2007-2008 // // 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. // // [History] ----------------------------------------------------------------- // // 03.02.2008-Milano: Ported from Object Pascal code of AggPas // #ifndef AGG_SPAN_GRADIENT_IMAGE_INCLUDED #define AGG_SPAN_GRADIENT_IMAGE_INCLUDED #include #include "agg_basics.h" #include "agg_span_gradient.h" #include "agg_color_rgba.h" #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" namespace agg { //==========================================================one_color_function template class one_color_function { public: typedef ColorT color_type; color_type m_color; one_color_function() : m_color() { } static unsigned size() { return 1; } const color_type& operator [] (unsigned i) const { return m_color; } color_type* operator [] (unsigned i) { return &m_color; } }; //==========================================================gradient_image template class gradient_image { private: //------------ fields typedef ColorT color_type; typedef agg::pixfmt_rgba32 pixfmt_type; agg::rgba8* m_buffer; int m_alocdx; int m_alocdy; int m_width; int m_height; color_type* m_color; one_color_function m_color_function; public: gradient_image() : m_color_function(), m_buffer(NULL), m_alocdx(0), m_alocdy(0), m_width(0), m_height(0) { m_color = m_color_function[0 ]; } ~gradient_image() { if (m_buffer) { delete [] m_buffer; } } void* image_create(int width, int height ) { void* result = NULL; if (width > m_alocdx || height > m_alocdy) { if (m_buffer) { delete [] m_buffer; } m_buffer = NULL; m_buffer = new agg::rgba8[width * height]; if (m_buffer) { m_alocdx = width; m_alocdy = height; } else { m_alocdx = 0; m_alocdy = 0; }; }; if (m_buffer) { m_width = width; m_height = height; for (int rows = 0; rows < height; rows++) { agg::rgba8* row = &m_buffer[rows * m_alocdx ]; std::memset(row ,0 ,m_width * 4 ); }; result = m_buffer; }; return result; } void* image_buffer() { return m_buffer; } int image_width() { return m_width; } int image_height() { return m_height; } int image_stride() { return m_alocdx * 4; } int calculate(int x, int y, int d) const { if (m_buffer) { int px = x >> agg::gradient_subpixel_shift; int py = y >> agg::gradient_subpixel_shift; px %= m_width; if (px < 0) { px += m_width; } py %= m_height; if (py < 0 ) { py += m_height; } rgba8* pixel = &m_buffer[py * m_alocdx + px ]; m_color->r = pixel->r; m_color->g = pixel->g; m_color->b = pixel->b; m_color->a = pixel->a; } else { m_color->r = 0; m_color->g = 0; m_color->b = 0; m_color->a = 0; } return 0; } const one_color_function& color_function() const { return m_color_function; } }; } #endif ragg/src/agg/include/agg_gsv_text.h0000644000176200001440000000767113504406270017010 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Class gsv_text // //---------------------------------------------------------------------------- #ifndef AGG_GSV_TEXT_INCLUDED #define AGG_GSV_TEXT_INCLUDED #include "agg_array.h" #include "agg_conv_stroke.h" #include "agg_conv_transform.h" namespace agg { //---------------------------------------------------------------gsv_text // // See Implementation agg_gsv_text.cpp // class gsv_text { enum status { initial, next_char, start_glyph, glyph }; public: gsv_text(); void font(const void* font); void flip(bool flip_y) { m_flip = flip_y; } void load_font(const char* file); void size(double height, double width=0.0); void space(double space); void line_space(double line_space); void start_point(double x, double y); void text(const char* text); double text_width(); void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: // not supposed to be copied gsv_text(const gsv_text&); const gsv_text& operator = (const gsv_text&); int16u value(const int8u* p) const { int16u v; if(m_big_endian) { *(int8u*)&v = p[1]; *((int8u*)&v + 1) = p[0]; } else { *(int8u*)&v = p[0]; *((int8u*)&v + 1) = p[1]; } return v; } private: double m_x; double m_y; double m_start_x; double m_width; double m_height; double m_space; double m_line_space; char m_chr[2]; char* m_text; pod_array m_text_buf; char* m_cur_chr; const void* m_font; pod_array m_loaded_font; status m_status; bool m_big_endian; bool m_flip; int8u* m_indices; int8* m_glyphs; int8* m_bglyph; int8* m_eglyph; double m_w; double m_h; }; //--------------------------------------------------------gsv_text_outline template class gsv_text_outline { public: gsv_text_outline(gsv_text& text, Transformer& trans) : m_polyline(text), m_trans(m_polyline, trans) { } void width(double w) { m_polyline.width(w); } void transformer(const Transformer* trans) { m_trans->transformer(trans); } void rewind(unsigned path_id) { m_trans.rewind(path_id); m_polyline.line_join(round_join); m_polyline.line_cap(round_cap); } unsigned vertex(double* x, double* y) { return m_trans.vertex(x, y); } private: conv_stroke m_polyline; conv_transform, Transformer> m_trans; }; } #endif ragg/src/agg/include/agg_pixfmt_gray.h0000644000176200001440000005776613504406270017510 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_PIXFMT_GRAY_INCLUDED #define AGG_PIXFMT_GRAY_INCLUDED #include #include "agg_pixfmt_base.h" #include "agg_rendering_buffer.h" namespace agg { //============================================================blender_gray template struct blender_gray { typedef ColorT color_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; // Blend pixels using the non-premultiplied form of Alvy-Ray Smith's // compositing function. Since the render buffer is opaque we skip the // initial premultiply and final demultiply. static AGG_INLINE void blend_pix(value_type* p, value_type cv, value_type alpha, cover_type cover) { blend_pix(p, cv, color_type::mult_cover(alpha, cover)); } static AGG_INLINE void blend_pix(value_type* p, value_type cv, value_type alpha) { *p = color_type::lerp(*p, cv, alpha); } }; //======================================================blender_gray_pre template struct blender_gray_pre { typedef ColorT color_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; // Blend pixels using the premultiplied form of Alvy-Ray Smith's // compositing function. static AGG_INLINE void blend_pix(value_type* p, value_type cv, value_type alpha, cover_type cover) { blend_pix(p, color_type::mult_cover(cv, cover), color_type::mult_cover(alpha, cover)); } static AGG_INLINE void blend_pix(value_type* p, value_type cv, value_type alpha) { *p = color_type::prelerp(*p, cv, alpha); } }; //=====================================================apply_gamma_dir_gray template class apply_gamma_dir_gray { public: typedef typename ColorT::value_type value_type; apply_gamma_dir_gray(const GammaLut& gamma) : m_gamma(gamma) {} AGG_INLINE void operator () (value_type* p) { *p = m_gamma.dir(*p); } private: const GammaLut& m_gamma; }; //=====================================================apply_gamma_inv_gray template class apply_gamma_inv_gray { public: typedef typename ColorT::value_type value_type; apply_gamma_inv_gray(const GammaLut& gamma) : m_gamma(gamma) {} AGG_INLINE void operator () (value_type* p) { *p = m_gamma.inv(*p); } private: const GammaLut& m_gamma; }; //=================================================pixfmt_alpha_blend_gray template class pixfmt_alpha_blend_gray { public: typedef pixfmt_gray_tag pixfmt_category; typedef RenBuf rbuf_type; typedef typename rbuf_type::row_data row_data; typedef Blender blender_type; typedef typename blender_type::color_type color_type; typedef int order_type; // A fake one typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; enum { num_components = 1, pix_width = sizeof(value_type) * Step, pix_step = Step, pix_offset = Offset, }; struct pixel_type { value_type c[num_components]; void set(value_type v) { c[0] = v; } void set(const color_type& color) { set(color.v); } void get(value_type& v) const { v = c[0]; } color_type get() const { return color_type(c[0]); } pixel_type* next() { return (pixel_type*)(c + pix_step); } const pixel_type* next() const { return (const pixel_type*)(c + pix_step); } pixel_type* advance(int n) { return (pixel_type*)(c + n * pix_step); } const pixel_type* advance(int n) const { return (const pixel_type*)(c + n * pix_step); } }; private: //-------------------------------------------------------------------- AGG_INLINE void blend_pix(pixel_type* p, value_type v, value_type a, unsigned cover) { blender_type::blend_pix(p->c, v, a, cover); } //-------------------------------------------------------------------- AGG_INLINE void blend_pix(pixel_type* p, value_type v, value_type a) { blender_type::blend_pix(p->c, v, a); } //-------------------------------------------------------------------- AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover) { blender_type::blend_pix(p->c, c.v, c.a, cover); } //-------------------------------------------------------------------- AGG_INLINE void blend_pix(pixel_type* p, const color_type& c) { blender_type::blend_pix(p->c, c.v, c.a); } //-------------------------------------------------------------------- AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover) { if (!c.is_transparent()) { if (c.is_opaque() && cover == cover_mask) { p->set(c); } else { blend_pix(p, c, cover); } } } //-------------------------------------------------------------------- AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c) { if (!c.is_transparent()) { if (c.is_opaque()) { p->set(c); } else { blend_pix(p, c); } } } public: //-------------------------------------------------------------------- explicit pixfmt_alpha_blend_gray(rbuf_type& rb) : m_rbuf(&rb) {} void attach(rbuf_type& rb) { m_rbuf = &rb; } //-------------------------------------------------------------------- template bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) { rect_i r(x1, y1, x2, y2); if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) { int stride = pixf.stride(); m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), (r.x2 - r.x1) + 1, (r.y2 - r.y1) + 1, stride); return true; } return false; } //-------------------------------------------------------------------- AGG_INLINE unsigned width() const { return m_rbuf->width(); } AGG_INLINE unsigned height() const { return m_rbuf->height(); } AGG_INLINE int stride() const { return m_rbuf->stride(); } //-------------------------------------------------------------------- int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } row_data row(int y) const { return m_rbuf->row(y); } //-------------------------------------------------------------------- AGG_INLINE int8u* pix_ptr(int x, int y) { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); } AGG_INLINE const int8u* pix_ptr(int x, int y) const { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); } // Return pointer to pixel value, forcing row to be allocated. AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len) { return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset)); } // Return pointer to pixel value, or null if row not allocated. AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const { int8u* p = m_rbuf->row_ptr(y); return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step + pix_offset)) : 0; } // Get pixel pointer from raw buffer pointer. AGG_INLINE static pixel_type* pix_value_ptr(void* p) { return (pixel_type*)((value_type*)p + pix_offset); } // Get pixel pointer from raw buffer pointer. AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) { return (const pixel_type*)((const value_type*)p + pix_offset); } //-------------------------------------------------------------------- AGG_INLINE static void write_plain_color(void* p, color_type c) { // Grayscale formats are implicitly premultiplied. c.premultiply(); pix_value_ptr(p)->set(c); } //-------------------------------------------------------------------- AGG_INLINE static color_type read_plain_color(const void* p) { return pix_value_ptr(p)->get(); } //-------------------------------------------------------------------- AGG_INLINE static void make_pix(int8u* p, const color_type& c) { ((pixel_type*)p)->set(c); } //-------------------------------------------------------------------- AGG_INLINE color_type pixel(int x, int y) const { if (const pixel_type* p = pix_value_ptr(x, y)) { return p->get(); } return color_type::no_color(); } //-------------------------------------------------------------------- AGG_INLINE void copy_pixel(int x, int y, const color_type& c) { pix_value_ptr(x, y, 1)->set(c); } //-------------------------------------------------------------------- AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) { copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover); } //-------------------------------------------------------------------- AGG_INLINE void copy_hline(int x, int y, unsigned len, const color_type& c) { pixel_type* p = pix_value_ptr(x, y, len); do { p->set(c); p = p->next(); } while(--len); } //-------------------------------------------------------------------- AGG_INLINE void copy_vline(int x, int y, unsigned len, const color_type& c) { do { pix_value_ptr(x, y++, 1)->set(c); } while (--len); } //-------------------------------------------------------------------- void blend_hline(int x, int y, unsigned len, const color_type& c, int8u cover) { if (!c.is_transparent()) { pixel_type* p = pix_value_ptr(x, y, len); if (c.is_opaque() && cover == cover_mask) { do { p->set(c); p = p->next(); } while (--len); } else { do { blend_pix(p, c, cover); p = p->next(); } while (--len); } } } //-------------------------------------------------------------------- void blend_vline(int x, int y, unsigned len, const color_type& c, int8u cover) { if (!c.is_transparent()) { if (c.is_opaque() && cover == cover_mask) { do { pix_value_ptr(x, y++, 1)->set(c); } while (--len); } else { do { blend_pix(pix_value_ptr(x, y++, 1), c, cover); } while (--len); } } } //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { if (!c.is_transparent()) { pixel_type* p = pix_value_ptr(x, y, len); do { if (c.is_opaque() && *covers == cover_mask) { p->set(c); } else { blend_pix(p, c, *covers); } p = p->next(); ++covers; } while (--len); } } //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { if (!c.is_transparent()) { do { pixel_type* p = pix_value_ptr(x, y++, 1); if (c.is_opaque() && *covers == cover_mask) { p->set(c); } else { blend_pix(p, c, *covers); } ++covers; } while (--len); } } //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, unsigned len, const color_type* colors) { pixel_type* p = pix_value_ptr(x, y, len); do { p->set(*colors++); p = p->next(); } while (--len); } //-------------------------------------------------------------------- void copy_color_vspan(int x, int y, unsigned len, const color_type* colors) { do { pix_value_ptr(x, y++, 1)->set(*colors++); } while (--len); } //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { pixel_type* p = pix_value_ptr(x, y, len); if (covers) { do { copy_or_blend_pix(p, *colors++, *covers++); p = p->next(); } while (--len); } else { if (cover == cover_mask) { do { copy_or_blend_pix(p, *colors++); p = p->next(); } while (--len); } else { do { copy_or_blend_pix(p, *colors++, cover); p = p->next(); } while (--len); } } } //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { if (covers) { do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); } while (--len); } else { if (cover == cover_mask) { do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); } while (--len); } else { do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); } while (--len); } } } //-------------------------------------------------------------------- template void for_each_pixel(Function f) { unsigned y; for (y = 0; y < height(); ++y) { row_data r = m_rbuf->row(y); if (r.ptr) { unsigned len = r.x2 - r.x1 + 1; pixel_type* p = pix_value_ptr(r.x1, y, len); do { f(p->c); p = p->next(); } while (--len); } } } //-------------------------------------------------------------------- template void apply_gamma_dir(const GammaLut& g) { for_each_pixel(apply_gamma_dir_gray(g)); } //-------------------------------------------------------------------- template void apply_gamma_inv(const GammaLut& g) { for_each_pixel(apply_gamma_inv_gray(g)); } //-------------------------------------------------------------------- template void copy_from(const RenBuf2& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len) { if (const int8u* p = from.row_ptr(ysrc)) { std::memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, p + xsrc * pix_width, len * pix_width); } } //-------------------------------------------------------------------- // Blend from single color, using grayscale surface as alpha channel. template void blend_from_color(const SrcPixelFormatRenderer& from, const color_type& color, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; typedef typename SrcPixelFormatRenderer::color_type src_color_type; if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); do { copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); psrc = psrc->next(); pdst = pdst->next(); } while (--len); } } //-------------------------------------------------------------------- // Blend from color table, using grayscale surface as indexes into table. // Obviously, this only works for integer value types. template void blend_from_lut(const SrcPixelFormatRenderer& from, const color_type* color_lut, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); do { copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); psrc = psrc->next(); pdst = pdst->next(); } while (--len); } } private: rbuf_type* m_rbuf; }; typedef blender_gray blender_gray8; typedef blender_gray blender_sgray8; typedef blender_gray blender_gray16; typedef blender_gray blender_gray32; typedef blender_gray_pre blender_gray8_pre; typedef blender_gray_pre blender_sgray8_pre; typedef blender_gray_pre blender_gray16_pre; typedef blender_gray_pre blender_gray32_pre; typedef pixfmt_alpha_blend_gray pixfmt_gray8; typedef pixfmt_alpha_blend_gray pixfmt_sgray8; typedef pixfmt_alpha_blend_gray pixfmt_gray16; typedef pixfmt_alpha_blend_gray pixfmt_gray32; typedef pixfmt_alpha_blend_gray pixfmt_gray8_pre; typedef pixfmt_alpha_blend_gray pixfmt_sgray8_pre; typedef pixfmt_alpha_blend_gray pixfmt_gray16_pre; typedef pixfmt_alpha_blend_gray pixfmt_gray32_pre; } #endif ragg/src/agg/include/agg_span_allocator.h0000644000176200001440000000341113504406270020132 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_SPAN_ALLOCATOR_INCLUDED #define AGG_SPAN_ALLOCATOR_INCLUDED #include "agg_array.h" namespace agg { //----------------------------------------------------------span_allocator template class span_allocator { public: typedef ColorT color_type; //-------------------------------------------------------------------- AGG_INLINE color_type* allocate(unsigned span_len) { if(span_len > m_span.size()) { // To reduce the number of reallocs we align the // span_len to 256 color elements. // Well, I just like this number and it looks reasonable. //----------------------- m_span.resize(((span_len + 255) >> 8) << 8); } return &m_span[0]; } AGG_INLINE color_type* span() { return &m_span[0]; } AGG_INLINE unsigned max_span_len() const { return m_span.size(); } private: pod_array m_span; }; } #endif ragg/src/agg/include/agg_span_gouraud_gray.h0000644000176200001440000002020213504406270020637 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_SPAN_GOURAUD_GRAY_INCLUDED #define AGG_SPAN_GOURAUD_GRAY_INCLUDED #include #include #include "agg_basics.h" #include "agg_color_gray.h" #include "agg_dda_line.h" #include "agg_span_gouraud.h" namespace agg { //=======================================================span_gouraud_gray template class span_gouraud_gray : public span_gouraud { public: typedef ColorT color_type; typedef typename color_type::value_type value_type; typedef span_gouraud base_type; typedef typename base_type::coord_type coord_type; enum subpixel_scale_e { subpixel_shift = 4, subpixel_scale = 1 << subpixel_shift }; private: //-------------------------------------------------------------------- struct gray_calc { void init(const coord_type& c1, const coord_type& c2) { m_x1 = c1.x - 0.5; m_y1 = c1.y - 0.5; m_dx = c2.x - c1.x; double dy = c2.y - c1.y; m_1dy = (std::fabs(dy) < 1e-10) ? 1e10 : 1.0 / dy; m_v1 = c1.color.v; m_a1 = c1.color.a; m_dv = c2.color.v - m_v1; m_da = c2.color.a - m_a1; } void calc(double y) { double k = (y - m_y1) * m_1dy; if(k < 0.0) k = 0.0; if(k > 1.0) k = 1.0; m_v = m_v1 + iround(m_dv * k); m_a = m_a1 + iround(m_da * k); m_x = iround((m_x1 + m_dx * k) * subpixel_scale); } double m_x1; double m_y1; double m_dx; double m_1dy; int m_v1; int m_a1; int m_dv; int m_da; int m_v; int m_a; int m_x; }; public: //-------------------------------------------------------------------- span_gouraud_gray() {} span_gouraud_gray(const color_type& c1, const color_type& c2, const color_type& c3, double x1, double y1, double x2, double y2, double x3, double y3, double d = 0) : base_type(c1, c2, c3, x1, y1, x2, y2, x3, y3, d) {} //-------------------------------------------------------------------- void prepare() { coord_type coord[3]; base_type::arrange_vertices(coord); m_y2 = int(coord[1].y); m_swap = cross_product(coord[0].x, coord[0].y, coord[2].x, coord[2].y, coord[1].x, coord[1].y) < 0.0; m_c1.init(coord[0], coord[2]); m_c2.init(coord[0], coord[1]); m_c3.init(coord[1], coord[2]); } //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { m_c1.calc(y); const gray_calc* pc1 = &m_c1; const gray_calc* pc2 = &m_c2; if(y < m_y2) { // Bottom part of the triangle (first subtriangle) //------------------------- m_c2.calc(y + m_c2.m_1dy); } else { // Upper part (second subtriangle) //------------------------- m_c3.calc(y - m_c3.m_1dy); pc2 = &m_c3; } if(m_swap) { // It means that the triangle is oriented clockwise, // so that we need to swap the controlling structures //------------------------- const gray_calc* t = pc2; pc2 = pc1; pc1 = t; } // Get the horizontal length with subpixel accuracy // and protect it from division by zero //------------------------- int nlen = std::abs(pc2->m_x - pc1->m_x); if(nlen <= 0) nlen = 1; dda_line_interpolator<14> v(pc1->m_v, pc2->m_v, nlen); dda_line_interpolator<14> a(pc1->m_a, pc2->m_a, nlen); // Calculate the starting point of the gradient with subpixel // accuracy and correct (roll back) the interpolators. // This operation will also clip the beginning of the span // if necessary. //------------------------- int start = pc1->m_x - (x << subpixel_shift); v -= start; a -= start; nlen += start; int vv, va; enum lim_e { lim = color_type::base_mask }; // Beginning part of the span. Since we rolled back the // interpolators, the color values may have overflow. // So that, we render the beginning part with checking // for overflow. It lasts until "start" is positive; // typically it's 1-2 pixels, but may be more in some cases. //------------------------- while(len && start > 0) { vv = v.y(); va = a.y(); if(vv < 0) vv = 0; if(vv > lim) vv = lim; if(va < 0) va = 0; if(va > lim) va = lim; span->v = (value_type)vv; span->a = (value_type)va; v += subpixel_scale; a += subpixel_scale; nlen -= subpixel_scale; start -= subpixel_scale; ++span; --len; } // Middle part, no checking for overflow. // Actual spans can be longer than the calculated length // because of anti-aliasing, thus, the interpolators can // overflow. But while "nlen" is positive we are safe. //------------------------- while(len && nlen > 0) { span->v = (value_type)v.y(); span->a = (value_type)a.y(); v += subpixel_scale; a += subpixel_scale; nlen -= subpixel_scale; ++span; --len; } // Ending part; checking for overflow. // Typically it's 1-2 pixels, but may be more in some cases. //------------------------- while(len) { vv = v.y(); va = a.y(); if(vv < 0) vv = 0; if(vv > lim) vv = lim; if(va < 0) va = 0; if(va > lim) va = lim; span->v = (value_type)vv; span->a = (value_type)va; v += subpixel_scale; a += subpixel_scale; ++span; --len; } } private: bool m_swap; int m_y2; gray_calc m_c1; gray_calc m_c2; gray_calc m_c3; }; } #endif ragg/src/agg/include/agg_conv_curve.h0000644000176200001440000001503213504406270017304 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // classes conv_curve // //---------------------------------------------------------------------------- #ifndef AGG_CONV_CURVE_INCLUDED #define AGG_CONV_CURVE_INCLUDED #include "agg_basics.h" #include "agg_curves.h" namespace agg { //---------------------------------------------------------------conv_curve // Curve converter class. Any path storage can have Bezier curves defined // by their control points. There're two types of curves supported: curve3 // and curve4. Curve3 is a conic Bezier curve with 2 endpoints and 1 control // point. Curve4 has 2 control points (4 points in total) and can be used // to interpolate more complicated curves. Curve4, unlike curve3 can be used // to approximate arcs, both circular and elliptical. Curves are approximated // with straight lines and one of the approaches is just to store the whole // sequence of vertices that approximate our curve. It takes additional // memory, and at the same time the consecutive vertices can be calculated // on demand. // // Initially, path storages are not suppose to keep all the vertices of the // curves (although, nothing prevents us from doing so). Instead, path_storage // keeps only vertices, needed to calculate a curve on demand. Those vertices // are marked with special commands. So, if the path_storage contains curves // (which are not real curves yet), and we render this storage directly, // all we will see is only 2 or 3 straight line segments (for curve3 and // curve4 respectively). If we need to see real curves drawn we need to // include this class into the conversion pipeline. // // Class conv_curve recognizes commands path_cmd_curve3 and path_cmd_curve4 // and converts these vertices into a move_to/line_to sequence. //----------------------------------------------------------------------- template class conv_curve { public: typedef Curve3 curve3_type; typedef Curve4 curve4_type; typedef conv_curve self_type; explicit conv_curve(VertexSource& source) : m_source(&source), m_last_x(0.0), m_last_y(0.0) {} void attach(VertexSource& source) { m_source = &source; } void approximation_method(curve_approximation_method_e v) { m_curve3.approximation_method(v); m_curve4.approximation_method(v); } curve_approximation_method_e approximation_method() const { return m_curve4.approximation_method(); } void approximation_scale(double s) { m_curve3.approximation_scale(s); m_curve4.approximation_scale(s); } double approximation_scale() const { return m_curve4.approximation_scale(); } void angle_tolerance(double v) { m_curve3.angle_tolerance(v); m_curve4.angle_tolerance(v); } double angle_tolerance() const { return m_curve4.angle_tolerance(); } void cusp_limit(double v) { m_curve3.cusp_limit(v); m_curve4.cusp_limit(v); } double cusp_limit() const { return m_curve4.cusp_limit(); } void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: conv_curve(const self_type&); const self_type& operator = (const self_type&); VertexSource* m_source; double m_last_x; double m_last_y; curve3_type m_curve3; curve4_type m_curve4; }; //------------------------------------------------------------------------ template void conv_curve::rewind(unsigned path_id) { m_source->rewind(path_id); m_last_x = 0.0; m_last_y = 0.0; m_curve3.reset(); m_curve4.reset(); } //------------------------------------------------------------------------ template unsigned conv_curve::vertex(double* x, double* y) { if(!is_stop(m_curve3.vertex(x, y))) { m_last_x = *x; m_last_y = *y; return path_cmd_line_to; } if(!is_stop(m_curve4.vertex(x, y))) { m_last_x = *x; m_last_y = *y; return path_cmd_line_to; } double ct2_x = 0; double ct2_y = 0; double end_x = 0; double end_y = 0; unsigned cmd = m_source->vertex(x, y); switch(cmd) { case path_cmd_curve3: m_source->vertex(&end_x, &end_y); m_curve3.init(m_last_x, m_last_y, *x, *y, end_x, end_y); m_curve3.vertex(x, y); // First call returns path_cmd_move_to m_curve3.vertex(x, y); // This is the first vertex of the curve cmd = path_cmd_line_to; break; case path_cmd_curve4: m_source->vertex(&ct2_x, &ct2_y); m_source->vertex(&end_x, &end_y); m_curve4.init(m_last_x, m_last_y, *x, *y, ct2_x, ct2_y, end_x, end_y); m_curve4.vertex(x, y); // First call returns path_cmd_move_to m_curve4.vertex(x, y); // This is the first vertex of the curve cmd = path_cmd_line_to; break; } m_last_x = *x; m_last_y = *y; return cmd; } } #endif ragg/src/agg/include/agg_span_interpolator_linear.h0000644000176200001440000001661013504406270022233 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_SPAN_INTERPOLATOR_LINEAR_INCLUDED #define AGG_SPAN_INTERPOLATOR_LINEAR_INCLUDED #include "agg_basics.h" #include "agg_dda_line.h" #include "agg_trans_affine.h" namespace agg { //================================================span_interpolator_linear template class span_interpolator_linear { public: typedef Transformer trans_type; enum subpixel_scale_e { subpixel_shift = SubpixelShift, subpixel_scale = 1 << subpixel_shift }; //-------------------------------------------------------------------- span_interpolator_linear() {} span_interpolator_linear(trans_type& trans) : m_trans(&trans) {} span_interpolator_linear(trans_type& trans, double x, double y, unsigned len) : m_trans(&trans) { begin(x, y, len); } //---------------------------------------------------------------- const trans_type& transformer() const { return *m_trans; } void transformer(trans_type& trans) { m_trans = &trans; } //---------------------------------------------------------------- void begin(double x, double y, unsigned len) { double tx; double ty; tx = x; ty = y; m_trans->transform(&tx, &ty); int x1 = iround(tx * subpixel_scale); int y1 = iround(ty * subpixel_scale); tx = x + len; ty = y; m_trans->transform(&tx, &ty); int x2 = iround(tx * subpixel_scale); int y2 = iround(ty * subpixel_scale); m_li_x = dda2_line_interpolator(x1, x2, len); m_li_y = dda2_line_interpolator(y1, y2, len); } //---------------------------------------------------------------- void resynchronize(double xe, double ye, unsigned len) { m_trans->transform(&xe, &ye); m_li_x = dda2_line_interpolator(m_li_x.y(), iround(xe * subpixel_scale), len); m_li_y = dda2_line_interpolator(m_li_y.y(), iround(ye * subpixel_scale), len); } //---------------------------------------------------------------- void operator++() { ++m_li_x; ++m_li_y; } //---------------------------------------------------------------- void coordinates(int* x, int* y) const { *x = m_li_x.y(); *y = m_li_y.y(); } private: trans_type* m_trans; dda2_line_interpolator m_li_x; dda2_line_interpolator m_li_y; }; //=====================================span_interpolator_linear_subdiv template class span_interpolator_linear_subdiv { public: typedef Transformer trans_type; enum subpixel_scale_e { subpixel_shift = SubpixelShift, subpixel_scale = 1 << subpixel_shift }; //---------------------------------------------------------------- span_interpolator_linear_subdiv() : m_subdiv_shift(4), m_subdiv_size(1 << m_subdiv_shift), m_subdiv_mask(m_subdiv_size - 1) {} span_interpolator_linear_subdiv(trans_type& trans, unsigned subdiv_shift = 4) : m_subdiv_shift(subdiv_shift), m_subdiv_size(1 << m_subdiv_shift), m_subdiv_mask(m_subdiv_size - 1), m_trans(&trans) {} span_interpolator_linear_subdiv(trans_type& trans, double x, double y, unsigned len, unsigned subdiv_shift = 4) : m_subdiv_shift(subdiv_shift), m_subdiv_size(1 << m_subdiv_shift), m_subdiv_mask(m_subdiv_size - 1), m_trans(&trans) { begin(x, y, len); } //---------------------------------------------------------------- const trans_type& transformer() const { return *m_trans; } void transformer(const trans_type& trans) { m_trans = &trans; } //---------------------------------------------------------------- unsigned subdiv_shift() const { return m_subdiv_shift; } void subdiv_shift(unsigned shift) { m_subdiv_shift = shift; m_subdiv_size = 1 << m_subdiv_shift; m_subdiv_mask = m_subdiv_size - 1; } //---------------------------------------------------------------- void begin(double x, double y, unsigned len) { double tx; double ty; m_pos = 1; m_src_x = iround(x * subpixel_scale) + subpixel_scale; m_src_y = y; m_len = len; if(len > m_subdiv_size) len = m_subdiv_size; tx = x; ty = y; m_trans->transform(&tx, &ty); int x1 = iround(tx * subpixel_scale); int y1 = iround(ty * subpixel_scale); tx = x + len; ty = y; m_trans->transform(&tx, &ty); m_li_x = dda2_line_interpolator(x1, iround(tx * subpixel_scale), len); m_li_y = dda2_line_interpolator(y1, iround(ty * subpixel_scale), len); } //---------------------------------------------------------------- void operator++() { ++m_li_x; ++m_li_y; if(m_pos >= m_subdiv_size) { unsigned len = m_len; if(len > m_subdiv_size) len = m_subdiv_size; double tx = double(m_src_x) / double(subpixel_scale) + len; double ty = m_src_y; m_trans->transform(&tx, &ty); m_li_x = dda2_line_interpolator(m_li_x.y(), iround(tx * subpixel_scale), len); m_li_y = dda2_line_interpolator(m_li_y.y(), iround(ty * subpixel_scale), len); m_pos = 0; } m_src_x += subpixel_scale; ++m_pos; --m_len; } //---------------------------------------------------------------- void coordinates(int* x, int* y) const { *x = m_li_x.y(); *y = m_li_y.y(); } private: unsigned m_subdiv_shift; unsigned m_subdiv_size; unsigned m_subdiv_mask; trans_type* m_trans; dda2_line_interpolator m_li_x; dda2_line_interpolator m_li_y; int m_src_x; double m_src_y; unsigned m_pos; unsigned m_len; }; } #endif ragg/src/agg/include/agg_vcgen_stroke.h0000644000176200001440000000677413504406270017641 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_VCGEN_STROKE_INCLUDED #define AGG_VCGEN_STROKE_INCLUDED #include "agg_math_stroke.h" namespace agg { //============================================================vcgen_stroke // // See Implementation agg_vcgen_stroke.cpp // Stroke generator // //------------------------------------------------------------------------ class vcgen_stroke { enum status_e { initial, ready, cap1, cap2, outline1, close_first, outline2, out_vertices, end_poly1, end_poly2, stop }; public: typedef vertex_sequence vertex_storage; typedef pod_bvector coord_storage; vcgen_stroke(); void line_cap(line_cap_e lc) { m_stroker.line_cap(lc); } void line_join(line_join_e lj) { m_stroker.line_join(lj); } void inner_join(inner_join_e ij) { m_stroker.inner_join(ij); } line_cap_e line_cap() const { return m_stroker.line_cap(); } line_join_e line_join() const { return m_stroker.line_join(); } inner_join_e inner_join() const { return m_stroker.inner_join(); } void width(double w) { m_stroker.width(w); } void miter_limit(double ml) { m_stroker.miter_limit(ml); } void miter_limit_theta(double t) { m_stroker.miter_limit_theta(t); } void inner_miter_limit(double ml) { m_stroker.inner_miter_limit(ml); } void approximation_scale(double as) { m_stroker.approximation_scale(as); } double width() const { return m_stroker.width(); } double miter_limit() const { return m_stroker.miter_limit(); } double inner_miter_limit() const { return m_stroker.inner_miter_limit(); } double approximation_scale() const { return m_stroker.approximation_scale(); } void shorten(double s) { m_shorten = s; } double shorten() const { return m_shorten; } // Vertex Generator Interface void remove_all(); void add_vertex(double x, double y, unsigned cmd); // Vertex Source Interface void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: vcgen_stroke(const vcgen_stroke&); const vcgen_stroke& operator = (const vcgen_stroke&); math_stroke m_stroker; vertex_storage m_src_vertices; coord_storage m_out_vertices; double m_shorten; unsigned m_closed; status_e m_status; status_e m_prev_status; unsigned m_src_vertex; unsigned m_out_vertex; }; } #endif ragg/src/agg/include/agg_config.h0000644000176200001440000000236213504406270016402 0ustar liggesusers#ifndef AGG_CONFIG_INCLUDED #define AGG_CONFIG_INCLUDED // This file can be used to redefine certain data types. //--------------------------------------- // 1. Default basic types such as: // // AGG_INT8 // AGG_INT8U // AGG_INT16 // AGG_INT16U // AGG_INT32 // AGG_INT32U // AGG_INT64 // AGG_INT64U // // Just replace this file with new defines if necessary. // For example, if your compiler doesn't have a 64 bit integer type // you can still use AGG if you define the follows: // // #define AGG_INT64 int // #define AGG_INT64U unsigned // // It will result in overflow in 16 bit-per-component image/pattern resampling // but it won't result any crash and the rest of the library will remain // fully functional. //--------------------------------------- // 2. Default rendering_buffer type. Can be: // // Provides faster access for massive pixel operations, // such as blur, image filtering: // #define AGG_RENDERING_BUFFER row_ptr_cache // // Provides cheaper creation and destruction (no mem allocs): // #define AGG_RENDERING_BUFFER row_accessor // // You can still use both of them simultaneously in your applications // This #define is used only for default rendering_buffer type, // in short hand typedefs like pixfmt_rgba32. #endif ragg/src/agg/include/agg_line_aa_basics.h0000644000176200001440000001515413504406270020054 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_LINE_AA_BASICS_INCLUDED #define AGG_LINE_AA_BASICS_INCLUDED #include #include "agg_basics.h" namespace agg { // See Implementation agg_line_aa_basics.cpp //------------------------------------------------------------------------- enum line_subpixel_scale_e { line_subpixel_shift = 8, //----line_subpixel_shift line_subpixel_scale = 1 << line_subpixel_shift, //----line_subpixel_scale line_subpixel_mask = line_subpixel_scale - 1, //----line_subpixel_mask line_max_coord = (1 << 28) - 1, //----line_max_coord line_max_length = 1 << (line_subpixel_shift + 10) //----line_max_length }; //------------------------------------------------------------------------- enum line_mr_subpixel_scale_e { line_mr_subpixel_shift = 4, //----line_mr_subpixel_shift line_mr_subpixel_scale = 1 << line_mr_subpixel_shift, //----line_mr_subpixel_scale line_mr_subpixel_mask = line_mr_subpixel_scale - 1 //----line_mr_subpixel_mask }; //------------------------------------------------------------------line_mr AGG_INLINE int line_mr(int x) { return x >> (line_subpixel_shift - line_mr_subpixel_shift); } //-------------------------------------------------------------------line_hr AGG_INLINE int line_hr(int x) { return x << (line_subpixel_shift - line_mr_subpixel_shift); } //---------------------------------------------------------------line_dbl_hr AGG_INLINE int line_dbl_hr(int x) { return x << line_subpixel_shift; } //---------------------------------------------------------------line_coord struct line_coord { AGG_INLINE static int conv(double x) { return iround(x * line_subpixel_scale); } }; //-----------------------------------------------------------line_coord_sat struct line_coord_sat { AGG_INLINE static int conv(double x) { return saturation::iround(x * line_subpixel_scale); } }; //==========================================================line_parameters struct line_parameters { //--------------------------------------------------------------------- line_parameters() {} line_parameters(int x1_, int y1_, int x2_, int y2_, int len_) : x1(x1_), y1(y1_), x2(x2_), y2(y2_), dx(std::abs(x2_ - x1_)), dy(std::abs(y2_ - y1_)), sx((x2_ > x1_) ? 1 : -1), sy((y2_ > y1_) ? 1 : -1), vertical(dy >= dx), inc(vertical ? sy : sx), len(len_), octant((sy & 4) | (sx & 2) | int(vertical)) { } //--------------------------------------------------------------------- unsigned orthogonal_quadrant() const { return s_orthogonal_quadrant[octant]; } unsigned diagonal_quadrant() const { return s_diagonal_quadrant[octant]; } //--------------------------------------------------------------------- bool same_orthogonal_quadrant(const line_parameters& lp) const { return s_orthogonal_quadrant[octant] == s_orthogonal_quadrant[lp.octant]; } //--------------------------------------------------------------------- bool same_diagonal_quadrant(const line_parameters& lp) const { return s_diagonal_quadrant[octant] == s_diagonal_quadrant[lp.octant]; } //--------------------------------------------------------------------- void divide(line_parameters& lp1, line_parameters& lp2) const { int xmid = (x1 + x2) >> 1; int ymid = (y1 + y2) >> 1; int len2 = len >> 1; lp1 = *this; lp2 = *this; lp1.x2 = xmid; lp1.y2 = ymid; lp1.len = len2; lp1.dx = std::abs(lp1.x2 - lp1.x1); lp1.dy = std::abs(lp1.y2 - lp1.y1); lp2.x1 = xmid; lp2.y1 = ymid; lp2.len = len2; lp2.dx = std::abs(lp2.x2 - lp2.x1); lp2.dy = std::abs(lp2.y2 - lp2.y1); } //--------------------------------------------------------------------- int x1, y1, x2, y2, dx, dy, sx, sy; bool vertical; int inc; int len; int octant; //--------------------------------------------------------------------- static const int8u s_orthogonal_quadrant[8]; static const int8u s_diagonal_quadrant[8]; }; // See Implementation agg_line_aa_basics.cpp //----------------------------------------------------------------bisectrix void bisectrix(const line_parameters& l1, const line_parameters& l2, int* x, int* y); //-------------------------------------------fix_degenerate_bisectrix_start void inline fix_degenerate_bisectrix_start(const line_parameters& lp, int* x, int* y) { int d = iround((double(*x - lp.x2) * double(lp.y2 - lp.y1) - double(*y - lp.y2) * double(lp.x2 - lp.x1)) / lp.len); if(d < line_subpixel_scale/2) { *x = lp.x1 + (lp.y2 - lp.y1); *y = lp.y1 - (lp.x2 - lp.x1); } } //---------------------------------------------fix_degenerate_bisectrix_end void inline fix_degenerate_bisectrix_end(const line_parameters& lp, int* x, int* y) { int d = iround((double(*x - lp.x2) * double(lp.y2 - lp.y1) - double(*y - lp.y2) * double(lp.x2 - lp.x1)) / lp.len); if(d < line_subpixel_scale/2) { *x = lp.x2 + (lp.y2 - lp.y1); *y = lp.y2 - (lp.x2 - lp.x1); } } } #endif ragg/src/agg/include/agg_scanline_storage_bin.h0000644000176200001440000004426613504406270021316 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // 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_SCANLINE_STORAGE_BIN_INCLUDED #define AGG_SCANLINE_STORAGE_BIN_INCLUDED #include #include #include "agg_array.h" namespace agg { //-----------------------------------------------scanline_storage_bin class scanline_storage_bin { public: //--------------------------------------------------------------- struct span_data { int32 x; int32 len; }; //--------------------------------------------------------------- struct scanline_data { int y; unsigned num_spans; unsigned start_span; }; //--------------------------------------------------------------- class embedded_scanline { public: //----------------------------------------------------------- class const_iterator { public: const_iterator() : m_storage(0) {} const_iterator(const embedded_scanline* sl) : m_storage(sl->m_storage), m_span_idx(sl->m_scanline.start_span) { m_span = m_storage->span_by_index(m_span_idx); } const span_data& operator*() const { return m_span; } const span_data* operator->() const { return &m_span; } void operator ++ () { ++m_span_idx; m_span = m_storage->span_by_index(m_span_idx); } private: const scanline_storage_bin* m_storage; unsigned m_span_idx; span_data m_span; }; friend class const_iterator; //----------------------------------------------------------- embedded_scanline(scanline_storage_bin& storage) : m_storage(&storage) { setup(0); } //----------------------------------------------------------- void reset(int, int) {} unsigned num_spans() const { return m_scanline.num_spans; } int y() const { return m_scanline.y; } const_iterator begin() const { return const_iterator(this); } //----------------------------------------------------------- void setup(unsigned scanline_idx) { m_scanline_idx = scanline_idx; m_scanline = m_storage->scanline_by_index(m_scanline_idx); } private: scanline_storage_bin* m_storage; scanline_data m_scanline; unsigned m_scanline_idx; }; //--------------------------------------------------------------- scanline_storage_bin() : m_spans(256-2), // Block increment size m_scanlines(), m_min_x(std::numeric_limits::max()), m_min_y(std::numeric_limits::max()), m_max_x(std::numeric_limits::min()), m_max_y(std::numeric_limits::min()), m_cur_scanline(0) { m_fake_scanline.y = 0; m_fake_scanline.num_spans = 0; m_fake_scanline.start_span = 0; m_fake_span.x = 0; m_fake_span.len = 0; } // Renderer Interface //--------------------------------------------------------------- void prepare() { m_scanlines.remove_all(); m_spans.remove_all(); m_min_x = std::numeric_limits::max(); m_min_y = std::numeric_limits::max(); m_max_x = std::numeric_limits::min(); m_max_y = std::numeric_limits::min(); m_cur_scanline = 0; } //--------------------------------------------------------------- template void render(const Scanline& sl) { scanline_data sl_this; int y = sl.y(); if(y < m_min_y) m_min_y = y; if(y > m_max_y) m_max_y = y; sl_this.y = y; sl_this.num_spans = sl.num_spans(); sl_this.start_span = m_spans.size(); typename Scanline::const_iterator span_iterator = sl.begin(); unsigned num_spans = sl_this.num_spans; for(;;) { span_data sp; sp.x = span_iterator->x; sp.len = (int32)std::abs((int)(span_iterator->len)); m_spans.add(sp); int x1 = sp.x; int x2 = sp.x + sp.len - 1; if(x1 < m_min_x) m_min_x = x1; if(x2 > m_max_x) m_max_x = x2; if(--num_spans == 0) break; ++span_iterator; } m_scanlines.add(sl_this); } //--------------------------------------------------------------- // Iterate scanlines interface 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; } //--------------------------------------------------------------- bool rewind_scanlines() { m_cur_scanline = 0; return m_scanlines.size() > 0; } //--------------------------------------------------------------- template bool sweep_scanline(Scanline& sl) { sl.reset_spans(); for(;;) { if(m_cur_scanline >= m_scanlines.size()) return false; const scanline_data& sl_this = m_scanlines[m_cur_scanline]; unsigned num_spans = sl_this.num_spans; unsigned span_idx = sl_this.start_span; do { const span_data& sp = m_spans[span_idx++]; sl.add_span(sp.x, sp.len, cover_full); } while(--num_spans); ++m_cur_scanline; if(sl.num_spans()) { sl.finalize(sl_this.y); break; } } return true; } //--------------------------------------------------------------- // Specialization for embedded_scanline bool sweep_scanline(embedded_scanline& sl) { do { if(m_cur_scanline >= m_scanlines.size()) return false; sl.setup(m_cur_scanline); ++m_cur_scanline; } while(sl.num_spans() == 0); return true; } //--------------------------------------------------------------- unsigned byte_size() const { unsigned i; unsigned size = sizeof(int32) * 4; // min_x, min_y, max_x, max_y for(i = 0; i < m_scanlines.size(); ++i) { size += sizeof(int32) * 2 + // Y, num_spans unsigned(m_scanlines[i].num_spans) * sizeof(int32) * 2; // X, span_len } return size; } //--------------------------------------------------------------- static void write_int32(int8u* dst, int32 val) { dst[0] = ((const int8u*)&val)[0]; dst[1] = ((const int8u*)&val)[1]; dst[2] = ((const int8u*)&val)[2]; dst[3] = ((const int8u*)&val)[3]; } //--------------------------------------------------------------- void serialize(int8u* data) const { unsigned i; write_int32(data, min_x()); // min_x data += sizeof(int32); write_int32(data, min_y()); // min_y data += sizeof(int32); write_int32(data, max_x()); // max_x data += sizeof(int32); write_int32(data, max_y()); // max_y data += sizeof(int32); for(i = 0; i < m_scanlines.size(); ++i) { const scanline_data& sl_this = m_scanlines[i]; write_int32(data, sl_this.y); // Y data += sizeof(int32); write_int32(data, sl_this.num_spans); // num_spans data += sizeof(int32); unsigned num_spans = sl_this.num_spans; unsigned span_idx = sl_this.start_span; do { const span_data& sp = m_spans[span_idx++]; write_int32(data, sp.x); // X data += sizeof(int32); write_int32(data, sp.len); // len data += sizeof(int32); } while(--num_spans); } } //--------------------------------------------------------------- const scanline_data& scanline_by_index(unsigned i) const { return (i < m_scanlines.size()) ? m_scanlines[i] : m_fake_scanline; } //--------------------------------------------------------------- const span_data& span_by_index(unsigned i) const { return (i < m_spans.size()) ? m_spans[i] : m_fake_span; } private: pod_bvector m_spans; pod_bvector m_scanlines; span_data m_fake_span; scanline_data m_fake_scanline; int m_min_x; int m_min_y; int m_max_x; int m_max_y; unsigned m_cur_scanline; }; //---------------------------------------serialized_scanlines_adaptor_bin class serialized_scanlines_adaptor_bin { public: typedef bool cover_type; //-------------------------------------------------------------------- class embedded_scanline { public: //---------------------------------------------------------------- class const_iterator { public: struct span { int32 x; int32 len; }; const_iterator() : m_ptr(0) {} const_iterator(const embedded_scanline* sl) : m_ptr(sl->m_ptr), m_dx(sl->m_dx) { m_span.x = read_int32() + m_dx; m_span.len = read_int32(); } const span& operator*() const { return m_span; } const span* operator->() const { return &m_span; } void operator ++ () { m_span.x = read_int32() + m_dx; m_span.len = read_int32(); } private: int read_int32() { int32 val; ((int8u*)&val)[0] = *m_ptr++; ((int8u*)&val)[1] = *m_ptr++; ((int8u*)&val)[2] = *m_ptr++; ((int8u*)&val)[3] = *m_ptr++; return val; } const int8u* m_ptr; span m_span; int m_dx; }; friend class const_iterator; //---------------------------------------------------------------- embedded_scanline() : m_ptr(0), m_y(0), m_num_spans(0) {} //---------------------------------------------------------------- void reset(int, int) {} unsigned num_spans() const { return m_num_spans; } int y() const { return m_y; } const_iterator begin() const { return const_iterator(this); } private: //---------------------------------------------------------------- int read_int32() { int32 val; ((int8u*)&val)[0] = *m_ptr++; ((int8u*)&val)[1] = *m_ptr++; ((int8u*)&val)[2] = *m_ptr++; ((int8u*)&val)[3] = *m_ptr++; return val; } public: //---------------------------------------------------------------- void init(const int8u* ptr, int dx, int dy) { m_ptr = ptr; m_y = read_int32() + dy; m_num_spans = unsigned(read_int32()); m_dx = dx; } private: const int8u* m_ptr; int m_y; unsigned m_num_spans; int m_dx; }; public: //-------------------------------------------------------------------- serialized_scanlines_adaptor_bin() : m_data(0), m_end(0), m_ptr(0), m_dx(0), m_dy(0), m_min_x(std::numeric_limits::max()), m_min_y(std::numeric_limits::max()), m_max_x(std::numeric_limits::min()), m_max_y(std::numeric_limits::min()) {} //-------------------------------------------------------------------- serialized_scanlines_adaptor_bin(const int8u* data, unsigned size, double dx, double dy) : m_data(data), m_end(data + size), m_ptr(data), m_dx(iround(dx)), m_dy(iround(dy)), m_min_x(std::numeric_limits::max()), m_min_y(std::numeric_limits::max()), m_max_x(std::numeric_limits::min()), m_max_y(std::numeric_limits::min()) {} //-------------------------------------------------------------------- void init(const int8u* data, unsigned size, double dx, double dy) { m_data = data; m_end = data + size; m_ptr = data; m_dx = iround(dx); m_dy = iround(dy); m_min_x = std::numeric_limits::max(); m_min_y = std::numeric_limits::max(); m_max_x = std::numeric_limits::min(); m_max_y = std::numeric_limits::min(); } private: //-------------------------------------------------------------------- int read_int32() { int32 val; ((int8u*)&val)[0] = *m_ptr++; ((int8u*)&val)[1] = *m_ptr++; ((int8u*)&val)[2] = *m_ptr++; ((int8u*)&val)[3] = *m_ptr++; return val; } public: // Iterate scanlines interface //-------------------------------------------------------------------- bool rewind_scanlines() { m_ptr = m_data; if(m_ptr < m_end) { m_min_x = read_int32() + m_dx; m_min_y = read_int32() + m_dy; m_max_x = read_int32() + m_dx; m_max_y = read_int32() + m_dy; } return m_ptr < m_end; } //-------------------------------------------------------------------- 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; } //-------------------------------------------------------------------- template bool sweep_scanline(Scanline& sl) { sl.reset_spans(); for(;;) { if(m_ptr >= m_end) return false; int y = read_int32() + m_dy; unsigned num_spans = read_int32(); do { int x = read_int32() + m_dx; int len = read_int32(); if(len < 0) len = -len; sl.add_span(x, unsigned(len), cover_full); } while(--num_spans); if(sl.num_spans()) { sl.finalize(y); break; } } return true; } //-------------------------------------------------------------------- // Specialization for embedded_scanline bool sweep_scanline(embedded_scanline& sl) { do { if(m_ptr >= m_end) return false; sl.init(m_ptr, m_dx, m_dy); // Jump to the next scanline //-------------------------- read_int32(); // Y int num_spans = read_int32(); // num_spans m_ptr += num_spans * sizeof(int32) * 2; } while(sl.num_spans() == 0); return true; } private: const int8u* m_data; const int8u* m_end; const int8u* m_ptr; int m_dx; int m_dy; int m_min_x; int m_min_y; int m_max_x; int m_max_y; }; } #endif ragg/src/agg/include/agg_embedded_raster_fonts.h0000644000176200001440000000414313504406270021456 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_EMBEDDED_RASTER_FONTS_INCLUDED #define AGG_EMBEDDED_RASTER_FONTS_INCLUDED #include "agg_basics.h" namespace agg { extern const int8u gse4x6[]; extern const int8u gse4x8[]; extern const int8u gse5x7[]; extern const int8u gse5x9[]; extern const int8u gse6x12[]; extern const int8u gse6x9[]; extern const int8u gse7x11[]; extern const int8u gse7x11_bold[]; extern const int8u gse7x15[]; extern const int8u gse7x15_bold[]; extern const int8u gse8x16[]; extern const int8u gse8x16_bold[]; extern const int8u mcs11_prop[]; extern const int8u mcs11_prop_condensed[]; extern const int8u mcs12_prop[]; extern const int8u mcs13_prop[]; extern const int8u mcs5x10_mono[]; extern const int8u mcs5x11_mono[]; extern const int8u mcs6x10_mono[]; extern const int8u mcs6x11_mono[]; extern const int8u mcs7x12_mono_high[]; extern const int8u mcs7x12_mono_low[]; extern const int8u verdana12[]; extern const int8u verdana12_bold[]; extern const int8u verdana13[]; extern const int8u verdana13_bold[]; extern const int8u verdana14[]; extern const int8u verdana14_bold[]; extern const int8u verdana16[]; extern const int8u verdana16_bold[]; extern const int8u verdana17[]; extern const int8u verdana17_bold[]; extern const int8u verdana18[]; extern const int8u verdana18_bold[]; } #endif ragg/src/agg/include/agg_rasterizer_compound_aa.h0000644000176200001440000005362713504406270021706 0ustar liggesusers//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // 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_COMPOUND_AA_INCLUDED #define AGG_RASTERIZER_COMPOUND_AA_INCLUDED #include #include "agg_rasterizer_cells_aa.h" #include "agg_rasterizer_sl_clip.h" namespace agg { //-----------------------------------------------------------cell_style_aa // A pixel cell. There're no constructors defined and it was done // intentionally in order to avoid extra overhead when allocating an // array of cells. struct cell_style_aa { int x; int y; int cover; int area; int16 left, right; void initial() { x = std::numeric_limits::max(); y = std::numeric_limits::max(); cover = 0; area = 0; left = -1; right = -1; } void style(const cell_style_aa& c) { left = c.left; right = c.right; } int not_equal(int ex, int ey, const cell_style_aa& c) const { return ((unsigned)ex - (unsigned)x) | ((unsigned)ey - (unsigned)y) | ((unsigned)left - (unsigned)c.left) | ((unsigned)right - (unsigned)c.right); } }; //===========================================================layer_order_e enum layer_order_e { layer_unsorted, //------layer_unsorted layer_direct, //------layer_direct layer_inverse //------layer_inverse }; //==================================================rasterizer_compound_aa template class rasterizer_compound_aa { struct style_info { unsigned start_cell; unsigned num_cells; int last_x; }; struct cell_info { int x, area, cover; }; public: typedef Clip clip_type; typedef typename Clip::conv_type conv_type; typedef typename Clip::coord_type coord_type; enum aa_scale_e { aa_shift = 8, aa_scale = 1 << aa_shift, aa_mask = aa_scale - 1, aa_scale2 = aa_scale * 2, aa_mask2 = aa_scale2 - 1 }; //-------------------------------------------------------------------- rasterizer_compound_aa() : m_outline(), m_clipper(), m_filling_rule(fill_non_zero), m_layer_order(layer_direct), m_styles(), // Active Styles m_ast(), // Active Style Table (unique values) m_asm(), // Active Style Mask m_cells(), m_cover_buf(), m_min_style(std::numeric_limits::max()), m_max_style(std::numeric_limits::min()), m_start_x(0), m_start_y(0), m_scan_y(std::numeric_limits::max()), m_sl_start(0), m_sl_len(0) {} //-------------------------------------------------------------------- void reset(); void reset_clipping(); void clip_box(double x1, double y1, double x2, double y2); void filling_rule(filling_rule_e filling_rule); void layer_order(layer_order_e order); //-------------------------------------------------------------------- void styles(int left, int right); void move_to(int x, int y); void line_to(int x, int y); void move_to_d(double x, double y); void line_to_d(double x, double y); void add_vertex(double x, double y, unsigned cmd); void edge(int x1, int y1, int x2, int y2); void edge_d(double x1, double y1, double x2, double y2); //------------------------------------------------------------------- template void add_path(VertexSource& vs, unsigned path_id=0) { double x; double y; unsigned cmd; vs.rewind(path_id); if(m_outline.sorted()) reset(); while(!is_stop(cmd = vs.vertex(&x, &y))) { add_vertex(x, y, cmd); } } //-------------------------------------------------------------------- int min_x() const { return m_outline.min_x(); } int min_y() const { return m_outline.min_y(); } int max_x() const { return m_outline.max_x(); } int max_y() const { return m_outline.max_y(); } int min_style() const { return m_min_style; } int max_style() const { return m_max_style; } //-------------------------------------------------------------------- void sort(); bool rewind_scanlines(); unsigned sweep_styles(); int scanline_start() const { return m_sl_start; } unsigned scanline_length() const { return m_sl_len; } unsigned style(unsigned style_idx) const; cover_type* allocate_cover_buffer(unsigned len); //-------------------------------------------------------------------- bool navigate_scanline(int y); bool hit_test(int tx, int ty); //-------------------------------------------------------------------- AGG_INLINE unsigned calculate_alpha(int area) const { int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift); if(cover < 0) cover = -cover; if(m_filling_rule == fill_even_odd) { cover &= aa_mask2; if(cover > aa_scale) { cover = aa_scale2 - cover; } } if(cover > aa_mask) cover = aa_mask; return cover; } //-------------------------------------------------------------------- // Sweeps one scanline with one style index. The style ID can be // determined by calling style(). template bool sweep_scanline(Scanline& sl, int style_idx) { int scan_y = m_scan_y - 1; if(scan_y > m_outline.max_y()) return false; sl.reset_spans(); if(style_idx < 0) { style_idx = 0; } else { style_idx++; } const style_info& st = m_styles[m_ast[style_idx]]; unsigned num_cells = st.num_cells; cell_info* cell = &m_cells[st.start_cell]; int cover = 0; while(num_cells--) { unsigned alpha; int x = cell->x; int area = cell->area; cover += cell->cover; ++cell; if(area) { alpha = calculate_alpha((cover << (poly_subpixel_shift + 1)) - area); sl.add_cell(x, alpha); x++; } if(num_cells && cell->x > x) { alpha = calculate_alpha(cover << (poly_subpixel_shift + 1)); if(alpha) { sl.add_span(x, cell->x - x, alpha); } } } if(sl.num_spans() == 0) return false; sl.finalize(scan_y); return true; } private: void add_style(int style_id); //-------------------------------------------------------------------- // Disable copying rasterizer_compound_aa(const rasterizer_compound_aa&); const rasterizer_compound_aa& operator = (const rasterizer_compound_aa&); private: rasterizer_cells_aa m_outline; clip_type m_clipper; filling_rule_e m_filling_rule; layer_order_e m_layer_order; pod_vector m_styles; // Active Styles pod_vector m_ast; // Active Style Table (unique values) pod_vector m_asm; // Active Style Mask pod_vector m_cells; pod_vector m_cover_buf; int m_min_style; int m_max_style; coord_type m_start_x; coord_type m_start_y; int m_scan_y; int m_sl_start; unsigned m_sl_len; }; //------------------------------------------------------------------------ template void rasterizer_compound_aa::reset() { m_outline.reset(); m_min_style = std::numeric_limits::max(); m_max_style = std::numeric_limits::min(); m_scan_y = std::numeric_limits::max(); m_sl_start = 0; m_sl_len = 0; } //------------------------------------------------------------------------ template void rasterizer_compound_aa::filling_rule(filling_rule_e filling_rule) { m_filling_rule = filling_rule; } //------------------------------------------------------------------------ template void rasterizer_compound_aa::layer_order(layer_order_e order) { m_layer_order = order; } //------------------------------------------------------------------------ template void rasterizer_compound_aa::clip_box(double x1, double y1, double x2, double y2) { reset(); m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), conv_type::upscale(x2), conv_type::upscale(y2)); } //------------------------------------------------------------------------ template void rasterizer_compound_aa::reset_clipping() { reset(); m_clipper.reset_clipping(); } //------------------------------------------------------------------------ template void rasterizer_compound_aa::styles(int left, int right) { cell_style_aa cell; cell.initial(); cell.left = (int16)left; cell.right = (int16)right; m_outline.style(cell); if(left >= 0 && left < m_min_style) m_min_style = left; if(left >= 0 && left > m_max_style) m_max_style = left; if(right >= 0 && right < m_min_style) m_min_style = right; if(right >= 0 && right > m_max_style) m_max_style = right; } //------------------------------------------------------------------------ template void rasterizer_compound_aa::move_to(int x, int y) { if(m_outline.sorted()) reset(); m_clipper.move_to(m_start_x = conv_type::downscale(x), m_start_y = conv_type::downscale(y)); } //------------------------------------------------------------------------ template void rasterizer_compound_aa::line_to(int x, int y) { m_clipper.line_to(m_outline, conv_type::downscale(x), conv_type::downscale(y)); } //------------------------------------------------------------------------ template void rasterizer_compound_aa::move_to_d(double x, double y) { if(m_outline.sorted()) reset(); m_clipper.move_to(m_start_x = conv_type::upscale(x), m_start_y = conv_type::upscale(y)); } //------------------------------------------------------------------------ template void rasterizer_compound_aa::line_to_d(double x, double y) { m_clipper.line_to(m_outline, conv_type::upscale(x), conv_type::upscale(y)); } //------------------------------------------------------------------------ template void rasterizer_compound_aa::add_vertex(double x, double y, unsigned cmd) { if(is_move_to(cmd)) { move_to_d(x, y); } else if(is_vertex(cmd)) { line_to_d(x, y); } else if(is_close(cmd)) { m_clipper.line_to(m_outline, m_start_x, m_start_y); } } //------------------------------------------------------------------------ template void rasterizer_compound_aa::edge(int x1, int y1, int x2, int y2) { if(m_outline.sorted()) reset(); m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1)); m_clipper.line_to(m_outline, conv_type::downscale(x2), conv_type::downscale(y2)); } //------------------------------------------------------------------------ template void rasterizer_compound_aa::edge_d(double x1, double y1, double x2, double y2) { if(m_outline.sorted()) reset(); m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); m_clipper.line_to(m_outline, conv_type::upscale(x2), conv_type::upscale(y2)); } //------------------------------------------------------------------------ template AGG_INLINE void rasterizer_compound_aa::sort() { m_outline.sort_cells(); } //------------------------------------------------------------------------ template AGG_INLINE bool rasterizer_compound_aa::rewind_scanlines() { m_outline.sort_cells(); if(m_outline.total_cells() == 0) { return false; } if(m_max_style < m_min_style) { return false; } m_scan_y = m_outline.min_y(); m_styles.allocate(m_max_style - m_min_style + 2, 128); return true; } //------------------------------------------------------------------------ template AGG_INLINE void rasterizer_compound_aa::add_style(int style_id) { if(style_id < 0) style_id = 0; else style_id -= m_min_style - 1; unsigned nbyte = style_id >> 3; unsigned mask = 1 << (style_id & 7); style_info* style = &m_styles[style_id]; if((m_asm[nbyte] & mask) == 0) { m_ast.add(style_id); m_asm[nbyte] |= mask; style->start_cell = 0; style->num_cells = 0; style->last_x = std::numeric_limits::min(); } ++style->start_cell; } //------------------------------------------------------------------------ // Returns the number of styles template unsigned rasterizer_compound_aa::sweep_styles() { for(;;) { if(m_scan_y > m_outline.max_y()) return 0; unsigned num_cells = m_outline.scanline_num_cells(m_scan_y); const cell_style_aa* const* cells = m_outline.scanline_cells(m_scan_y); unsigned num_styles = m_max_style - m_min_style + 2; const cell_style_aa* curr_cell; unsigned style_id; style_info* style; cell_info* cell; m_cells.allocate(num_cells * 2, 256); // Each cell can have two styles m_ast.capacity(num_styles, 64); m_asm.allocate((num_styles + 7) >> 3, 8); m_asm.zero(); if(num_cells) { // Pre-add zero (for no-fill style, that is, -1). // We need that to ensure that the "-1 style" would go first. m_asm[0] |= 1; m_ast.add(0); style = &m_styles[0]; style->start_cell = 0; style->num_cells = 0; style->last_x = std::numeric_limits::min(); m_sl_start = cells[0]->x; m_sl_len = cells[num_cells-1]->x - m_sl_start + 1; while(num_cells--) { curr_cell = *cells++; add_style(curr_cell->left); add_style(curr_cell->right); } // Convert the Y-histogram into the array of starting indexes unsigned i; unsigned start_cell = 0; for(i = 0; i < m_ast.size(); i++) { style_info& st = m_styles[m_ast[i]]; unsigned v = st.start_cell; st.start_cell = start_cell; start_cell += v; } cells = m_outline.scanline_cells(m_scan_y); num_cells = m_outline.scanline_num_cells(m_scan_y); while(num_cells--) { curr_cell = *cells++; style_id = (curr_cell->left < 0) ? 0 : curr_cell->left - m_min_style + 1; style = &m_styles[style_id]; if(curr_cell->x == style->last_x) { cell = &m_cells[style->start_cell + style->num_cells - 1]; cell->area += curr_cell->area; cell->cover += curr_cell->cover; } else { cell = &m_cells[style->start_cell + style->num_cells]; cell->x = curr_cell->x; cell->area = curr_cell->area; cell->cover = curr_cell->cover; style->last_x = curr_cell->x; style->num_cells++; } style_id = (curr_cell->right < 0) ? 0 : curr_cell->right - m_min_style + 1; style = &m_styles[style_id]; if(curr_cell->x == style->last_x) { cell = &m_cells[style->start_cell + style->num_cells - 1]; cell->area -= curr_cell->area; cell->cover -= curr_cell->cover; } else { cell = &m_cells[style->start_cell + style->num_cells]; cell->x = curr_cell->x; cell->area = -curr_cell->area; cell->cover = -curr_cell->cover; style->last_x = curr_cell->x; style->num_cells++; } } } if(m_ast.size() > 1) break; ++m_scan_y; } ++m_scan_y; if(m_layer_order != layer_unsorted) { range_adaptor > ra(m_ast, 1, m_ast.size() - 1); if(m_layer_order == layer_direct) quick_sort(ra, unsigned_greater); else quick_sort(ra, unsigned_less); } return m_ast.size() - 1; } //------------------------------------------------------------------------ // Returns style ID depending of the existing style index template AGG_INLINE unsigned rasterizer_compound_aa::style(unsigned style_idx) const { return m_ast[style_idx + 1] + m_min_style - 1; } //------------------------------------------------------------------------ template AGG_INLINE bool rasterizer_compound_aa::navigate_scanline(int y) { m_outline.sort_cells(); if(m_outline.total_cells() == 0) { return false; } if(m_max_style < m_min_style) { return false; } if(y < m_outline.min_y() || y > m_outline.max_y()) { return false; } m_scan_y = y; m_styles.allocate(m_max_style - m_min_style + 2, 128); return true; } //------------------------------------------------------------------------ template bool rasterizer_compound_aa::hit_test(int tx, int ty) { if(!navigate_scanline(ty)) { return false; } unsigned num_styles = sweep_styles(); if(num_styles <= 0) { return false; } scanline_hit_test sl(tx); sweep_scanline(sl, -1); return sl.hit(); } //------------------------------------------------------------------------ template cover_type* rasterizer_compound_aa::allocate_cover_buffer(unsigned len) { m_cover_buf.allocate(len, 256); return &m_cover_buf[0]; } } #endif ragg/src/agg/include/agg_rasterizer_scanline_aa.h0000644000176200001440000004040013654030127021637 0ustar liggesusers//---------------------------------------------------------------------------- // 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_SCANLINE_AA_INCLUDED #define AGG_RASTERIZER_SCANLINE_AA_INCLUDED #include "agg_rasterizer_cells_aa.h" #include "agg_rasterizer_sl_clip.h" #include "agg_rasterizer_scanline_aa_nogamma.h" #include "agg_gamma_functions.h" namespace agg { //==================================================rasterizer_scanline_aa // Polygon rasterizer that is used to render filled polygons with // high-quality Anti-Aliasing. Internally, by default, the class uses // integer coordinates in format 24.8, i.e. 24 bits for integer part // and 8 bits for fractional - see poly_subpixel_shift. This class can be // used in the following way: // // 1. filling_rule(filling_rule_e ft) - optional. // // 2. gamma() - optional. // // 3. reset() // // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create // more than one contour, but each contour must consist of at least 3 // vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3); // is the absolute minimum of vertices that define a triangle. // The algorithm does not check either the number of vertices nor // coincidence of their coordinates, but in the worst case it just // won't draw anything. // The orger of the vertices (clockwise or counterclockwise) // is important when using the non-zero filling rule (fill_non_zero). // In this case the vertex order of all the contours must be the same // if you want your intersecting polygons to be without "holes". // You actually can use different vertices order. If the contours do not // intersect each other the order is not important anyway. If they do, // contours with the same vertex order will be rendered without "holes" // while the intersecting contours with different orders will have "holes". // // filling_rule() and gamma() can be called anytime before "sweeping". //------------------------------------------------------------------------ template class rasterizer_scanline_aa { enum status { status_initial, status_move_to, status_line_to, status_closed }; public: typedef Clip clip_type; typedef typename Clip::conv_type conv_type; typedef typename Clip::coord_type coord_type; enum aa_scale_e { aa_shift = 8, aa_scale = 1 << aa_shift, aa_mask = aa_scale - 1, aa_scale2 = aa_scale * 2, aa_mask2 = aa_scale2 - 1 }; //-------------------------------------------------------------------- rasterizer_scanline_aa(unsigned cell_block_limit=1024) : m_outline(cell_block_limit), m_clipper(), m_filling_rule(fill_non_zero), m_auto_close(true), m_start_x(0), m_start_y(0), m_status(status_initial) { int i; for(i = 0; i < aa_scale; i++) m_gamma[i] = i; } //-------------------------------------------------------------------- template rasterizer_scanline_aa(const GammaF& gamma_function, unsigned cell_block_limit) : m_outline(cell_block_limit), m_clipper(m_outline), m_filling_rule(fill_non_zero), m_auto_close(true), m_start_x(0), m_start_y(0), m_status(status_initial) { gamma(gamma_function); } //-------------------------------------------------------------------- void reset(); void reset_clipping(); void clip_box(double x1, double y1, double x2, double y2); void filling_rule(filling_rule_e filling_rule); void auto_close(bool flag) { m_auto_close = flag; } //-------------------------------------------------------------------- template void gamma(const GammaF& gamma_function) { int i; for(i = 0; i < aa_scale; i++) { m_gamma[i] = uround(gamma_function(double(i) / aa_mask) * aa_mask); } } //-------------------------------------------------------------------- unsigned apply_gamma(unsigned cover) const { return m_gamma[cover]; } //-------------------------------------------------------------------- void move_to(int x, int y); void line_to(int x, int y); void move_to_d(double x, double y); void line_to_d(double x, double y); void close_polygon(); void add_vertex(double x, double y, unsigned cmd); void edge(int x1, int y1, int x2, int y2); void edge_d(double x1, double y1, double x2, double y2); //------------------------------------------------------------------- template void add_path(VertexSource& vs, unsigned path_id=0) { double x = 0; double y = 0; unsigned cmd; vs.rewind(path_id); if(m_outline.sorted()) reset(); while(!is_stop(cmd = vs.vertex(&x, &y))) { add_vertex(x, y, cmd); } } //-------------------------------------------------------------------- int min_x() const { return m_outline.min_x(); } int min_y() const { return m_outline.min_y(); } int max_x() const { return m_outline.max_x(); } int max_y() const { return m_outline.max_y(); } //-------------------------------------------------------------------- void sort(); bool rewind_scanlines(); bool navigate_scanline(int y); //-------------------------------------------------------------------- AGG_INLINE unsigned calculate_alpha(int area) const { int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift); if(cover < 0) cover = -cover; if(m_filling_rule == fill_even_odd) { cover &= aa_mask2; if(cover > aa_scale) { cover = aa_scale2 - cover; } } if(cover > aa_mask) cover = aa_mask; return m_gamma[cover]; } //-------------------------------------------------------------------- template bool sweep_scanline(Scanline& sl) { for(;;) { if(m_scan_y > m_outline.max_y()) return false; sl.reset_spans(); unsigned num_cells = m_outline.scanline_num_cells(m_scan_y); const cell_aa* const* cells = m_outline.scanline_cells(m_scan_y); int cover = 0; while(num_cells) { const cell_aa* cur_cell = *cells; int x = cur_cell->x; int area = cur_cell->area; unsigned alpha; cover += cur_cell->cover; //accumulate all cells with the same X while(--num_cells) { cur_cell = *++cells; if(cur_cell->x != x) break; area += cur_cell->area; cover += cur_cell->cover; } if(area) { alpha = calculate_alpha(( ((unsigned int) cover) << (poly_subpixel_shift + 1)) - area); if(alpha) { sl.add_cell(x, alpha); } x++; } if(num_cells && cur_cell->x > x) { alpha = calculate_alpha( ((unsigned int) cover) << (poly_subpixel_shift + 1)); if(alpha) { sl.add_span(x, cur_cell->x - x, alpha); } } } if(sl.num_spans()) break; ++m_scan_y; } sl.finalize(m_scan_y); ++m_scan_y; return true; } //-------------------------------------------------------------------- bool hit_test(int tx, int ty); private: //-------------------------------------------------------------------- // Disable copying rasterizer_scanline_aa(const rasterizer_scanline_aa&); const rasterizer_scanline_aa& operator = (const rasterizer_scanline_aa&); private: rasterizer_cells_aa m_outline; clip_type m_clipper; int m_gamma[aa_scale]; filling_rule_e m_filling_rule; bool m_auto_close; coord_type m_start_x; coord_type m_start_y; unsigned m_status; int m_scan_y; }; //------------------------------------------------------------------------ template void rasterizer_scanline_aa::reset() { m_outline.reset(); m_status = status_initial; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::filling_rule(filling_rule_e filling_rule) { m_filling_rule = filling_rule; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::clip_box(double x1, double y1, double x2, double y2) { reset(); m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), conv_type::upscale(x2), conv_type::upscale(y2)); } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::reset_clipping() { reset(); m_clipper.reset_clipping(); } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::close_polygon() { if(m_status == status_line_to) { m_clipper.line_to(m_outline, m_start_x, m_start_y); m_status = status_closed; } } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::move_to(int x, int y) { if(m_outline.sorted()) reset(); if(m_auto_close) close_polygon(); m_clipper.move_to(m_start_x = conv_type::downscale(x), m_start_y = conv_type::downscale(y)); m_status = status_move_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::line_to(int x, int y) { m_clipper.line_to(m_outline, conv_type::downscale(x), conv_type::downscale(y)); m_status = status_line_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::move_to_d(double x, double y) { if(m_outline.sorted()) reset(); if(m_auto_close) close_polygon(); m_clipper.move_to(m_start_x = conv_type::upscale(x), m_start_y = conv_type::upscale(y)); m_status = status_move_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::line_to_d(double x, double y) { m_clipper.line_to(m_outline, conv_type::upscale(x), conv_type::upscale(y)); m_status = status_line_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::add_vertex(double x, double y, unsigned cmd) { if(is_move_to(cmd)) { move_to_d(x, y); } else if(is_vertex(cmd)) { line_to_d(x, y); } else if(is_close(cmd)) { close_polygon(); } } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::edge(int x1, int y1, int x2, int y2) { if(m_outline.sorted()) reset(); m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1)); m_clipper.line_to(m_outline, conv_type::downscale(x2), conv_type::downscale(y2)); m_status = status_move_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::edge_d(double x1, double y1, double x2, double y2) { if(m_outline.sorted()) reset(); m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); m_clipper.line_to(m_outline, conv_type::upscale(x2), conv_type::upscale(y2)); m_status = status_move_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa::sort() { if(m_auto_close) close_polygon(); m_outline.sort_cells(); } //------------------------------------------------------------------------ template AGG_INLINE bool rasterizer_scanline_aa::rewind_scanlines() { if(m_auto_close) close_polygon(); m_outline.sort_cells(); if(m_outline.total_cells() == 0) { return false; } m_scan_y = m_outline.min_y(); return true; } //------------------------------------------------------------------------ template AGG_INLINE bool rasterizer_scanline_aa::navigate_scanline(int y) { if(m_auto_close) close_polygon(); m_outline.sort_cells(); if(m_outline.total_cells() == 0 || y < m_outline.min_y() || y > m_outline.max_y()) { return false; } m_scan_y = y; return true; } //------------------------------------------------------------------------ template bool rasterizer_scanline_aa::hit_test(int tx, int ty) { if(!navigate_scanline(ty)) return false; scanline_hit_test sl(tx); sweep_scanline(sl); return sl.hit(); } } #endif ragg/src/agg/include/agg_rendering_buffer_dynarow.h0000644000176200001440000001171113504406270022204 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // class rendering_buffer_dynarow // //---------------------------------------------------------------------------- #ifndef AGG_RENDERING_BUFFER_DYNAROW_INCLUDED #define AGG_RENDERING_BUFFER_DYNAROW_INCLUDED #include #include "agg_array.h" namespace agg { //===============================================rendering_buffer_dynarow // Rendering buffer class with dynamic allocation of the rows. // The rows are allocated as needed when requesting for span_ptr(). // The class automatically calculates min_x and max_x for each row. // Generally it's more efficient to use this class as a temporary buffer // for rendering a few lines and then to blend it with another buffer. // class rendering_buffer_dynarow { public: typedef row_info row_data; //------------------------------------------------------------------- ~rendering_buffer_dynarow() { init(0,0,0); } //------------------------------------------------------------------- rendering_buffer_dynarow() : m_rows(), m_width(0), m_height(0), m_byte_width(0) { } // Allocate and clear the buffer //-------------------------------------------------------------------- rendering_buffer_dynarow(unsigned width, unsigned height, unsigned byte_width) : m_rows(height), m_width(width), m_height(height), m_byte_width(byte_width) { std::memset(&m_rows[0], 0, sizeof(row_data) * height); } // Allocate and clear the buffer //-------------------------------------------------------------------- void init(unsigned width, unsigned height, unsigned byte_width) { unsigned i; for(i = 0; i < m_height; ++i) { pod_allocator::deallocate((int8u*)m_rows[i].ptr, m_byte_width); } if(width && height) { m_width = width; m_height = height; m_byte_width = byte_width; m_rows.resize(height); std::memset(&m_rows[0], 0, sizeof(row_data) * height); } } //-------------------------------------------------------------------- unsigned width() const { return m_width; } unsigned height() const { return m_height; } unsigned byte_width() const { return m_byte_width; } // The main function used for rendering. Returns pointer to the // pre-allocated span. Memory for the row is allocated as needed. //-------------------------------------------------------------------- int8u* row_ptr(int x, int y, unsigned len) { row_data* r = &m_rows[y]; int x2 = x + len - 1; if(r->ptr) { if(x < r->x1) { r->x1 = x; } if(x2 > r->x2) { r->x2 = x2; } } else { int8u* p = pod_allocator::allocate(m_byte_width); r->ptr = p; r->x1 = x; r->x2 = x2; std::memset(p, 0, m_byte_width); } return (int8u*)r->ptr; } //-------------------------------------------------------------------- const int8u* row_ptr(int y) const { return m_rows[y].ptr; } int8u* row_ptr(int y) { return row_ptr(0, y, m_width); } row_data row (int y) const { return m_rows[y]; } private: //-------------------------------------------------------------------- // Prohibit copying rendering_buffer_dynarow(const rendering_buffer_dynarow&); const rendering_buffer_dynarow& operator = (const rendering_buffer_dynarow&); private: //-------------------------------------------------------------------- pod_array m_rows; // Pointers to each row of the buffer unsigned m_width; // Width in pixels unsigned m_height; // Height in pixels unsigned m_byte_width; // Width in bytes }; } #endif ragg/src/agg/include/agg_span_gouraud_rgba.h0000644000176200001440000002324613504406270020623 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_SPAN_GOURAUD_RGBA_INCLUDED #define AGG_SPAN_GOURAUD_RGBA_INCLUDED #include #include "agg_basics.h" #include "agg_color_rgba.h" #include "agg_dda_line.h" #include "agg_span_gouraud.h" namespace agg { //=======================================================span_gouraud_rgba template class span_gouraud_rgba : public span_gouraud { public: typedef ColorT color_type; typedef typename ColorT::value_type value_type; typedef span_gouraud base_type; typedef typename base_type::coord_type coord_type; enum subpixel_scale_e { subpixel_shift = 4, subpixel_scale = 1 << subpixel_shift }; private: //-------------------------------------------------------------------- struct rgba_calc { void init(const coord_type& c1, const coord_type& c2) { m_x1 = c1.x - 0.5; m_y1 = c1.y - 0.5; m_dx = c2.x - c1.x; double dy = c2.y - c1.y; m_1dy = (dy < 1e-5) ? 1e5 : 1.0 / dy; m_r1 = c1.color.r; m_g1 = c1.color.g; m_b1 = c1.color.b; m_a1 = c1.color.a; m_dr = c2.color.r - m_r1; m_dg = c2.color.g - m_g1; m_db = c2.color.b - m_b1; m_da = c2.color.a - m_a1; } void calc(double y) { double k = (y - m_y1) * m_1dy; if(k < 0.0) k = 0.0; if(k > 1.0) k = 1.0; m_r = m_r1 + iround(m_dr * k); m_g = m_g1 + iround(m_dg * k); m_b = m_b1 + iround(m_db * k); m_a = m_a1 + iround(m_da * k); m_x = iround((m_x1 + m_dx * k) * subpixel_scale); } double m_x1; double m_y1; double m_dx; double m_1dy; int m_r1; int m_g1; int m_b1; int m_a1; int m_dr; int m_dg; int m_db; int m_da; int m_r; int m_g; int m_b; int m_a; int m_x; }; public: //-------------------------------------------------------------------- span_gouraud_rgba() {} span_gouraud_rgba(const color_type& c1, const color_type& c2, const color_type& c3, double x1, double y1, double x2, double y2, double x3, double y3, double d = 0) : base_type(c1, c2, c3, x1, y1, x2, y2, x3, y3, d) {} //-------------------------------------------------------------------- void prepare() { coord_type coord[3]; base_type::arrange_vertices(coord); m_y2 = int(coord[1].y); m_swap = cross_product(coord[0].x, coord[0].y, coord[2].x, coord[2].y, coord[1].x, coord[1].y) < 0.0; m_rgba1.init(coord[0], coord[2]); m_rgba2.init(coord[0], coord[1]); m_rgba3.init(coord[1], coord[2]); } //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { m_rgba1.calc(y);//(m_rgba1.m_1dy > 2) ? m_rgba1.m_y1 : y); const rgba_calc* pc1 = &m_rgba1; const rgba_calc* pc2 = &m_rgba2; if(y <= m_y2) { // Bottom part of the triangle (first subtriangle) //------------------------- m_rgba2.calc(y + m_rgba2.m_1dy); } else { // Upper part (second subtriangle) m_rgba3.calc(y - m_rgba3.m_1dy); //------------------------- pc2 = &m_rgba3; } if(m_swap) { // It means that the triangle is oriented clockwise, // so that we need to swap the controlling structures //------------------------- const rgba_calc* t = pc2; pc2 = pc1; pc1 = t; } // Get the horizontal length with subpixel accuracy // and protect it from division by zero //------------------------- int nlen = std::abs(pc2->m_x - pc1->m_x); if(nlen <= 0) nlen = 1; dda_line_interpolator<14> r(pc1->m_r, pc2->m_r, nlen); dda_line_interpolator<14> g(pc1->m_g, pc2->m_g, nlen); dda_line_interpolator<14> b(pc1->m_b, pc2->m_b, nlen); dda_line_interpolator<14> a(pc1->m_a, pc2->m_a, nlen); // Calculate the starting point of the gradient with subpixel // accuracy and correct (roll back) the interpolators. // This operation will also clip the beginning of the span // if necessary. //------------------------- int start = pc1->m_x - (x << subpixel_shift); r -= start; g -= start; b -= start; a -= start; nlen += start; int vr, vg, vb, va; enum lim_e { lim = color_type::base_mask }; // Beginning part of the span. Since we rolled back the // interpolators, the color values may have overflow. // So that, we render the beginning part with checking // for overflow. It lasts until "start" is positive; // typically it's 1-2 pixels, but may be more in some cases. //------------------------- while(len && start > 0) { vr = r.y(); vg = g.y(); vb = b.y(); va = a.y(); if(vr < 0) { vr = 0; } if(vr > lim) { vr = lim; } if(vg < 0) { vg = 0; } if(vg > lim) { vg = lim; } if(vb < 0) { vb = 0; } if(vb > lim) { vb = lim; } if(va < 0) { va = 0; } if(va > lim) { va = lim; } span->r = (value_type)vr; span->g = (value_type)vg; span->b = (value_type)vb; span->a = (value_type)va; r += subpixel_scale; g += subpixel_scale; b += subpixel_scale; a += subpixel_scale; nlen -= subpixel_scale; start -= subpixel_scale; ++span; --len; } // Middle part, no checking for overflow. // Actual spans can be longer than the calculated length // because of anti-aliasing, thus, the interpolators can // overflow. But while "nlen" is positive we are safe. //------------------------- while(len && nlen > 0) { span->r = (value_type)r.y(); span->g = (value_type)g.y(); span->b = (value_type)b.y(); span->a = (value_type)a.y(); r += subpixel_scale; g += subpixel_scale; b += subpixel_scale; a += subpixel_scale; nlen -= subpixel_scale; ++span; --len; } // Ending part; checking for overflow. // Typically it's 1-2 pixels, but may be more in some cases. //------------------------- while(len) { vr = r.y(); vg = g.y(); vb = b.y(); va = a.y(); if(vr < 0) { vr = 0; } if(vr > lim) { vr = lim; } if(vg < 0) { vg = 0; } if(vg > lim) { vg = lim; } if(vb < 0) { vb = 0; } if(vb > lim) { vb = lim; } if(va < 0) { va = 0; } if(va > lim) { va = lim; } span->r = (value_type)vr; span->g = (value_type)vg; span->b = (value_type)vb; span->a = (value_type)va; r += subpixel_scale; g += subpixel_scale; b += subpixel_scale; a += subpixel_scale; ++span; --len; } } private: bool m_swap; int m_y2; rgba_calc m_rgba1; rgba_calc m_rgba2; rgba_calc m_rgba3; }; } #endif ragg/src/agg/include/agg_conv_transform.h0000644000176200001440000000377413504406270020205 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // class conv_transform // //---------------------------------------------------------------------------- #ifndef AGG_CONV_TRANSFORM_INCLUDED #define AGG_CONV_TRANSFORM_INCLUDED #include "agg_basics.h" #include "agg_trans_affine.h" namespace agg { //----------------------------------------------------------conv_transform template class conv_transform { public: conv_transform(VertexSource& source, Transformer& tr) : m_source(&source), m_trans(&tr) {} void attach(VertexSource& source) { m_source = &source; } void rewind(unsigned path_id) { m_source->rewind(path_id); } unsigned vertex(double* x, double* y) { unsigned cmd = m_source->vertex(x, y); if(is_vertex(cmd)) { m_trans->transform(x, y); } return cmd; } void transformer(Transformer& tr) { m_trans = &tr; } private: conv_transform(const conv_transform&); const conv_transform& operator = (const conv_transform&); VertexSource* m_source; Transformer* m_trans; }; } #endif ragg/src/agg/include/agg_path_storage_integer.h0000644000176200001440000002325313506443647021347 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_PATH_STORAGE_INTEGER_INCLUDED #define AGG_PATH_STORAGE_INTEGER_INCLUDED #include #include #include "agg_array.h" namespace agg { //---------------------------------------------------------vertex_integer template struct vertex_integer { typedef typename std::make_unsigned::type uT; enum path_cmd { cmd_move_to = 0, cmd_line_to = 1, cmd_curve3 = 2, cmd_curve4 = 3 }; enum coord_scale_e { coord_shift = CoordShift, coord_scale = 1 << coord_shift }; T x,y; vertex_integer() {} vertex_integer(T x_, T y_, unsigned flag) : x((( (uT) x_ << 1) & ~1) | (flag & 1)), y((( (uT) y_ << 1) & ~1) | (flag >> 1)) {} unsigned vertex(double* x_, double* y_, double dx=0, double dy=0, double scale=1.0) const { *x_ = dx + (double(x >> 1) / coord_scale) * scale; *y_ = dy + (double(y >> 1) / coord_scale) * scale; switch(((y & 1) << 1) | (x & 1)) { case cmd_move_to: return path_cmd_move_to; case cmd_line_to: return path_cmd_line_to; case cmd_curve3: return path_cmd_curve3; case cmd_curve4: return path_cmd_curve4; } return path_cmd_stop; } }; //---------------------------------------------------path_storage_integer template class path_storage_integer { public: typedef T value_type; typedef vertex_integer vertex_integer_type; //-------------------------------------------------------------------- path_storage_integer() : m_storage(), m_vertex_idx(0), m_closed(true) {} //-------------------------------------------------------------------- void remove_all() { m_storage.remove_all(); } //-------------------------------------------------------------------- void move_to(T x, T y) { m_storage.add(vertex_integer_type(x, y, vertex_integer_type::cmd_move_to)); } //-------------------------------------------------------------------- void line_to(T x, T y) { m_storage.add(vertex_integer_type(x, y, vertex_integer_type::cmd_line_to)); } //-------------------------------------------------------------------- void curve3(T x_ctrl, T y_ctrl, T x_to, T y_to) { m_storage.add(vertex_integer_type(x_ctrl, y_ctrl, vertex_integer_type::cmd_curve3)); m_storage.add(vertex_integer_type(x_to, y_to, vertex_integer_type::cmd_curve3)); } //-------------------------------------------------------------------- void curve4(T x_ctrl1, T y_ctrl1, T x_ctrl2, T y_ctrl2, T x_to, T y_to) { m_storage.add(vertex_integer_type(x_ctrl1, y_ctrl1, vertex_integer_type::cmd_curve4)); m_storage.add(vertex_integer_type(x_ctrl2, y_ctrl2, vertex_integer_type::cmd_curve4)); m_storage.add(vertex_integer_type(x_to, y_to, vertex_integer_type::cmd_curve4)); } //-------------------------------------------------------------------- void close_polygon() {} //-------------------------------------------------------------------- unsigned size() const { return m_storage.size(); } unsigned vertex(unsigned idx, double* x, double* y) const { return m_storage[idx].vertex(x, y); } //-------------------------------------------------------------------- unsigned byte_size() const { return m_storage.size() * sizeof(vertex_integer_type); } void serialize(int8u* ptr) const { unsigned i; for(i = 0; i < m_storage.size(); i++) { std::memcpy(ptr, &m_storage[i], sizeof(vertex_integer_type)); ptr += sizeof(vertex_integer_type); } } //-------------------------------------------------------------------- void rewind(unsigned) { m_vertex_idx = 0; m_closed = true; } //-------------------------------------------------------------------- unsigned vertex(double* x, double* y) { if(m_storage.size() < 2 || m_vertex_idx > m_storage.size()) { *x = 0; *y = 0; return path_cmd_stop; } if(m_vertex_idx == m_storage.size()) { *x = 0; *y = 0; ++m_vertex_idx; return path_cmd_end_poly | path_flags_close; } unsigned cmd = m_storage[m_vertex_idx].vertex(x, y); if(is_move_to(cmd) && !m_closed) { *x = 0; *y = 0; m_closed = true; return path_cmd_end_poly | path_flags_close; } m_closed = false; ++m_vertex_idx; return cmd; } //-------------------------------------------------------------------- rect_d bounding_rect() const { rect_d bounds(1e100, 1e100, -1e100, -1e100); if(m_storage.size() == 0) { bounds.x1 = bounds.y1 = bounds.x2 = bounds.y2 = 0.0; } else { unsigned i; for(i = 0; i < m_storage.size(); i++) { double x, y; m_storage[i].vertex(&x, &y); if(x < bounds.x1) bounds.x1 = x; if(y < bounds.y1) bounds.y1 = y; if(x > bounds.x2) bounds.x2 = x; if(y > bounds.y2) bounds.y2 = y; } } return bounds; } private: pod_bvector m_storage; unsigned m_vertex_idx; bool m_closed; }; //-----------------------------------------serialized_integer_path_adaptor template class serialized_integer_path_adaptor { public: typedef vertex_integer vertex_integer_type; //-------------------------------------------------------------------- serialized_integer_path_adaptor() : m_data(0), m_end(0), m_ptr(0), m_dx(0.0), m_dy(0.0), m_scale(1.0), m_vertices(0) {} //-------------------------------------------------------------------- serialized_integer_path_adaptor(const int8u* data, unsigned size, double dx, double dy) : m_data(data), m_end(data + size), m_ptr(data), m_dx(dx), m_dy(dy), m_vertices(0) {} //-------------------------------------------------------------------- void init(const int8u* data, unsigned size, double dx, double dy, double scale=1.0) { m_data = data; m_end = data + size; m_ptr = data; m_dx = dx; m_dy = dy; m_scale = scale; m_vertices = 0; } //-------------------------------------------------------------------- void rewind(unsigned) { m_ptr = m_data; m_vertices = 0; } //-------------------------------------------------------------------- unsigned vertex(double* x, double* y) { if(m_data == 0 || m_ptr > m_end) { *x = 0; *y = 0; return path_cmd_stop; } if(m_ptr == m_end) { *x = 0; *y = 0; m_ptr += sizeof(vertex_integer_type); return path_cmd_end_poly | path_flags_close; } vertex_integer_type v; std::memcpy(&v, m_ptr, sizeof(vertex_integer_type)); unsigned cmd = v.vertex(x, y, m_dx, m_dy, m_scale); if(is_move_to(cmd) && m_vertices > 2) { *x = 0; *y = 0; m_vertices = 0; return path_cmd_end_poly | path_flags_close; } ++m_vertices; m_ptr += sizeof(vertex_integer_type); return cmd; } private: const int8u* m_data; const int8u* m_end; const int8u* m_ptr; double m_dx; double m_dy; double m_scale; unsigned m_vertices; }; } #endif ragg/src/agg/include/agg_pixfmt_amask_adaptor.h0000644000176200001440000002047013504406270021332 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_PIXFMT_AMASK_ADAPTOR_INCLUDED #define AGG_PIXFMT_AMASK_ADAPTOR_INCLUDED #include #include "agg_array.h" #include "agg_rendering_buffer.h" namespace agg { //==================================================pixfmt_amask_adaptor template class pixfmt_amask_adaptor { public: typedef PixFmt pixfmt_type; typedef typename pixfmt_type::color_type color_type; typedef typename pixfmt_type::row_data row_data; typedef AlphaMask amask_type; typedef typename amask_type::cover_type cover_type; private: enum span_extra_tail_e { span_extra_tail = 256 }; void realloc_span(unsigned len) { if(len > m_span.size()) { m_span.resize(len + span_extra_tail); } } void init_span(unsigned len) { realloc_span(len); std::memset(&m_span[0], amask_type::cover_full, len * sizeof(cover_type)); } void init_span(unsigned len, const cover_type* covers) { realloc_span(len); std::memcpy(&m_span[0], covers, len * sizeof(cover_type)); } public: pixfmt_amask_adaptor(pixfmt_type& pixf, amask_type& mask) : m_pixf(&pixf), m_mask(&mask), m_span() {} void attach_pixfmt(pixfmt_type& pixf) { m_pixf = &pixf; } void attach_alpha_mask(amask_type& mask) { m_mask = &mask; } //-------------------------------------------------------------------- template bool attach_pixfmt(PixFmt2& pixf, int x1, int y1, int x2, int y2) { return m_pixf->attach(pixf, x1, y1, x2, y2); } //-------------------------------------------------------------------- unsigned width() const { return m_pixf->width(); } unsigned height() const { return m_pixf->height(); } //-------------------------------------------------------------------- color_type pixel(int x, int y) { return m_pixf->pixel(x, y); } //-------------------------------------------------------------------- void copy_pixel(int x, int y, const color_type& c) { m_pixf->blend_pixel(x, y, c, m_mask->pixel(x, y)); } //-------------------------------------------------------------------- void blend_pixel(int x, int y, const color_type& c, cover_type cover) { m_pixf->blend_pixel(x, y, c, m_mask->combine_pixel(x, y, cover)); } //-------------------------------------------------------------------- void copy_hline(int x, int y, unsigned len, const color_type& c) { realloc_span(len); m_mask->fill_hspan(x, y, &m_span[0], len); m_pixf->blend_solid_hspan(x, y, len, c, &m_span[0]); } //-------------------------------------------------------------------- void blend_hline(int x, int y, unsigned len, const color_type& c, cover_type) { init_span(len); m_mask->combine_hspan(x, y, &m_span[0], len); m_pixf->blend_solid_hspan(x, y, len, c, &m_span[0]); } //-------------------------------------------------------------------- void copy_vline(int x, int y, unsigned len, const color_type& c) { realloc_span(len); m_mask->fill_vspan(x, y, &m_span[0], len); m_pixf->blend_solid_vspan(x, y, len, c, &m_span[0]); } //-------------------------------------------------------------------- void blend_vline(int x, int y, unsigned len, const color_type& c, cover_type) { init_span(len); m_mask->combine_vspan(x, y, &m_span[0], len); m_pixf->blend_solid_vspan(x, y, len, c, &m_span[0]); } //-------------------------------------------------------------------- void copy_from(const rendering_buffer& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len) { m_pixf->copy_from(from, xdst, ydst, xsrc, ysrc, len); } //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, unsigned len, const color_type& c, const cover_type* covers) { init_span(len, covers); m_mask->combine_hspan(x, y, &m_span[0], len); m_pixf->blend_solid_hspan(x, y, len, c, &m_span[0]); } //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, unsigned len, const color_type& c, const cover_type* covers) { init_span(len, covers); m_mask->combine_vspan(x, y, &m_span[0], len); m_pixf->blend_solid_vspan(x, y, len, c, &m_span[0]); } //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, unsigned len, const color_type* colors) { realloc_span(len); m_mask->fill_hspan(x, y, &m_span[0], len); m_pixf->blend_color_hspan(x, y, len, colors, &m_span[0], cover_full); } //-------------------------------------------------------------------- void copy_color_vspan(int x, int y, unsigned len, const color_type* colors) { realloc_span(len); m_mask->fill_vspan(x, y, &m_span[0], len); m_pixf->blend_color_vspan(x, y, len, colors, &m_span[0], cover_full); } //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, unsigned len, const color_type* colors, const cover_type* covers, cover_type cover = cover_full) { if(covers) { init_span(len, covers); m_mask->combine_hspan(x, y, &m_span[0], len); } else { realloc_span(len); m_mask->fill_hspan(x, y, &m_span[0], len); } m_pixf->blend_color_hspan(x, y, len, colors, &m_span[0], cover); } //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, unsigned len, const color_type* colors, const cover_type* covers, cover_type cover = cover_full) { if(covers) { init_span(len, covers); m_mask->combine_vspan(x, y, &m_span[0], len); } else { realloc_span(len); m_mask->fill_vspan(x, y, &m_span[0], len); } m_pixf->blend_color_vspan(x, y, len, colors, &m_span[0], cover); } private: pixfmt_type* m_pixf; const amask_type* m_mask; pod_array m_span; }; } #endif ragg/src/agg/include/agg_rasterizer_sl_clip.h0000644000176200001440000003113513504406270021034 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_RASTERIZER_SL_CLIP_INCLUDED #define AGG_RASTERIZER_SL_CLIP_INCLUDED #include "agg_clip_liang_barsky.h" namespace agg { //--------------------------------------------------------poly_max_coord_e enum poly_max_coord_e { poly_max_coord = (1 << 30) - 1 //----poly_max_coord }; //------------------------------------------------------------ras_conv_int struct ras_conv_int { typedef int coord_type; static AGG_INLINE int mul_div(double a, double b, double c) { return iround(a * b / c); } static int xi(int v) { return v; } static int yi(int v) { return v; } static int upscale(double v) { return iround(v * poly_subpixel_scale); } static int downscale(int v) { return v; } }; //--------------------------------------------------------ras_conv_int_sat struct ras_conv_int_sat { typedef int coord_type; static AGG_INLINE int mul_div(double a, double b, double c) { return saturation::iround(a * b / c); } static int xi(int v) { return v; } static int yi(int v) { return v; } static int upscale(double v) { return saturation::iround(v * poly_subpixel_scale); } static int downscale(int v) { return v; } }; //---------------------------------------------------------ras_conv_int_3x struct ras_conv_int_3x { typedef int coord_type; static AGG_INLINE int mul_div(double a, double b, double c) { return iround(a * b / c); } static int xi(int v) { return v * 3; } static int yi(int v) { return v; } static int upscale(double v) { return iround(v * poly_subpixel_scale); } static int downscale(int v) { return v; } }; //-----------------------------------------------------------ras_conv_dbl struct ras_conv_dbl { typedef double coord_type; static AGG_INLINE double mul_div(double a, double b, double c) { return a * b / c; } static int xi(double v) { return iround(v * poly_subpixel_scale); } static int yi(double v) { return iround(v * poly_subpixel_scale); } static double upscale(double v) { return v; } static double downscale(int v) { return v / double(poly_subpixel_scale); } }; //--------------------------------------------------------ras_conv_dbl_3x struct ras_conv_dbl_3x { typedef double coord_type; static AGG_INLINE double mul_div(double a, double b, double c) { return a * b / c; } static int xi(double v) { return iround(v * poly_subpixel_scale * 3); } static int yi(double v) { return iround(v * poly_subpixel_scale); } static double upscale(double v) { return v; } static double downscale(int v) { return v / double(poly_subpixel_scale); } }; //------------------------------------------------------rasterizer_sl_clip template class rasterizer_sl_clip { public: typedef Conv conv_type; typedef typename Conv::coord_type coord_type; typedef rect_base rect_type; //-------------------------------------------------------------------- rasterizer_sl_clip() : m_clip_box(0,0,0,0), m_x1(0), m_y1(0), m_f1(0), m_clipping(false) {} //-------------------------------------------------------------------- void reset_clipping() { m_clipping = false; } //-------------------------------------------------------------------- void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2) { m_clip_box = rect_type(x1, y1, x2, y2); m_clip_box.normalize(); m_clipping = true; } //-------------------------------------------------------------------- void move_to(coord_type x1, coord_type y1) { m_x1 = x1; m_y1 = y1; if(m_clipping) m_f1 = clipping_flags(x1, y1, m_clip_box); } private: //------------------------------------------------------------------------ template AGG_INLINE void line_clip_y(Rasterizer& ras, coord_type x1, coord_type y1, coord_type x2, coord_type y2, unsigned f1, unsigned f2) const { f1 &= 10; f2 &= 10; if((f1 | f2) == 0) { // Fully visible ras.line(Conv::xi(x1), Conv::yi(y1), Conv::xi(x2), Conv::yi(y2)); } else { if(f1 == f2) { // Invisible by Y return; } coord_type tx1 = x1; coord_type ty1 = y1; coord_type tx2 = x2; coord_type ty2 = y2; if(f1 & 8) // y1 < clip.y1 { tx1 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1); ty1 = m_clip_box.y1; } if(f1 & 2) // y1 > clip.y2 { tx1 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1); ty1 = m_clip_box.y2; } if(f2 & 8) // y2 < clip.y1 { tx2 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1); ty2 = m_clip_box.y1; } if(f2 & 2) // y2 > clip.y2 { tx2 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1); ty2 = m_clip_box.y2; } ras.line(Conv::xi(tx1), Conv::yi(ty1), Conv::xi(tx2), Conv::yi(ty2)); } } public: //-------------------------------------------------------------------- template void line_to(Rasterizer& ras, coord_type x2, coord_type y2) { if(m_clipping) { unsigned f2 = clipping_flags(x2, y2, m_clip_box); if((m_f1 & 10) == (f2 & 10) && (m_f1 & 10) != 0) { // Invisible by Y m_x1 = x2; m_y1 = y2; m_f1 = f2; return; } coord_type x1 = m_x1; coord_type y1 = m_y1; unsigned f1 = m_f1; coord_type y3, y4; unsigned f3, f4; switch(((f1 & 5) << 1) | (f2 & 5)) { case 0: // Visible by X line_clip_y(ras, x1, y1, x2, y2, f1, f2); break; case 1: // x2 > clip.x2 y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); f3 = clipping_flags_y(y3, m_clip_box); line_clip_y(ras, x1, y1, m_clip_box.x2, y3, f1, f3); line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x2, y2, f3, f2); break; case 2: // x1 > clip.x2 y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); f3 = clipping_flags_y(y3, m_clip_box); line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3); line_clip_y(ras, m_clip_box.x2, y3, x2, y2, f3, f2); break; case 3: // x1 > clip.x2 && x2 > clip.x2 line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y2, f1, f2); break; case 4: // x2 < clip.x1 y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); f3 = clipping_flags_y(y3, m_clip_box); line_clip_y(ras, x1, y1, m_clip_box.x1, y3, f1, f3); line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x1, y2, f3, f2); break; case 6: // x1 > clip.x2 && x2 < clip.x1 y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); y4 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); f3 = clipping_flags_y(y3, m_clip_box); f4 = clipping_flags_y(y4, m_clip_box); line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3); line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x1, y4, f3, f4); line_clip_y(ras, m_clip_box.x1, y4, m_clip_box.x1, y2, f4, f2); break; case 8: // x1 < clip.x1 y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); f3 = clipping_flags_y(y3, m_clip_box); line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3); line_clip_y(ras, m_clip_box.x1, y3, x2, y2, f3, f2); break; case 9: // x1 < clip.x1 && x2 > clip.x2 y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); y4 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); f3 = clipping_flags_y(y3, m_clip_box); f4 = clipping_flags_y(y4, m_clip_box); line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3); line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x2, y4, f3, f4); line_clip_y(ras, m_clip_box.x2, y4, m_clip_box.x2, y2, f4, f2); break; case 12: // x1 < clip.x1 && x2 < clip.x1 line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y2, f1, f2); break; } m_f1 = f2; } else { ras.line(Conv::xi(m_x1), Conv::yi(m_y1), Conv::xi(x2), Conv::yi(y2)); } m_x1 = x2; m_y1 = y2; } private: rect_type m_clip_box; coord_type m_x1; coord_type m_y1; unsigned m_f1; bool m_clipping; }; //---------------------------------------------------rasterizer_sl_no_clip class rasterizer_sl_no_clip { public: typedef ras_conv_int conv_type; typedef int coord_type; rasterizer_sl_no_clip() : m_x1(0), m_y1(0) {} void reset_clipping() {} void clip_box(coord_type, coord_type, coord_type, coord_type) {} void move_to(coord_type x1, coord_type y1) { m_x1 = x1; m_y1 = y1; } template void line_to(Rasterizer& ras, coord_type x2, coord_type y2) { ras.line(m_x1, m_y1, x2, y2); m_x1 = x2; m_y1 = y2; } private: int m_x1, m_y1; }; // -----rasterizer_sl_clip_int // -----rasterizer_sl_clip_int_sat // -----rasterizer_sl_clip_int_3x // -----rasterizer_sl_clip_dbl // -----rasterizer_sl_clip_dbl_3x //------------------------------------------------------------------------ typedef rasterizer_sl_clip rasterizer_sl_clip_int; typedef rasterizer_sl_clip rasterizer_sl_clip_int_sat; typedef rasterizer_sl_clip rasterizer_sl_clip_int_3x; typedef rasterizer_sl_clip rasterizer_sl_clip_dbl; typedef rasterizer_sl_clip rasterizer_sl_clip_dbl_3x; } #endif ragg/src/agg/include/agg_renderer_markers.h0000644000176200001440000010662313504406270020474 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // class renderer_markers // //---------------------------------------------------------------------------- #ifndef AGG_RENDERER_MARKERS_INCLUDED #define AGG_RENDERER_MARKERS_INCLUDED #include "agg_basics.h" #include "agg_renderer_primitives.h" namespace agg { //---------------------------------------------------------------marker_e enum marker_e { marker_square, marker_diamond, marker_circle, marker_crossed_circle, marker_semiellipse_left, marker_semiellipse_right, marker_semiellipse_up, marker_semiellipse_down, marker_triangle_left, marker_triangle_right, marker_triangle_up, marker_triangle_down, marker_four_rays, marker_cross, marker_x, marker_dash, marker_dot, marker_pixel, end_of_markers }; //--------------------------------------------------------renderer_markers template class renderer_markers : public renderer_primitives { public: typedef renderer_primitives base_type; typedef BaseRenderer base_ren_type; typedef typename base_ren_type::color_type color_type; //-------------------------------------------------------------------- renderer_markers(base_ren_type& rbuf) : base_type(rbuf) {} //-------------------------------------------------------------------- bool visible(int x, int y, int r) const { rect_i rc(x-r, y-r, x+y, y+r); return rc.clip(base_type::ren().bounding_clip_box()); } //-------------------------------------------------------------------- void square(int x, int y, int r) { if(visible(x, y, r)) { if(r) base_type::outlined_rectangle(x-r, y-r, x+r, y+r); else base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } //-------------------------------------------------------------------- void diamond(int x, int y, int r) { if(visible(x, y, r)) { if(r) { int dy = -r; int dx = 0; do { base_type::ren().blend_pixel(x - dx, y + dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x + dx, y + dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x - dx, y - dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x + dx, y - dy, base_type::line_color(), cover_full); if(dx) { base_type::ren().blend_hline(x-dx+1, y+dy, x+dx-1, base_type::fill_color(), cover_full); base_type::ren().blend_hline(x-dx+1, y-dy, x+dx-1, base_type::fill_color(), cover_full); } ++dy; ++dx; } while(dy <= 0); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //-------------------------------------------------------------------- void circle(int x, int y, int r) { if(visible(x, y, r)) { if(r) base_type::outlined_ellipse(x, y, r, r); else base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } //-------------------------------------------------------------------- void crossed_circle(int x, int y, int r) { if(visible(x, y, r)) { if(r) { base_type::outlined_ellipse(x, y, r, r); int r6 = r + (r >> 1); if(r <= 2) r6++; r >>= 1; base_type::ren().blend_hline(x-r6, y, x-r, base_type::line_color(), cover_full); base_type::ren().blend_hline(x+r, y, x+r6, base_type::line_color(), cover_full); base_type::ren().blend_vline(x, y-r6, y-r, base_type::line_color(), cover_full); base_type::ren().blend_vline(x, y+r, y+r6, base_type::line_color(), cover_full); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //------------------------------------------------------------------------ void semiellipse_left(int x, int y, int r) { if(visible(x, y, r)) { if(r) { int r8 = r * 4 / 5; int dy = -r; int dx = 0; ellipse_bresenham_interpolator ei(r * 3 / 5, r+r8); do { dx += ei.dx(); dy += ei.dy(); base_type::ren().blend_pixel(x + dy, y + dx, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x + dy, y - dx, base_type::line_color(), cover_full); if(ei.dy() && dx) { base_type::ren().blend_vline(x+dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); } ++ei; } while(dy < r8); base_type::ren().blend_vline(x+dy, y-dx, y+dx, base_type::line_color(), cover_full); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //-------------------------------------------------------------------- void semiellipse_right(int x, int y, int r) { if(visible(x, y, r)) { if(r) { int r8 = r * 4 / 5; int dy = -r; int dx = 0; ellipse_bresenham_interpolator ei(r * 3 / 5, r+r8); do { dx += ei.dx(); dy += ei.dy(); base_type::ren().blend_pixel(x - dy, y + dx, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x - dy, y - dx, base_type::line_color(), cover_full); if(ei.dy() && dx) { base_type::ren().blend_vline(x-dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); } ++ei; } while(dy < r8); base_type::ren().blend_vline(x-dy, y-dx, y+dx, base_type::line_color(), cover_full); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //-------------------------------------------------------------------- void semiellipse_up(int x, int y, int r) { if(visible(x, y, r)) { if(r) { int r8 = r * 4 / 5; int dy = -r; int dx = 0; ellipse_bresenham_interpolator ei(r * 3 / 5, r+r8); do { dx += ei.dx(); dy += ei.dy(); base_type::ren().blend_pixel(x + dx, y - dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x - dx, y - dy, base_type::line_color(), cover_full); if(ei.dy() && dx) { base_type::ren().blend_hline(x-dx+1, y-dy, x+dx-1, base_type::fill_color(), cover_full); } ++ei; } while(dy < r8); base_type::ren().blend_hline(x-dx, y-dy-1, x+dx, base_type::line_color(), cover_full); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //-------------------------------------------------------------------- void semiellipse_down(int x, int y, int r) { if(visible(x, y, r)) { if(r) { int r8 = r * 4 / 5; int dy = -r; int dx = 0; ellipse_bresenham_interpolator ei(r * 3 / 5, r+r8); do { dx += ei.dx(); dy += ei.dy(); base_type::ren().blend_pixel(x + dx, y + dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x - dx, y + dy, base_type::line_color(), cover_full); if(ei.dy() && dx) { base_type::ren().blend_hline(x-dx+1, y+dy, x+dx-1, base_type::fill_color(), cover_full); } ++ei; } while(dy < r8); base_type::ren().blend_hline(x-dx, y+dy+1, x+dx, base_type::line_color(), cover_full); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //-------------------------------------------------------------------- void triangle_left(int x, int y, int r) { if(visible(x, y, r)) { if(r) { int dy = -r; int dx = 0; int flip = 0; int r6 = r * 3 / 5; do { base_type::ren().blend_pixel(x + dy, y - dx, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x + dy, y + dx, base_type::line_color(), cover_full); if(dx) { base_type::ren().blend_vline(x+dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); } ++dy; dx += flip; flip ^= 1; } while(dy < r6); base_type::ren().blend_vline(x+dy, y-dx, y+dx, base_type::line_color(), cover_full); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //-------------------------------------------------------------------- void triangle_right(int x, int y, int r) { if(visible(x, y, r)) { if(r) { int dy = -r; int dx = 0; int flip = 0; int r6 = r * 3 / 5; do { base_type::ren().blend_pixel(x - dy, y - dx, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x - dy, y + dx, base_type::line_color(), cover_full); if(dx) { base_type::ren().blend_vline(x-dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); } ++dy; dx += flip; flip ^= 1; } while(dy < r6); base_type::ren().blend_vline(x-dy, y-dx, y+dx, base_type::line_color(), cover_full); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //-------------------------------------------------------------------- void triangle_up(int x, int y, int r) { if(visible(x, y, r)) { if(r) { int dy = -r; int dx = 0; int flip = 0; int r6 = r * 3 / 5; do { base_type::ren().blend_pixel(x - dx, y - dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x + dx, y - dy, base_type::line_color(), cover_full); if(dx) { base_type::ren().blend_hline(x-dx+1, y-dy, x+dx-1, base_type::fill_color(), cover_full); } ++dy; dx += flip; flip ^= 1; } while(dy < r6); base_type::ren().blend_hline(x-dx, y-dy, x+dx, base_type::line_color(), cover_full); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //-------------------------------------------------------------------- void triangle_down(int x, int y, int r) { if(visible(x, y, r)) { if(r) { int dy = -r; int dx = 0; int flip = 0; int r6 = r * 3 / 5; do { base_type::ren().blend_pixel(x - dx, y + dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x + dx, y + dy, base_type::line_color(), cover_full); if(dx) { base_type::ren().blend_hline(x-dx+1, y+dy, x+dx-1, base_type::fill_color(), cover_full); } ++dy; dx += flip; flip ^= 1; } while(dy < r6); base_type::ren().blend_hline(x-dx, y+dy, x+dx, base_type::line_color(), cover_full); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //-------------------------------------------------------------------- void four_rays(int x, int y, int r) { if(visible(x, y, r)) { if(r) { int dy = -r; int dx = 0; int flip = 0; int r3 = -(r / 3); do { base_type::ren().blend_pixel(x - dx, y + dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x + dx, y + dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x - dx, y - dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x + dx, y - dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x + dy, y - dx, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x + dy, y + dx, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x - dy, y - dx, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x - dy, y + dx, base_type::line_color(), cover_full); if(dx) { base_type::ren().blend_hline(x-dx+1, y+dy, x+dx-1, base_type::fill_color(), cover_full); base_type::ren().blend_hline(x-dx+1, y-dy, x+dx-1, base_type::fill_color(), cover_full); base_type::ren().blend_vline(x+dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); base_type::ren().blend_vline(x-dy, y-dx+1, y+dx-1, base_type::fill_color(), cover_full); } ++dy; dx += flip; flip ^= 1; } while(dy <= r3); base_type::solid_rectangle(x+r3+1, y+r3+1, x-r3-1, y-r3-1); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //-------------------------------------------------------------------- void cross(int x, int y, int r) { if(visible(x, y, r)) { if(r) { base_type::ren().blend_vline(x, y-r, y+r, base_type::line_color(), cover_full); base_type::ren().blend_hline(x-r, y, x+r, base_type::line_color(), cover_full); } else { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } } //-------------------------------------------------------------------- void xing(int x, int y, int r) { if(visible(x, y, r)) { if(r) { int dy = -r * 7 / 10; do { base_type::ren().blend_pixel(x + dy, y + dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x - dy, y + dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x + dy, y - dy, base_type::line_color(), cover_full); base_type::ren().blend_pixel(x - dy, y - dy, base_type::line_color(), cover_full); ++dy; } while(dy < 0); } base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } //-------------------------------------------------------------------- void dash(int x, int y, int r) { if(visible(x, y, r)) { if(r) base_type::ren().blend_hline(x-r, y, x+r, base_type::line_color(), cover_full); else base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } //-------------------------------------------------------------------- void dot(int x, int y, int r) { if(visible(x, y, r)) { if(r) base_type::solid_ellipse(x, y, r, r); else base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } } //-------------------------------------------------------------------- void pixel(int x, int y, int) { base_type::ren().blend_pixel(x, y, base_type::fill_color(), cover_full); } //-------------------------------------------------------------------- void marker(int x, int y, int r, marker_e type) { switch(type) { case marker_square: square(x, y, r); break; case marker_diamond: diamond(x, y, r); break; case marker_circle: circle(x, y, r); break; case marker_crossed_circle: crossed_circle(x, y, r); break; case marker_semiellipse_left: semiellipse_left(x, y, r); break; case marker_semiellipse_right: semiellipse_right(x, y, r); break; case marker_semiellipse_up: semiellipse_up(x, y, r); break; case marker_semiellipse_down: semiellipse_down(x, y, r); break; case marker_triangle_left: triangle_left(x, y, r); break; case marker_triangle_right: triangle_right(x, y, r); break; case marker_triangle_up: triangle_up(x, y, r); break; case marker_triangle_down: triangle_down(x, y, r); break; case marker_four_rays: four_rays(x, y, r); break; case marker_cross: cross(x, y, r); break; case marker_x: xing(x, y, r); break; case marker_dash: dash(x, y, r); break; case marker_dot: dot(x, y, r); break; case marker_pixel: pixel(x, y, r); break; case end_of_markers: break; } } //-------------------------------------------------------------------- template void markers(int n, const T* x, const T* y, T r, marker_e type) { if(n <= 0) return; if(r == 0) { do { base_type::ren().blend_pixel(int(*x), int(*y), base_type::fill_color(), cover_full); ++x; ++y; } while(--n); return; } switch(type) { case marker_square: do { square (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_diamond: do { diamond (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_circle: do { circle (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_crossed_circle: do { crossed_circle (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_semiellipse_left: do { semiellipse_left (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_semiellipse_right: do { semiellipse_right(int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_semiellipse_up: do { semiellipse_up (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_semiellipse_down: do { semiellipse_down (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_triangle_left: do { triangle_left (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_triangle_right: do { triangle_right (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_triangle_up: do { triangle_up (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_triangle_down: do { triangle_down (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_four_rays: do { four_rays (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_cross: do { cross (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_x: do { xing (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_dash: do { dash (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_dot: do { dot (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case marker_pixel: do { pixel (int(*x), int(*y), int(r)); ++x; ++y; } while(--n); break; case end_of_markers: break; } } //-------------------------------------------------------------------- template void markers(int n, const T* x, const T* y, const T* r, marker_e type) { if(n <= 0) return; switch(type) { case marker_square: do { square (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_diamond: do { diamond (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_circle: do { circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_crossed_circle: do { crossed_circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_semiellipse_left: do { semiellipse_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_semiellipse_right: do { semiellipse_right(int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_semiellipse_up: do { semiellipse_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_semiellipse_down: do { semiellipse_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_triangle_left: do { triangle_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_triangle_right: do { triangle_right (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_triangle_up: do { triangle_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_triangle_down: do { triangle_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_four_rays: do { four_rays (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_cross: do { cross (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_x: do { xing (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_dash: do { dash (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_dot: do { dot (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case marker_pixel: do { pixel (int(*x), int(*y), int(*r)); ++x; ++y; ++r; } while(--n); break; case end_of_markers: break; } } //-------------------------------------------------------------------- template void markers(int n, const T* x, const T* y, const T* r, const color_type* fc, marker_e type) { if(n <= 0) return; switch(type) { case marker_square: do { base_type::fill_color(*fc); square (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_diamond: do { base_type::fill_color(*fc); diamond (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_circle: do { base_type::fill_color(*fc); circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_crossed_circle: do { base_type::fill_color(*fc); crossed_circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_semiellipse_left: do { base_type::fill_color(*fc); semiellipse_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_semiellipse_right: do { base_type::fill_color(*fc); semiellipse_right(int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_semiellipse_up: do { base_type::fill_color(*fc); semiellipse_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_semiellipse_down: do { base_type::fill_color(*fc); semiellipse_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_triangle_left: do { base_type::fill_color(*fc); triangle_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_triangle_right: do { base_type::fill_color(*fc); triangle_right (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_triangle_up: do { base_type::fill_color(*fc); triangle_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_triangle_down: do { base_type::fill_color(*fc); triangle_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_four_rays: do { base_type::fill_color(*fc); four_rays (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_cross: do { base_type::fill_color(*fc); cross (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_x: do { base_type::fill_color(*fc); xing (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_dash: do { base_type::fill_color(*fc); dash (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_dot: do { base_type::fill_color(*fc); dot (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case marker_pixel: do { base_type::fill_color(*fc); pixel (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; } while(--n); break; case end_of_markers: break; } } //-------------------------------------------------------------------- template void markers(int n, const T* x, const T* y, const T* r, const color_type* fc, const color_type* lc, marker_e type) { if(n <= 0) return; switch(type) { case marker_square: do { base_type::fill_color(*fc); base_type::line_color(*lc); square (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_diamond: do { base_type::fill_color(*fc); base_type::line_color(*lc); diamond (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_circle: do { base_type::fill_color(*fc); base_type::line_color(*lc); circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_crossed_circle: do { base_type::fill_color(*fc); base_type::line_color(*lc); crossed_circle (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_semiellipse_left: do { base_type::fill_color(*fc); base_type::line_color(*lc); semiellipse_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_semiellipse_right: do { base_type::fill_color(*fc); base_type::line_color(*lc); semiellipse_right(int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_semiellipse_up: do { base_type::fill_color(*fc); base_type::line_color(*lc); semiellipse_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_semiellipse_down: do { base_type::fill_color(*fc); base_type::line_color(*lc); semiellipse_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_triangle_left: do { base_type::fill_color(*fc); base_type::line_color(*lc); triangle_left (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_triangle_right: do { base_type::fill_color(*fc); base_type::line_color(*lc); triangle_right (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_triangle_up: do { base_type::fill_color(*fc); base_type::line_color(*lc); triangle_up (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_triangle_down: do { base_type::fill_color(*fc); base_type::line_color(*lc); triangle_down (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_four_rays: do { base_type::fill_color(*fc); base_type::line_color(*lc); four_rays (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_cross: do { base_type::fill_color(*fc); base_type::line_color(*lc); cross (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_x: do { base_type::fill_color(*fc); base_type::line_color(*lc); xing (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_dash: do { base_type::fill_color(*fc); base_type::line_color(*lc); dash (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_dot: do { base_type::fill_color(*fc); base_type::line_color(*lc); dot (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case marker_pixel: do { base_type::fill_color(*fc); base_type::line_color(*lc); pixel (int(*x), int(*y), int(*r)); ++x; ++y; ++r; ++fc; ++lc; } while(--n); break; case end_of_markers: break; } } }; } #endif ragg/src/agg/include/agg_conv_segmentator.h0000644000176200001440000000330013504406270020503 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_CONV_SEGMENTATOR_INCLUDED #define AGG_CONV_SEGMENTATOR_INCLUDED #include "agg_basics.h" #include "agg_conv_adaptor_vpgen.h" #include "agg_vpgen_segmentator.h" namespace agg { //========================================================conv_segmentator template struct conv_segmentator : public conv_adaptor_vpgen { typedef conv_adaptor_vpgen base_type; conv_segmentator(VertexSource& vs) : conv_adaptor_vpgen(vs) {} void approximation_scale(double s) { base_type::vpgen().approximation_scale(s); } double approximation_scale() const { return base_type::vpgen().approximation_scale(); } private: conv_segmentator(const conv_segmentator&); const conv_segmentator& operator = (const conv_segmentator&); }; } #endif ragg/src/agg/include/agg_renderer_outline_image.h0000644000176200001440000010630513504406270021646 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_RENDERER_OUTLINE_IMAGE_INCLUDED #define AGG_RENDERER_OUTLINE_IMAGE_INCLUDED #include #include "agg_array.h" #include "agg_math.h" #include "agg_line_aa_basics.h" #include "agg_dda_line.h" #include "agg_rendering_buffer.h" #include "agg_clip_liang_barsky.h" namespace agg { //========================================================line_image_scale template class line_image_scale { public: typedef typename Source::color_type color_type; line_image_scale(const Source& src, double height) : m_source(src), m_height(height), m_scale(src.height() / height), m_scale_inv(height / src.height()) { } double width() const { return m_source.width(); } double height() const { return m_height; } color_type pixel(int x, int y) const { if (m_scale < 1.0) { // Interpolate between nearest source pixels. double src_y = (y + 0.5) * m_scale - 0.5; int h = m_source.height() - 1; int y1 = ifloor(src_y); int y2 = y1 + 1; rgba pix1 = (y1 < 0) ? rgba::no_color() : rgba(m_source.pixel(x, y1)); rgba pix2 = (y2 > h) ? rgba::no_color() : rgba(m_source.pixel(x, y2)); return pix1.gradient(pix2, src_y - y1); } else { // Average source pixels between y and y+1. double src_y1 = (y + 0.5) * m_scale - 0.5; double src_y2 = src_y1 + m_scale; int h = m_source.height() - 1; int y1 = ifloor(src_y1); int y2 = ifloor(src_y2); rgba c = rgba::no_color(); if (y1 >= 0) c += rgba(m_source.pixel(x, y1)) *= y1 + 1 - src_y1; while (++y1 < y2) { if (y1 <= h) c += m_source.pixel(x, y1); } if (y2 <= h) c += rgba(m_source.pixel(x, y2)) *= src_y2 - y2; return c *= m_scale_inv; } } private: line_image_scale(const line_image_scale&); const line_image_scale& operator = (const line_image_scale&); const Source& m_source; double m_height; double m_scale; double m_scale_inv; }; //======================================================line_image_pattern template class line_image_pattern { public: typedef Filter filter_type; typedef typename filter_type::color_type color_type; //-------------------------------------------------------------------- line_image_pattern(Filter& filter) : m_filter(&filter), m_dilation(filter.dilation() + 1), m_dilation_hr(m_dilation << line_subpixel_shift), m_data(), m_width(0), m_height(0), m_width_hr(0), m_half_height_hr(0), m_offset_y_hr(0) { } // Create //-------------------------------------------------------------------- template line_image_pattern(Filter& filter, const Source& src) : m_filter(&filter), m_dilation(filter.dilation() + 1), m_dilation_hr(m_dilation << line_subpixel_shift), m_data(), m_width(0), m_height(0), m_width_hr(0), m_half_height_hr(0), m_offset_y_hr(0) { create(src); } // Create //-------------------------------------------------------------------- template void create(const Source& src) { m_height = uceil(src.height()); m_width = uceil(src.width()); m_width_hr = uround(src.width() * line_subpixel_scale); m_half_height_hr = uround(src.height() * line_subpixel_scale/2); m_offset_y_hr = m_dilation_hr + m_half_height_hr - line_subpixel_scale/2; m_half_height_hr += line_subpixel_scale/2; m_data.resize((m_width + m_dilation * 2) * (m_height + m_dilation * 2)); m_buf.attach(&m_data[0], m_width + m_dilation * 2, m_height + m_dilation * 2, m_width + m_dilation * 2); unsigned x, y; color_type* d1; color_type* d2; for(y = 0; y < m_height; y++) { d1 = m_buf.row_ptr(y + m_dilation) + m_dilation; for(x = 0; x < m_width; x++) { *d1++ = src.pixel(x, y); } } const color_type* s1; const color_type* s2; for(y = 0; y < m_dilation; y++) { //s1 = m_buf.row_ptr(m_height + m_dilation - 1) + m_dilation; //s2 = m_buf.row_ptr(m_dilation) + m_dilation; d1 = m_buf.row_ptr(m_dilation + m_height + y) + m_dilation; d2 = m_buf.row_ptr(m_dilation - y - 1) + m_dilation; for(x = 0; x < m_width; x++) { //*d1++ = color_type(*s1++, 0); //*d2++ = color_type(*s2++, 0); *d1++ = color_type::no_color(); *d2++ = color_type::no_color(); } } unsigned h = m_height + m_dilation * 2; for(y = 0; y < h; y++) { s1 = m_buf.row_ptr(y) + m_dilation; s2 = m_buf.row_ptr(y) + m_dilation + m_width; d1 = m_buf.row_ptr(y) + m_dilation + m_width; d2 = m_buf.row_ptr(y) + m_dilation; for(x = 0; x < m_dilation; x++) { *d1++ = *s1++; *--d2 = *--s2; } } } //-------------------------------------------------------------------- int pattern_width() const { return m_width_hr; } int line_width() const { return m_half_height_hr; } double width() const { return m_height; } //-------------------------------------------------------------------- void pixel(color_type* p, int x, int y) const { m_filter->pixel_high_res(m_buf.rows(), p, x % m_width_hr + m_dilation_hr, y + m_offset_y_hr); } //-------------------------------------------------------------------- const filter_type& filter() const { return *m_filter; } private: line_image_pattern(const line_image_pattern&); const line_image_pattern& operator = (const line_image_pattern&); protected: row_ptr_cache m_buf; const filter_type* m_filter; unsigned m_dilation; int m_dilation_hr; pod_array m_data; unsigned m_width; unsigned m_height; int m_width_hr; int m_half_height_hr; int m_offset_y_hr; }; //=================================================line_image_pattern_pow2 template class line_image_pattern_pow2 : public line_image_pattern { public: typedef Filter filter_type; typedef typename filter_type::color_type color_type; typedef line_image_pattern base_type; //-------------------------------------------------------------------- line_image_pattern_pow2(Filter& filter) : line_image_pattern(filter), m_mask(line_subpixel_mask) {} //-------------------------------------------------------------------- template line_image_pattern_pow2(Filter& filter, const Source& src) : line_image_pattern(filter), m_mask(line_subpixel_mask) { create(src); } //-------------------------------------------------------------------- template void create(const Source& src) { line_image_pattern::create(src); m_mask = 1; while(m_mask < base_type::m_width) { m_mask <<= 1; m_mask |= 1; } m_mask <<= line_subpixel_shift - 1; m_mask |= line_subpixel_mask; base_type::m_width_hr = m_mask + 1; } //-------------------------------------------------------------------- void pixel(color_type* p, int x, int y) const { base_type::m_filter->pixel_high_res( base_type::m_buf.rows(), p, (x & m_mask) + base_type::m_dilation_hr, y + base_type::m_offset_y_hr); } private: unsigned m_mask; }; //===================================================distance_interpolator4 class distance_interpolator4 { public: //--------------------------------------------------------------------- distance_interpolator4() {} distance_interpolator4(int x1, int y1, int x2, int y2, int sx, int sy, int ex, int ey, int len, double scale, int x, int y) : m_dx(x2 - x1), m_dy(y2 - y1), m_dx_start(line_mr(sx) - line_mr(x1)), m_dy_start(line_mr(sy) - line_mr(y1)), m_dx_end(line_mr(ex) - line_mr(x2)), m_dy_end(line_mr(ey) - line_mr(y2)), m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) - double(y + line_subpixel_scale/2 - y2) * double(m_dx))), m_dist_start((line_mr(x + line_subpixel_scale/2) - line_mr(sx)) * m_dy_start - (line_mr(y + line_subpixel_scale/2) - line_mr(sy)) * m_dx_start), m_dist_end((line_mr(x + line_subpixel_scale/2) - line_mr(ex)) * m_dy_end - (line_mr(y + line_subpixel_scale/2) - line_mr(ey)) * m_dx_end), m_len(uround(len / scale)) { double d = len * scale; int dx = iround(((x2 - x1) << line_subpixel_shift) / d); int dy = iround(((y2 - y1) << line_subpixel_shift) / d); m_dx_pict = -dy; m_dy_pict = dx; m_dist_pict = ((x + line_subpixel_scale/2 - (x1 - dy)) * m_dy_pict - (y + line_subpixel_scale/2 - (y1 + dx)) * m_dx_pict) >> line_subpixel_shift; m_dx <<= line_subpixel_shift; m_dy <<= line_subpixel_shift; m_dx_start <<= line_mr_subpixel_shift; m_dy_start <<= line_mr_subpixel_shift; m_dx_end <<= line_mr_subpixel_shift; m_dy_end <<= line_mr_subpixel_shift; } //--------------------------------------------------------------------- void inc_x() { m_dist += m_dy; m_dist_start += m_dy_start; m_dist_pict += m_dy_pict; m_dist_end += m_dy_end; } //--------------------------------------------------------------------- void dec_x() { m_dist -= m_dy; m_dist_start -= m_dy_start; m_dist_pict -= m_dy_pict; m_dist_end -= m_dy_end; } //--------------------------------------------------------------------- void inc_y() { m_dist -= m_dx; m_dist_start -= m_dx_start; m_dist_pict -= m_dx_pict; m_dist_end -= m_dx_end; } //--------------------------------------------------------------------- void dec_y() { m_dist += m_dx; m_dist_start += m_dx_start; m_dist_pict += m_dx_pict; m_dist_end += m_dx_end; } //--------------------------------------------------------------------- void inc_x(int dy) { m_dist += m_dy; m_dist_start += m_dy_start; m_dist_pict += m_dy_pict; m_dist_end += m_dy_end; if(dy > 0) { m_dist -= m_dx; m_dist_start -= m_dx_start; m_dist_pict -= m_dx_pict; m_dist_end -= m_dx_end; } if(dy < 0) { m_dist += m_dx; m_dist_start += m_dx_start; m_dist_pict += m_dx_pict; m_dist_end += m_dx_end; } } //--------------------------------------------------------------------- void dec_x(int dy) { m_dist -= m_dy; m_dist_start -= m_dy_start; m_dist_pict -= m_dy_pict; m_dist_end -= m_dy_end; if(dy > 0) { m_dist -= m_dx; m_dist_start -= m_dx_start; m_dist_pict -= m_dx_pict; m_dist_end -= m_dx_end; } if(dy < 0) { m_dist += m_dx; m_dist_start += m_dx_start; m_dist_pict += m_dx_pict; m_dist_end += m_dx_end; } } //--------------------------------------------------------------------- void inc_y(int dx) { m_dist -= m_dx; m_dist_start -= m_dx_start; m_dist_pict -= m_dx_pict; m_dist_end -= m_dx_end; if(dx > 0) { m_dist += m_dy; m_dist_start += m_dy_start; m_dist_pict += m_dy_pict; m_dist_end += m_dy_end; } if(dx < 0) { m_dist -= m_dy; m_dist_start -= m_dy_start; m_dist_pict -= m_dy_pict; m_dist_end -= m_dy_end; } } //--------------------------------------------------------------------- void dec_y(int dx) { m_dist += m_dx; m_dist_start += m_dx_start; m_dist_pict += m_dx_pict; m_dist_end += m_dx_end; if(dx > 0) { m_dist += m_dy; m_dist_start += m_dy_start; m_dist_pict += m_dy_pict; m_dist_end += m_dy_end; } if(dx < 0) { m_dist -= m_dy; m_dist_start -= m_dy_start; m_dist_pict -= m_dy_pict; m_dist_end -= m_dy_end; } } //--------------------------------------------------------------------- int dist() const { return m_dist; } int dist_start() const { return m_dist_start; } int dist_pict() const { return m_dist_pict; } int dist_end() const { return m_dist_end; } //--------------------------------------------------------------------- int dx() const { return m_dx; } int dy() const { return m_dy; } int dx_start() const { return m_dx_start; } int dy_start() const { return m_dy_start; } int dx_pict() const { return m_dx_pict; } int dy_pict() const { return m_dy_pict; } int dx_end() const { return m_dx_end; } int dy_end() const { return m_dy_end; } int len() const { return m_len; } private: //--------------------------------------------------------------------- int m_dx; int m_dy; int m_dx_start; int m_dy_start; int m_dx_pict; int m_dy_pict; int m_dx_end; int m_dy_end; int m_dist; int m_dist_start; int m_dist_pict; int m_dist_end; int m_len; }; //==================================================line_interpolator_image template class line_interpolator_image { public: typedef Renderer renderer_type; typedef typename Renderer::color_type color_type; //--------------------------------------------------------------------- enum max_half_width_e { max_half_width = 64 }; //--------------------------------------------------------------------- line_interpolator_image(renderer_type& ren, const line_parameters& lp, int sx, int sy, int ex, int ey, int pattern_start, double scale_x) : m_lp(lp), m_li(lp.vertical ? line_dbl_hr(lp.x2 - lp.x1) : line_dbl_hr(lp.y2 - lp.y1), lp.vertical ? std::abs(lp.y2 - lp.y1) : std::abs(lp.x2 - lp.x1) + 1), m_di(lp.x1, lp.y1, lp.x2, lp.y2, sx, sy, ex, ey, lp.len, scale_x, lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask), m_ren(ren), m_x(lp.x1 >> line_subpixel_shift), m_y(lp.y1 >> line_subpixel_shift), m_old_x(m_x), m_old_y(m_y), m_count((lp.vertical ? std::abs((lp.y2 >> line_subpixel_shift) - m_y) : std::abs((lp.x2 >> line_subpixel_shift) - m_x))), m_width(ren.subpixel_width()), //m_max_extent(m_width >> (line_subpixel_shift - 2)), m_max_extent((m_width + line_subpixel_scale) >> line_subpixel_shift), m_start(pattern_start + (m_max_extent + 2) * ren.pattern_width()), m_step(0) { agg::dda2_line_interpolator li(0, lp.vertical ? (lp.dy << agg::line_subpixel_shift) : (lp.dx << agg::line_subpixel_shift), lp.len); unsigned i; int stop = m_width + line_subpixel_scale * 2; for(i = 0; i < max_half_width; ++i) { m_dist_pos[i] = li.y(); if(m_dist_pos[i] >= stop) break; ++li; } m_dist_pos[i] = 0x7FFF0000; int dist1_start; int dist2_start; int npix = 1; if(lp.vertical) { do { --m_li; m_y -= lp.inc; m_x = (m_lp.x1 + m_li.y()) >> line_subpixel_shift; if(lp.inc > 0) m_di.dec_y(m_x - m_old_x); else m_di.inc_y(m_x - m_old_x); m_old_x = m_x; dist1_start = dist2_start = m_di.dist_start(); int dx = 0; if(dist1_start < 0) ++npix; do { dist1_start += m_di.dy_start(); dist2_start -= m_di.dy_start(); if(dist1_start < 0) ++npix; if(dist2_start < 0) ++npix; ++dx; } while(m_dist_pos[dx] <= m_width); if(npix == 0) break; npix = 0; } while(--m_step >= -m_max_extent); } else { do { --m_li; m_x -= lp.inc; m_y = (m_lp.y1 + m_li.y()) >> line_subpixel_shift; if(lp.inc > 0) m_di.dec_x(m_y - m_old_y); else m_di.inc_x(m_y - m_old_y); m_old_y = m_y; dist1_start = dist2_start = m_di.dist_start(); int dy = 0; if(dist1_start < 0) ++npix; do { dist1_start -= m_di.dx_start(); dist2_start += m_di.dx_start(); if(dist1_start < 0) ++npix; if(dist2_start < 0) ++npix; ++dy; } while(m_dist_pos[dy] <= m_width); if(npix == 0) break; npix = 0; } while(--m_step >= -m_max_extent); } m_li.adjust_forward(); m_step -= m_max_extent; } //--------------------------------------------------------------------- bool step_hor() { ++m_li; m_x += m_lp.inc; m_y = (m_lp.y1 + m_li.y()) >> line_subpixel_shift; if(m_lp.inc > 0) m_di.inc_x(m_y - m_old_y); else m_di.dec_x(m_y - m_old_y); m_old_y = m_y; int s1 = m_di.dist() / m_lp.len; int s2 = -s1; if(m_lp.inc < 0) s1 = -s1; int dist_start; int dist_pict; int dist_end; int dy; int dist; dist_start = m_di.dist_start(); dist_pict = m_di.dist_pict() + m_start; dist_end = m_di.dist_end(); color_type* p0 = m_colors + max_half_width + 2; color_type* p1 = p0; int npix = 0; p1->clear(); if(dist_end > 0) { if(dist_start <= 0) { m_ren.pixel(p1, dist_pict, s2); } ++npix; } ++p1; dy = 1; while((dist = m_dist_pos[dy]) - s1 <= m_width) { dist_start -= m_di.dx_start(); dist_pict -= m_di.dx_pict(); dist_end -= m_di.dx_end(); p1->clear(); if(dist_end > 0 && dist_start <= 0) { if(m_lp.inc > 0) dist = -dist; m_ren.pixel(p1, dist_pict, s2 - dist); ++npix; } ++p1; ++dy; } dy = 1; dist_start = m_di.dist_start(); dist_pict = m_di.dist_pict() + m_start; dist_end = m_di.dist_end(); while((dist = m_dist_pos[dy]) + s1 <= m_width) { dist_start += m_di.dx_start(); dist_pict += m_di.dx_pict(); dist_end += m_di.dx_end(); --p0; p0->clear(); if(dist_end > 0 && dist_start <= 0) { if(m_lp.inc > 0) dist = -dist; m_ren.pixel(p0, dist_pict, s2 + dist); ++npix; } ++dy; } m_ren.blend_color_vspan(m_x, m_y - dy + 1, unsigned(p1 - p0), p0); return npix && ++m_step < m_count; } //--------------------------------------------------------------------- bool step_ver() { ++m_li; m_y += m_lp.inc; m_x = (m_lp.x1 + m_li.y()) >> line_subpixel_shift; if(m_lp.inc > 0) m_di.inc_y(m_x - m_old_x); else m_di.dec_y(m_x - m_old_x); m_old_x = m_x; int s1 = m_di.dist() / m_lp.len; int s2 = -s1; if(m_lp.inc > 0) s1 = -s1; int dist_start; int dist_pict; int dist_end; int dist; int dx; dist_start = m_di.dist_start(); dist_pict = m_di.dist_pict() + m_start; dist_end = m_di.dist_end(); color_type* p0 = m_colors + max_half_width + 2; color_type* p1 = p0; int npix = 0; p1->clear(); if(dist_end > 0) { if(dist_start <= 0) { m_ren.pixel(p1, dist_pict, s2); } ++npix; } ++p1; dx = 1; while((dist = m_dist_pos[dx]) - s1 <= m_width) { dist_start += m_di.dy_start(); dist_pict += m_di.dy_pict(); dist_end += m_di.dy_end(); p1->clear(); if(dist_end > 0 && dist_start <= 0) { if(m_lp.inc > 0) dist = -dist; m_ren.pixel(p1, dist_pict, s2 + dist); ++npix; } ++p1; ++dx; } dx = 1; dist_start = m_di.dist_start(); dist_pict = m_di.dist_pict() + m_start; dist_end = m_di.dist_end(); while((dist = m_dist_pos[dx]) + s1 <= m_width) { dist_start -= m_di.dy_start(); dist_pict -= m_di.dy_pict(); dist_end -= m_di.dy_end(); --p0; p0->clear(); if(dist_end > 0 && dist_start <= 0) { if(m_lp.inc > 0) dist = -dist; m_ren.pixel(p0, dist_pict, s2 - dist); ++npix; } ++dx; } m_ren.blend_color_hspan(m_x - dx + 1, m_y, unsigned(p1 - p0), p0); return npix && ++m_step < m_count; } //--------------------------------------------------------------------- int pattern_end() const { return m_start + m_di.len(); } //--------------------------------------------------------------------- bool vertical() const { return m_lp.vertical; } int width() const { return m_width; } int count() const { return m_count; } private: line_interpolator_image(const line_interpolator_image&); const line_interpolator_image& operator = (const line_interpolator_image&); protected: const line_parameters& m_lp; dda2_line_interpolator m_li; distance_interpolator4 m_di; renderer_type& m_ren; int m_plen; int m_x; int m_y; int m_old_x; int m_old_y; int m_count; int m_width; int m_max_extent; int m_start; int m_step; int m_dist_pos[max_half_width + 1]; color_type m_colors[max_half_width * 2 + 4]; }; //===================================================renderer_outline_image template class renderer_outline_image { public: //--------------------------------------------------------------------- typedef BaseRenderer base_ren_type; typedef renderer_outline_image self_type; typedef typename base_ren_type::color_type color_type; typedef ImagePattern pattern_type; //--------------------------------------------------------------------- renderer_outline_image(base_ren_type& ren, pattern_type& patt) : m_ren(&ren), m_pattern(&patt), m_start(0), m_scale_x(1.0), m_clip_box(0,0,0,0), m_clipping(false) {} void attach(base_ren_type& ren) { m_ren = &ren; } //--------------------------------------------------------------------- void pattern(pattern_type& p) { m_pattern = &p; } pattern_type& pattern() const { return *m_pattern; } //--------------------------------------------------------------------- void reset_clipping() { m_clipping = false; } void clip_box(double x1, double y1, double x2, double y2) { m_clip_box.x1 = line_coord_sat::conv(x1); m_clip_box.y1 = line_coord_sat::conv(y1); m_clip_box.x2 = line_coord_sat::conv(x2); m_clip_box.y2 = line_coord_sat::conv(y2); m_clipping = true; } //--------------------------------------------------------------------- void scale_x(double s) { m_scale_x = s; } double scale_x() const { return m_scale_x; } //--------------------------------------------------------------------- void start_x(double s) { m_start = iround(s * line_subpixel_scale); } double start_x() const { return double(m_start) / line_subpixel_scale; } //--------------------------------------------------------------------- int subpixel_width() const { return m_pattern->line_width(); } int pattern_width() const { return m_pattern->pattern_width(); } double width() const { return double(subpixel_width()) / line_subpixel_scale; } //------------------------------------------------------------------------- void pixel(color_type* p, int x, int y) const { m_pattern->pixel(p, x, y); } //------------------------------------------------------------------------- void blend_color_hspan(int x, int y, unsigned len, const color_type* colors) { m_ren->blend_color_hspan(x, y, len, colors, 0); } //------------------------------------------------------------------------- void blend_color_vspan(int x, int y, unsigned len, const color_type* colors) { m_ren->blend_color_vspan(x, y, len, colors, 0); } //------------------------------------------------------------------------- static bool accurate_join_only() { return true; } //------------------------------------------------------------------------- template void semidot(Cmp, int, int, int, int) { } //------------------------------------------------------------------------- void pie(int, int, int, int, int, int) { } //------------------------------------------------------------------------- void line0(const line_parameters&) { } //------------------------------------------------------------------------- void line1(const line_parameters&, int, int) { } //------------------------------------------------------------------------- void line2(const line_parameters&, int, int) { } //------------------------------------------------------------------------- void line3_no_clip(const line_parameters& lp, int sx, int sy, int ex, int ey) { if(lp.len > line_max_length) { line_parameters lp1, lp2; lp.divide(lp1, lp2); int mx = lp1.x2 + (lp1.y2 - lp1.y1); int my = lp1.y2 - (lp1.x2 - lp1.x1); line3_no_clip(lp1, (lp.x1 + sx) >> 1, (lp.y1 + sy) >> 1, mx, my); line3_no_clip(lp2, mx, my, (lp.x2 + ex) >> 1, (lp.y2 + ey) >> 1); return; } fix_degenerate_bisectrix_start(lp, &sx, &sy); fix_degenerate_bisectrix_end(lp, &ex, &ey); line_interpolator_image li(*this, lp, sx, sy, ex, ey, m_start, m_scale_x); if(li.vertical()) { while(li.step_ver()); } else { while(li.step_hor()); } m_start += uround(lp.len / m_scale_x); } //------------------------------------------------------------------------- void line3(const line_parameters& lp, int sx, int sy, int ex, int ey) { if(m_clipping) { int x1 = lp.x1; int y1 = lp.y1; int x2 = lp.x2; int y2 = lp.y2; unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box); int start = m_start; if((flags & 4) == 0) { if(flags) { line_parameters lp2(x1, y1, x2, y2, uround(calc_distance(x1, y1, x2, y2))); if(flags & 1) { m_start += uround(calc_distance(lp.x1, lp.y1, x1, y1) / m_scale_x); sx = x1 + (y2 - y1); sy = y1 - (x2 - x1); } else { while(std::abs(sx - lp.x1) + std::abs(sy - lp.y1) > lp2.len) { sx = (lp.x1 + sx) >> 1; sy = (lp.y1 + sy) >> 1; } } if(flags & 2) { ex = x2 + (y2 - y1); ey = y2 - (x2 - x1); } else { while(std::abs(ex - lp.x2) + std::abs(ey - lp.y2) > lp2.len) { ex = (lp.x2 + ex) >> 1; ey = (lp.y2 + ey) >> 1; } } line3_no_clip(lp2, sx, sy, ex, ey); } else { line3_no_clip(lp, sx, sy, ex, ey); } } m_start = start + uround(lp.len / m_scale_x); } else { line3_no_clip(lp, sx, sy, ex, ey); } } private: base_ren_type* m_ren; pattern_type* m_pattern; int m_start; double m_scale_x; rect_i m_clip_box; bool m_clipping; }; } #endif ragg/src/agg/include/agg_conv_clip_polygon.h0000644000176200001440000000472513504406270020665 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Polygon clipping converter // There an optimized Liang-Basky algorithm is used. // The algorithm doesn't optimize the degenerate edges, i.e. it will never // break a closed polygon into two or more ones, instead, there will be // degenerate edges coinciding with the respective clipping boundaries. // This is a sub-optimal solution, because that optimization would require // extra, rather expensive math while the rasterizer tolerates it quite well, // without any considerable overhead. // //---------------------------------------------------------------------------- #ifndef AGG_CONV_CLIP_POLYGON_INCLUDED #define AGG_CONV_CLIP_POLYGON_INCLUDED #include "agg_basics.h" #include "agg_conv_adaptor_vpgen.h" #include "agg_vpgen_clip_polygon.h" namespace agg { //=======================================================conv_clip_polygon template struct conv_clip_polygon : public conv_adaptor_vpgen { typedef conv_adaptor_vpgen base_type; conv_clip_polygon(VertexSource& vs) : conv_adaptor_vpgen(vs) {} void clip_box(double x1, double y1, double x2, double y2) { base_type::vpgen().clip_box(x1, y1, x2, y2); } double x1() const { return base_type::vpgen().x1(); } double y1() const { return base_type::vpgen().y1(); } double x2() const { return base_type::vpgen().x2(); } double y2() const { return base_type::vpgen().y2(); } private: conv_clip_polygon(const conv_clip_polygon&); const conv_clip_polygon& operator = (const conv_clip_polygon&); }; } #endif ragg/src/agg/include/agg_span_interpolator_persp.h0000644000176200001440000003661313504406270022117 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_SPAN_INTERPOLATOR_PERSP_INCLUDED #define AGG_SPAN_INTERPOLATOR_PERSP_INCLUDED #include #include "agg_trans_perspective.h" #include "agg_dda_line.h" namespace agg { //===========================================span_interpolator_persp_exact template class span_interpolator_persp_exact { public: typedef trans_perspective trans_type; typedef trans_perspective::iterator_x iterator_type; enum subpixel_scale_e { subpixel_shift = SubpixelShift, subpixel_scale = 1 << subpixel_shift }; //-------------------------------------------------------------------- span_interpolator_persp_exact() {} //-------------------------------------------------------------------- // Arbitrary quadrangle transformations span_interpolator_persp_exact(const double* src, const double* dst) { quad_to_quad(src, dst); } //-------------------------------------------------------------------- // Direct transformations span_interpolator_persp_exact(double x1, double y1, double x2, double y2, const double* quad) { rect_to_quad(x1, y1, x2, y2, quad); } //-------------------------------------------------------------------- // Reverse transformations span_interpolator_persp_exact(const double* quad, double x1, double y1, double x2, double y2) { quad_to_rect(quad, x1, y1, x2, y2); } //-------------------------------------------------------------------- // Set the transformations using two arbitrary quadrangles. void quad_to_quad(const double* src, const double* dst) { m_trans_dir.quad_to_quad(src, dst); m_trans_inv.quad_to_quad(dst, src); } //-------------------------------------------------------------------- // Set the direct transformations, i.e., rectangle -> quadrangle void rect_to_quad(double x1, double y1, double x2, double y2, const double* quad) { double src[8]; src[0] = src[6] = x1; src[2] = src[4] = x2; src[1] = src[3] = y1; src[5] = src[7] = y2; quad_to_quad(src, quad); } //-------------------------------------------------------------------- // Set the reverse transformations, i.e., quadrangle -> rectangle void quad_to_rect(const double* quad, double x1, double y1, double x2, double y2) { double dst[8]; dst[0] = dst[6] = x1; dst[2] = dst[4] = x2; dst[1] = dst[3] = y1; dst[5] = dst[7] = y2; quad_to_quad(quad, dst); } //-------------------------------------------------------------------- // Check if the equations were solved successfully bool is_valid() const { return m_trans_dir.is_valid(); } //---------------------------------------------------------------- void begin(double x, double y, unsigned len) { m_iterator = m_trans_dir.begin(x, y, 1.0); double xt = m_iterator.x; double yt = m_iterator.y; double dx; double dy; const double delta = 1/double(subpixel_scale); dx = xt + delta; dy = yt; m_trans_inv.transform(&dx, &dy); dx -= x; dy -= y; int sx1 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; dx = xt; dy = yt + delta; m_trans_inv.transform(&dx, &dy); dx -= x; dy -= y; int sy1 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; x += len; xt = x; yt = y; m_trans_dir.transform(&xt, &yt); dx = xt + delta; dy = yt; m_trans_inv.transform(&dx, &dy); dx -= x; dy -= y; int sx2 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; dx = xt; dy = yt + delta; m_trans_inv.transform(&dx, &dy); dx -= x; dy -= y; int sy2 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; m_scale_x = dda2_line_interpolator(sx1, sx2, len); m_scale_y = dda2_line_interpolator(sy1, sy2, len); } //---------------------------------------------------------------- void resynchronize(double xe, double ye, unsigned len) { // Assume x1,y1 are equal to the ones at the previous end point int sx1 = m_scale_x.y(); int sy1 = m_scale_y.y(); // Calculate transformed coordinates at x2,y2 double xt = xe; double yt = ye; m_trans_dir.transform(&xt, &yt); const double delta = 1/double(subpixel_scale); double dx; double dy; // Calculate scale by X at x2,y2 dx = xt + delta; dy = yt; m_trans_inv.transform(&dx, &dy); dx -= xe; dy -= ye; int sx2 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; // Calculate scale by Y at x2,y2 dx = xt; dy = yt + delta; m_trans_inv.transform(&dx, &dy); dx -= xe; dy -= ye; int sy2 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; // Initialize the interpolators m_scale_x = dda2_line_interpolator(sx1, sx2, len); m_scale_y = dda2_line_interpolator(sy1, sy2, len); } //---------------------------------------------------------------- void operator++() { ++m_iterator; ++m_scale_x; ++m_scale_y; } //---------------------------------------------------------------- void coordinates(int* x, int* y) const { *x = iround(m_iterator.x * subpixel_scale); *y = iround(m_iterator.y * subpixel_scale); } //---------------------------------------------------------------- void local_scale(int* x, int* y) { *x = m_scale_x.y(); *y = m_scale_y.y(); } //---------------------------------------------------------------- void transform(double* x, double* y) const { m_trans_dir.transform(x, y); } private: trans_type m_trans_dir; trans_type m_trans_inv; iterator_type m_iterator; dda2_line_interpolator m_scale_x; dda2_line_interpolator m_scale_y; }; //============================================span_interpolator_persp_lerp template class span_interpolator_persp_lerp { public: typedef trans_perspective trans_type; enum subpixel_scale_e { subpixel_shift = SubpixelShift, subpixel_scale = 1 << subpixel_shift }; //-------------------------------------------------------------------- span_interpolator_persp_lerp() {} //-------------------------------------------------------------------- // Arbitrary quadrangle transformations span_interpolator_persp_lerp(const double* src, const double* dst) { quad_to_quad(src, dst); } //-------------------------------------------------------------------- // Direct transformations span_interpolator_persp_lerp(double x1, double y1, double x2, double y2, const double* quad) { rect_to_quad(x1, y1, x2, y2, quad); } //-------------------------------------------------------------------- // Reverse transformations span_interpolator_persp_lerp(const double* quad, double x1, double y1, double x2, double y2) { quad_to_rect(quad, x1, y1, x2, y2); } //-------------------------------------------------------------------- // Set the transformations using two arbitrary quadrangles. void quad_to_quad(const double* src, const double* dst) { m_trans_dir.quad_to_quad(src, dst); m_trans_inv.quad_to_quad(dst, src); } //-------------------------------------------------------------------- // Set the direct transformations, i.e., rectangle -> quadrangle void rect_to_quad(double x1, double y1, double x2, double y2, const double* quad) { double src[8]; src[0] = src[6] = x1; src[2] = src[4] = x2; src[1] = src[3] = y1; src[5] = src[7] = y2; quad_to_quad(src, quad); } //-------------------------------------------------------------------- // Set the reverse transformations, i.e., quadrangle -> rectangle void quad_to_rect(const double* quad, double x1, double y1, double x2, double y2) { double dst[8]; dst[0] = dst[6] = x1; dst[2] = dst[4] = x2; dst[1] = dst[3] = y1; dst[5] = dst[7] = y2; quad_to_quad(quad, dst); } //-------------------------------------------------------------------- // Check if the equations were solved successfully bool is_valid() const { return m_trans_dir.is_valid(); } //---------------------------------------------------------------- void begin(double x, double y, unsigned len) { // Calculate transformed coordinates at x1,y1 double xt = x; double yt = y; m_trans_dir.transform(&xt, &yt); int x1 = iround(xt * subpixel_scale); int y1 = iround(yt * subpixel_scale); double dx; double dy; const double delta = 1/double(subpixel_scale); // Calculate scale by X at x1,y1 dx = xt + delta; dy = yt; m_trans_inv.transform(&dx, &dy); dx -= x; dy -= y; int sx1 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; // Calculate scale by Y at x1,y1 dx = xt; dy = yt + delta; m_trans_inv.transform(&dx, &dy); dx -= x; dy -= y; int sy1 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; // Calculate transformed coordinates at x2,y2 x += len; xt = x; yt = y; m_trans_dir.transform(&xt, &yt); int x2 = iround(xt * subpixel_scale); int y2 = iround(yt * subpixel_scale); // Calculate scale by X at x2,y2 dx = xt + delta; dy = yt; m_trans_inv.transform(&dx, &dy); dx -= x; dy -= y; int sx2 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; // Calculate scale by Y at x2,y2 dx = xt; dy = yt + delta; m_trans_inv.transform(&dx, &dy); dx -= x; dy -= y; int sy2 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; // Initialize the interpolators m_coord_x = dda2_line_interpolator(x1, x2, len); m_coord_y = dda2_line_interpolator(y1, y2, len); m_scale_x = dda2_line_interpolator(sx1, sx2, len); m_scale_y = dda2_line_interpolator(sy1, sy2, len); } //---------------------------------------------------------------- void resynchronize(double xe, double ye, unsigned len) { // Assume x1,y1 are equal to the ones at the previous end point int x1 = m_coord_x.y(); int y1 = m_coord_y.y(); int sx1 = m_scale_x.y(); int sy1 = m_scale_y.y(); // Calculate transformed coordinates at x2,y2 double xt = xe; double yt = ye; m_trans_dir.transform(&xt, &yt); int x2 = iround(xt * subpixel_scale); int y2 = iround(yt * subpixel_scale); const double delta = 1/double(subpixel_scale); double dx; double dy; // Calculate scale by X at x2,y2 dx = xt + delta; dy = yt; m_trans_inv.transform(&dx, &dy); dx -= xe; dy -= ye; int sx2 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; // Calculate scale by Y at x2,y2 dx = xt; dy = yt + delta; m_trans_inv.transform(&dx, &dy); dx -= xe; dy -= ye; int sy2 = uround(subpixel_scale/std::sqrt(dx*dx + dy*dy)) >> subpixel_shift; // Initialize the interpolators m_coord_x = dda2_line_interpolator(x1, x2, len); m_coord_y = dda2_line_interpolator(y1, y2, len); m_scale_x = dda2_line_interpolator(sx1, sx2, len); m_scale_y = dda2_line_interpolator(sy1, sy2, len); } //---------------------------------------------------------------- void operator++() { ++m_coord_x; ++m_coord_y; ++m_scale_x; ++m_scale_y; } //---------------------------------------------------------------- void coordinates(int* x, int* y) const { *x = m_coord_x.y(); *y = m_coord_y.y(); } //---------------------------------------------------------------- void local_scale(int* x, int* y) { *x = m_scale_x.y(); *y = m_scale_y.y(); } //---------------------------------------------------------------- void transform(double* x, double* y) const { m_trans_dir.transform(x, y); } private: trans_type m_trans_dir; trans_type m_trans_inv; dda2_line_interpolator m_coord_x; dda2_line_interpolator m_coord_y; dda2_line_interpolator m_scale_x; dda2_line_interpolator m_scale_y; }; } #endif ragg/src/agg/include/agg_span_gouraud.h0000644000176200001440000001313713504406270017626 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_SPAN_GOURAUD_INCLUDED #define AGG_SPAN_GOURAUD_INCLUDED #include "agg_basics.h" #include "agg_math.h" namespace agg { //============================================================span_gouraud template class span_gouraud { public: typedef ColorT color_type; struct coord_type { double x; double y; color_type color; }; //-------------------------------------------------------------------- span_gouraud() : m_vertex(0) { m_cmd[0] = path_cmd_stop; } //-------------------------------------------------------------------- span_gouraud(const color_type& c1, const color_type& c2, const color_type& c3, double x1, double y1, double x2, double y2, double x3, double y3, double d) : m_vertex(0) { colors(c1, c2, c3); triangle(x1, y1, x2, y2, x3, y3, d); } //-------------------------------------------------------------------- void colors(ColorT c1, ColorT c2, ColorT c3) { m_coord[0].color = c1; m_coord[1].color = c2; m_coord[2].color = c3; } //-------------------------------------------------------------------- // Sets the triangle and dilates it if needed. // The trick here is to calculate beveled joins in the vertices of the // triangle and render it as a 6-vertex polygon. // It's necessary to achieve numerical stability. // However, the coordinates to interpolate colors are calculated // as miter joins (calc_intersection). void triangle(double x1, double y1, double x2, double y2, double x3, double y3, double d) { m_coord[0].x = m_x[0] = x1; m_coord[0].y = m_y[0] = y1; m_coord[1].x = m_x[1] = x2; m_coord[1].y = m_y[1] = y2; m_coord[2].x = m_x[2] = x3; m_coord[2].y = m_y[2] = y3; m_cmd[0] = path_cmd_move_to; m_cmd[1] = path_cmd_line_to; m_cmd[2] = path_cmd_line_to; m_cmd[3] = path_cmd_stop; if(d != 0.0) { dilate_triangle(m_coord[0].x, m_coord[0].y, m_coord[1].x, m_coord[1].y, m_coord[2].x, m_coord[2].y, m_x, m_y, d); calc_intersection(m_x[4], m_y[4], m_x[5], m_y[5], m_x[0], m_y[0], m_x[1], m_y[1], &m_coord[0].x, &m_coord[0].y); calc_intersection(m_x[0], m_y[0], m_x[1], m_y[1], m_x[2], m_y[2], m_x[3], m_y[3], &m_coord[1].x, &m_coord[1].y); calc_intersection(m_x[2], m_y[2], m_x[3], m_y[3], m_x[4], m_y[4], m_x[5], m_y[5], &m_coord[2].x, &m_coord[2].y); m_cmd[3] = path_cmd_line_to; m_cmd[4] = path_cmd_line_to; m_cmd[5] = path_cmd_line_to; m_cmd[6] = path_cmd_stop; } } //-------------------------------------------------------------------- // Vertex Source Interface to feed the coordinates to the rasterizer void rewind(unsigned) { m_vertex = 0; } //-------------------------------------------------------------------- unsigned vertex(double* x, double* y) { *x = m_x[m_vertex]; *y = m_y[m_vertex]; return m_cmd[m_vertex++]; } protected: //-------------------------------------------------------------------- void arrange_vertices(coord_type* coord) const { coord[0] = m_coord[0]; coord[1] = m_coord[1]; coord[2] = m_coord[2]; if(m_coord[0].y > m_coord[2].y) { coord[0] = m_coord[2]; coord[2] = m_coord[0]; } coord_type tmp; if(coord[0].y > coord[1].y) { tmp = coord[1]; coord[1] = coord[0]; coord[0] = tmp; } if(coord[1].y > coord[2].y) { tmp = coord[2]; coord[2] = coord[1]; coord[1] = tmp; } } private: //-------------------------------------------------------------------- coord_type m_coord[3]; double m_x[8]; double m_y[8]; unsigned m_cmd[8]; unsigned m_vertex; }; } #endif ragg/src/agg/include/agg_scanline_bin.h0000644000176200001440000001707013504406270017563 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Class scanline_bin - binary scanline. // //---------------------------------------------------------------------------- // // Adaptation for 32-bit screen coordinates (scanline32_bin) 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_SCANLINE_BIN_INCLUDED #define AGG_SCANLINE_BIN_INCLUDED #include "agg_array.h" namespace agg { //=============================================================scanline_bin // // This is binary scaline container which supports the interface // used in the rasterizer::render(). See description of agg_scanline_u8 // for details. // //------------------------------------------------------------------------ class scanline_bin { public: typedef int32 coord_type; struct span { int16 x; int16 len; }; typedef const span* const_iterator; //-------------------------------------------------------------------- scanline_bin() : m_last_x(0x7FFFFFF0), m_spans(), m_cur_span(0) { } //-------------------------------------------------------------------- void reset(int min_x, int max_x) { unsigned max_len = max_x - min_x + 3; if(max_len > m_spans.size()) { m_spans.resize(max_len); } m_last_x = 0x7FFFFFF0; m_cur_span = &m_spans[0]; } //-------------------------------------------------------------------- void add_cell(int x, unsigned) { if(x == m_last_x+1) { m_cur_span->len++; } else { ++m_cur_span; m_cur_span->x = (int16)x; m_cur_span->len = 1; } m_last_x = x; } //-------------------------------------------------------------------- void add_span(int x, unsigned len, unsigned) { if(x == m_last_x+1) { m_cur_span->len = (int16)(m_cur_span->len + len); } else { ++m_cur_span; m_cur_span->x = (int16)x; m_cur_span->len = (int16)len; } m_last_x = x + len - 1; } //-------------------------------------------------------------------- void add_cells(int x, unsigned len, const void*) { add_span(x, len, 0); } //-------------------------------------------------------------------- void finalize(int y) { m_y = y; } //-------------------------------------------------------------------- void reset_spans() { m_last_x = 0x7FFFFFF0; m_cur_span = &m_spans[0]; } //-------------------------------------------------------------------- int y() const { return m_y; } unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); } const_iterator begin() const { return &m_spans[1]; } private: scanline_bin(const scanline_bin&); const scanline_bin operator = (const scanline_bin&); int m_last_x; int m_y; pod_array m_spans; span* m_cur_span; }; //===========================================================scanline32_bin class scanline32_bin { public: typedef int32 coord_type; //-------------------------------------------------------------------- struct span { span() {} span(coord_type x_, coord_type len_) : x(x_), len(len_) {} coord_type x; coord_type len; }; typedef pod_bvector span_array_type; //-------------------------------------------------------------------- class const_iterator { public: const_iterator(const span_array_type& spans) : m_spans(spans), m_span_idx(0) {} const span& operator*() const { return m_spans[m_span_idx]; } const span* operator->() const { return &m_spans[m_span_idx]; } void operator ++ () { ++m_span_idx; } private: const span_array_type& m_spans; unsigned m_span_idx; }; //-------------------------------------------------------------------- scanline32_bin() : m_max_len(0), m_last_x(0x7FFFFFF0) {} //-------------------------------------------------------------------- void reset(int, int) { m_last_x = 0x7FFFFFF0; m_spans.remove_all(); } //-------------------------------------------------------------------- void add_cell(int x, unsigned) { if(x == m_last_x+1) { m_spans.last().len++; } else { m_spans.add(span(coord_type(x), 1)); } m_last_x = x; } //-------------------------------------------------------------------- void add_span(int x, unsigned len, unsigned) { if(x == m_last_x+1) { m_spans.last().len += coord_type(len); } else { m_spans.add(span(coord_type(x), coord_type(len))); } m_last_x = x + len - 1; } //-------------------------------------------------------------------- void add_cells(int x, unsigned len, const void*) { add_span(x, len, 0); } //-------------------------------------------------------------------- void finalize(int y) { m_y = y; } //-------------------------------------------------------------------- void reset_spans() { m_last_x = 0x7FFFFFF0; m_spans.remove_all(); } //-------------------------------------------------------------------- int y() const { return m_y; } unsigned num_spans() const { return m_spans.size(); } const_iterator begin() const { return const_iterator(m_spans); } private: scanline32_bin(const scanline32_bin&); const scanline32_bin operator = (const scanline32_bin&); unsigned m_max_len; int m_last_x; int m_y; span_array_type m_spans; }; } #endif ragg/src/agg/include/agg_alpha_mask_u8.h0000644000176200001440000004425413504406270017657 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // scanline_u8 class // //---------------------------------------------------------------------------- #ifndef AGG_ALPHA_MASK_U8_INCLUDED #define AGG_ALPHA_MASK_U8_INCLUDED #include #include "agg_basics.h" #include "agg_rendering_buffer.h" namespace agg { //===================================================one_component_mask_u8 struct one_component_mask_u8 { static unsigned calculate(const int8u* p) { return *p; } }; //=====================================================rgb_to_gray_mask_u8 template struct rgb_to_gray_mask_u8 { static unsigned calculate(const int8u* p) { return (p[R]*77 + p[G]*150 + p[B]*29) >> 8; } }; //==========================================================alpha_mask_u8 template class alpha_mask_u8 { public: typedef int8u cover_type; typedef alpha_mask_u8 self_type; enum cover_scale_e { cover_shift = 8, cover_none = 0, cover_full = 255 }; alpha_mask_u8() : m_rbuf(0) {} explicit alpha_mask_u8(rendering_buffer& rbuf) : m_rbuf(&rbuf) {} void attach(rendering_buffer& rbuf) { m_rbuf = &rbuf; } MaskF& mask_function() { return m_mask_function; } const MaskF& mask_function() const { return m_mask_function; } //-------------------------------------------------------------------- cover_type pixel(int x, int y) const { if(x >= 0 && y >= 0 && x < (int)m_rbuf->width() && y < (int)m_rbuf->height()) { return (cover_type)m_mask_function.calculate( m_rbuf->row_ptr(y) + x * Step + Offset); } return 0; } //-------------------------------------------------------------------- cover_type combine_pixel(int x, int y, cover_type val) const { if(x >= 0 && y >= 0 && x < (int)m_rbuf->width() && y < (int)m_rbuf->height()) { return (cover_type)((cover_full + val * m_mask_function.calculate( m_rbuf->row_ptr(y) + x * Step + Offset)) >> cover_shift); } return 0; } //-------------------------------------------------------------------- void fill_hspan(int x, int y, cover_type* dst, int num_pix) const { int xmax = m_rbuf->width() - 1; int ymax = m_rbuf->height() - 1; int count = num_pix; cover_type* covers = dst; if(y < 0 || y > ymax) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } if(x < 0) { count += x; if(count <= 0) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } std::memset(covers, 0, -x * sizeof(cover_type)); covers -= x; x = 0; } if(x + count > xmax) { int rest = x + count - xmax - 1; count -= rest; if(count <= 0) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } std::memset(covers + count, 0, rest * sizeof(cover_type)); } const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; do { *covers++ = (cover_type)m_mask_function.calculate(mask); mask += Step; } while(--count); } //-------------------------------------------------------------------- void combine_hspan(int x, int y, cover_type* dst, int num_pix) const { int xmax = m_rbuf->width() - 1; int ymax = m_rbuf->height() - 1; int count = num_pix; cover_type* covers = dst; if(y < 0 || y > ymax) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } if(x < 0) { count += x; if(count <= 0) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } std::memset(covers, 0, -x * sizeof(cover_type)); covers -= x; x = 0; } if(x + count > xmax) { int rest = x + count - xmax - 1; count -= rest; if(count <= 0) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } std::memset(covers + count, 0, rest * sizeof(cover_type)); } const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; do { *covers = (cover_type)((cover_full + (*covers) * m_mask_function.calculate(mask)) >> cover_shift); ++covers; mask += Step; } while(--count); } //-------------------------------------------------------------------- void fill_vspan(int x, int y, cover_type* dst, int num_pix) const { int xmax = m_rbuf->width() - 1; int ymax = m_rbuf->height() - 1; int count = num_pix; cover_type* covers = dst; if(x < 0 || x > xmax) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } if(y < 0) { count += y; if(count <= 0) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } std::memset(covers, 0, -y * sizeof(cover_type)); covers -= y; y = 0; } if(y + count > ymax) { int rest = y + count - ymax - 1; count -= rest; if(count <= 0) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } std::memset(covers + count, 0, rest * sizeof(cover_type)); } const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; do { *covers++ = (cover_type)m_mask_function.calculate(mask); mask += m_rbuf->stride(); } while(--count); } //-------------------------------------------------------------------- void combine_vspan(int x, int y, cover_type* dst, int num_pix) const { int xmax = m_rbuf->width() - 1; int ymax = m_rbuf->height() - 1; int count = num_pix; cover_type* covers = dst; if(x < 0 || x > xmax) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } if(y < 0) { count += y; if(count <= 0) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } std::memset(covers, 0, -y * sizeof(cover_type)); covers -= y; y = 0; } if(y + count > ymax) { int rest = y + count - ymax - 1; count -= rest; if(count <= 0) { std::memset(dst, 0, num_pix * sizeof(cover_type)); return; } std::memset(covers + count, 0, rest * sizeof(cover_type)); } const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; do { *covers = (cover_type)((cover_full + (*covers) * m_mask_function.calculate(mask)) >> cover_shift); ++covers; mask += m_rbuf->stride(); } while(--count); } private: alpha_mask_u8(const self_type&); const self_type& operator = (const self_type&); rendering_buffer* m_rbuf; MaskF m_mask_function; }; typedef alpha_mask_u8<1, 0> alpha_mask_gray8; //----alpha_mask_gray8 typedef alpha_mask_u8<3, 0> alpha_mask_rgb24r; //----alpha_mask_rgb24r typedef alpha_mask_u8<3, 1> alpha_mask_rgb24g; //----alpha_mask_rgb24g typedef alpha_mask_u8<3, 2> alpha_mask_rgb24b; //----alpha_mask_rgb24b typedef alpha_mask_u8<3, 2> alpha_mask_bgr24r; //----alpha_mask_bgr24r typedef alpha_mask_u8<3, 1> alpha_mask_bgr24g; //----alpha_mask_bgr24g typedef alpha_mask_u8<3, 0> alpha_mask_bgr24b; //----alpha_mask_bgr24b typedef alpha_mask_u8<4, 0> alpha_mask_rgba32r; //----alpha_mask_rgba32r typedef alpha_mask_u8<4, 1> alpha_mask_rgba32g; //----alpha_mask_rgba32g typedef alpha_mask_u8<4, 2> alpha_mask_rgba32b; //----alpha_mask_rgba32b typedef alpha_mask_u8<4, 3> alpha_mask_rgba32a; //----alpha_mask_rgba32a typedef alpha_mask_u8<4, 1> alpha_mask_argb32r; //----alpha_mask_argb32r typedef alpha_mask_u8<4, 2> alpha_mask_argb32g; //----alpha_mask_argb32g typedef alpha_mask_u8<4, 3> alpha_mask_argb32b; //----alpha_mask_argb32b typedef alpha_mask_u8<4, 0> alpha_mask_argb32a; //----alpha_mask_argb32a typedef alpha_mask_u8<4, 2> alpha_mask_bgra32r; //----alpha_mask_bgra32r typedef alpha_mask_u8<4, 1> alpha_mask_bgra32g; //----alpha_mask_bgra32g typedef alpha_mask_u8<4, 0> alpha_mask_bgra32b; //----alpha_mask_bgra32b typedef alpha_mask_u8<4, 3> alpha_mask_bgra32a; //----alpha_mask_bgra32a typedef alpha_mask_u8<4, 3> alpha_mask_abgr32r; //----alpha_mask_abgr32r typedef alpha_mask_u8<4, 2> alpha_mask_abgr32g; //----alpha_mask_abgr32g typedef alpha_mask_u8<4, 1> alpha_mask_abgr32b; //----alpha_mask_abgr32b typedef alpha_mask_u8<4, 0> alpha_mask_abgr32a; //----alpha_mask_abgr32a typedef alpha_mask_u8<3, 0, rgb_to_gray_mask_u8<0, 1, 2> > alpha_mask_rgb24gray; //----alpha_mask_rgb24gray typedef alpha_mask_u8<3, 0, rgb_to_gray_mask_u8<2, 1, 0> > alpha_mask_bgr24gray; //----alpha_mask_bgr24gray typedef alpha_mask_u8<4, 0, rgb_to_gray_mask_u8<0, 1, 2> > alpha_mask_rgba32gray; //----alpha_mask_rgba32gray typedef alpha_mask_u8<4, 1, rgb_to_gray_mask_u8<0, 1, 2> > alpha_mask_argb32gray; //----alpha_mask_argb32gray typedef alpha_mask_u8<4, 0, rgb_to_gray_mask_u8<2, 1, 0> > alpha_mask_bgra32gray; //----alpha_mask_bgra32gray typedef alpha_mask_u8<4, 1, rgb_to_gray_mask_u8<2, 1, 0> > alpha_mask_abgr32gray; //----alpha_mask_abgr32gray //==========================================================amask_no_clip_u8 template class amask_no_clip_u8 { public: typedef int8u cover_type; typedef amask_no_clip_u8 self_type; enum cover_scale_e { cover_shift = 8, cover_none = 0, cover_full = 255 }; amask_no_clip_u8() : m_rbuf(0) {} explicit amask_no_clip_u8(rendering_buffer& rbuf) : m_rbuf(&rbuf) {} void attach(rendering_buffer& rbuf) { m_rbuf = &rbuf; } MaskF& mask_function() { return m_mask_function; } const MaskF& mask_function() const { return m_mask_function; } //-------------------------------------------------------------------- cover_type pixel(int x, int y) const { return (cover_type)m_mask_function.calculate( m_rbuf->row_ptr(y) + x * Step + Offset); } //-------------------------------------------------------------------- cover_type combine_pixel(int x, int y, cover_type val) const { return (cover_type)((cover_full + val * m_mask_function.calculate( m_rbuf->row_ptr(y) + x * Step + Offset)) >> cover_shift); } //-------------------------------------------------------------------- void fill_hspan(int x, int y, cover_type* dst, int num_pix) const { const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; do { *dst++ = (cover_type)m_mask_function.calculate(mask); mask += Step; } while(--num_pix); } //-------------------------------------------------------------------- void combine_hspan(int x, int y, cover_type* dst, int num_pix) const { const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; do { *dst = (cover_type)((cover_full + (*dst) * m_mask_function.calculate(mask)) >> cover_shift); ++dst; mask += Step; } while(--num_pix); } //-------------------------------------------------------------------- void fill_vspan(int x, int y, cover_type* dst, int num_pix) const { const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; do { *dst++ = (cover_type)m_mask_function.calculate(mask); mask += m_rbuf->stride(); } while(--num_pix); } //-------------------------------------------------------------------- void combine_vspan(int x, int y, cover_type* dst, int num_pix) const { const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; do { *dst = (cover_type)((cover_full + (*dst) * m_mask_function.calculate(mask)) >> cover_shift); ++dst; mask += m_rbuf->stride(); } while(--num_pix); } private: amask_no_clip_u8(const self_type&); const self_type& operator = (const self_type&); rendering_buffer* m_rbuf; MaskF m_mask_function; }; typedef amask_no_clip_u8<1, 0> amask_no_clip_gray8; //----amask_no_clip_gray8 typedef amask_no_clip_u8<3, 0> amask_no_clip_rgb24r; //----amask_no_clip_rgb24r typedef amask_no_clip_u8<3, 1> amask_no_clip_rgb24g; //----amask_no_clip_rgb24g typedef amask_no_clip_u8<3, 2> amask_no_clip_rgb24b; //----amask_no_clip_rgb24b typedef amask_no_clip_u8<3, 2> amask_no_clip_bgr24r; //----amask_no_clip_bgr24r typedef amask_no_clip_u8<3, 1> amask_no_clip_bgr24g; //----amask_no_clip_bgr24g typedef amask_no_clip_u8<3, 0> amask_no_clip_bgr24b; //----amask_no_clip_bgr24b typedef amask_no_clip_u8<4, 0> amask_no_clip_rgba32r; //----amask_no_clip_rgba32r typedef amask_no_clip_u8<4, 1> amask_no_clip_rgba32g; //----amask_no_clip_rgba32g typedef amask_no_clip_u8<4, 2> amask_no_clip_rgba32b; //----amask_no_clip_rgba32b typedef amask_no_clip_u8<4, 3> amask_no_clip_rgba32a; //----amask_no_clip_rgba32a typedef amask_no_clip_u8<4, 1> amask_no_clip_argb32r; //----amask_no_clip_argb32r typedef amask_no_clip_u8<4, 2> amask_no_clip_argb32g; //----amask_no_clip_argb32g typedef amask_no_clip_u8<4, 3> amask_no_clip_argb32b; //----amask_no_clip_argb32b typedef amask_no_clip_u8<4, 0> amask_no_clip_argb32a; //----amask_no_clip_argb32a typedef amask_no_clip_u8<4, 2> amask_no_clip_bgra32r; //----amask_no_clip_bgra32r typedef amask_no_clip_u8<4, 1> amask_no_clip_bgra32g; //----amask_no_clip_bgra32g typedef amask_no_clip_u8<4, 0> amask_no_clip_bgra32b; //----amask_no_clip_bgra32b typedef amask_no_clip_u8<4, 3> amask_no_clip_bgra32a; //----amask_no_clip_bgra32a typedef amask_no_clip_u8<4, 3> amask_no_clip_abgr32r; //----amask_no_clip_abgr32r typedef amask_no_clip_u8<4, 2> amask_no_clip_abgr32g; //----amask_no_clip_abgr32g typedef amask_no_clip_u8<4, 1> amask_no_clip_abgr32b; //----amask_no_clip_abgr32b typedef amask_no_clip_u8<4, 0> amask_no_clip_abgr32a; //----amask_no_clip_abgr32a typedef amask_no_clip_u8<3, 0, rgb_to_gray_mask_u8<0, 1, 2> > amask_no_clip_rgb24gray; //----amask_no_clip_rgb24gray typedef amask_no_clip_u8<3, 0, rgb_to_gray_mask_u8<2, 1, 0> > amask_no_clip_bgr24gray; //----amask_no_clip_bgr24gray typedef amask_no_clip_u8<4, 0, rgb_to_gray_mask_u8<0, 1, 2> > amask_no_clip_rgba32gray; //----amask_no_clip_rgba32gray typedef amask_no_clip_u8<4, 1, rgb_to_gray_mask_u8<0, 1, 2> > amask_no_clip_argb32gray; //----amask_no_clip_argb32gray typedef amask_no_clip_u8<4, 0, rgb_to_gray_mask_u8<2, 1, 0> > amask_no_clip_bgra32gray; //----amask_no_clip_bgra32gray typedef amask_no_clip_u8<4, 1, rgb_to_gray_mask_u8<2, 1, 0> > amask_no_clip_abgr32gray; //----amask_no_clip_abgr32gray } #endif ragg/src/agg/include/agg_conv_dash.h0000644000176200001440000000422213504406270017076 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // conv_dash // //---------------------------------------------------------------------------- #ifndef AGG_CONV_DASH_INCLUDED #define AGG_CONV_DASH_INCLUDED #include "agg_basics.h" #include "agg_vcgen_dash.h" #include "agg_conv_adaptor_vcgen.h" namespace agg { //---------------------------------------------------------------conv_dash template struct conv_dash : public conv_adaptor_vcgen { typedef Markers marker_type; typedef conv_adaptor_vcgen base_type; conv_dash(VertexSource& vs) : conv_adaptor_vcgen(vs) { } void remove_all_dashes() { base_type::generator().remove_all_dashes(); } void add_dash(double dash_len, double gap_len) { base_type::generator().add_dash(dash_len, gap_len); } void dash_start(double ds) { base_type::generator().dash_start(ds); } void shorten(double s) { base_type::generator().shorten(s); } double shorten() const { return base_type::generator().shorten(); } private: conv_dash(const conv_dash&); const conv_dash& operator = (const conv_dash&); }; } #endif ragg/src/agg/include/agg_gamma_functions.h0000644000176200001440000000666313504406270020317 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_GAMMA_FUNCTIONS_INCLUDED #define AGG_GAMMA_FUNCTIONS_INCLUDED #include "agg_basics.h" namespace agg { //===============================================================gamma_none struct gamma_none { double operator()(double x) const { return x; } }; //==============================================================gamma_power class gamma_power { public: gamma_power() : m_gamma(1.0) {} gamma_power(double g) : m_gamma(g) {} void gamma(double g) { m_gamma = g; } double gamma() const { return m_gamma; } double operator() (double x) const { return pow(x, m_gamma); } private: double m_gamma; }; //==========================================================gamma_threshold class gamma_threshold { public: gamma_threshold() : m_threshold(0.5) {} gamma_threshold(double t) : m_threshold(t) {} void threshold(double t) { m_threshold = t; } double threshold() const { return m_threshold; } double operator() (double x) const { return (x < m_threshold) ? 0.0 : 1.0; } private: double m_threshold; }; //============================================================gamma_linear class gamma_linear { public: gamma_linear() : m_start(0.0), m_end(1.0) {} gamma_linear(double s, double e) : m_start(s), m_end(e) {} void set(double s, double e) { m_start = s; m_end = e; } void start(double s) { m_start = s; } void end(double e) { m_end = e; } double start() const { return m_start; } double end() const { return m_end; } double operator() (double x) const { if(x < m_start) return 0.0; if(x > m_end) return 1.0; return (x - m_start) / (m_end - m_start); } private: double m_start; double m_end; }; //==========================================================gamma_multiply class gamma_multiply { public: gamma_multiply() : m_mul(1.0) {} gamma_multiply(double v) : m_mul(v) {} void value(double v) { m_mul = v; } double value() const { return m_mul; } double operator() (double x) const { double y = x * m_mul; if(y > 1.0) y = 1.0; return y; } private: double m_mul; }; inline double sRGB_to_linear(double x) { return (x <= 0.04045) ? (x / 12.92) : pow((x + 0.055) / (1.055), 2.4); } inline double linear_to_sRGB(double x) { return (x <= 0.0031308) ? (x * 12.92) : (1.055 * pow(x, 1 / 2.4) - 0.055); } } #endif ragg/src/agg/include/agg_glyph_raster_bin.h0000644000176200001440000001142313504406270020466 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_GLYPH_RASTER_BIN_INCLUDED #define AGG_GLYPH_RASTER_BIN_INCLUDED #include #include "agg_basics.h" namespace agg { //========================================================glyph_raster_bin template class glyph_raster_bin { public: typedef ColorT color_type; //-------------------------------------------------------------------- struct glyph_rect { int x1,y1,x2,y2; double dx, dy; }; //-------------------------------------------------------------------- glyph_raster_bin(const int8u* font) : m_font(font), m_big_endian(false) { int t = 1; if(*(char*)&t == 0) m_big_endian = true; std::memset(m_span, 0, sizeof(m_span)); } //-------------------------------------------------------------------- const int8u* font() const { return m_font; } void font(const int8u* f) { m_font = f; } //-------------------------------------------------------------------- double height() const { return m_font[0]; } double base_line() const { return m_font[1]; } //-------------------------------------------------------------------- template double width(const CharT* str) const { unsigned start_char = m_font[2]; unsigned num_chars = m_font[3]; unsigned w = 0; while(*str) { unsigned glyph = *str; const int8u* bits = m_font + 4 + num_chars * 2 + value(m_font + 4 + (glyph - start_char) * 2); w += *bits; ++str; } return w; } //-------------------------------------------------------------------- void prepare(glyph_rect* r, double x, double y, unsigned glyph, bool flip) { unsigned start_char = m_font[2]; unsigned num_chars = m_font[3]; m_bits = m_font + 4 + num_chars * 2 + value(m_font + 4 + (glyph - start_char) * 2); m_glyph_width = *m_bits++; m_glyph_byte_width = (m_glyph_width + 7) >> 3; r->x1 = int(x); r->x2 = r->x1 + m_glyph_width - 1; if(flip) { r->y1 = int(y) - m_font[0] + m_font[1]; r->y2 = r->y1 + m_font[0] - 1; } else { r->y1 = int(y) - m_font[1] + 1; r->y2 = r->y1 + m_font[0] - 1; } r->dx = m_glyph_width; r->dy = 0; } //-------------------------------------------------------------------- const cover_type* span(unsigned i) { i = m_font[0] - i - 1; const int8u* bits = m_bits + i * m_glyph_byte_width; unsigned j; unsigned val = *bits; unsigned nb = 0; for(j = 0; j < m_glyph_width; ++j) { m_span[j] = (cover_type)((val & 0x80) ? cover_full : cover_none); val <<= 1; if(++nb >= 8) { val = *++bits; nb = 0; } } return m_span; } private: //-------------------------------------------------------------------- int16u value(const int8u* p) const { int16u v; if(m_big_endian) { *(int8u*)&v = p[1]; *((int8u*)&v + 1) = p[0]; } else { *(int8u*)&v = p[0]; *((int8u*)&v + 1) = p[1]; } return v; } //-------------------------------------------------------------------- const int8u* m_font; bool m_big_endian; cover_type m_span[32]; const int8u* m_bits; unsigned m_glyph_width; unsigned m_glyph_byte_width; }; } #endif ragg/src/agg/include/agg_renderer_scanline.h0000644000176200001440000010272313504406270020621 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_RENDERER_SCANLINE_INCLUDED #define AGG_RENDERER_SCANLINE_INCLUDED #include #include #include #include "agg_basics.h" #include "agg_renderer_base.h" namespace agg { //================================================render_scanline_aa_solid template void render_scanline_aa_solid(const Scanline& sl, BaseRenderer& ren, const ColorT& color) { int y = sl.y(); unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { int x = span->x; if(span->len > 0) { ren.blend_solid_hspan(x, y, (unsigned)span->len, color, span->covers); } else { ren.blend_hline(x, y, (unsigned)(x - span->len - 1), color, *(span->covers)); } if(--num_spans == 0) break; ++span; } } //===============================================render_scanlines_aa_solid template void render_scanlines_aa_solid(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, const ColorT& color) { if(ras.rewind_scanlines()) { // Explicitly convert "color" to the BaseRenderer color type. // For example, it can be called with color type "rgba", while // "rgba8" is needed. Otherwise it will be implicitly // converted in the loop many times. //---------------------- typename BaseRenderer::color_type ren_color = color; sl.reset(ras.min_x(), ras.max_x()); while(ras.sweep_scanline(sl)) { //render_scanline_aa_solid(sl, ren, ren_color); // This code is equivalent to the above call (copy/paste). // It's just a "manual" optimization for old compilers, // like Microsoft Visual C++ v6.0 //------------------------------- int y = sl.y(); unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { int x = span->x; if(span->len > 0) { ren.blend_solid_hspan(x, y, (unsigned)span->len, ren_color, span->covers); } else { ren.blend_hline(x, y, (unsigned)(x - span->len - 1), ren_color, *(span->covers)); } if(--num_spans == 0) break; ++span; } } } } //==============================================renderer_scanline_aa_solid template class renderer_scanline_aa_solid { public: typedef BaseRenderer base_ren_type; typedef typename base_ren_type::color_type color_type; //-------------------------------------------------------------------- renderer_scanline_aa_solid() : m_ren(0) {} explicit renderer_scanline_aa_solid(base_ren_type& ren) : m_ren(&ren) {} void attach(base_ren_type& ren) { m_ren = &ren; } //-------------------------------------------------------------------- void color(const color_type& c) { m_color = c; } const color_type& color() const { return m_color; } //-------------------------------------------------------------------- void prepare() {} //-------------------------------------------------------------------- template void render(const Scanline& sl) { render_scanline_aa_solid(sl, *m_ren, m_color); } private: base_ren_type* m_ren; color_type m_color; }; //======================================================render_scanline_aa template void render_scanline_aa(const Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { int y = sl.y(); unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { int x = span->x; int len = span->len; const typename Scanline::cover_type* covers = span->covers; if(len < 0) len = -len; typename BaseRenderer::color_type* colors = alloc.allocate(len); span_gen.generate(colors, x, y, len); ren.blend_color_hspan(x, y, len, colors, (span->len < 0) ? 0 : covers, *covers); if(--num_spans == 0) break; ++span; } } //=====================================================render_scanlines_aa template void render_scanlines_aa(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { if(ras.rewind_scanlines()) { sl.reset(ras.min_x(), ras.max_x()); span_gen.prepare(); while(ras.sweep_scanline(sl)) { render_scanline_aa(sl, ren, alloc, span_gen); } } } //====================================================renderer_scanline_aa template class renderer_scanline_aa { public: typedef BaseRenderer base_ren_type; typedef SpanAllocator alloc_type; typedef SpanGenerator span_gen_type; //-------------------------------------------------------------------- renderer_scanline_aa() : m_ren(0), m_alloc(0), m_span_gen(0) {} renderer_scanline_aa(base_ren_type& ren, alloc_type& alloc, span_gen_type& span_gen) : m_ren(&ren), m_alloc(&alloc), m_span_gen(&span_gen) {} void attach(base_ren_type& ren, alloc_type& alloc, span_gen_type& span_gen) { m_ren = &ren; m_alloc = &alloc; m_span_gen = &span_gen; } //-------------------------------------------------------------------- void prepare() { m_span_gen->prepare(); } //-------------------------------------------------------------------- template void render(const Scanline& sl) { render_scanline_aa(sl, *m_ren, *m_alloc, *m_span_gen); } private: base_ren_type* m_ren; alloc_type* m_alloc; span_gen_type* m_span_gen; }; //===============================================render_scanline_bin_solid template void render_scanline_bin_solid(const Scanline& sl, BaseRenderer& ren, const ColorT& color) { unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { ren.blend_hline(span->x, sl.y(), span->x - 1 + ((span->len < 0) ? -span->len : span->len), color, cover_full); if(--num_spans == 0) break; ++span; } } //==============================================render_scanlines_bin_solid template void render_scanlines_bin_solid(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, const ColorT& color) { if(ras.rewind_scanlines()) { // Explicitly convert "color" to the BaseRenderer color type. // For example, it can be called with color type "rgba", while // "rgba8" is needed. Otherwise it will be implicitly // converted in the loop many times. //---------------------- typename BaseRenderer::color_type ren_color(color); sl.reset(ras.min_x(), ras.max_x()); while(ras.sweep_scanline(sl)) { //render_scanline_bin_solid(sl, ren, ren_color); // This code is equivalent to the above call (copy/paste). // It's just a "manual" optimization for old compilers, // like Microsoft Visual C++ v6.0 //------------------------------- unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { ren.blend_hline(span->x, sl.y(), span->x - 1 + ((span->len < 0) ? -span->len : span->len), ren_color, cover_full); if(--num_spans == 0) break; ++span; } } } } //=============================================renderer_scanline_bin_solid template class renderer_scanline_bin_solid { public: typedef BaseRenderer base_ren_type; typedef typename base_ren_type::color_type color_type; //-------------------------------------------------------------------- renderer_scanline_bin_solid() : m_ren(0) {} explicit renderer_scanline_bin_solid(base_ren_type& ren) : m_ren(&ren) {} void attach(base_ren_type& ren) { m_ren = &ren; } //-------------------------------------------------------------------- void color(const color_type& c) { m_color = c; } const color_type& color() const { return m_color; } //-------------------------------------------------------------------- void prepare() {} //-------------------------------------------------------------------- template void render(const Scanline& sl) { render_scanline_bin_solid(sl, *m_ren, m_color); } private: base_ren_type* m_ren; color_type m_color; }; //======================================================render_scanline_bin template void render_scanline_bin(const Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { int y = sl.y(); unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { int x = span->x; int len = span->len; if(len < 0) len = -len; typename BaseRenderer::color_type* colors = alloc.allocate(len); span_gen.generate(colors, x, y, len); ren.blend_color_hspan(x, y, len, colors, 0, cover_full); if(--num_spans == 0) break; ++span; } } //=====================================================render_scanlines_bin template void render_scanlines_bin(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { if(ras.rewind_scanlines()) { sl.reset(ras.min_x(), ras.max_x()); span_gen.prepare(); while(ras.sweep_scanline(sl)) { render_scanline_bin(sl, ren, alloc, span_gen); } } } //====================================================renderer_scanline_bin template class renderer_scanline_bin { public: typedef BaseRenderer base_ren_type; typedef SpanAllocator alloc_type; typedef SpanGenerator span_gen_type; //-------------------------------------------------------------------- renderer_scanline_bin() : m_ren(0), m_alloc(0), m_span_gen(0) {} renderer_scanline_bin(base_ren_type& ren, alloc_type& alloc, span_gen_type& span_gen) : m_ren(&ren), m_alloc(&alloc), m_span_gen(&span_gen) {} void attach(base_ren_type& ren, alloc_type& alloc, span_gen_type& span_gen) { m_ren = &ren; m_alloc = &alloc; m_span_gen = &span_gen; } //-------------------------------------------------------------------- void prepare() { m_span_gen->prepare(); } //-------------------------------------------------------------------- template void render(const Scanline& sl) { render_scanline_bin(sl, *m_ren, *m_alloc, *m_span_gen); } private: base_ren_type* m_ren; alloc_type* m_alloc; span_gen_type* m_span_gen; }; //========================================================render_scanlines template void render_scanlines(Rasterizer& ras, Scanline& sl, Renderer& ren) { if(ras.rewind_scanlines()) { sl.reset(ras.min_x(), ras.max_x()); ren.prepare(); while(ras.sweep_scanline(sl)) { ren.render(sl); } } } //========================================================render_all_paths template void render_all_paths(Rasterizer& ras, Scanline& sl, Renderer& r, VertexSource& vs, const ColorStorage& as, const PathId& path_id, unsigned num_paths) { for(unsigned i = 0; i < num_paths; i++) { ras.reset(); ras.add_path(vs, path_id[i]); r.color(as[i]); render_scanlines(ras, sl, r); } } //=============================================render_scanlines_compound template void render_scanlines_compound(Rasterizer& ras, ScanlineAA& sl_aa, ScanlineBin& sl_bin, BaseRenderer& ren, SpanAllocator& alloc, StyleHandler& sh) { if(ras.rewind_scanlines()) { int min_x = ras.min_x(); int len = ras.max_x() - min_x + 2; sl_aa.reset(min_x, ras.max_x()); sl_bin.reset(min_x, ras.max_x()); typedef typename BaseRenderer::color_type color_type; color_type* color_span = alloc.allocate(len * 2); color_type* mix_buffer = color_span + len; unsigned num_spans; unsigned num_styles; unsigned style; bool solid; while((num_styles = ras.sweep_styles()) > 0) { typename ScanlineAA::const_iterator span_aa; if(num_styles == 1) { // Optimization for a single style. Happens often //------------------------- if(ras.sweep_scanline(sl_aa, 0)) { style = ras.style(0); if(sh.is_solid(style)) { // Just solid fill //----------------------- render_scanline_aa_solid(sl_aa, ren, sh.color(style)); } else { // Arbitrary span generator //----------------------- span_aa = sl_aa.begin(); num_spans = sl_aa.num_spans(); for(;;) { len = span_aa->len; sh.generate_span(color_span, span_aa->x, sl_aa.y(), len, style); ren.blend_color_hspan(span_aa->x, sl_aa.y(), span_aa->len, color_span, span_aa->covers); if(--num_spans == 0) break; ++span_aa; } } } } else { if(ras.sweep_scanline(sl_bin, -1)) { // Clear the spans of the mix_buffer //-------------------- typename ScanlineBin::const_iterator span_bin = sl_bin.begin(); num_spans = sl_bin.num_spans(); for(;;) { std::memset(mix_buffer + span_bin->x - min_x, 0, span_bin->len * sizeof(color_type)); if(--num_spans == 0) break; ++span_bin; } unsigned i; for(i = 0; i < num_styles; i++) { style = ras.style(i); solid = sh.is_solid(style); if(ras.sweep_scanline(sl_aa, i)) { color_type* colors; color_type* cspan; typename ScanlineAA::cover_type* covers; span_aa = sl_aa.begin(); num_spans = sl_aa.num_spans(); if(solid) { // Just solid fill //----------------------- for(;;) { color_type c = sh.color(style); len = span_aa->len; colors = mix_buffer + span_aa->x - min_x; covers = span_aa->covers; do { if(*covers == cover_full) { *colors = c; } else { colors->add(c, *covers); } ++colors; ++covers; } while(--len); if(--num_spans == 0) break; ++span_aa; } } else { // Arbitrary span generator //----------------------- for(;;) { len = span_aa->len; colors = mix_buffer + span_aa->x - min_x; cspan = color_span; sh.generate_span(cspan, span_aa->x, sl_aa.y(), len, style); covers = span_aa->covers; do { if(*covers == cover_full) { *colors = *cspan; } else { colors->add(*cspan, *covers); } ++cspan; ++colors; ++covers; } while(--len); if(--num_spans == 0) break; ++span_aa; } } } } // Emit the blended result as a color hspan //------------------------- span_bin = sl_bin.begin(); num_spans = sl_bin.num_spans(); for(;;) { ren.blend_color_hspan(span_bin->x, sl_bin.y(), span_bin->len, mix_buffer + span_bin->x - min_x, 0, cover_full); if(--num_spans == 0) break; ++span_bin; } } // if(ras.sweep_scanline(sl_bin, -1)) } // if(num_styles == 1) ... else } // while((num_styles = ras.sweep_styles()) > 0) } // if(ras.rewind_scanlines()) } //=======================================render_scanlines_compound_layered template void render_scanlines_compound_layered(Rasterizer& ras, ScanlineAA& sl_aa, BaseRenderer& ren, SpanAllocator& alloc, StyleHandler& sh) { if(ras.rewind_scanlines()) { int min_x = ras.min_x(); int len = ras.max_x() - min_x + 2; sl_aa.reset(min_x, ras.max_x()); typedef typename BaseRenderer::color_type color_type; color_type* color_span = alloc.allocate(len * 2); color_type* mix_buffer = color_span + len; cover_type* cover_buffer = ras.allocate_cover_buffer(len); unsigned num_spans; unsigned num_styles; unsigned style; bool solid; while((num_styles = ras.sweep_styles()) > 0) { typename ScanlineAA::const_iterator span_aa; if(num_styles == 1) { // Optimization for a single style. Happens often //------------------------- if(ras.sweep_scanline(sl_aa, 0)) { style = ras.style(0); if(sh.is_solid(style)) { // Just solid fill //----------------------- render_scanline_aa_solid(sl_aa, ren, sh.color(style)); } else { // Arbitrary span generator //----------------------- span_aa = sl_aa.begin(); num_spans = sl_aa.num_spans(); for(;;) { len = span_aa->len; sh.generate_span(color_span, span_aa->x, sl_aa.y(), len, style); ren.blend_color_hspan(span_aa->x, sl_aa.y(), span_aa->len, color_span, span_aa->covers); if(--num_spans == 0) break; ++span_aa; } } } } else { int sl_start = ras.scanline_start(); unsigned sl_len = ras.scanline_length(); if(sl_len) { std::memset(mix_buffer + sl_start - min_x, 0, sl_len * sizeof(color_type)); std::memset(cover_buffer + sl_start - min_x, 0, sl_len * sizeof(cover_type)); int sl_y = std::numeric_limits::max(); unsigned i; for(i = 0; i < num_styles; i++) { style = ras.style(i); solid = sh.is_solid(style); if(ras.sweep_scanline(sl_aa, i)) { unsigned cover; color_type* colors; color_type* cspan; cover_type* src_covers; cover_type* dst_covers; span_aa = sl_aa.begin(); num_spans = sl_aa.num_spans(); sl_y = sl_aa.y(); if(solid) { // Just solid fill //----------------------- for(;;) { color_type c = sh.color(style); len = span_aa->len; colors = mix_buffer + span_aa->x - min_x; src_covers = span_aa->covers; dst_covers = cover_buffer + span_aa->x - min_x; do { cover = *src_covers; if(*dst_covers + cover > cover_full) { cover = cover_full - *dst_covers; } if(cover) { colors->add(c, cover); *dst_covers += cover; } ++colors; ++src_covers; ++dst_covers; } while(--len); if(--num_spans == 0) break; ++span_aa; } } else { // Arbitrary span generator //----------------------- for(;;) { len = span_aa->len; colors = mix_buffer + span_aa->x - min_x; cspan = color_span; sh.generate_span(cspan, span_aa->x, sl_aa.y(), len, style); src_covers = span_aa->covers; dst_covers = cover_buffer + span_aa->x - min_x; do { cover = *src_covers; if(*dst_covers + cover > cover_full) { cover = cover_full - *dst_covers; } if(cover) { colors->add(*cspan, cover); *dst_covers += cover; } ++cspan; ++colors; ++src_covers; ++dst_covers; } while(--len); if(--num_spans == 0) break; ++span_aa; } } } } ren.blend_color_hspan(sl_start, sl_y, sl_len, mix_buffer + sl_start - min_x, 0, cover_full); } //if(sl_len) } //if(num_styles == 1) ... else } //while((num_styles = ras.sweep_styles()) > 0) } //if(ras.rewind_scanlines()) } } #endif ragg/src/agg/include/agg_conv_unclose_polygon.h0000644000176200001440000000325413504406270021402 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_CONV_UNCLOSE_POLYGON_INCLUDED #define AGG_CONV_UNCLOSE_POLYGON_INCLUDED #include "agg_basics.h" namespace agg { //====================================================conv_unclose_polygon template class conv_unclose_polygon { public: explicit conv_unclose_polygon(VertexSource& vs) : m_source(&vs) {} void attach(VertexSource& source) { m_source = &source; } void rewind(unsigned path_id) { m_source->rewind(path_id); } unsigned vertex(double* x, double* y) { unsigned cmd = m_source->vertex(x, y); if(is_end_poly(cmd)) cmd &= ~path_flags_close; return cmd; } private: conv_unclose_polygon(const conv_unclose_polygon&); const conv_unclose_polygon& operator = (const conv_unclose_polygon&); VertexSource* m_source; }; } #endif ragg/src/agg/include/agg_vcgen_dash.h0000644000176200001440000000512313504406270017234 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Line dash generator // //---------------------------------------------------------------------------- #ifndef AGG_VCGEN_DASH_INCLUDED #define AGG_VCGEN_DASH_INCLUDED #include "agg_basics.h" #include "agg_vertex_sequence.h" namespace agg { //---------------------------------------------------------------vcgen_dash // // See Implementation agg_vcgen_dash.cpp // class vcgen_dash { enum max_dashes_e { max_dashes = 32 }; enum status_e { initial, ready, polyline, stop }; public: typedef vertex_sequence vertex_storage; vcgen_dash(); void remove_all_dashes(); void add_dash(double dash_len, double gap_len); void dash_start(double ds); void shorten(double s) { m_shorten = s; } double shorten() const { return m_shorten; } // Vertex Generator Interface void remove_all(); void add_vertex(double x, double y, unsigned cmd); // Vertex Source Interface void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: vcgen_dash(const vcgen_dash&); const vcgen_dash& operator = (const vcgen_dash&); void calc_dash_start(double ds); double m_dashes[max_dashes]; double m_total_dash_len; unsigned m_num_dashes; double m_dash_start; double m_shorten; double m_curr_dash_start; unsigned m_curr_dash; double m_curr_rest; const vertex_dist* m_v1; const vertex_dist* m_v2; vertex_storage m_src_vertices; unsigned m_closed; status_e m_status; unsigned m_src_vertex; }; } #endif ragg/src/agg/include/agg_font_cache_manager2.h0000644000176200001440000002140013504406270020774 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_FONT_CACHE_MANAGER2_INCLUDED #define AGG_FONT_CACHE_MANAGER2_INCLUDED #include #include #include #include "agg_array.h" namespace agg { namespace fman { //---------------------------------------------------------glyph_data_type enum glyph_data_type { glyph_data_invalid = 0, glyph_data_mono = 1, glyph_data_gray8 = 2, glyph_data_outline = 3 }; //-------------------------------------------------------------cached_glyph struct cached_glyph { void * cached_font; unsigned glyph_code; unsigned glyph_index; int8u* data; unsigned data_size; glyph_data_type data_type; rect_i bounds; double advance_x; double advance_y; }; //--------------------------------------------------------------cached_glyphs class cached_glyphs { public: enum block_size_e { block_size = 16384-16 }; //-------------------------------------------------------------------- cached_glyphs() : m_allocator(block_size) { std::memset(m_glyphs, 0, sizeof(m_glyphs)); } //-------------------------------------------------------------------- const cached_glyph* find_glyph(unsigned glyph_code) const { unsigned msb = (glyph_code >> 8) & 0xFF; if(m_glyphs[msb]) { return m_glyphs[msb][glyph_code & 0xFF]; } return 0; } //-------------------------------------------------------------------- cached_glyph* cache_glyph( void * cached_font, unsigned glyph_code, unsigned glyph_index, unsigned data_size, glyph_data_type data_type, const rect_i& bounds, double advance_x, double advance_y) { unsigned msb = (glyph_code >> 8) & 0xFF; if(m_glyphs[msb] == 0) { m_glyphs[msb] = (cached_glyph**)m_allocator.allocate(sizeof(cached_glyph*) * 256, sizeof(cached_glyph*)); std::memset(m_glyphs[msb], 0, sizeof(cached_glyph*) * 256); } unsigned lsb = glyph_code & 0xFF; if(m_glyphs[msb][lsb]) return 0; // Already exists, do not overwrite cached_glyph* glyph = (cached_glyph*)m_allocator.allocate(sizeof(cached_glyph), sizeof(double)); glyph->cached_font = cached_font; glyph->glyph_code = glyph_code; glyph->glyph_index = glyph_index; glyph->data = m_allocator.allocate(data_size); glyph->data_size = data_size; glyph->data_type = data_type; glyph->bounds = bounds; glyph->advance_x = advance_x; glyph->advance_y = advance_y; return m_glyphs[msb][lsb] = glyph; } private: block_allocator m_allocator; cached_glyph** m_glyphs[256]; }; //------------------------------------------------------------------------ enum glyph_rendering { glyph_ren_native_mono, glyph_ren_native_gray8, glyph_ren_outline, glyph_ren_agg_mono, glyph_ren_agg_gray8 }; //------------------------------------------------------font_cache_manager template class font_cache_manager { public: typedef FontEngine font_engine_type; typedef font_cache_manager self_type; typedef typename font_engine_type::path_adaptor_type path_adaptor_type; typedef typename font_engine_type::gray8_adaptor_type gray8_adaptor_type; typedef typename gray8_adaptor_type::embedded_scanline gray8_scanline_type; typedef typename font_engine_type::mono_adaptor_type mono_adaptor_type; typedef typename mono_adaptor_type::embedded_scanline mono_scanline_type; struct cached_font { cached_font( font_engine_type& engine, typename FontEngine::loaded_face *face, double height, double width, bool hinting, glyph_rendering rendering ) : m_engine( engine ) , m_face( face ) , m_height( height ) , m_width( width ) , m_hinting( hinting ) , m_rendering( rendering ) { select_face(); m_face_height=m_face->height(); m_face_width=m_face->width(); m_face_ascent=m_face->ascent(); m_face_descent=m_face->descent(); m_face_ascent_b=m_face->ascent_b(); m_face_descent_b=m_face->descent_b(); } double height() const { return m_face_height; } double width() const { return m_face_width; } double ascent() const { return m_face_ascent; } double descent() const { return m_face_descent; } double ascent_b() const { return m_face_ascent_b; } double descent_b() const { return m_face_descent_b; } bool add_kerning( const cached_glyph *first, const cached_glyph *second, double* x, double* y) { if( !first || !second ) return false; select_face(); return m_face->add_kerning( first->glyph_index, second->glyph_index, x, y ); } void select_face() { m_face->select_instance( m_height, m_width, m_hinting, m_rendering ); } const cached_glyph *get_glyph(unsigned cp) { const cached_glyph *glyph=m_glyphs.find_glyph(cp); if( glyph==0 ) { typename FontEngine::prepared_glyph prepared; select_face(); bool success=m_face->prepare_glyph(cp, &prepared); if( success ) { glyph=m_glyphs.cache_glyph( this, prepared.glyph_code, prepared.glyph_index, prepared.data_size, prepared.data_type, prepared.bounds, prepared.advance_x, prepared.advance_y ); assert( glyph!=0 ); m_face->write_glyph_to(&prepared,glyph->data); } } return glyph; } font_engine_type& m_engine; typename FontEngine::loaded_face *m_face; double m_height; double m_width; bool m_hinting; glyph_rendering m_rendering; double m_face_height; double m_face_width; double m_face_ascent; double m_face_descent; double m_face_ascent_b; double m_face_descent_b; cached_glyphs m_glyphs; }; //-------------------------------------------------------------------- font_cache_manager(font_engine_type& engine, unsigned max_fonts=32) :m_engine(engine) { } //-------------------------------------------------------------------- void init_embedded_adaptors(const cached_glyph* gl, double x, double y, double scale=1.0) { if(gl) { switch(gl->data_type) { default: return; case glyph_data_mono: m_mono_adaptor.init(gl->data, gl->data_size, x, y); break; case glyph_data_gray8: m_gray8_adaptor.init(gl->data, gl->data_size, x, y); break; case glyph_data_outline: m_path_adaptor.init(gl->data, gl->data_size, x, y, scale); break; } } } //-------------------------------------------------------------------- path_adaptor_type& path_adaptor() { return m_path_adaptor; } gray8_adaptor_type& gray8_adaptor() { return m_gray8_adaptor; } gray8_scanline_type& gray8_scanline() { return m_gray8_scanline; } mono_adaptor_type& mono_adaptor() { return m_mono_adaptor; } mono_scanline_type& mono_scanline() { return m_mono_scanline; } private: //-------------------------------------------------------------------- font_cache_manager(const self_type&); const self_type& operator = (const self_type&); font_engine_type& m_engine; path_adaptor_type m_path_adaptor; gray8_adaptor_type m_gray8_adaptor; gray8_scanline_type m_gray8_scanline; mono_adaptor_type m_mono_adaptor; mono_scanline_type m_mono_scanline; }; } } #endif ragg/src/agg/include/agg_color_rgba.h0000644000176200001440000012726613654206404017264 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_COLOR_RGBA_INCLUDED #define AGG_COLOR_RGBA_INCLUDED #include #include "agg_basics.h" #include "agg_gamma_lut.h" namespace agg { // Supported component orders for RGB and RGBA pixel formats //======================================================================= struct order_rgb { enum rgb_e { R=0, G=1, B=2, N=3 }; }; struct order_bgr { enum bgr_e { B=0, G=1, R=2, N=3 }; }; struct order_rgba { enum rgba_e { R=0, G=1, B=2, A=3, N=4 }; }; struct order_argb { enum argb_e { A=0, R=1, G=2, B=3, N=4 }; }; struct order_abgr { enum abgr_e { A=0, B=1, G=2, R=3, N=4 }; }; struct order_bgra { enum bgra_e { B=0, G=1, R=2, A=3, N=4 }; }; // Colorspace tag types. struct linear {}; struct sRGB {}; //====================================================================rgba struct rgba { typedef double value_type; double r; double g; double b; double a; //-------------------------------------------------------------------- rgba() {} //-------------------------------------------------------------------- rgba(double r_, double g_, double b_, double a_=1.0) : r(r_), g(g_), b(b_), a(a_) {} //-------------------------------------------------------------------- rgba(const rgba& c, double a_) : r(c.r), g(c.g), b(c.b), a(a_) {} //-------------------------------------------------------------------- rgba& clear() { r = g = b = a = 0; return *this; } //-------------------------------------------------------------------- rgba& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- rgba& opacity(double a_) { if (a_ < 0) a = 0; else if (a_ > 1) a = 1; else a = a_; return *this; } //-------------------------------------------------------------------- double opacity() const { return a; } //-------------------------------------------------------------------- rgba& premultiply() { r *= a; g *= a; b *= a; return *this; } //-------------------------------------------------------------------- rgba& premultiply(double a_) { if (a <= 0 || a_ <= 0) { r = g = b = a = 0; } else { a_ /= a; r *= a_; g *= a_; b *= a_; a = a_; } return *this; } //-------------------------------------------------------------------- rgba& demultiply() { if (a == 0) { r = g = b = 0; } else { double a_ = 1.0 / a; r *= a_; g *= a_; b *= a_; } return *this; } //-------------------------------------------------------------------- rgba gradient(rgba c, double k) const { rgba ret; ret.r = r + (c.r - r) * k; ret.g = g + (c.g - g) * k; ret.b = b + (c.b - b) * k; ret.a = a + (c.a - a) * k; return ret; } rgba& operator+=(const rgba& c) { r += c.r; g += c.g; b += c.b; a += c.a; return *this; } rgba& operator*=(double k) { r *= k; g *= k; b *= k; a *= k; return *this; } //-------------------------------------------------------------------- static rgba no_color() { return rgba(0,0,0,0); } //-------------------------------------------------------------------- static rgba from_wavelength(double wl, double gamma = 1.0); //-------------------------------------------------------------------- explicit rgba(double wavelen, double gamma=1.0) { *this = from_wavelength(wavelen, gamma); } }; inline rgba operator+(const rgba& a, const rgba& b) { return rgba(a) += b; } inline rgba operator*(const rgba& a, double b) { return rgba(a) *= b; } //------------------------------------------------------------------------ inline rgba rgba::from_wavelength(double wl, double gamma) { rgba t(0.0, 0.0, 0.0); if (wl >= 380.0 && wl <= 440.0) { t.r = -1.0 * (wl - 440.0) / (440.0 - 380.0); t.b = 1.0; } else if (wl >= 440.0 && wl <= 490.0) { t.g = (wl - 440.0) / (490.0 - 440.0); t.b = 1.0; } else if (wl >= 490.0 && wl <= 510.0) { t.g = 1.0; t.b = -1.0 * (wl - 510.0) / (510.0 - 490.0); } else if (wl >= 510.0 && wl <= 580.0) { t.r = (wl - 510.0) / (580.0 - 510.0); t.g = 1.0; } else if (wl >= 580.0 && wl <= 645.0) { t.r = 1.0; t.g = -1.0 * (wl - 645.0) / (645.0 - 580.0); } else if (wl >= 645.0 && wl <= 780.0) { t.r = 1.0; } double s = 1.0; if (wl > 700.0) s = 0.3 + 0.7 * (780.0 - wl) / (780.0 - 700.0); else if (wl < 420.0) s = 0.3 + 0.7 * (wl - 380.0) / (420.0 - 380.0); t.r = std::pow(t.r * s, gamma); t.g = std::pow(t.g * s, gamma); t.b = std::pow(t.b * s, gamma); return t; } inline rgba rgba_pre(double r, double g, double b, double a) { return rgba(r, g, b, a).premultiply(); } //===================================================================rgba8 template struct rgba8T { typedef int8u value_type; typedef int32u calc_type; typedef int32 long_type; enum base_scale_e { base_shift = 8, base_scale = 1 << base_shift, base_mask = base_scale - 1, base_MSB = 1 << (base_shift - 1) }; typedef rgba8T self_type; value_type r; value_type g; value_type b; value_type a; static void convert(rgba8T& dst, const rgba8T& src) { dst.r = sRGB_conv::rgb_from_sRGB(src.r); dst.g = sRGB_conv::rgb_from_sRGB(src.g); dst.b = sRGB_conv::rgb_from_sRGB(src.b); dst.a = src.a; } static void convert(rgba8T& dst, const rgba8T& src) { dst.r = sRGB_conv::rgb_to_sRGB(src.r); dst.g = sRGB_conv::rgb_to_sRGB(src.g); dst.b = sRGB_conv::rgb_to_sRGB(src.b); dst.a = src.a; } static void convert(rgba8T& dst, const rgba& src) { dst.r = value_type(uround(src.r * base_mask)); dst.g = value_type(uround(src.g * base_mask)); dst.b = value_type(uround(src.b * base_mask)); dst.a = value_type(uround(src.a * base_mask)); } static void convert(rgba8T& dst, const rgba& src) { // Use the "float" table. dst.r = sRGB_conv::rgb_to_sRGB(float(src.r)); dst.g = sRGB_conv::rgb_to_sRGB(float(src.g)); dst.b = sRGB_conv::rgb_to_sRGB(float(src.b)); dst.a = sRGB_conv::alpha_to_sRGB(float(src.a)); } static void convert(rgba& dst, const rgba8T& src) { dst.r = src.r / 255.0; dst.g = src.g / 255.0; dst.b = src.b / 255.0; dst.a = src.a / 255.0; } static void convert(rgba& dst, const rgba8T& src) { // Use the "float" table. dst.r = sRGB_conv::rgb_from_sRGB(src.r); dst.g = sRGB_conv::rgb_from_sRGB(src.g); dst.b = sRGB_conv::rgb_from_sRGB(src.b); dst.a = sRGB_conv::alpha_from_sRGB(src.a); } //-------------------------------------------------------------------- rgba8T() {} //-------------------------------------------------------------------- rgba8T(unsigned r_, unsigned g_, unsigned b_, unsigned a_ = base_mask) : r(value_type(r_)), g(value_type(g_)), b(value_type(b_)), a(value_type(a_)) {} //-------------------------------------------------------------------- rgba8T(const rgba& c) { convert(*this, c); } //-------------------------------------------------------------------- rgba8T(const self_type& c, unsigned a_) : r(c.r), g(c.g), b(c.b), a(value_type(a_)) {} //-------------------------------------------------------------------- template rgba8T(const rgba8T& c) { convert(*this, c); } //-------------------------------------------------------------------- operator rgba() const { rgba c; convert(c, *this); return c; } //-------------------------------------------------------------------- static AGG_INLINE double to_double(value_type a) { return double(a) / base_mask; } //-------------------------------------------------------------------- static AGG_INLINE value_type from_double(double a) { return value_type(uround(a * base_mask)); } //-------------------------------------------------------------------- static AGG_INLINE value_type empty_value() { return 0; } //-------------------------------------------------------------------- static AGG_INLINE value_type full_value() { return base_mask; } //-------------------------------------------------------------------- AGG_INLINE bool is_transparent() const { return a == 0; } //-------------------------------------------------------------------- AGG_INLINE bool is_opaque() const { return a == base_mask; } //-------------------------------------------------------------------- static AGG_INLINE value_type invert(value_type x) { return base_mask - x; } //-------------------------------------------------------------------- // Fixed-point multiply, exact over int8u. static AGG_INLINE value_type multiply(value_type a, value_type b) { calc_type t = a * b + base_MSB; return value_type(((t >> base_shift) + t) >> base_shift); } //-------------------------------------------------------------------- static AGG_INLINE value_type demultiply(value_type a, value_type b) { if (a * b == 0) { return 0; } else if (a >= b) { return base_mask; } else return value_type((a * base_mask + (b >> 1)) / b); } //-------------------------------------------------------------------- template static AGG_INLINE T downscale(T a) { return a >> base_shift; } //-------------------------------------------------------------------- template static AGG_INLINE T downshift(T a, unsigned n) { return a >> n; } //-------------------------------------------------------------------- // Fixed-point multiply, exact over int8u. // Specifically for multiplying a color component by a cover. static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return multiply(a, b); } //-------------------------------------------------------------------- static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return multiply(b, a); } //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return p + q - multiply(p, a); } //-------------------------------------------------------------------- // Interpolate p to q by a. static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { int t = (q - p) * a + base_MSB - (p > q); return value_type(p + (((t >> base_shift) + t) >> base_shift)); } //-------------------------------------------------------------------- self_type& clear() { r = g = b = a = 0; return *this; } //-------------------------------------------------------------------- self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- self_type& opacity(double a_) { if (a_ < 0) a = 0; else if (a_ > 1) a = 1; else a = (value_type)uround(a_ * double(base_mask)); return *this; } //-------------------------------------------------------------------- double opacity() const { return double(a) / double(base_mask); } //-------------------------------------------------------------------- AGG_INLINE self_type& premultiply() { if (a != base_mask) { if (a == 0) { r = g = b = 0; } else { r = multiply(r, a); g = multiply(g, a); b = multiply(b, a); } } return *this; } //-------------------------------------------------------------------- AGG_INLINE self_type& premultiply(unsigned a_) { if (a != base_mask || a_ < base_mask) { if (a == 0 || a_ == 0) { r = g = b = a = 0; } else { calc_type r_ = (calc_type(r) * a_) / a; calc_type g_ = (calc_type(g) * a_) / a; calc_type b_ = (calc_type(b) * a_) / a; r = value_type((r_ > a_) ? a_ : r_); g = value_type((g_ > a_) ? a_ : g_); b = value_type((b_ > a_) ? a_ : b_); a = value_type(a_); } } return *this; } //-------------------------------------------------------------------- AGG_INLINE self_type& demultiply() { if (a < base_mask) { if (a == 0) { r = g = b = 0; } else { calc_type r_ = (calc_type(r) * base_mask) / a; calc_type g_ = (calc_type(g) * base_mask) / a; calc_type b_ = (calc_type(b) * base_mask) / a; r = value_type((r_ > calc_type(base_mask)) ? calc_type(base_mask) : r_); g = value_type((g_ > calc_type(base_mask)) ? calc_type(base_mask) : g_); b = value_type((b_ > calc_type(base_mask)) ? calc_type(base_mask) : b_); } } return *this; } //-------------------------------------------------------------------- AGG_INLINE self_type gradient(const self_type& c, double k) const { self_type ret; calc_type ik = uround(k * base_mask); ret.r = lerp(r, c.r, ik); ret.g = lerp(g, c.g, ik); ret.b = lerp(b, c.b, ik); ret.a = lerp(a, c.a, ik); return ret; } //-------------------------------------------------------------------- AGG_INLINE void add(const self_type& c, unsigned cover) { calc_type cr, cg, cb, ca; if (cover == cover_mask) { if (c.a == base_mask) { *this = c; return; } else { cr = r + c.r; cg = g + c.g; cb = b + c.b; ca = a + c.a; } } else { cr = r + mult_cover(c.r, cover); cg = g + mult_cover(c.g, cover); cb = b + mult_cover(c.b, cover); ca = a + mult_cover(c.a, cover); } r = (value_type)((cr > calc_type(base_mask)) ? calc_type(base_mask) : cr); g = (value_type)((cg > calc_type(base_mask)) ? calc_type(base_mask) : cg); b = (value_type)((cb > calc_type(base_mask)) ? calc_type(base_mask) : cb); a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca); } //-------------------------------------------------------------------- template AGG_INLINE void apply_gamma_dir(const GammaLUT& gamma) { r = gamma.dir(r); g = gamma.dir(g); b = gamma.dir(b); } //-------------------------------------------------------------------- template AGG_INLINE void apply_gamma_inv(const GammaLUT& gamma) { r = gamma.inv(r); g = gamma.inv(g); b = gamma.inv(b); } //-------------------------------------------------------------------- static self_type no_color() { return self_type(0,0,0,0); } //-------------------------------------------------------------------- static self_type from_wavelength(double wl, double gamma = 1.0) { return self_type(rgba::from_wavelength(wl, gamma)); } }; typedef rgba8T rgba8; typedef rgba8T srgba8; //-------------------------------------------------------------rgb8_packed inline rgba8 rgb8_packed(unsigned v) { return rgba8((v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); } //-------------------------------------------------------------bgr8_packed inline rgba8 bgr8_packed(unsigned v) { return rgba8(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF); } //------------------------------------------------------------argb8_packed inline rgba8 argb8_packed(unsigned v) { return rgba8((v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF, v >> 24); } //---------------------------------------------------------rgba8_gamma_dir template rgba8 rgba8_gamma_dir(rgba8 c, const GammaLUT& gamma) { return rgba8(gamma.dir(c.r), gamma.dir(c.g), gamma.dir(c.b), c.a); } //---------------------------------------------------------rgba8_gamma_inv template rgba8 rgba8_gamma_inv(rgba8 c, const GammaLUT& gamma) { return rgba8(gamma.inv(c.r), gamma.inv(c.g), gamma.inv(c.b), c.a); } //==================================================================rgba16 struct rgba16 { typedef int16u value_type; typedef int32u calc_type; typedef int64 long_type; enum base_scale_e { base_shift = 16, base_scale = 1 << base_shift, base_mask = base_scale - 1, base_MSB = 1 << (base_shift - 1) }; typedef rgba16 self_type; value_type r; value_type g; value_type b; value_type a; //-------------------------------------------------------------------- rgba16() {} //-------------------------------------------------------------------- rgba16(unsigned r_, unsigned g_, unsigned b_, unsigned a_=base_mask) : r(value_type(r_)), g(value_type(g_)), b(value_type(b_)), a(value_type(a_)) {} //-------------------------------------------------------------------- rgba16(const self_type& c, unsigned a_) : r(c.r), g(c.g), b(c.b), a(value_type(a_)) {} //-------------------------------------------------------------------- rgba16(const rgba& c) : r((value_type)uround(c.r * double(base_mask))), g((value_type)uround(c.g * double(base_mask))), b((value_type)uround(c.b * double(base_mask))), a((value_type)uround(c.a * double(base_mask))) {} //-------------------------------------------------------------------- rgba16(const rgba8& c) : r(value_type((value_type(c.r) << 8) | c.r)), g(value_type((value_type(c.g) << 8) | c.g)), b(value_type((value_type(c.b) << 8) | c.b)), a(value_type((value_type(c.a) << 8) | c.a)) {} //-------------------------------------------------------------------- rgba16(const srgba8& c) : r(sRGB_conv::rgb_from_sRGB(c.r)), g(sRGB_conv::rgb_from_sRGB(c.g)), b(sRGB_conv::rgb_from_sRGB(c.b)), a(sRGB_conv::alpha_from_sRGB(c.a)) {} //-------------------------------------------------------------------- operator rgba() const { return rgba( r / 65535.0, g / 65535.0, b / 65535.0, a / 65535.0); } //-------------------------------------------------------------------- operator rgba8() const { return rgba8(r >> 8, g >> 8, b >> 8, a >> 8); } //-------------------------------------------------------------------- operator srgba8() const { // Return (non-premultiplied) sRGB values. return srgba8( sRGB_conv::rgb_to_sRGB(r), sRGB_conv::rgb_to_sRGB(g), sRGB_conv::rgb_to_sRGB(b), sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- static AGG_INLINE double to_double(value_type a) { return double(a) / base_mask; } //-------------------------------------------------------------------- static AGG_INLINE value_type from_double(double a) { return value_type(uround(a * base_mask)); } //-------------------------------------------------------------------- static AGG_INLINE value_type empty_value() { return 0; } //-------------------------------------------------------------------- static AGG_INLINE value_type full_value() { return base_mask; } //-------------------------------------------------------------------- AGG_INLINE bool is_transparent() const { return a == 0; } //-------------------------------------------------------------------- AGG_INLINE bool is_opaque() const { return a == base_mask; } //-------------------------------------------------------------------- static AGG_INLINE value_type invert(value_type x) { return base_mask - x; } //-------------------------------------------------------------------- // Fixed-point multiply, exact over int16u. static AGG_INLINE value_type multiply(value_type a, value_type b) { calc_type t = calc_type(a) * b + base_MSB; return value_type(((t >> base_shift) + t) >> base_shift); } //-------------------------------------------------------------------- static AGG_INLINE value_type demultiply(value_type a, value_type b) { if (a * b == 0) { return 0; } else if (a >= b) { return base_mask; } else return value_type((a * base_mask + (b >> 1)) / b); } //-------------------------------------------------------------------- template static AGG_INLINE T downscale(T a) { return a >> base_shift; } //-------------------------------------------------------------------- template static AGG_INLINE T downshift(T a, unsigned n) { return a >> n; } //-------------------------------------------------------------------- // Fixed-point multiply, almost exact over int16u. // Specifically for multiplying a color component by a cover. static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return multiply(a, (b << 8) | b); } //-------------------------------------------------------------------- static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return multiply((a << 8) | a, b) >> 8; } //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return p + q - multiply(p, a); } //-------------------------------------------------------------------- // Interpolate p to q by a. static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { int t = (q - p) * a + base_MSB - (p > q); return value_type(p + (((t >> base_shift) + t) >> base_shift)); } //-------------------------------------------------------------------- self_type& clear() { r = g = b = a = 0; return *this; } //-------------------------------------------------------------------- self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- AGG_INLINE self_type& opacity(double a_) { if (a_ < 0) a = 0; if (a_ > 1) a = 1; a = value_type(uround(a_ * double(base_mask))); return *this; } //-------------------------------------------------------------------- double opacity() const { return double(a) / double(base_mask); } //-------------------------------------------------------------------- AGG_INLINE self_type& premultiply() { if (a != base_mask) { if (a == 0) { r = g = b = 0; } else { r = multiply(r, a); g = multiply(g, a); b = multiply(b, a); } } return *this; } //-------------------------------------------------------------------- AGG_INLINE self_type& premultiply(unsigned a_) { if (a < base_mask || a_ < base_mask) { if (a == 0 || a_ == 0) { r = g = b = a = 0; } else { calc_type r_ = (calc_type(r) * a_) / a; calc_type g_ = (calc_type(g) * a_) / a; calc_type b_ = (calc_type(b) * a_) / a; r = value_type((r_ > a_) ? a_ : r_); g = value_type((g_ > a_) ? a_ : g_); b = value_type((b_ > a_) ? a_ : b_); a = value_type(a_); } } return *this; } //-------------------------------------------------------------------- AGG_INLINE self_type& demultiply() { if (a < base_mask) { if (a == 0) { r = g = b = 0; } else { calc_type r_ = (calc_type(r) * base_mask) / a; calc_type g_ = (calc_type(g) * base_mask) / a; calc_type b_ = (calc_type(b) * base_mask) / a; r = value_type((r_ > calc_type(base_mask)) ? calc_type(base_mask) : r_); g = value_type((g_ > calc_type(base_mask)) ? calc_type(base_mask) : g_); b = value_type((b_ > calc_type(base_mask)) ? calc_type(base_mask) : b_); } } return *this; } //-------------------------------------------------------------------- AGG_INLINE self_type gradient(const self_type& c, double k) const { self_type ret; calc_type ik = uround(k * base_mask); ret.r = lerp(r, c.r, ik); ret.g = lerp(g, c.g, ik); ret.b = lerp(b, c.b, ik); ret.a = lerp(a, c.a, ik); return ret; } //-------------------------------------------------------------------- AGG_INLINE void add(const self_type& c, unsigned cover) { calc_type cr, cg, cb, ca; if (cover == cover_mask) { if (c.a == base_mask) { *this = c; return; } else { cr = r + c.r; cg = g + c.g; cb = b + c.b; ca = a + c.a; } } else { cr = r + mult_cover(c.r, cover); cg = g + mult_cover(c.g, cover); cb = b + mult_cover(c.b, cover); ca = a + mult_cover(c.a, cover); } r = (value_type)((cr > calc_type(base_mask)) ? calc_type(base_mask) : cr); g = (value_type)((cg > calc_type(base_mask)) ? calc_type(base_mask) : cg); b = (value_type)((cb > calc_type(base_mask)) ? calc_type(base_mask) : cb); a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca); } //-------------------------------------------------------------------- template AGG_INLINE void apply_gamma_dir(const GammaLUT& gamma) { r = gamma.dir(r); g = gamma.dir(g); b = gamma.dir(b); } //-------------------------------------------------------------------- template AGG_INLINE void apply_gamma_inv(const GammaLUT& gamma) { r = gamma.inv(r); g = gamma.inv(g); b = gamma.inv(b); } //-------------------------------------------------------------------- static self_type no_color() { return self_type(0,0,0,0); } //-------------------------------------------------------------------- static self_type from_wavelength(double wl, double gamma = 1.0) { return self_type(rgba::from_wavelength(wl, gamma)); } }; //------------------------------------------------------rgba16_gamma_dir template rgba16 rgba16_gamma_dir(rgba16 c, const GammaLUT& gamma) { return rgba16(gamma.dir(c.r), gamma.dir(c.g), gamma.dir(c.b), c.a); } //------------------------------------------------------rgba16_gamma_inv template rgba16 rgba16_gamma_inv(rgba16 c, const GammaLUT& gamma) { return rgba16(gamma.inv(c.r), gamma.inv(c.g), gamma.inv(c.b), c.a); } //====================================================================rgba32 struct rgba32 { typedef float value_type; typedef double calc_type; typedef double long_type; typedef rgba32 self_type; value_type r; value_type g; value_type b; value_type a; //-------------------------------------------------------------------- rgba32() {} //-------------------------------------------------------------------- rgba32(value_type r_, value_type g_, value_type b_, value_type a_= 1) : r(r_), g(g_), b(b_), a(a_) {} //-------------------------------------------------------------------- rgba32(const self_type& c, float a_) : r(c.r), g(c.g), b(c.b), a(a_) {} //-------------------------------------------------------------------- rgba32(const rgba& c) : r(value_type(c.r)), g(value_type(c.g)), b(value_type(c.b)), a(value_type(c.a)) {} //-------------------------------------------------------------------- rgba32(const rgba8& c) : r(value_type(c.r / 255.0)), g(value_type(c.g / 255.0)), b(value_type(c.b / 255.0)), a(value_type(c.a / 255.0)) {} //-------------------------------------------------------------------- rgba32(const srgba8& c) : r(sRGB_conv::rgb_from_sRGB(c.r)), g(sRGB_conv::rgb_from_sRGB(c.g)), b(sRGB_conv::rgb_from_sRGB(c.b)), a(sRGB_conv::alpha_from_sRGB(c.a)) {} //-------------------------------------------------------------------- rgba32(const rgba16& c) : r(value_type(c.r / 65535.0)), g(value_type(c.g / 65535.0)), b(value_type(c.b / 65535.0)), a(value_type(c.a / 65535.0)) {} //-------------------------------------------------------------------- operator rgba() const { return rgba(r, g, b, a); } //-------------------------------------------------------------------- operator rgba8() const { return rgba8( uround(r * 255.0), uround(g * 255.0), uround(b * 255.0), uround(a * 255.0)); } //-------------------------------------------------------------------- operator srgba8() const { return srgba8( sRGB_conv::rgb_to_sRGB(r), sRGB_conv::rgb_to_sRGB(g), sRGB_conv::rgb_to_sRGB(b), sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- operator rgba16() const { return rgba8( uround(r * 65535.0), uround(g * 65535.0), uround(b * 65535.0), uround(a * 65535.0)); } //-------------------------------------------------------------------- static AGG_INLINE double to_double(value_type a) { return a; } //-------------------------------------------------------------------- static AGG_INLINE value_type from_double(double a) { return value_type(a); } //-------------------------------------------------------------------- static AGG_INLINE value_type empty_value() { return 0; } //-------------------------------------------------------------------- static AGG_INLINE value_type full_value() { return 1; } //-------------------------------------------------------------------- AGG_INLINE bool is_transparent() const { return a <= 0; } //-------------------------------------------------------------------- AGG_INLINE bool is_opaque() const { return a >= 1; } //-------------------------------------------------------------------- static AGG_INLINE value_type invert(value_type x) { return 1 - x; } //-------------------------------------------------------------------- static AGG_INLINE value_type multiply(value_type a, value_type b) { return value_type(a * b); } //-------------------------------------------------------------------- static AGG_INLINE value_type demultiply(value_type a, value_type b) { return (b == 0) ? 0 : value_type(a / b); } //-------------------------------------------------------------------- template static AGG_INLINE T downscale(T a) { return a; } //-------------------------------------------------------------------- template static AGG_INLINE T downshift(T a, unsigned n) { return n > 0 ? a / (1 << n) : a; } //-------------------------------------------------------------------- static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return value_type(a * b / cover_mask); } //-------------------------------------------------------------------- static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return cover_type(uround(a * b)); } //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return (1 - a) * p + q; // more accurate than "p + q - p * a" } //-------------------------------------------------------------------- // Interpolate p to q by a. static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { // The form "p + a * (q - p)" avoids a multiplication, but may produce an // inaccurate result. For example, "p + (q - p)" may not be exactly equal // to q. Therefore, stick to the basic expression, which at least produces // the correct result at either extreme. return (1 - a) * p + a * q; } //-------------------------------------------------------------------- self_type& clear() { r = g = b = a = 0; return *this; } //-------------------------------------------------------------------- self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- AGG_INLINE self_type& opacity(double a_) { if (a_ < 0) a = 0; else if (a_ > 1) a = 1; else a = value_type(a_); return *this; } //-------------------------------------------------------------------- double opacity() const { return a; } //-------------------------------------------------------------------- AGG_INLINE self_type& premultiply() { if (a < 1) { if (a <= 0) { r = g = b = 0; } else { r *= a; g *= a; b *= a; } } return *this; } //-------------------------------------------------------------------- AGG_INLINE self_type& demultiply() { if (a < 1) { if (a <= 0) { r = g = b = 0; } else { r /= a; g /= a; b /= a; } } return *this; } //-------------------------------------------------------------------- AGG_INLINE self_type gradient(const self_type& c, double k) const { self_type ret; ret.r = value_type(r + (c.r - r) * k); ret.g = value_type(g + (c.g - g) * k); ret.b = value_type(b + (c.b - b) * k); ret.a = value_type(a + (c.a - a) * k); return ret; } //-------------------------------------------------------------------- AGG_INLINE void add(const self_type& c, unsigned cover) { if (cover == cover_mask) { if (c.is_opaque()) { *this = c; return; } else { r += c.r; g += c.g; b += c.b; a += c.a; } } else { r += mult_cover(c.r, cover); g += mult_cover(c.g, cover); b += mult_cover(c.b, cover); a += mult_cover(c.a, cover); } if (a > 1) a = 1; if (r > a) r = a; if (g > a) g = a; if (b > a) b = a; } //-------------------------------------------------------------------- template AGG_INLINE void apply_gamma_dir(const GammaLUT& gamma) { r = gamma.dir(r); g = gamma.dir(g); b = gamma.dir(b); } //-------------------------------------------------------------------- template AGG_INLINE void apply_gamma_inv(const GammaLUT& gamma) { r = gamma.inv(r); g = gamma.inv(g); b = gamma.inv(b); } //-------------------------------------------------------------------- static self_type no_color() { return self_type(0,0,0,0); } //-------------------------------------------------------------------- static self_type from_wavelength(double wl, double gamma = 1) { return self_type(rgba::from_wavelength(wl, gamma)); } }; } #endif ragg/src/agg/include/agg_bezier_arc.h0000644000176200001440000001323113504406270017237 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Arc generator. Produces at most 4 consecutive cubic bezier curves, i.e., // 4, 7, 10, or 13 vertices. // //---------------------------------------------------------------------------- #ifndef AGG_BEZIER_ARC_INCLUDED #define AGG_BEZIER_ARC_INCLUDED #include "agg_conv_transform.h" namespace agg { //----------------------------------------------------------------------- void arc_to_bezier(double cx, double cy, double rx, double ry, double start_angle, double sweep_angle, double* curve); //==============================================================bezier_arc // // See implemantaion agg_bezier_arc.cpp // class bezier_arc { public: //-------------------------------------------------------------------- bezier_arc() : m_vertex(26), m_num_vertices(0), m_cmd(path_cmd_line_to) {} bezier_arc(double x, double y, double rx, double ry, double start_angle, double sweep_angle) { init(x, y, rx, ry, start_angle, sweep_angle); } //-------------------------------------------------------------------- void init(double x, double y, double rx, double ry, double start_angle, double sweep_angle); //-------------------------------------------------------------------- void rewind(unsigned) { m_vertex = 0; } //-------------------------------------------------------------------- unsigned vertex(double* x, double* y) { if(m_vertex >= m_num_vertices) return path_cmd_stop; *x = m_vertices[m_vertex]; *y = m_vertices[m_vertex + 1]; m_vertex += 2; return (m_vertex == 2) ? unsigned(path_cmd_move_to) : m_cmd; } // Supplemantary functions. num_vertices() actually returns doubled // number of vertices. That is, for 1 vertex it returns 2. //-------------------------------------------------------------------- unsigned num_vertices() const { return m_num_vertices; } const double* vertices() const { return m_vertices; } double* vertices() { return m_vertices; } private: unsigned m_vertex; unsigned m_num_vertices; double m_vertices[26]; unsigned m_cmd; }; //==========================================================bezier_arc_svg // Compute an SVG-style bezier arc. // // Computes an elliptical arc from (x1, y1) to (x2, y2). The size and // orientation of the ellipse are defined by two radii (rx, ry) // and an x-axis-rotation, which indicates how the ellipse as a whole // is rotated relative to the current coordinate system. The center // (cx, cy) of the ellipse is calculated automatically to satisfy the // constraints imposed by the other parameters. // large-arc-flag and sweep-flag contribute to the automatic calculations // and help determine how the arc is drawn. class bezier_arc_svg { public: //-------------------------------------------------------------------- bezier_arc_svg() : m_arc(), m_radii_ok(false) {} bezier_arc_svg(double x1, double y1, double rx, double ry, double angle, bool large_arc_flag, bool sweep_flag, double x2, double y2) : m_arc(), m_radii_ok(false) { init(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2); } //-------------------------------------------------------------------- void init(double x1, double y1, double rx, double ry, double angle, bool large_arc_flag, bool sweep_flag, double x2, double y2); //-------------------------------------------------------------------- bool radii_ok() const { return m_radii_ok; } //-------------------------------------------------------------------- void rewind(unsigned) { m_arc.rewind(0); } //-------------------------------------------------------------------- unsigned vertex(double* x, double* y) { return m_arc.vertex(x, y); } // Supplemantary functions. num_vertices() actually returns doubled // number of vertices. That is, for 1 vertex it returns 2. //-------------------------------------------------------------------- unsigned num_vertices() const { return m_arc.num_vertices(); } const double* vertices() const { return m_arc.vertices(); } double* vertices() { return m_arc.vertices(); } private: bezier_arc m_arc; bool m_radii_ok; }; } #endif ragg/src/agg/include/agg_vcgen_markers_term.h0000644000176200001440000000373113504406270021013 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_VCGEN_MARKERS_TERM_INCLUDED #define AGG_VCGEN_MARKERS_TERM_INCLUDED #include "agg_basics.h" #include "agg_vertex_sequence.h" namespace agg { //======================================================vcgen_markers_term // // See Implemantation agg_vcgen_markers_term.cpp // Terminal markers generator (arrowhead/arrowtail) // //------------------------------------------------------------------------ class vcgen_markers_term { public: vcgen_markers_term() : m_curr_id(0), m_curr_idx(0) {} // Vertex Generator Interface void remove_all(); void add_vertex(double x, double y, unsigned cmd); // Vertex Source Interface void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: vcgen_markers_term(const vcgen_markers_term&); const vcgen_markers_term& operator = (const vcgen_markers_term&); struct coord_type { double x, y; coord_type() {} coord_type(double x_, double y_) : x(x_), y(y_) {} }; typedef pod_bvector coord_storage; coord_storage m_markers; unsigned m_curr_id; unsigned m_curr_idx; }; } #endif ragg/src/agg/include/agg_span_gradient_contour.h0000644000176200001440000001702513504406270021526 0ustar liggesusers//---------------------------------------------------------------------------- // AGG Contribution Pack - Gradients 1 (AGG CP - Gradients 1) // http://milan.marusinec.sk/aggcp // // For Anti-Grain Geometry - Version 2.4 // http://www.antigrain.org // // Contribution Created By: // Milan Marusinec alias Milano // milan@marusinec.sk // Copyright (c) 2007-2008 // // 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. // // [History] ----------------------------------------------------------------- // // 02.02.2008-Milano: Ported from Object Pascal code of AggPas // #ifndef AGG_SPAN_GRADIENT_CONTOUR_INCLUDED #define AGG_SPAN_GRADIENT_CONTOUR_INCLUDED #include "agg_basics.h" #include "agg_trans_affine.h" #include "agg_path_storage.h" #include "agg_pixfmt_gray.h" #include "agg_conv_transform.h" #include "agg_conv_curve.h" #include "agg_bounding_rect.h" #include "agg_renderer_base.h" #include "agg_renderer_primitives.h" #include "agg_rasterizer_outline.h" #include "agg_span_gradient.h" #include #include #include namespace agg { //==========================================================gradient_contour class gradient_contour { private: int8u* m_buffer; int m_width; int m_height; int m_frame; double m_d1; double m_d2; public: gradient_contour() : m_buffer(NULL), m_width(0), m_height(0), m_frame(10), m_d1(0), m_d2(100) { } gradient_contour(double d1, double d2) : m_buffer(NULL), m_width(0), m_height(0), m_frame(10), m_d1(d1), m_d2(d2) { } ~gradient_contour() { if (m_buffer) { delete [] m_buffer; } } int8u* contour_create(path_storage* ps ); int contour_width() { return m_width; } int contour_height() { return m_height; } void d1(double d ) { m_d1 = d; } void d2(double d ) { m_d2 = d; } void frame(int f ) { m_frame = f; } int frame() { return m_frame; } int calculate(int x, int y, int d) const { if (m_buffer) { int px = x >> agg::gradient_subpixel_shift; int py = y >> agg::gradient_subpixel_shift; px %= m_width; if (px < 0) { px += m_width; } py %= m_height; if (py < 0 ) { py += m_height; } return iround(m_buffer[py * m_width + px ] * (m_d2 / 256 ) + m_d1 ) << gradient_subpixel_shift; } else { return 0; } } }; static AGG_INLINE int square(int x ) { return x * x; } // DT algorithm by: Pedro Felzenszwalb void dt(float* spanf, float* spang, float* spanr, int* spann ,int length ) { int k = 0; float s; spann[0 ] = 0; spang[0 ] = -FLT_MAX; spang[1 ] = FLT_MAX; for (int q = 1; q <= length - 1; q++) { s = ((spanf[q ] + square(q ) ) - (spanf[spann[k ] ] + square(spann[k ] ) ) ) / (2 * q - 2 * spann[k ] ); while (s <= spang[k ]) { k--; s = ((spanf[q ] + square(q ) ) - (spanf[spann[k ] ] + square(spann[k ] ) ) ) / (2 * q - 2 * spann[k ] ); } k++; spann[k ] = q; spang[k ] = s; spang[k + 1 ] = FLT_MAX; } k = 0; for (int q = 0; q <= length - 1; q++) { while (spang[k + 1 ] < q ) { k++; } spanr[q ] = square(q - spann[k ] ) + spanf[spann[k ] ]; } } // DT algorithm by: Pedro Felzenszwalb int8u* gradient_contour::contour_create(path_storage* ps ) { int8u* result = NULL; if (ps) { // I. Render Black And White NonAA Stroke of the Path // Path Bounding Box + Some Frame Space Around [configurable] agg::conv_curve conv(*ps); double x1, y1, x2, y2; if (agg::bounding_rect_single(conv ,0 ,&x1 ,&y1 ,&x2 ,&y2 )) { // Create BW Rendering Surface int width = int(ceil(x2 - x1 ) ) + m_frame * 2 + 1; int height = int(ceil(y2 - y1 ) ) + m_frame * 2 + 1; int8u* buffer = new int8u[width * height]; if (buffer) { std::memset(buffer ,255 ,width * height ); // Setup VG Engine & Render agg::rendering_buffer rb; rb.attach(buffer ,width ,height ,width ); agg::pixfmt_gray8 pf(rb); agg::renderer_base renb(pf ); agg::renderer_primitives > prim(renb ); agg::rasterizer_outline > > ras(prim ); agg::trans_affine mtx; mtx *= agg::trans_affine_translation(-x1 + m_frame, -y1 + m_frame ); agg::conv_transform > trans(conv ,mtx ); prim.line_color(agg::rgba8(0 ,0 ,0 ,255 ) ); ras.add_path(trans ); // II. Distance Transform // Create Float Buffer + 0 vs infinity assignment float* image = new float[width * height]; if (image) { for (int y = 0, l = 0; y < height; y++ ) { for (int x = 0; x < width; x++, l++ ) { if (buffer[l ] == 0) { image[l ] = 0.0; } else { image[l ] = FLT_MAX; } } } // DT of 2d // SubBuff max width,height int length = width; if (height > length) { length = height; } float* spanf = new float[length]; float* spang = new float[length + 1]; float* spanr = new float[length]; int* spann = new int[length]; if ((spanf) && (spang) && (spanr) && (spann)) { // Transform along columns for (int x = 0; x < width; x++ ) { for (int y = 0; y < height; y++ ) { spanf[y] = image[y * width + x]; } // DT of 1d dt(spanf ,spang ,spanr ,spann ,height ); for (int y = 0; y < height; y++ ) { image[y * width + x] = spanr[y]; } } // Transform along rows for (int y = 0; y < height; y++ ) { for (int x = 0; x < width; x++ ) { spanf[x] = image[y * width + x]; } // DT of 1d dt(spanf ,spang ,spanr ,spann ,width ); for (int x = 0; x < width; x++ ) { image[y * width + x] = spanr[x]; } } // Take Square Roots, Min & Max float min = std::sqrt(image[0] ); float max = min; for (int y = 0, l = 0; y < height; y++ ) { for (int x = 0; x < width; x++, l++ ) { image[l] = std::sqrt(image[l]); if (min > image[l]) { min = image[l]; } if (max < image[l]) { max = image[l]; } } } // III. Convert To Grayscale if (min == max) { std::memset(buffer ,0 ,width * height ); } else { float scale = 255 / (max - min ); for (int y = 0, l = 0; y < height; y++ ) { for (int x = 0; x < width; x++ ,l++ ) { buffer[l] = int8u(int((image[l] - min ) * scale )); } } } // OK if (m_buffer) { delete [] m_buffer; } m_buffer = buffer; m_width = width; m_height = height; buffer = NULL; result = m_buffer; } if (spanf) { delete [] spanf; } if (spang) { delete [] spang; } if (spanr) { delete [] spanr; } if (spann) { delete [] spann; } delete [] image; } } if (buffer) { delete [] buffer; } } } return result; } } #endif ragg/src/agg/include/agg_conv_concat.h0000644000176200001440000000427513504406270017436 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_CONV_CONCAT_INCLUDED #define AGG_CONV_CONCAT_INCLUDED #include "agg_basics.h" namespace agg { //=============================================================conv_concat // Concatenation of two paths. Usually used to combine lines or curves // with markers such as arrowheads template class conv_concat { public: conv_concat(VS1& source1, VS2& source2) : m_source1(&source1), m_source2(&source2), m_status(2) {} void attach1(VS1& source) { m_source1 = &source; } void attach2(VS2& source) { m_source2 = &source; } void rewind(unsigned path_id) { m_source1->rewind(path_id); m_source2->rewind(0); m_status = 0; } unsigned vertex(double* x, double* y) { unsigned cmd; if(m_status == 0) { cmd = m_source1->vertex(x, y); if(!is_stop(cmd)) return cmd; m_status = 1; } if(m_status == 1) { cmd = m_source2->vertex(x, y); if(!is_stop(cmd)) return cmd; m_status = 2; } return path_cmd_stop; } private: conv_concat(const conv_concat&); const conv_concat& operator = (const conv_concat&); VS1* m_source1; VS2* m_source2; int m_status; }; } #endif ragg/src/agg/include/agg_blur.h0000644000176200001440000014535413504406270016112 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // The Stack Blur Algorithm was invented by Mario Klingemann, // mario@quasimondo.com and described here: // http://incubator.quasimondo.com/processing/fast_blur_deluxe.php // (search phrase "Stackblur: Fast But Goodlooking"). // The major improvement is that there's no more division table // that was very expensive to create for large blur radii. Insted, // for 8-bit per channel and radius not exceeding 254 the division is // replaced by multiplication and shift. // //---------------------------------------------------------------------------- #ifndef AGG_BLUR_INCLUDED #define AGG_BLUR_INCLUDED #include #include #include "agg_array.h" #include "agg_pixfmt_base.h" #include "agg_pixfmt_transposer.h" namespace agg { template struct stack_blur_tables { static int16u const g_stack_blur8_mul[255]; static int8u const g_stack_blur8_shr[255]; }; //------------------------------------------------------------------------ template int16u const stack_blur_tables::g_stack_blur8_mul[255] = { 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512, 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512, 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456, 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512, 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328, 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456, 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335, 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512, 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405, 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328, 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271, 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456, 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388, 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335, 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292, 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259 }; //------------------------------------------------------------------------ template int8u const stack_blur_tables::g_stack_blur8_shr[255] = { 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 }; //==============================================================stack_blur template class stack_blur { public: typedef ColorT color_type; typedef CalculatorT calculator_type; //-------------------------------------------------------------------- template void blur_x(Img& img, unsigned radius) { if(radius < 1) return; unsigned x, y, xp, i; unsigned stack_ptr; unsigned stack_start; color_type pix; color_type* stack_pix; calculator_type sum; calculator_type sum_in; calculator_type sum_out; unsigned w = img.width(); unsigned h = img.height(); unsigned wm = w - 1; unsigned div = radius * 2 + 1; unsigned div_sum = (radius + 1) * (radius + 1); unsigned mul_sum = 0; unsigned shr_sum = 0; unsigned max_val = color_type::base_mask; if(max_val <= 255 && radius < 255) { mul_sum = stack_blur_tables::g_stack_blur8_mul[radius]; shr_sum = stack_blur_tables::g_stack_blur8_shr[radius]; } m_buf.allocate(w, 128); m_stack.allocate(div, 32); for(y = 0; y < h; y++) { sum.clear(); sum_in.clear(); sum_out.clear(); pix = img.pixel(0, y); for(i = 0; i <= radius; i++) { m_stack[i] = pix; sum.add(pix, i + 1); sum_out.add(pix); } for(i = 1; i <= radius; i++) { pix = img.pixel((i > wm) ? wm : i, y); m_stack[i + radius] = pix; sum.add(pix, radius + 1 - i); sum_in.add(pix); } stack_ptr = radius; for(x = 0; x < w; x++) { if(mul_sum) sum.calc_pix(m_buf[x], mul_sum, shr_sum); else sum.calc_pix(m_buf[x], div_sum); sum.sub(sum_out); stack_start = stack_ptr + div - radius; if(stack_start >= div) stack_start -= div; stack_pix = &m_stack[stack_start]; sum_out.sub(*stack_pix); xp = x + radius + 1; if(xp > wm) xp = wm; pix = img.pixel(xp, y); *stack_pix = pix; sum_in.add(pix); sum.add(sum_in); ++stack_ptr; if(stack_ptr >= div) stack_ptr = 0; stack_pix = &m_stack[stack_ptr]; sum_out.add(*stack_pix); sum_in.sub(*stack_pix); } img.copy_color_hspan(0, y, w, &m_buf[0]); } } //-------------------------------------------------------------------- template void blur_y(Img& img, unsigned radius) { pixfmt_transposer img2(img); blur_x(img2, radius); } //-------------------------------------------------------------------- template void blur(Img& img, unsigned radius) { blur_x(img, radius); pixfmt_transposer img2(img); blur_x(img2, radius); } private: pod_vector m_buf; pod_vector m_stack; }; //====================================================stack_blur_calc_rgba template struct stack_blur_calc_rgba { typedef T value_type; value_type r,g,b,a; AGG_INLINE void clear() { r = g = b = a = 0; } template AGG_INLINE void add(const ArgT& v) { r += v.r; g += v.g; b += v.b; a += v.a; } template AGG_INLINE void add(const ArgT& v, unsigned k) { r += v.r * k; g += v.g * k; b += v.b * k; a += v.a * k; } template AGG_INLINE void sub(const ArgT& v) { r -= v.r; g -= v.g; b -= v.b; a -= v.a; } template AGG_INLINE void calc_pix(ArgT& v, unsigned div) { typedef typename ArgT::value_type value_type; v.r = value_type(r / div); v.g = value_type(g / div); v.b = value_type(b / div); v.a = value_type(a / div); } template AGG_INLINE void calc_pix(ArgT& v, unsigned mul, unsigned shr) { typedef typename ArgT::value_type value_type; v.r = value_type((r * mul) >> shr); v.g = value_type((g * mul) >> shr); v.b = value_type((b * mul) >> shr); v.a = value_type((a * mul) >> shr); } }; //=====================================================stack_blur_calc_rgb template struct stack_blur_calc_rgb { typedef T value_type; value_type r,g,b; AGG_INLINE void clear() { r = g = b = 0; } template AGG_INLINE void add(const ArgT& v) { r += v.r; g += v.g; b += v.b; } template AGG_INLINE void add(const ArgT& v, unsigned k) { r += v.r * k; g += v.g * k; b += v.b * k; } template AGG_INLINE void sub(const ArgT& v) { r -= v.r; g -= v.g; b -= v.b; } template AGG_INLINE void calc_pix(ArgT& v, unsigned div) { typedef typename ArgT::value_type value_type; v.r = value_type(r / div); v.g = value_type(g / div); v.b = value_type(b / div); } template AGG_INLINE void calc_pix(ArgT& v, unsigned mul, unsigned shr) { typedef typename ArgT::value_type value_type; v.r = value_type((r * mul) >> shr); v.g = value_type((g * mul) >> shr); v.b = value_type((b * mul) >> shr); } }; //====================================================stack_blur_calc_gray template struct stack_blur_calc_gray { typedef T value_type; value_type v; AGG_INLINE void clear() { v = 0; } template AGG_INLINE void add(const ArgT& a) { v += a.v; } template AGG_INLINE void add(const ArgT& a, unsigned k) { v += a.v * k; } template AGG_INLINE void sub(const ArgT& a) { v -= a.v; } template AGG_INLINE void calc_pix(ArgT& a, unsigned div) { typedef typename ArgT::value_type value_type; a.v = value_type(v / div); } template AGG_INLINE void calc_pix(ArgT& a, unsigned mul, unsigned shr) { typedef typename ArgT::value_type value_type; a.v = value_type((v * mul) >> shr); } }; //========================================================stack_blur_gray8 template void stack_blur_gray8(Img& img, unsigned rx, unsigned ry) { unsigned x, y, xp, yp, i; unsigned stack_ptr; unsigned stack_start; const int8u* src_pix_ptr; int8u* dst_pix_ptr; unsigned pix; unsigned stack_pix; unsigned sum; unsigned sum_in; unsigned sum_out; unsigned w = img.width(); unsigned h = img.height(); unsigned wm = w - 1; unsigned hm = h - 1; unsigned div; unsigned mul_sum; unsigned shr_sum; pod_vector stack; if(rx > 0) { if(rx > 254) rx = 254; div = rx * 2 + 1; mul_sum = stack_blur_tables::g_stack_blur8_mul[rx]; shr_sum = stack_blur_tables::g_stack_blur8_shr[rx]; stack.allocate(div); for(y = 0; y < h; y++) { sum = sum_in = sum_out = 0; src_pix_ptr = img.pix_ptr(0, y); pix = *src_pix_ptr; for(i = 0; i <= rx; i++) { stack[i] = pix; sum += pix * (i + 1); sum_out += pix; } for(i = 1; i <= rx; i++) { if(i <= wm) src_pix_ptr += Img::pix_width; pix = *src_pix_ptr; stack[i + rx] = pix; sum += pix * (rx + 1 - i); sum_in += pix; } stack_ptr = rx; xp = rx; if(xp > wm) xp = wm; src_pix_ptr = img.pix_ptr(xp, y); dst_pix_ptr = img.pix_ptr(0, y); for(x = 0; x < w; x++) { *dst_pix_ptr = (sum * mul_sum) >> shr_sum; dst_pix_ptr += Img::pix_width; sum -= sum_out; stack_start = stack_ptr + div - rx; if(stack_start >= div) stack_start -= div; sum_out -= stack[stack_start]; if(xp < wm) { src_pix_ptr += Img::pix_width; pix = *src_pix_ptr; ++xp; } stack[stack_start] = pix; sum_in += pix; sum += sum_in; ++stack_ptr; if(stack_ptr >= div) stack_ptr = 0; stack_pix = stack[stack_ptr]; sum_out += stack_pix; sum_in -= stack_pix; } } } if(ry > 0) { if(ry > 254) ry = 254; div = ry * 2 + 1; mul_sum = stack_blur_tables::g_stack_blur8_mul[ry]; shr_sum = stack_blur_tables::g_stack_blur8_shr[ry]; stack.allocate(div); int stride = img.stride(); for(x = 0; x < w; x++) { sum = sum_in = sum_out = 0; src_pix_ptr = img.pix_ptr(x, 0); pix = *src_pix_ptr; for(i = 0; i <= ry; i++) { stack[i] = pix; sum += pix * (i + 1); sum_out += pix; } for(i = 1; i <= ry; i++) { if(i <= hm) src_pix_ptr += stride; pix = *src_pix_ptr; stack[i + ry] = pix; sum += pix * (ry + 1 - i); sum_in += pix; } stack_ptr = ry; yp = ry; if(yp > hm) yp = hm; src_pix_ptr = img.pix_ptr(x, yp); dst_pix_ptr = img.pix_ptr(x, 0); for(y = 0; y < h; y++) { *dst_pix_ptr = (sum * mul_sum) >> shr_sum; dst_pix_ptr += stride; sum -= sum_out; stack_start = stack_ptr + div - ry; if(stack_start >= div) stack_start -= div; sum_out -= stack[stack_start]; if(yp < hm) { src_pix_ptr += stride; pix = *src_pix_ptr; ++yp; } stack[stack_start] = pix; sum_in += pix; sum += sum_in; ++stack_ptr; if(stack_ptr >= div) stack_ptr = 0; stack_pix = stack[stack_ptr]; sum_out += stack_pix; sum_in -= stack_pix; } } } } //========================================================stack_blur_rgb24 template void stack_blur_rgb24(Img& img, unsigned rx, unsigned ry) { typedef typename Img::color_type color_type; typedef typename Img::order_type order_type; enum order_e { R = order_type::R, G = order_type::G, B = order_type::B }; unsigned x, y, xp, yp, i; unsigned stack_ptr; unsigned stack_start; const int8u* src_pix_ptr; int8u* dst_pix_ptr; color_type* stack_pix_ptr; unsigned sum_r; unsigned sum_g; unsigned sum_b; unsigned sum_in_r; unsigned sum_in_g; unsigned sum_in_b; unsigned sum_out_r; unsigned sum_out_g; unsigned sum_out_b; unsigned w = img.width(); unsigned h = img.height(); unsigned wm = w - 1; unsigned hm = h - 1; unsigned div; unsigned mul_sum; unsigned shr_sum; pod_vector stack; if(rx > 0) { if(rx > 254) rx = 254; div = rx * 2 + 1; mul_sum = stack_blur_tables::g_stack_blur8_mul[rx]; shr_sum = stack_blur_tables::g_stack_blur8_shr[rx]; stack.allocate(div); for(y = 0; y < h; y++) { sum_r = sum_g = sum_b = sum_in_r = sum_in_g = sum_in_b = sum_out_r = sum_out_g = sum_out_b = 0; src_pix_ptr = img.pix_ptr(0, y); for(i = 0; i <= rx; i++) { stack_pix_ptr = &stack[i]; stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; sum_r += src_pix_ptr[R] * (i + 1); sum_g += src_pix_ptr[G] * (i + 1); sum_b += src_pix_ptr[B] * (i + 1); sum_out_r += src_pix_ptr[R]; sum_out_g += src_pix_ptr[G]; sum_out_b += src_pix_ptr[B]; } for(i = 1; i <= rx; i++) { if(i <= wm) src_pix_ptr += Img::pix_width; stack_pix_ptr = &stack[i + rx]; stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; sum_r += src_pix_ptr[R] * (rx + 1 - i); sum_g += src_pix_ptr[G] * (rx + 1 - i); sum_b += src_pix_ptr[B] * (rx + 1 - i); sum_in_r += src_pix_ptr[R]; sum_in_g += src_pix_ptr[G]; sum_in_b += src_pix_ptr[B]; } stack_ptr = rx; xp = rx; if(xp > wm) xp = wm; src_pix_ptr = img.pix_ptr(xp, y); dst_pix_ptr = img.pix_ptr(0, y); for(x = 0; x < w; x++) { dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; dst_pix_ptr += Img::pix_width; sum_r -= sum_out_r; sum_g -= sum_out_g; sum_b -= sum_out_b; stack_start = stack_ptr + div - rx; if(stack_start >= div) stack_start -= div; stack_pix_ptr = &stack[stack_start]; sum_out_r -= stack_pix_ptr->r; sum_out_g -= stack_pix_ptr->g; sum_out_b -= stack_pix_ptr->b; if(xp < wm) { src_pix_ptr += Img::pix_width; ++xp; } stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; sum_in_r += src_pix_ptr[R]; sum_in_g += src_pix_ptr[G]; sum_in_b += src_pix_ptr[B]; sum_r += sum_in_r; sum_g += sum_in_g; sum_b += sum_in_b; ++stack_ptr; if(stack_ptr >= div) stack_ptr = 0; stack_pix_ptr = &stack[stack_ptr]; sum_out_r += stack_pix_ptr->r; sum_out_g += stack_pix_ptr->g; sum_out_b += stack_pix_ptr->b; sum_in_r -= stack_pix_ptr->r; sum_in_g -= stack_pix_ptr->g; sum_in_b -= stack_pix_ptr->b; } } } if(ry > 0) { if(ry > 254) ry = 254; div = ry * 2 + 1; mul_sum = stack_blur_tables::g_stack_blur8_mul[ry]; shr_sum = stack_blur_tables::g_stack_blur8_shr[ry]; stack.allocate(div); int stride = img.stride(); for(x = 0; x < w; x++) { sum_r = sum_g = sum_b = sum_in_r = sum_in_g = sum_in_b = sum_out_r = sum_out_g = sum_out_b = 0; src_pix_ptr = img.pix_ptr(x, 0); for(i = 0; i <= ry; i++) { stack_pix_ptr = &stack[i]; stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; sum_r += src_pix_ptr[R] * (i + 1); sum_g += src_pix_ptr[G] * (i + 1); sum_b += src_pix_ptr[B] * (i + 1); sum_out_r += src_pix_ptr[R]; sum_out_g += src_pix_ptr[G]; sum_out_b += src_pix_ptr[B]; } for(i = 1; i <= ry; i++) { if(i <= hm) src_pix_ptr += stride; stack_pix_ptr = &stack[i + ry]; stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; sum_r += src_pix_ptr[R] * (ry + 1 - i); sum_g += src_pix_ptr[G] * (ry + 1 - i); sum_b += src_pix_ptr[B] * (ry + 1 - i); sum_in_r += src_pix_ptr[R]; sum_in_g += src_pix_ptr[G]; sum_in_b += src_pix_ptr[B]; } stack_ptr = ry; yp = ry; if(yp > hm) yp = hm; src_pix_ptr = img.pix_ptr(x, yp); dst_pix_ptr = img.pix_ptr(x, 0); for(y = 0; y < h; y++) { dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; dst_pix_ptr += stride; sum_r -= sum_out_r; sum_g -= sum_out_g; sum_b -= sum_out_b; stack_start = stack_ptr + div - ry; if(stack_start >= div) stack_start -= div; stack_pix_ptr = &stack[stack_start]; sum_out_r -= stack_pix_ptr->r; sum_out_g -= stack_pix_ptr->g; sum_out_b -= stack_pix_ptr->b; if(yp < hm) { src_pix_ptr += stride; ++yp; } stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; sum_in_r += src_pix_ptr[R]; sum_in_g += src_pix_ptr[G]; sum_in_b += src_pix_ptr[B]; sum_r += sum_in_r; sum_g += sum_in_g; sum_b += sum_in_b; ++stack_ptr; if(stack_ptr >= div) stack_ptr = 0; stack_pix_ptr = &stack[stack_ptr]; sum_out_r += stack_pix_ptr->r; sum_out_g += stack_pix_ptr->g; sum_out_b += stack_pix_ptr->b; sum_in_r -= stack_pix_ptr->r; sum_in_g -= stack_pix_ptr->g; sum_in_b -= stack_pix_ptr->b; } } } } //=======================================================stack_blur_rgba32 template void stack_blur_rgba32(Img& img, unsigned rx, unsigned ry) { typedef typename Img::color_type color_type; typedef typename Img::order_type order_type; enum order_e { R = order_type::R, G = order_type::G, B = order_type::B, A = order_type::A }; unsigned x, y, xp, yp, i; unsigned stack_ptr; unsigned stack_start; const int8u* src_pix_ptr; int8u* dst_pix_ptr; color_type* stack_pix_ptr; unsigned sum_r; unsigned sum_g; unsigned sum_b; unsigned sum_a; unsigned sum_in_r; unsigned sum_in_g; unsigned sum_in_b; unsigned sum_in_a; unsigned sum_out_r; unsigned sum_out_g; unsigned sum_out_b; unsigned sum_out_a; unsigned w = img.width(); unsigned h = img.height(); unsigned wm = w - 1; unsigned hm = h - 1; unsigned div; unsigned mul_sum; unsigned shr_sum; pod_vector stack; if(rx > 0) { if(rx > 254) rx = 254; div = rx * 2 + 1; mul_sum = stack_blur_tables::g_stack_blur8_mul[rx]; shr_sum = stack_blur_tables::g_stack_blur8_shr[rx]; stack.allocate(div); for(y = 0; y < h; y++) { sum_r = sum_g = sum_b = sum_a = sum_in_r = sum_in_g = sum_in_b = sum_in_a = sum_out_r = sum_out_g = sum_out_b = sum_out_a = 0; src_pix_ptr = img.pix_ptr(0, y); for(i = 0; i <= rx; i++) { stack_pix_ptr = &stack[i]; stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; stack_pix_ptr->a = src_pix_ptr[A]; sum_r += src_pix_ptr[R] * (i + 1); sum_g += src_pix_ptr[G] * (i + 1); sum_b += src_pix_ptr[B] * (i + 1); sum_a += src_pix_ptr[A] * (i + 1); sum_out_r += src_pix_ptr[R]; sum_out_g += src_pix_ptr[G]; sum_out_b += src_pix_ptr[B]; sum_out_a += src_pix_ptr[A]; } for(i = 1; i <= rx; i++) { if(i <= wm) src_pix_ptr += Img::pix_width; stack_pix_ptr = &stack[i + rx]; stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; stack_pix_ptr->a = src_pix_ptr[A]; sum_r += src_pix_ptr[R] * (rx + 1 - i); sum_g += src_pix_ptr[G] * (rx + 1 - i); sum_b += src_pix_ptr[B] * (rx + 1 - i); sum_a += src_pix_ptr[A] * (rx + 1 - i); sum_in_r += src_pix_ptr[R]; sum_in_g += src_pix_ptr[G]; sum_in_b += src_pix_ptr[B]; sum_in_a += src_pix_ptr[A]; } stack_ptr = rx; xp = rx; if(xp > wm) xp = wm; src_pix_ptr = img.pix_ptr(xp, y); dst_pix_ptr = img.pix_ptr(0, y); for(x = 0; x < w; x++) { dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum; dst_pix_ptr += Img::pix_width; sum_r -= sum_out_r; sum_g -= sum_out_g; sum_b -= sum_out_b; sum_a -= sum_out_a; stack_start = stack_ptr + div - rx; if(stack_start >= div) stack_start -= div; stack_pix_ptr = &stack[stack_start]; sum_out_r -= stack_pix_ptr->r; sum_out_g -= stack_pix_ptr->g; sum_out_b -= stack_pix_ptr->b; sum_out_a -= stack_pix_ptr->a; if(xp < wm) { src_pix_ptr += Img::pix_width; ++xp; } stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; stack_pix_ptr->a = src_pix_ptr[A]; sum_in_r += src_pix_ptr[R]; sum_in_g += src_pix_ptr[G]; sum_in_b += src_pix_ptr[B]; sum_in_a += src_pix_ptr[A]; sum_r += sum_in_r; sum_g += sum_in_g; sum_b += sum_in_b; sum_a += sum_in_a; ++stack_ptr; if(stack_ptr >= div) stack_ptr = 0; stack_pix_ptr = &stack[stack_ptr]; sum_out_r += stack_pix_ptr->r; sum_out_g += stack_pix_ptr->g; sum_out_b += stack_pix_ptr->b; sum_out_a += stack_pix_ptr->a; sum_in_r -= stack_pix_ptr->r; sum_in_g -= stack_pix_ptr->g; sum_in_b -= stack_pix_ptr->b; sum_in_a -= stack_pix_ptr->a; } } } if(ry > 0) { if(ry > 254) ry = 254; div = ry * 2 + 1; mul_sum = stack_blur_tables::g_stack_blur8_mul[ry]; shr_sum = stack_blur_tables::g_stack_blur8_shr[ry]; stack.allocate(div); int stride = img.stride(); for(x = 0; x < w; x++) { sum_r = sum_g = sum_b = sum_a = sum_in_r = sum_in_g = sum_in_b = sum_in_a = sum_out_r = sum_out_g = sum_out_b = sum_out_a = 0; src_pix_ptr = img.pix_ptr(x, 0); for(i = 0; i <= ry; i++) { stack_pix_ptr = &stack[i]; stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; stack_pix_ptr->a = src_pix_ptr[A]; sum_r += src_pix_ptr[R] * (i + 1); sum_g += src_pix_ptr[G] * (i + 1); sum_b += src_pix_ptr[B] * (i + 1); sum_a += src_pix_ptr[A] * (i + 1); sum_out_r += src_pix_ptr[R]; sum_out_g += src_pix_ptr[G]; sum_out_b += src_pix_ptr[B]; sum_out_a += src_pix_ptr[A]; } for(i = 1; i <= ry; i++) { if(i <= hm) src_pix_ptr += stride; stack_pix_ptr = &stack[i + ry]; stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; stack_pix_ptr->a = src_pix_ptr[A]; sum_r += src_pix_ptr[R] * (ry + 1 - i); sum_g += src_pix_ptr[G] * (ry + 1 - i); sum_b += src_pix_ptr[B] * (ry + 1 - i); sum_a += src_pix_ptr[A] * (ry + 1 - i); sum_in_r += src_pix_ptr[R]; sum_in_g += src_pix_ptr[G]; sum_in_b += src_pix_ptr[B]; sum_in_a += src_pix_ptr[A]; } stack_ptr = ry; yp = ry; if(yp > hm) yp = hm; src_pix_ptr = img.pix_ptr(x, yp); dst_pix_ptr = img.pix_ptr(x, 0); for(y = 0; y < h; y++) { dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum; dst_pix_ptr += stride; sum_r -= sum_out_r; sum_g -= sum_out_g; sum_b -= sum_out_b; sum_a -= sum_out_a; stack_start = stack_ptr + div - ry; if(stack_start >= div) stack_start -= div; stack_pix_ptr = &stack[stack_start]; sum_out_r -= stack_pix_ptr->r; sum_out_g -= stack_pix_ptr->g; sum_out_b -= stack_pix_ptr->b; sum_out_a -= stack_pix_ptr->a; if(yp < hm) { src_pix_ptr += stride; ++yp; } stack_pix_ptr->r = src_pix_ptr[R]; stack_pix_ptr->g = src_pix_ptr[G]; stack_pix_ptr->b = src_pix_ptr[B]; stack_pix_ptr->a = src_pix_ptr[A]; sum_in_r += src_pix_ptr[R]; sum_in_g += src_pix_ptr[G]; sum_in_b += src_pix_ptr[B]; sum_in_a += src_pix_ptr[A]; sum_r += sum_in_r; sum_g += sum_in_g; sum_b += sum_in_b; sum_a += sum_in_a; ++stack_ptr; if(stack_ptr >= div) stack_ptr = 0; stack_pix_ptr = &stack[stack_ptr]; sum_out_r += stack_pix_ptr->r; sum_out_g += stack_pix_ptr->g; sum_out_b += stack_pix_ptr->b; sum_out_a += stack_pix_ptr->a; sum_in_r -= stack_pix_ptr->r; sum_in_g -= stack_pix_ptr->g; sum_in_b -= stack_pix_ptr->b; sum_in_a -= stack_pix_ptr->a; } } } } //===========================================================recursive_blur template class recursive_blur { public: typedef ColorT color_type; typedef CalculatorT calculator_type; typedef typename color_type::value_type value_type; typedef typename calculator_type::value_type calc_type; //-------------------------------------------------------------------- template void blur_x(Img& img, double radius) { if(radius < 0.62) return; if(img.width() < 3) return; calc_type s = calc_type(radius * 0.5); calc_type q = calc_type((s < 2.5) ? 3.97156 - 4.14554 * std::sqrt(1 - 0.26891 * s) : 0.98711 * s - 0.96330); calc_type q2 = calc_type(q * q); calc_type q3 = calc_type(q2 * q); calc_type b0 = calc_type(1.0 / (1.578250 + 2.444130 * q + 1.428100 * q2 + 0.422205 * q3)); calc_type b1 = calc_type( 2.44413 * q + 2.85619 * q2 + 1.26661 * q3); calc_type b2 = calc_type(-1.42810 * q2 + -1.26661 * q3); calc_type b3 = calc_type(0.422205 * q3); calc_type b = calc_type(1 - (b1 + b2 + b3) * b0); b1 *= b0; b2 *= b0; b3 *= b0; int w = img.width(); int h = img.height(); int wm = w-1; int x, y; m_sum1.allocate(w); m_sum2.allocate(w); m_buf.allocate(w); for(y = 0; y < h; y++) { calculator_type c; c.from_pix(img.pixel(0, y)); m_sum1[0].calc(b, b1, b2, b3, c, c, c, c); c.from_pix(img.pixel(1, y)); m_sum1[1].calc(b, b1, b2, b3, c, m_sum1[0], m_sum1[0], m_sum1[0]); c.from_pix(img.pixel(2, y)); m_sum1[2].calc(b, b1, b2, b3, c, m_sum1[1], m_sum1[0], m_sum1[0]); for(x = 3; x < w; ++x) { c.from_pix(img.pixel(x, y)); m_sum1[x].calc(b, b1, b2, b3, c, m_sum1[x-1], m_sum1[x-2], m_sum1[x-3]); } m_sum2[wm ].calc(b, b1, b2, b3, m_sum1[wm ], m_sum1[wm ], m_sum1[wm], m_sum1[wm]); m_sum2[wm-1].calc(b, b1, b2, b3, m_sum1[wm-1], m_sum2[wm ], m_sum2[wm], m_sum2[wm]); m_sum2[wm-2].calc(b, b1, b2, b3, m_sum1[wm-2], m_sum2[wm-1], m_sum2[wm], m_sum2[wm]); m_sum2[wm ].to_pix(m_buf[wm ]); m_sum2[wm-1].to_pix(m_buf[wm-1]); m_sum2[wm-2].to_pix(m_buf[wm-2]); for(x = wm-3; x >= 0; --x) { m_sum2[x].calc(b, b1, b2, b3, m_sum1[x], m_sum2[x+1], m_sum2[x+2], m_sum2[x+3]); m_sum2[x].to_pix(m_buf[x]); } img.copy_color_hspan(0, y, w, &m_buf[0]); } } //-------------------------------------------------------------------- template void blur_y(Img& img, double radius) { pixfmt_transposer img2(img); blur_x(img2, radius); } //-------------------------------------------------------------------- template void blur(Img& img, double radius) { blur_x(img, radius); pixfmt_transposer img2(img); blur_x(img2, radius); } private: agg::pod_vector m_sum1; agg::pod_vector m_sum2; agg::pod_vector m_buf; }; //=================================================recursive_blur_calc_rgba template struct recursive_blur_calc_rgba { typedef T value_type; typedef recursive_blur_calc_rgba self_type; value_type r,g,b,a; template AGG_INLINE void from_pix(const ColorT& c) { r = c.r; g = c.g; b = c.b; a = c.a; } AGG_INLINE void calc(value_type b1, value_type b2, value_type b3, value_type b4, const self_type& c1, const self_type& c2, const self_type& c3, const self_type& c4) { r = b1*c1.r + b2*c2.r + b3*c3.r + b4*c4.r; g = b1*c1.g + b2*c2.g + b3*c3.g + b4*c4.g; b = b1*c1.b + b2*c2.b + b3*c3.b + b4*c4.b; a = b1*c1.a + b2*c2.a + b3*c3.a + b4*c4.a; } template AGG_INLINE void to_pix(ColorT& c) const { typedef typename ColorT::value_type cv_type; c.r = cv_type(r); c.g = cv_type(g); c.b = cv_type(b); c.a = cv_type(a); } }; //=================================================recursive_blur_calc_rgb template struct recursive_blur_calc_rgb { typedef T value_type; typedef recursive_blur_calc_rgb self_type; value_type r,g,b; template AGG_INLINE void from_pix(const ColorT& c) { r = c.r; g = c.g; b = c.b; } AGG_INLINE void calc(value_type b1, value_type b2, value_type b3, value_type b4, const self_type& c1, const self_type& c2, const self_type& c3, const self_type& c4) { r = b1*c1.r + b2*c2.r + b3*c3.r + b4*c4.r; g = b1*c1.g + b2*c2.g + b3*c3.g + b4*c4.g; b = b1*c1.b + b2*c2.b + b3*c3.b + b4*c4.b; } template AGG_INLINE void to_pix(ColorT& c) const { typedef typename ColorT::value_type cv_type; c.r = cv_type(r); c.g = cv_type(g); c.b = cv_type(b); } }; //================================================recursive_blur_calc_gray template struct recursive_blur_calc_gray { typedef T value_type; typedef recursive_blur_calc_gray self_type; value_type v; template AGG_INLINE void from_pix(const ColorT& c) { v = c.v; } AGG_INLINE void calc(value_type b1, value_type b2, value_type b3, value_type b4, const self_type& c1, const self_type& c2, const self_type& c3, const self_type& c4) { v = b1*c1.v + b2*c2.v + b3*c3.v + b4*c4.v; } template AGG_INLINE void to_pix(ColorT& c) const { typedef typename ColorT::value_type cv_type; c.v = cv_type(v); } }; //================================================slight_blur // Special-purpose filter for applying a Gaussian blur with a radius small enough // that the blur only affects adjacent pixels. A Gaussian curve with a standard // deviation of r/2 is used, as per the HTML/CSS spec. At 3 standard deviations, // the contribution drops to less than 0.005, i.e. less than half a percent, // therefore the radius can be at least 1.33 before errors become significant. // This filter is useful for smoothing artifacts caused by detail rendered // at the pixel scale, e.g. single-pixel lines. Note that the filter should // only be used with premultiplied pixel formats (or those without alpha). // See the "line_thickness" example for a demonstration. template class slight_blur { public: typedef typename PixFmt::pixel_type pixel_type; typedef typename PixFmt::value_type value_type; typedef typename PixFmt::order_type order_type; slight_blur(double r = 1.33) { radius(r); } void radius(double r) { if (r > 0) { // Sample the gaussian curve at 0 and r/2 standard deviations. // At 3 standard deviations, the response is < 0.005. double pi = 3.14159; double n = 2 / r; m_g0 = 1 / std::sqrt(2 * pi); m_g1 = m_g0 * exp(-n * n); // Normalize. double sum = m_g0 + 2 * m_g1; m_g0 /= sum; m_g1 /= sum; } else { m_g0 = 1; m_g1 = 0; } } void blur(PixFmt& img, rect_i bounds) { // Make sure we stay within the image area. bounds.clip(rect_i(0, 0, img.width() - 1, img.height() - 1)); int w = bounds.x2 - bounds.x1 + 1; int h = bounds.y2 - bounds.y1 + 1; if (w < 3 || h < 3) return; // Allocate 3 rows of buffer space. m_buf.allocate(w * 3); // Set up row pointers pixel_type * begin = &m_buf[0]; pixel_type * r0 = begin; pixel_type * r1 = r0 + w; pixel_type * r2 = r1 + w; pixel_type * end = r2 + w; // Horizontally blur the first two input rows. calc_row(img, bounds.x1, bounds.y1, w, r0); std::memcpy(r1, r0, w * sizeof(pixel_type)); for (int y = 0; ; ) { // Get pointer to first pixel. pixel_type* p = img.pix_value_ptr(bounds.x1, bounds.y1 + y, bounds.x1 + w); // Horizontally blur the row below. if (y + 1 < h) { calc_row(img, bounds.x1, bounds.y1 + y + 1, w, r2); } else { std::memcpy(r2, r1, w * sizeof(pixel_type)); // duplicate bottom row } // Combine blurred rows into destination. for (int x = 0; x < w; ++x) { calc_pixel(*r0++, *r1++, *r2++, *p++); } if (++y >= h) break; // Wrap bottom row pointer around to top of buffer. if (r2 == end) r2 = begin; else if (r1 == end) r1 = begin; else if (r0 == end) r0 = begin; } } private: void calc_row(PixFmt& img, int x, int y, int w, pixel_type* row) { const int wm = w - 1; pixel_type* p = img.pix_value_ptr(x, y, w); pixel_type c[3]; pixel_type* p0 = c; pixel_type* p1 = c + 1; pixel_type* p2 = c + 2; pixel_type* end = c + 3; *p0 = *p1 = *p; for (int x = 0; x < wm; ++x) { *p2 = *(p = p->next()); calc_pixel(*p0++, *p1++, *p2++, *row++); if (p0 == end) p0 = c; else if (p1 == end) p1 = c; else if (p2 == end) p2 = c; } calc_pixel(*p0, *p1, *p1, *row); } void calc_pixel( pixel_type const & c1, pixel_type const & c2, pixel_type const & c3, pixel_type & x) { calc_pixel(c1, c2, c3, x, PixFmt::pixfmt_category()); } void calc_pixel( pixel_type const & c1, pixel_type const & c2, pixel_type const & c3, pixel_type & x, pixfmt_gray_tag) { x.c[0] = calc_value(c1.c[0], c2.c[0], c3.c[0]); } void calc_pixel( pixel_type const & c1, pixel_type const & c2, pixel_type const & c3, pixel_type & x, pixfmt_rgb_tag) { enum { R = order_type::R, G = order_type::G, B = order_type::B }; x.c[R] = calc_value(c1.c[R], c2.c[R], c3.c[R]); x.c[G] = calc_value(c1.c[G], c2.c[G], c3.c[G]); x.c[B] = calc_value(c1.c[B], c2.c[B], c3.c[B]); } void calc_pixel( pixel_type const & c1, pixel_type const & c2, pixel_type const & c3, pixel_type & x, pixfmt_rgba_tag) { enum { R = order_type::R, G = order_type::G, B = order_type::B, A = order_type::A }; x.c[R] = calc_value(c1.c[R], c2.c[R], c3.c[R]); x.c[G] = calc_value(c1.c[G], c2.c[G], c3.c[G]); x.c[B] = calc_value(c1.c[B], c2.c[B], c3.c[B]); x.c[A] = calc_value(c1.c[A], c2.c[A], c3.c[A]); } value_type calc_value(value_type v1, value_type v2, value_type v3) { return value_type(m_g1 * v1 + m_g0 * v2 + m_g1 * v3); } double m_g0, m_g1; pod_vector m_buf; }; // Helper functions for applying blur to a surface without having to create an intermediate object. template void apply_slight_blur(PixFmt& img, const rect_i& bounds, double r = 1) { if (r > 0) slight_blur(r).blur(img, bounds); } template void apply_slight_blur(PixFmt& img, double r = 1) { if (r > 0) slight_blur(r).blur(img, rect_i(0, 0, img.width() - 1, img.height() - 1)); } template void apply_slight_blur(renderer_base& img, const rect_i& bounds, double r = 1) { if (r > 0) slight_blur(r).blur(img.ren(), bounds); } template void apply_slight_blur(renderer_base& img, double r = 1) { if (r > 0) slight_blur(r).blur(img.ren(), img.clip_box()); } } #endif ragg/src/agg/include/agg_trans_perspective.h0000644000176200001440000006172313504406270020703 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Perspective 2D transformations // //---------------------------------------------------------------------------- #ifndef AGG_TRANS_PERSPECTIVE_INCLUDED #define AGG_TRANS_PERSPECTIVE_INCLUDED #include #include "agg_trans_affine.h" namespace agg { //=======================================================trans_perspective struct trans_perspective { double sx, shy, w0, shx, sy, w1, tx, ty, w2; //------------------------------------------------------- Construction // Identity matrix trans_perspective() : sx (1), shy(0), w0(0), shx(0), sy (1), w1(0), tx (0), ty (0), w2(1) {} // Custom matrix trans_perspective(double v0, double v1, double v2, double v3, double v4, double v5, double v6, double v7, double v8) : sx (v0), shy(v1), w0(v2), shx(v3), sy (v4), w1(v5), tx (v6), ty (v7), w2(v8) {} // Custom matrix from m[9] explicit trans_perspective(const double* m) : sx (m[0]), shy(m[1]), w0(m[2]), shx(m[3]), sy (m[4]), w1(m[5]), tx (m[6]), ty (m[7]), w2(m[8]) {} // From affine explicit trans_perspective(const trans_affine& a) : sx (a.sx ), shy(a.shy), w0(0), shx(a.shx), sy (a.sy ), w1(0), tx (a.tx ), ty (a.ty ), w2(1) {} // Rectangle to quadrilateral trans_perspective(double x1, double y1, double x2, double y2, const double* quad); // Quadrilateral to rectangle trans_perspective(const double* quad, double x1, double y1, double x2, double y2); // Arbitrary quadrilateral transformations trans_perspective(const double* src, const double* dst); //-------------------------------------- Quadrilateral transformations // The arguments are double[8] that are mapped to quadrilaterals: // x1,y1, x2,y2, x3,y3, x4,y4 bool quad_to_quad(const double* qs, const double* qd); bool rect_to_quad(double x1, double y1, double x2, double y2, const double* q); bool quad_to_rect(const double* q, double x1, double y1, double x2, double y2); // Map square (0,0,1,1) to the quadrilateral and vice versa bool square_to_quad(const double* q); bool quad_to_square(const double* q); //--------------------------------------------------------- Operations // Reset - load an identity matrix const trans_perspective& reset(); // Invert matrix. Returns false in degenerate case bool invert(); // Direct transformations operations const trans_perspective& translate(double x, double y); const trans_perspective& rotate(double a); const trans_perspective& scale(double s); const trans_perspective& scale(double x, double y); // Multiply the matrix by another one const trans_perspective& multiply(const trans_perspective& m); // Multiply "m" by "this" and assign the result to "this" const trans_perspective& premultiply(const trans_perspective& m); // Multiply matrix to inverse of another one const trans_perspective& multiply_inv(const trans_perspective& m); // Multiply inverse of "m" by "this" and assign the result to "this" const trans_perspective& premultiply_inv(const trans_perspective& m); // Multiply the matrix by another one const trans_perspective& multiply(const trans_affine& m); // Multiply "m" by "this" and assign the result to "this" const trans_perspective& premultiply(const trans_affine& m); // Multiply the matrix by inverse of another one const trans_perspective& multiply_inv(const trans_affine& m); // Multiply inverse of "m" by "this" and assign the result to "this" const trans_perspective& premultiply_inv(const trans_affine& m); //--------------------------------------------------------- Load/Store void store_to(double* m) const; const trans_perspective& load_from(const double* m); //---------------------------------------------------------- Operators // Multiply the matrix by another one const trans_perspective& operator *= (const trans_perspective& m) { return multiply(m); } const trans_perspective& operator *= (const trans_affine& m) { return multiply(m); } // Multiply the matrix by inverse of another one const trans_perspective& operator /= (const trans_perspective& m) { return multiply_inv(m); } const trans_perspective& operator /= (const trans_affine& m) { return multiply_inv(m); } // Multiply the matrix by another one and return // the result in a separete matrix. trans_perspective operator * (const trans_perspective& m) const { return trans_perspective(*this).multiply(m); } trans_perspective operator * (const trans_affine& m) const { return trans_perspective(*this).multiply(m); } // Multiply the matrix by inverse of another one // and return the result in a separete matrix. trans_perspective operator / (const trans_perspective& m) const { return trans_perspective(*this).multiply_inv(m); } trans_perspective operator / (const trans_affine& m) const { return trans_perspective(*this).multiply_inv(m); } // Calculate and return the inverse matrix trans_perspective operator ~ () const { trans_perspective ret = *this; ret.invert(); return ret; } // Equal operator with default epsilon bool operator == (const trans_perspective& m) const { return is_equal(m, affine_epsilon); } // Not Equal operator with default epsilon bool operator != (const trans_perspective& m) const { return !is_equal(m, affine_epsilon); } //---------------------------------------------------- Transformations // Direct transformation of x and y void transform(double* x, double* y) const; // Direct transformation of x and y, affine part only void transform_affine(double* x, double* y) const; // Direct transformation of x and y, 2x2 matrix only, no translation void transform_2x2(double* x, double* y) const; // Inverse transformation of x and y. It works slow because // it explicitly inverts the matrix on every call. For massive // operations it's better to invert() the matrix and then use // direct transformations. void inverse_transform(double* x, double* y) const; //---------------------------------------------------------- Auxiliary const trans_perspective& from_affine(const trans_affine& a); double determinant() const; double determinant_reciprocal() const; bool is_valid(double epsilon = affine_epsilon) const; bool is_identity(double epsilon = affine_epsilon) const; bool is_equal(const trans_perspective& m, double epsilon = affine_epsilon) const; // Determine the major affine parameters. Use with caution // considering possible degenerate cases. double scale() const; double rotation() const; void translation(double* dx, double* dy) const; void scaling(double* x, double* y) const; void scaling_abs(double* x, double* y) const; //-------------------------------------------------------------------- class iterator_x { double den; double den_step; double nom_x; double nom_x_step; double nom_y; double nom_y_step; public: double x; double y; iterator_x() {} iterator_x(double px, double py, double step, const trans_perspective& m) : den(px * m.w0 + py * m.w1 + m.w2), den_step(m.w0 * step), nom_x(px * m.sx + py * m.shx + m.tx), nom_x_step(step * m.sx), nom_y(px * m.shy + py * m.sy + m.ty), nom_y_step(step * m.shy), x(nom_x / den), y(nom_y / den) {} void operator ++ () { den += den_step; nom_x += nom_x_step; nom_y += nom_y_step; double d = 1.0 / den; x = nom_x * d; y = nom_y * d; } }; //-------------------------------------------------------------------- iterator_x begin(double x, double y, double step) const { return iterator_x(x, y, step, *this); } }; //------------------------------------------------------------------------ inline bool trans_perspective::square_to_quad(const double* q) { double dx = q[0] - q[2] + q[4] - q[6]; double dy = q[1] - q[3] + q[5] - q[7]; if(dx == 0.0 && dy == 0.0) { // Affine case (parallelogram) //--------------- sx = q[2] - q[0]; shy = q[3] - q[1]; w0 = 0.0; shx = q[4] - q[2]; sy = q[5] - q[3]; w1 = 0.0; tx = q[0]; ty = q[1]; w2 = 1.0; } else { double dx1 = q[2] - q[4]; double dy1 = q[3] - q[5]; double dx2 = q[6] - q[4]; double dy2 = q[7] - q[5]; double den = dx1 * dy2 - dx2 * dy1; if(den == 0.0) { // Singular case //--------------- sx = shy = w0 = shx = sy = w1 = tx = ty = w2 = 0.0; return false; } // General case //--------------- double u = (dx * dy2 - dy * dx2) / den; double v = (dy * dx1 - dx * dy1) / den; sx = q[2] - q[0] + u * q[2]; shy = q[3] - q[1] + u * q[3]; w0 = u; shx = q[6] - q[0] + v * q[6]; sy = q[7] - q[1] + v * q[7]; w1 = v; tx = q[0]; ty = q[1]; w2 = 1.0; } return true; } //------------------------------------------------------------------------ inline bool trans_perspective::invert() { double d0 = sy * w2 - w1 * ty; double d1 = w0 * ty - shy * w2; double d2 = shy * w1 - w0 * sy; double d = sx * d0 + shx * d1 + tx * d2; if(d == 0.0) { sx = shy = w0 = shx = sy = w1 = tx = ty = w2 = 0.0; return false; } d = 1.0 / d; trans_perspective a = *this; sx = d * d0; shy = d * d1; w0 = d * d2; shx = d * (a.w1 *a.tx - a.shx*a.w2); sy = d * (a.sx *a.w2 - a.w0 *a.tx); w1 = d * (a.w0 *a.shx - a.sx *a.w1); tx = d * (a.shx*a.ty - a.sy *a.tx); ty = d * (a.shy*a.tx - a.sx *a.ty); w2 = d * (a.sx *a.sy - a.shy*a.shx); return true; } //------------------------------------------------------------------------ inline bool trans_perspective::quad_to_square(const double* q) { if(!square_to_quad(q)) return false; invert(); return true; } //------------------------------------------------------------------------ inline bool trans_perspective::quad_to_quad(const double* qs, const double* qd) { trans_perspective p; if(! quad_to_square(qs)) return false; if(!p.square_to_quad(qd)) return false; multiply(p); return true; } //------------------------------------------------------------------------ inline bool trans_perspective::rect_to_quad(double x1, double y1, double x2, double y2, const double* q) { double r[8]; r[0] = r[6] = x1; r[2] = r[4] = x2; r[1] = r[3] = y1; r[5] = r[7] = y2; return quad_to_quad(r, q); } //------------------------------------------------------------------------ inline bool trans_perspective::quad_to_rect(const double* q, double x1, double y1, double x2, double y2) { double r[8]; r[0] = r[6] = x1; r[2] = r[4] = x2; r[1] = r[3] = y1; r[5] = r[7] = y2; return quad_to_quad(q, r); } //------------------------------------------------------------------------ inline trans_perspective::trans_perspective(double x1, double y1, double x2, double y2, const double* quad) { rect_to_quad(x1, y1, x2, y2, quad); } //------------------------------------------------------------------------ inline trans_perspective::trans_perspective(const double* quad, double x1, double y1, double x2, double y2) { quad_to_rect(quad, x1, y1, x2, y2); } //------------------------------------------------------------------------ inline trans_perspective::trans_perspective(const double* src, const double* dst) { quad_to_quad(src, dst); } //------------------------------------------------------------------------ inline const trans_perspective& trans_perspective::reset() { sx = 1; shy = 0; w0 = 0; shx = 0; sy = 1; w1 = 0; tx = 0; ty = 0; w2 = 1; return *this; } //------------------------------------------------------------------------ inline const trans_perspective& trans_perspective::multiply(const trans_perspective& a) { trans_perspective b = *this; sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0; shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1; tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2; shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0; sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1; ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2; w0 = a.w0 *b.sx + a.w1 *b.shy + a.w2*b.w0; w1 = a.w0 *b.shx + a.w1 *b.sy + a.w2*b.w1; w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2*b.w2; return *this; } //------------------------------------------------------------------------ inline const trans_perspective& trans_perspective::multiply(const trans_affine& a) { trans_perspective b = *this; sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0; shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1; tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2; shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0; sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1; ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2; return *this; } //------------------------------------------------------------------------ inline const trans_perspective& trans_perspective::premultiply(const trans_perspective& b) { trans_perspective a = *this; sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0; shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1; tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2; shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0; sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1; ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2; w0 = a.w0 *b.sx + a.w1 *b.shy + a.w2*b.w0; w1 = a.w0 *b.shx + a.w1 *b.sy + a.w2*b.w1; w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2*b.w2; return *this; } //------------------------------------------------------------------------ inline const trans_perspective& trans_perspective::premultiply(const trans_affine& b) { trans_perspective a = *this; sx = a.sx *b.sx + a.shx*b.shy; shx = a.sx *b.shx + a.shx*b.sy; tx = a.sx *b.tx + a.shx*b.ty + a.tx; shy = a.shy*b.sx + a.sy *b.shy; sy = a.shy*b.shx + a.sy *b.sy; ty = a.shy*b.tx + a.sy *b.ty + a.ty; w0 = a.w0 *b.sx + a.w1 *b.shy; w1 = a.w0 *b.shx + a.w1 *b.sy; w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2; return *this; } //------------------------------------------------------------------------ const trans_perspective& trans_perspective::multiply_inv(const trans_perspective& m) { trans_perspective t = m; t.invert(); return multiply(t); } //------------------------------------------------------------------------ const trans_perspective& trans_perspective::multiply_inv(const trans_affine& m) { trans_affine t = m; t.invert(); return multiply(t); } //------------------------------------------------------------------------ const trans_perspective& trans_perspective::premultiply_inv(const trans_perspective& m) { trans_perspective t = m; t.invert(); return *this = t.multiply(*this); } //------------------------------------------------------------------------ const trans_perspective& trans_perspective::premultiply_inv(const trans_affine& m) { trans_perspective t(m); t.invert(); return *this = t.multiply(*this); } //------------------------------------------------------------------------ inline const trans_perspective& trans_perspective::translate(double x, double y) { tx += x; ty += y; return *this; } //------------------------------------------------------------------------ inline const trans_perspective& trans_perspective::rotate(double a) { multiply(trans_affine_rotation(a)); return *this; } //------------------------------------------------------------------------ inline const trans_perspective& trans_perspective::scale(double s) { multiply(trans_affine_scaling(s)); return *this; } //------------------------------------------------------------------------ inline const trans_perspective& trans_perspective::scale(double x, double y) { multiply(trans_affine_scaling(x, y)); return *this; } //------------------------------------------------------------------------ inline void trans_perspective::transform(double* px, double* py) const { double x = *px; double y = *py; double m = 1.0 / (x*w0 + y*w1 + w2); *px = m * (x*sx + y*shx + tx); *py = m * (x*shy + y*sy + ty); } //------------------------------------------------------------------------ inline void trans_perspective::transform_affine(double* x, double* y) const { double tmp = *x; *x = tmp * sx + *y * shx + tx; *y = tmp * shy + *y * sy + ty; } //------------------------------------------------------------------------ inline void trans_perspective::transform_2x2(double* x, double* y) const { double tmp = *x; *x = tmp * sx + *y * shx; *y = tmp * shy + *y * sy; } //------------------------------------------------------------------------ inline void trans_perspective::inverse_transform(double* x, double* y) const { trans_perspective t(*this); if(t.invert()) t.transform(x, y); } //------------------------------------------------------------------------ inline void trans_perspective::store_to(double* m) const { *m++ = sx; *m++ = shy; *m++ = w0; *m++ = shx; *m++ = sy; *m++ = w1; *m++ = tx; *m++ = ty; *m++ = w2; } //------------------------------------------------------------------------ inline const trans_perspective& trans_perspective::load_from(const double* m) { sx = *m++; shy = *m++; w0 = *m++; shx = *m++; sy = *m++; w1 = *m++; tx = *m++; ty = *m++; w2 = *m++; return *this; } //------------------------------------------------------------------------ inline const trans_perspective& trans_perspective::from_affine(const trans_affine& a) { sx = a.sx; shy = a.shy; w0 = 0; shx = a.shx; sy = a.sy; w1 = 0; tx = a.tx; ty = a.ty; w2 = 1; return *this; } //------------------------------------------------------------------------ inline double trans_perspective::determinant() const { return sx * (sy * w2 - ty * w1) + shx * (ty * w0 - shy * w2) + tx * (shy * w1 - sy * w0); } //------------------------------------------------------------------------ inline double trans_perspective::determinant_reciprocal() const { return 1.0 / determinant(); } //------------------------------------------------------------------------ inline bool trans_perspective::is_valid(double epsilon) const { return std::fabs(sx) > epsilon && std::fabs(sy) > epsilon && std::fabs(w2) > epsilon; } //------------------------------------------------------------------------ inline bool trans_perspective::is_identity(double epsilon) const { return is_equal_eps(sx, 1.0, epsilon) && is_equal_eps(shy, 0.0, epsilon) && is_equal_eps(w0, 0.0, epsilon) && is_equal_eps(shx, 0.0, epsilon) && is_equal_eps(sy, 1.0, epsilon) && is_equal_eps(w1, 0.0, epsilon) && is_equal_eps(tx, 0.0, epsilon) && is_equal_eps(ty, 0.0, epsilon) && is_equal_eps(w2, 1.0, epsilon); } //------------------------------------------------------------------------ inline bool trans_perspective::is_equal(const trans_perspective& m, double epsilon) const { return is_equal_eps(sx, m.sx, epsilon) && is_equal_eps(shy, m.shy, epsilon) && is_equal_eps(w0, m.w0, epsilon) && is_equal_eps(shx, m.shx, epsilon) && is_equal_eps(sy, m.sy, epsilon) && is_equal_eps(w1, m.w1, epsilon) && is_equal_eps(tx, m.tx, epsilon) && is_equal_eps(ty, m.ty, epsilon) && is_equal_eps(w2, m.w2, epsilon); } //------------------------------------------------------------------------ inline double trans_perspective::scale() const { double x = 0.707106781 * sx + 0.707106781 * shx; double y = 0.707106781 * shy + 0.707106781 * sy; return std::sqrt(x*x + y*y); } //------------------------------------------------------------------------ inline double trans_perspective::rotation() const { double x1 = 0.0; double y1 = 0.0; double x2 = 1.0; double y2 = 0.0; transform(&x1, &y1); transform(&x2, &y2); return std::atan2(y2-y1, x2-x1); } //------------------------------------------------------------------------ void trans_perspective::translation(double* dx, double* dy) const { *dx = tx; *dy = ty; } //------------------------------------------------------------------------ void trans_perspective::scaling(double* x, double* y) const { double x1 = 0.0; double y1 = 0.0; double x2 = 1.0; double y2 = 1.0; trans_perspective t(*this); t *= trans_affine_rotation(-rotation()); t.transform(&x1, &y1); t.transform(&x2, &y2); *x = x2 - x1; *y = y2 - y1; } //------------------------------------------------------------------------ void trans_perspective::scaling_abs(double* x, double* y) const { *x = std::sqrt(sx * sx + shx * shx); *y = std::sqrt(shy * shy + sy * sy); } } #endif ragg/src/agg/include/agg_bitset_iterator.h0000644000176200001440000000261413504406270020340 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_BITSET_ITERATOR_INCLUDED #define AGG_BITSET_ITERATOR_INCLUDED #include "agg_basics.h" namespace agg { class bitset_iterator { public: bitset_iterator(const int8u* bits, unsigned offset = 0) : m_bits(bits + (offset >> 3)), m_mask(0x80 >> (offset & 7)) {} void operator ++ () { m_mask >>= 1; if(m_mask == 0) { ++m_bits; m_mask = 0x80; } } unsigned bit() const { return (*m_bits) & m_mask; } private: const int8u* m_bits; int8u m_mask; }; } #endif ragg/src/agg/include/agg_conv_adaptor_vcgen.h0000644000176200001440000001155013504406270020775 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_CONV_ADAPTOR_VCGEN_INCLUDED #define AGG_CONV_ADAPTOR_VCGEN_INCLUDED #include "agg_basics.h" namespace agg { //------------------------------------------------------------null_markers struct null_markers { void remove_all() {} void add_vertex(double, double, unsigned) {} void prepare_src() {} void rewind(unsigned) {} unsigned vertex(double*, double*) { return path_cmd_stop; } }; //------------------------------------------------------conv_adaptor_vcgen template class conv_adaptor_vcgen { enum status { initial, accumulate, generate }; public: explicit conv_adaptor_vcgen(VertexSource& source) : m_source(&source), m_status(initial) {} void attach(VertexSource& source) { m_source = &source; } Generator& generator() { return m_generator; } const Generator& generator() const { return m_generator; } Markers& markers() { return m_markers; } const Markers& markers() const { return m_markers; } void rewind(unsigned path_id) { m_source->rewind(path_id); m_status = initial; } unsigned vertex(double* x, double* y); private: // Prohibit copying conv_adaptor_vcgen(const conv_adaptor_vcgen&); const conv_adaptor_vcgen& operator = (const conv_adaptor_vcgen&); VertexSource* m_source; Generator m_generator; Markers m_markers; status m_status; unsigned m_last_cmd; double m_start_x; double m_start_y; }; //------------------------------------------------------------------------ template unsigned conv_adaptor_vcgen::vertex(double* x, double* y) { unsigned cmd = path_cmd_stop; bool done = false; while(!done) { switch(m_status) { case initial: m_markers.remove_all(); m_last_cmd = m_source->vertex(&m_start_x, &m_start_y); m_status = accumulate; case accumulate: if(is_stop(m_last_cmd)) return path_cmd_stop; m_generator.remove_all(); m_generator.add_vertex(m_start_x, m_start_y, path_cmd_move_to); m_markers.add_vertex(m_start_x, m_start_y, path_cmd_move_to); for(;;) { cmd = m_source->vertex(x, y); if(is_vertex(cmd)) { m_last_cmd = cmd; if(is_move_to(cmd)) { m_start_x = *x; m_start_y = *y; break; } m_generator.add_vertex(*x, *y, cmd); m_markers.add_vertex(*x, *y, path_cmd_line_to); } else { if(is_stop(cmd)) { m_last_cmd = path_cmd_stop; break; } if(is_end_poly(cmd)) { m_generator.add_vertex(*x, *y, cmd); break; } } } m_generator.rewind(0); m_status = generate; case generate: cmd = m_generator.vertex(x, y); if(is_stop(cmd)) { m_status = accumulate; break; } done = true; break; } } return cmd; } } #endif ragg/src/agg/include/agg_span_solid.h0000644000176200001440000000324613504406270017272 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // span_solid_rgba8 // //---------------------------------------------------------------------------- #ifndef AGG_SPAN_SOLID_INCLUDED #define AGG_SPAN_SOLID_INCLUDED #include "agg_basics.h" namespace agg { //--------------------------------------------------------------span_solid template class span_solid { public: typedef ColorT color_type; //-------------------------------------------------------------------- void color(const color_type& c) { m_color = c; } const color_type& color() const { return m_color; } //-------------------------------------------------------------------- void prepare() {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { do { *span++ = m_color; } while(--len); } private: color_type m_color; }; } #endif ragg/src/agg/include/agg_renderer_primitives.h0000644000176200001440000001717513504406270021226 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // class renderer_primitives // //---------------------------------------------------------------------------- #ifndef AGG_RENDERER_PRIMITIVES_INCLUDED #define AGG_RENDERER_PRIMITIVES_INCLUDED #include "agg_basics.h" #include "agg_renderer_base.h" #include "agg_dda_line.h" #include "agg_ellipse_bresenham.h" namespace agg { //-----------------------------------------------------renderer_primitives template class renderer_primitives { public: typedef BaseRenderer base_ren_type; typedef typename base_ren_type::color_type color_type; //-------------------------------------------------------------------- explicit renderer_primitives(base_ren_type& ren) : m_ren(&ren), m_fill_color(), m_line_color(), m_curr_x(0), m_curr_y(0) {} void attach(base_ren_type& ren) { m_ren = &ren; } //-------------------------------------------------------------------- static int coord(double c) { return iround(c * line_bresenham_interpolator::subpixel_scale); } //-------------------------------------------------------------------- void fill_color(const color_type& c) { m_fill_color = c; } void line_color(const color_type& c) { m_line_color = c; } const color_type& fill_color() const { return m_fill_color; } const color_type& line_color() const { return m_line_color; } //-------------------------------------------------------------------- void rectangle(int x1, int y1, int x2, int y2) { m_ren->blend_hline(x1, y1, x2-1, m_line_color, cover_full); m_ren->blend_vline(x2, y1, y2-1, m_line_color, cover_full); m_ren->blend_hline(x1+1, y2, x2, m_line_color, cover_full); m_ren->blend_vline(x1, y1+1, y2, m_line_color, cover_full); } //-------------------------------------------------------------------- void solid_rectangle(int x1, int y1, int x2, int y2) { m_ren->blend_bar(x1, y1, x2, y2, m_fill_color, cover_full); } //-------------------------------------------------------------------- void outlined_rectangle(int x1, int y1, int x2, int y2) { rectangle(x1, y1, x2, y2); m_ren->blend_bar(x1+1, y1+1, x2-1, y2-1, m_fill_color, cover_full); } //-------------------------------------------------------------------- void ellipse(int x, int y, int rx, int ry) { ellipse_bresenham_interpolator ei(rx, ry); int dx = 0; int dy = -ry; do { dx += ei.dx(); dy += ei.dy(); m_ren->blend_pixel(x + dx, y + dy, m_line_color, cover_full); m_ren->blend_pixel(x + dx, y - dy, m_line_color, cover_full); m_ren->blend_pixel(x - dx, y - dy, m_line_color, cover_full); m_ren->blend_pixel(x - dx, y + dy, m_line_color, cover_full); ++ei; } while(dy < 0); } //-------------------------------------------------------------------- void solid_ellipse(int x, int y, int rx, int ry) { ellipse_bresenham_interpolator ei(rx, ry); int dx = 0; int dy = -ry; int dy0 = dy; int dx0 = dx; do { dx += ei.dx(); dy += ei.dy(); if(dy != dy0) { m_ren->blend_hline(x-dx0, y+dy0, x+dx0, m_fill_color, cover_full); m_ren->blend_hline(x-dx0, y-dy0, x+dx0, m_fill_color, cover_full); } dx0 = dx; dy0 = dy; ++ei; } while(dy < 0); m_ren->blend_hline(x-dx0, y+dy0, x+dx0, m_fill_color, cover_full); } //-------------------------------------------------------------------- void outlined_ellipse(int x, int y, int rx, int ry) { ellipse_bresenham_interpolator ei(rx, ry); int dx = 0; int dy = -ry; do { dx += ei.dx(); dy += ei.dy(); m_ren->blend_pixel(x + dx, y + dy, m_line_color, cover_full); m_ren->blend_pixel(x + dx, y - dy, m_line_color, cover_full); m_ren->blend_pixel(x - dx, y - dy, m_line_color, cover_full); m_ren->blend_pixel(x - dx, y + dy, m_line_color, cover_full); if(ei.dy() && dx) { m_ren->blend_hline(x-dx+1, y+dy, x+dx-1, m_fill_color, cover_full); m_ren->blend_hline(x-dx+1, y-dy, x+dx-1, m_fill_color, cover_full); } ++ei; } while(dy < 0); } //-------------------------------------------------------------------- void line(int x1, int y1, int x2, int y2, bool last=false) { line_bresenham_interpolator li(x1, y1, x2, y2); unsigned len = li.len(); if(len == 0) { if(last) { m_ren->blend_pixel(li.line_lr(x1), li.line_lr(y1), m_line_color, cover_full); } return; } if(last) ++len; if(li.is_ver()) { do { m_ren->blend_pixel(li.x2(), li.y1(), m_line_color, cover_full); li.vstep(); } while(--len); } else { do { m_ren->blend_pixel(li.x1(), li.y2(), m_line_color, cover_full); li.hstep(); } while(--len); } } //-------------------------------------------------------------------- void move_to(int x, int y) { m_curr_x = x; m_curr_y = y; } //-------------------------------------------------------------------- void line_to(int x, int y, bool last=false) { line(m_curr_x, m_curr_y, x, y, last); m_curr_x = x; m_curr_y = y; } //-------------------------------------------------------------------- const base_ren_type& ren() const { return *m_ren; } base_ren_type& ren() { return *m_ren; } //-------------------------------------------------------------------- const rendering_buffer& rbuf() const { return m_ren->rbuf(); } rendering_buffer& rbuf() { return m_ren->rbuf(); } private: base_ren_type* m_ren; color_type m_fill_color; color_type m_line_color; int m_curr_x; int m_curr_y; }; } #endif ragg/src/agg/include/util/0000755000176200001440000000000014147726441015131 5ustar liggesusersragg/src/agg/include/util/agg_color_conv.h0000644000176200001440000000746313442776214020275 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Conversion from one colorspace/pixel format to another // //---------------------------------------------------------------------------- #ifndef AGG_COLOR_CONV_INCLUDED #define AGG_COLOR_CONV_INCLUDED #include #include "agg_basics.h" #include "agg_rendering_buffer.h" namespace agg { //--------------------------------------------------------------color_conv template void color_conv(RenBuf* dst, const RenBuf* src, CopyRow copy_row_functor) { unsigned width = src->width(); unsigned height = src->height(); if(dst->width() < width) width = dst->width(); if(dst->height() < height) height = dst->height(); if(width) { unsigned y; for(y = 0; y < height; y++) { copy_row_functor(dst->row_ptr(0, y, width), src->row_ptr(y), width); } } } //---------------------------------------------------------color_conv_row template void color_conv_row(int8u* dst, const int8u* src, unsigned width, CopyRow copy_row_functor) { copy_row_functor(dst, src, width); } //---------------------------------------------------------color_conv_same template class color_conv_same { public: void operator () (int8u* dst, const int8u* src, unsigned width) const { std::memmove(dst, src, width*BPP); } }; // Generic pixel converter. template struct conv_pixel { void operator()(void* dst, const void* src) const { // Read a pixel from the source format and write it to the destination format. DstFormat::write_plain_color(dst, SrcFormat::read_plain_color(src)); } }; // Generic row converter. Uses conv_pixel to convert individual pixels. template struct conv_row { void operator()(void* dst, const void* src, unsigned width) const { conv_pixel conv; do { conv(dst, src); dst = (int8u*)dst + DstFormat::pix_width; src = (int8u*)src + SrcFormat::pix_width; } while (--width); } }; // Specialization for case where source and destination formats are identical. template struct conv_row { void operator()(void* dst, const void* src, unsigned width) const { std::memmove(dst, src, width * Format::pix_width); } }; // Top-level conversion function, converts one pixel format to any other. template void convert(RenBuf* dst, const RenBuf* src) { color_conv(dst, src, conv_row()); } } #endif ragg/src/agg/include/agg_vcgen_contour.h0000644000176200001440000000657413504406270020021 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_VCGEN_CONTOUR_INCLUDED #define AGG_VCGEN_CONTOUR_INCLUDED #include "agg_math_stroke.h" namespace agg { //----------------------------------------------------------vcgen_contour // // See Implementation agg_vcgen_contour.cpp // class vcgen_contour { enum status_e { initial, ready, outline, out_vertices, end_poly, stop }; public: typedef vertex_sequence vertex_storage; typedef pod_bvector coord_storage; vcgen_contour(); void line_cap(line_cap_e lc) { m_stroker.line_cap(lc); } void line_join(line_join_e lj) { m_stroker.line_join(lj); } void inner_join(inner_join_e ij) { m_stroker.inner_join(ij); } line_cap_e line_cap() const { return m_stroker.line_cap(); } line_join_e line_join() const { return m_stroker.line_join(); } inner_join_e inner_join() const { return m_stroker.inner_join(); } void width(double w) { m_stroker.width(m_width = w); } void miter_limit(double ml) { m_stroker.miter_limit(ml); } void miter_limit_theta(double t) { m_stroker.miter_limit_theta(t); } void inner_miter_limit(double ml) { m_stroker.inner_miter_limit(ml); } void approximation_scale(double as) { m_stroker.approximation_scale(as); } double width() const { return m_width; } double miter_limit() const { return m_stroker.miter_limit(); } double inner_miter_limit() const { return m_stroker.inner_miter_limit(); } double approximation_scale() const { return m_stroker.approximation_scale(); } void auto_detect_orientation(bool v) { m_auto_detect = v; } bool auto_detect_orientation() const { return m_auto_detect; } // Generator interface void remove_all(); void add_vertex(double x, double y, unsigned cmd); // Vertex Source Interface void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: vcgen_contour(const vcgen_contour&); const vcgen_contour& operator = (const vcgen_contour&); math_stroke m_stroker; double m_width; vertex_storage m_src_vertices; coord_storage m_out_vertices; status_e m_status; unsigned m_src_vertex; unsigned m_out_vertex; unsigned m_closed; unsigned m_orientation; bool m_auto_detect; }; } #endif ragg/src/agg/include/agg_clip_liang_barsky.h0000644000176200001440000002263213504406270020613 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Liang-Barsky clipping // //---------------------------------------------------------------------------- #ifndef AGG_CLIP_LIANG_BARSKY_INCLUDED #define AGG_CLIP_LIANG_BARSKY_INCLUDED #include "agg_basics.h" namespace agg { //------------------------------------------------------------------------ enum clipping_flags_e { clipping_flags_x1_clipped = 4, clipping_flags_x2_clipped = 1, clipping_flags_y1_clipped = 8, clipping_flags_y2_clipped = 2, clipping_flags_x_clipped = clipping_flags_x1_clipped | clipping_flags_x2_clipped, clipping_flags_y_clipped = clipping_flags_y1_clipped | clipping_flags_y2_clipped }; //----------------------------------------------------------clipping_flags // Determine the clipping code of the vertex according to the // Cyrus-Beck line clipping algorithm // // | | // 0110 | 0010 | 0011 // | | // -------+--------+-------- clip_box.y2 // | | // 0100 | 0000 | 0001 // | | // -------+--------+-------- clip_box.y1 // | | // 1100 | 1000 | 1001 // | | // clip_box.x1 clip_box.x2 // // template inline unsigned clipping_flags(T x, T y, const rect_base& clip_box) { return (x > clip_box.x2) | ((y > clip_box.y2) << 1) | ((x < clip_box.x1) << 2) | ((y < clip_box.y1) << 3); } //--------------------------------------------------------clipping_flags_x template inline unsigned clipping_flags_x(T x, const rect_base& clip_box) { return (x > clip_box.x2) | ((x < clip_box.x1) << 2); } //--------------------------------------------------------clipping_flags_y template inline unsigned clipping_flags_y(T y, const rect_base& clip_box) { return ((y > clip_box.y2) << 1) | ((y < clip_box.y1) << 3); } //-------------------------------------------------------clip_liang_barsky template inline unsigned clip_liang_barsky(T x1, T y1, T x2, T y2, const rect_base& clip_box, T* x, T* y) { const double nearzero = 1e-30; double deltax = x2 - x1; double deltay = y2 - y1; double xin; double xout; double yin; double yout; double tinx; double tiny; double toutx; double touty; double tin1; double tin2; double tout1; unsigned np = 0; if(deltax == 0.0) { // bump off of the vertical deltax = (x1 > clip_box.x1) ? -nearzero : nearzero; } if(deltay == 0.0) { // bump off of the horizontal deltay = (y1 > clip_box.y1) ? -nearzero : nearzero; } if(deltax > 0.0) { // points to right xin = clip_box.x1; xout = clip_box.x2; } else { xin = clip_box.x2; xout = clip_box.x1; } if(deltay > 0.0) { // points up yin = clip_box.y1; yout = clip_box.y2; } else { yin = clip_box.y2; yout = clip_box.y1; } tinx = (xin - x1) / deltax; tiny = (yin - y1) / deltay; if (tinx < tiny) { // hits x first tin1 = tinx; tin2 = tiny; } else { // hits y first tin1 = tiny; tin2 = tinx; } if(tin1 <= 1.0) { if(0.0 < tin1) { *x++ = (T)xin; *y++ = (T)yin; ++np; } if(tin2 <= 1.0) { toutx = (xout - x1) / deltax; touty = (yout - y1) / deltay; tout1 = (toutx < touty) ? toutx : touty; if(tin2 > 0.0 || tout1 > 0.0) { if(tin2 <= tout1) { if(tin2 > 0.0) { if(tinx > tiny) { *x++ = (T)xin; *y++ = (T)(y1 + tinx * deltay); } else { *x++ = (T)(x1 + tiny * deltax); *y++ = (T)yin; } ++np; } if(tout1 < 1.0) { if(toutx < touty) { *x++ = (T)xout; *y++ = (T)(y1 + toutx * deltay); } else { *x++ = (T)(x1 + touty * deltax); *y++ = (T)yout; } } else { *x++ = x2; *y++ = y2; } ++np; } else { if(tinx > tiny) { *x++ = (T)xin; *y++ = (T)yout; } else { *x++ = (T)xout; *y++ = (T)yin; } ++np; } } } } return np; } //---------------------------------------------------------------------------- template bool clip_move_point(T x1, T y1, T x2, T y2, const rect_base& clip_box, T* x, T* y, unsigned flags) { T bound; if(flags & clipping_flags_x_clipped) { if(x1 == x2) { return false; } bound = (flags & clipping_flags_x1_clipped) ? clip_box.x1 : clip_box.x2; *y = (T)(double(bound - x1) * (y2 - y1) / (x2 - x1) + y1); *x = bound; } flags = clipping_flags_y(*y, clip_box); if(flags & clipping_flags_y_clipped) { if(y1 == y2) { return false; } bound = (flags & clipping_flags_y1_clipped) ? clip_box.y1 : clip_box.y2; *x = (T)(double(bound - y1) * (x2 - x1) / (y2 - y1) + x1); *y = bound; } return true; } //-------------------------------------------------------clip_line_segment // Returns: ret >= 4 - Fully clipped // (ret & 1) != 0 - First point has been moved // (ret & 2) != 0 - Second point has been moved // template unsigned clip_line_segment(T* x1, T* y1, T* x2, T* y2, const rect_base& clip_box) { unsigned f1 = clipping_flags(*x1, *y1, clip_box); unsigned f2 = clipping_flags(*x2, *y2, clip_box); unsigned ret = 0; if((f2 | f1) == 0) { // Fully visible return 0; } if((f1 & clipping_flags_x_clipped) != 0 && (f1 & clipping_flags_x_clipped) == (f2 & clipping_flags_x_clipped)) { // Fully clipped return 4; } if((f1 & clipping_flags_y_clipped) != 0 && (f1 & clipping_flags_y_clipped) == (f2 & clipping_flags_y_clipped)) { // Fully clipped return 4; } T tx1 = *x1; T ty1 = *y1; T tx2 = *x2; T ty2 = *y2; if(f1) { if(!clip_move_point(tx1, ty1, tx2, ty2, clip_box, x1, y1, f1)) { return 4; } if(*x1 == *x2 && *y1 == *y2) { return 4; } ret |= 1; } if(f2) { if(!clip_move_point(tx1, ty1, tx2, ty2, clip_box, x2, y2, f2)) { return 4; } if(*x1 == *x2 && *y1 == *y2) { return 4; } ret |= 2; } return ret; } } #endif ragg/src/agg/include/agg_scanline_p.h0000644000176200001440000002441013504406270017246 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Class scanline_p - a general purpose scanline container with packed spans. // //---------------------------------------------------------------------------- // // Adaptation for 32-bit screen coordinates (scanline32_p) 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_SCANLINE_P_INCLUDED #define AGG_SCANLINE_P_INCLUDED #include #include "agg_array.h" namespace agg { //=============================================================scanline_p8 // // This is a general purpose scaline container which supports the interface // used in the rasterizer::render(). See description of scanline_u8 // for details. // //------------------------------------------------------------------------ class scanline_p8 { public: typedef scanline_p8 self_type; typedef int8u cover_type; typedef int16 coord_type; //-------------------------------------------------------------------- struct span { coord_type x; coord_type len; // If negative, it's a solid span, covers is valid const cover_type* covers; }; typedef span* iterator; typedef const span* const_iterator; scanline_p8() : m_last_x(0x7FFFFFF0), m_covers(), m_cover_ptr(0), m_spans(), m_cur_span(0) { } //-------------------------------------------------------------------- void reset(int min_x, int max_x) { unsigned max_len = max_x - min_x + 3; if(max_len > m_spans.size()) { m_spans.resize(max_len); m_covers.resize(max_len); } m_last_x = 0x7FFFFFF0; m_cover_ptr = &m_covers[0]; m_cur_span = &m_spans[0]; m_cur_span->len = 0; } //-------------------------------------------------------------------- void add_cell(int x, unsigned cover) { *m_cover_ptr = (cover_type)cover; if(x == m_last_x+1 && m_cur_span->len > 0) { m_cur_span->len++; } else { m_cur_span++; m_cur_span->covers = m_cover_ptr; m_cur_span->x = (int16)x; m_cur_span->len = 1; } m_last_x = x; m_cover_ptr++; } //-------------------------------------------------------------------- void add_cells(int x, unsigned len, const cover_type* covers) { std::memcpy(m_cover_ptr, covers, len * sizeof(cover_type)); if(x == m_last_x+1 && m_cur_span->len > 0) { m_cur_span->len += (int16)len; } else { m_cur_span++; m_cur_span->covers = m_cover_ptr; m_cur_span->x = (int16)x; m_cur_span->len = (int16)len; } m_cover_ptr += len; m_last_x = x + len - 1; } //-------------------------------------------------------------------- void add_span(int x, unsigned len, unsigned cover) { if(x == m_last_x+1 && m_cur_span->len < 0 && cover == *m_cur_span->covers) { m_cur_span->len -= (int16)len; } else { *m_cover_ptr = (cover_type)cover; m_cur_span++; m_cur_span->covers = m_cover_ptr++; m_cur_span->x = (int16)x; m_cur_span->len = (int16)(-int(len)); } m_last_x = x + len - 1; } //-------------------------------------------------------------------- void finalize(int y) { m_y = y; } //-------------------------------------------------------------------- void reset_spans() { m_last_x = 0x7FFFFFF0; m_cover_ptr = &m_covers[0]; m_cur_span = &m_spans[0]; m_cur_span->len = 0; } //-------------------------------------------------------------------- int y() const { return m_y; } unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); } const_iterator begin() const { return &m_spans[1]; } private: scanline_p8(const self_type&); const self_type& operator = (const self_type&); int m_last_x; int m_y; pod_array m_covers; cover_type* m_cover_ptr; pod_array m_spans; span* m_cur_span; }; //==========================================================scanline32_p8 class scanline32_p8 { public: typedef scanline32_p8 self_type; typedef int8u cover_type; typedef int32 coord_type; struct span { span() {} span(coord_type x_, coord_type len_, const cover_type* covers_) : x(x_), len(len_), covers(covers_) {} coord_type x; coord_type len; // If negative, it's a solid span, covers is valid const cover_type* covers; }; typedef pod_bvector span_array_type; //-------------------------------------------------------------------- class const_iterator { public: const_iterator(const span_array_type& spans) : m_spans(spans), m_span_idx(0) {} const span& operator*() const { return m_spans[m_span_idx]; } const span* operator->() const { return &m_spans[m_span_idx]; } void operator ++ () { ++m_span_idx; } private: const span_array_type& m_spans; unsigned m_span_idx; }; //-------------------------------------------------------------------- scanline32_p8() : m_max_len(0), m_last_x(0x7FFFFFF0), m_covers(), m_cover_ptr(0) { } //-------------------------------------------------------------------- void reset(int min_x, int max_x) { unsigned max_len = max_x - min_x + 3; if(max_len > m_covers.size()) { m_covers.resize(max_len); } m_last_x = 0x7FFFFFF0; m_cover_ptr = &m_covers[0]; m_spans.remove_all(); } //-------------------------------------------------------------------- void add_cell(int x, unsigned cover) { *m_cover_ptr = cover_type(cover); if(x == m_last_x+1 && m_spans.size() && m_spans.last().len > 0) { m_spans.last().len++; } else { m_spans.add(span(coord_type(x), 1, m_cover_ptr)); } m_last_x = x; m_cover_ptr++; } //-------------------------------------------------------------------- void add_cells(int x, unsigned len, const cover_type* covers) { std::memcpy(m_cover_ptr, covers, len * sizeof(cover_type)); if(x == m_last_x+1 && m_spans.size() && m_spans.last().len > 0) { m_spans.last().len += coord_type(len); } else { m_spans.add(span(coord_type(x), coord_type(len), m_cover_ptr)); } m_cover_ptr += len; m_last_x = x + len - 1; } //-------------------------------------------------------------------- void add_span(int x, unsigned len, unsigned cover) { if(x == m_last_x+1 && m_spans.size() && m_spans.last().len < 0 && cover == *m_spans.last().covers) { m_spans.last().len -= coord_type(len); } else { *m_cover_ptr = cover_type(cover); m_spans.add(span(coord_type(x), -coord_type(len), m_cover_ptr++)); } m_last_x = x + len - 1; } //-------------------------------------------------------------------- void finalize(int y) { m_y = y; } //-------------------------------------------------------------------- void reset_spans() { m_last_x = 0x7FFFFFF0; m_cover_ptr = &m_covers[0]; m_spans.remove_all(); } //-------------------------------------------------------------------- int y() const { return m_y; } unsigned num_spans() const { return m_spans.size(); } const_iterator begin() const { return const_iterator(m_spans); } private: scanline32_p8(const self_type&); const self_type& operator = (const self_type&); unsigned m_max_len; int m_last_x; int m_y; pod_array m_covers; cover_type* m_cover_ptr; span_array_type m_spans; }; } #endif ragg/src/agg/include/agg_vpgen_clip_polyline.h0000644000176200001440000000441313504406270021175 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_VPGEN_CLIP_POLYLINE_INCLUDED #define AGG_VPGEN_CLIP_POLYLINE_INCLUDED #include "agg_basics.h" namespace agg { //======================================================vpgen_clip_polyline // // See Implementation agg_vpgen_clip_polyline.cpp // class vpgen_clip_polyline { public: vpgen_clip_polyline() : m_clip_box(0, 0, 1, 1), m_x1(0), m_y1(0), m_num_vertices(0), m_vertex(0), m_move_to(false) { } void clip_box(double x1, double y1, double x2, double y2) { m_clip_box.x1 = x1; m_clip_box.y1 = y1; m_clip_box.x2 = x2; m_clip_box.y2 = y2; m_clip_box.normalize(); } double x1() const { return m_clip_box.x1; } double y1() const { return m_clip_box.y1; } double x2() const { return m_clip_box.x2; } double y2() const { return m_clip_box.y2; } static bool auto_close() { return false; } static bool auto_unclose() { return true; } void reset(); void move_to(double x, double y); void line_to(double x, double y); unsigned vertex(double* x, double* y); private: rect_d m_clip_box; double m_x1; double m_y1; double m_x[2]; double m_y[2]; unsigned m_cmd[2]; unsigned m_num_vertices; unsigned m_vertex; bool m_move_to; }; } #endif ragg/src/agg/include/agg_rounded_rect.h0000644000176200001440000000430513504406270017611 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Rounded rectangle vertex generator // //---------------------------------------------------------------------------- #ifndef AGG_ROUNDED_RECT_INCLUDED #define AGG_ROUNDED_RECT_INCLUDED #include "agg_basics.h" #include "agg_arc.h" namespace agg { //------------------------------------------------------------rounded_rect // // See Implemantation agg_rounded_rect.cpp // class rounded_rect { public: rounded_rect() {} rounded_rect(double x1, double y1, double x2, double y2, double r); void rect(double x1, double y1, double x2, double y2); void radius(double r); void radius(double rx, double ry); void radius(double rx_bottom, double ry_bottom, double rx_top, double ry_top); void radius(double rx1, double ry1, double rx2, double ry2, double rx3, double ry3, double rx4, double ry4); void normalize_radius(); void approximation_scale(double s) { m_arc.approximation_scale(s); } double approximation_scale() const { return m_arc.approximation_scale(); } void rewind(unsigned); unsigned vertex(double* x, double* y); private: double m_x1; double m_y1; double m_x2; double m_y2; double m_rx1; double m_ry1; double m_rx2; double m_ry2; double m_rx3; double m_ry3; double m_rx4; double m_ry4; unsigned m_status; arc m_arc; }; } #endif ragg/src/agg/include/agg_trans_affine.h0000644000176200001440000004470013504406270017576 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Affine transformation classes. // //---------------------------------------------------------------------------- #ifndef AGG_TRANS_AFFINE_INCLUDED #define AGG_TRANS_AFFINE_INCLUDED #include #include "agg_basics.h" namespace agg { const double affine_epsilon = 1e-14; //============================================================trans_affine // // See Implementation agg_trans_affine.cpp // // Affine transformation are linear transformations in Cartesian coordinates // (strictly speaking not only in Cartesian, but for the beginning we will // think so). They are rotation, scaling, translation and skewing. // After any affine transformation a line segment remains a line segment // and it will never become a curve. // // There will be no math about matrix calculations, since it has been // described many times. Ask yourself a very simple question: // "why do we need to understand and use some matrix stuff instead of just // rotating, scaling and so on". The answers are: // // 1. Any combination of transformations can be done by only 4 multiplications // and 4 additions in floating point. // 2. One matrix transformation is equivalent to the number of consecutive // discrete transformations, i.e. the matrix "accumulates" all transformations // in the order of their settings. Suppose we have 4 transformations: // * rotate by 30 degrees, // * scale X to 2.0, // * scale Y to 1.5, // * move to (100, 100). // The result will depend on the order of these transformations, // and the advantage of matrix is that the sequence of discret calls: // rotate(30), scaleX(2.0), scaleY(1.5), move(100,100) // will have exactly the same result as the following matrix transformations: // // affine_matrix m; // m *= rotate_matrix(30); // m *= scaleX_matrix(2.0); // m *= scaleY_matrix(1.5); // m *= move_matrix(100,100); // // m.transform_my_point_at_last(x, y); // // What is the good of it? In real life we will set-up the matrix only once // and then transform many points, let alone the convenience to set any // combination of transformations. // // So, how to use it? Very easy - literally as it's shown above. Not quite, // let us write a correct example: // // agg::trans_affine m; // m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0); // m *= agg::trans_affine_scaling(2.0, 1.5); // m *= agg::trans_affine_translation(100.0, 100.0); // m.transform(&x, &y); // // The affine matrix is all you need to perform any linear transformation, // but all transformations have origin point (0,0). It means that we need to // use 2 translations if we want to rotate someting around (100,100): // // m *= agg::trans_affine_translation(-100.0, -100.0); // move to (0,0) // m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0); // rotate // m *= agg::trans_affine_translation(100.0, 100.0); // move back to (100,100) //---------------------------------------------------------------------- struct trans_affine { double sx, shy, shx, sy, tx, ty; //------------------------------------------ Construction // Identity matrix trans_affine() : sx(1.0), shy(0.0), shx(0.0), sy(1.0), tx(0.0), ty(0.0) {} // Custom matrix. Usually used in derived classes trans_affine(double v0, double v1, double v2, double v3, double v4, double v5) : sx(v0), shy(v1), shx(v2), sy(v3), tx(v4), ty(v5) {} // Custom matrix from m[6] explicit trans_affine(const double* m) : sx(m[0]), shy(m[1]), shx(m[2]), sy(m[3]), tx(m[4]), ty(m[5]) {} // Rectangle to a parallelogram. trans_affine(double x1, double y1, double x2, double y2, const double* parl) { rect_to_parl(x1, y1, x2, y2, parl); } // Parallelogram to a rectangle. trans_affine(const double* parl, double x1, double y1, double x2, double y2) { parl_to_rect(parl, x1, y1, x2, y2); } // Arbitrary parallelogram transformation. trans_affine(const double* src, const double* dst) { parl_to_parl(src, dst); } //---------------------------------- Parellelogram transformations // transform a parallelogram to another one. Src and dst are // pointers to arrays of three points (double[6], x1,y1,...) that // identify three corners of the parallelograms assuming implicit // fourth point. The arguments are arrays of double[6] mapped // to x1,y1, x2,y2, x3,y3 where the coordinates are: // *-----------------* // / (x3,y3)/ // / / // /(x1,y1) (x2,y2)/ // *-----------------* const trans_affine& parl_to_parl(const double* src, const double* dst); const trans_affine& rect_to_parl(double x1, double y1, double x2, double y2, const double* parl); const trans_affine& parl_to_rect(const double* parl, double x1, double y1, double x2, double y2); //------------------------------------------ Operations // Reset - load an identity matrix const trans_affine& reset(); // Direct transformations operations const trans_affine& translate(double x, double y); const trans_affine& rotate(double a); const trans_affine& scale(double s); const trans_affine& scale(double x, double y); // Multiply matrix to another one const trans_affine& multiply(const trans_affine& m); // Multiply "m" to "this" and assign the result to "this" const trans_affine& premultiply(const trans_affine& m); // Multiply matrix to inverse of another one const trans_affine& multiply_inv(const trans_affine& m); // Multiply inverse of "m" to "this" and assign the result to "this" const trans_affine& premultiply_inv(const trans_affine& m); // Invert matrix. Do not try to invert degenerate matrices, // there's no check for validity. If you set scale to 0 and // then try to invert matrix, expect unpredictable result. const trans_affine& invert(); // Mirroring around X const trans_affine& flip_x(); // Mirroring around Y const trans_affine& flip_y(); //------------------------------------------- Load/Store // Store matrix to an array [6] of double void store_to(double* m) const { *m++ = sx; *m++ = shy; *m++ = shx; *m++ = sy; *m++ = tx; *m++ = ty; } // Load matrix from an array [6] of double const trans_affine& load_from(const double* m) { sx = *m++; shy = *m++; shx = *m++; sy = *m++; tx = *m++; ty = *m++; return *this; } //------------------------------------------- Operators // Multiply the matrix by another one const trans_affine& operator *= (const trans_affine& m) { return multiply(m); } // Multiply the matrix by inverse of another one const trans_affine& operator /= (const trans_affine& m) { return multiply_inv(m); } // Multiply the matrix by another one and return // the result in a separete matrix. trans_affine operator * (const trans_affine& m) const { return trans_affine(*this).multiply(m); } // Multiply the matrix by inverse of another one // and return the result in a separete matrix. trans_affine operator / (const trans_affine& m) const { return trans_affine(*this).multiply_inv(m); } // Calculate and return the inverse matrix trans_affine operator ~ () const { trans_affine ret = *this; return ret.invert(); } // Equal operator with default epsilon bool operator == (const trans_affine& m) const { return is_equal(m, affine_epsilon); } // Not Equal operator with default epsilon bool operator != (const trans_affine& m) const { return !is_equal(m, affine_epsilon); } //-------------------------------------------- Transformations // Direct transformation of x and y void transform(double* x, double* y) const; // Direct transformation of x and y, 2x2 matrix only, no translation void transform_2x2(double* x, double* y) const; // Inverse transformation of x and y. It works slower than the // direct transformation. For massive operations it's better to // invert() the matrix and then use direct transformations. void inverse_transform(double* x, double* y) const; //-------------------------------------------- Auxiliary // Calculate the determinant of matrix double determinant() const { return sx * sy - shy * shx; } // Calculate the reciprocal of the determinant double determinant_reciprocal() const { return 1.0 / (sx * sy - shy * shx); } // Get the average scale (by X and Y). // Basically used to calculate the approximation_scale when // decomposinting curves into line segments. double scale() const; // Check to see if the matrix is not degenerate bool is_valid(double epsilon = affine_epsilon) const; // Check to see if it's an identity matrix bool is_identity(double epsilon = affine_epsilon) const; // Check to see if two matrices are equal bool is_equal(const trans_affine& m, double epsilon = affine_epsilon) const; // Determine the major parameters. Use with caution considering // possible degenerate cases. double rotation() const; void translation(double* dx, double* dy) const; void scaling(double* x, double* y) const; void scaling_abs(double* x, double* y) const; }; //------------------------------------------------------------------------ inline void trans_affine::transform(double* x, double* y) const { double tmp = *x; *x = tmp * sx + *y * shx + tx; *y = tmp * shy + *y * sy + ty; } //------------------------------------------------------------------------ inline void trans_affine::transform_2x2(double* x, double* y) const { double tmp = *x; *x = tmp * sx + *y * shx; *y = tmp * shy + *y * sy; } //------------------------------------------------------------------------ inline void trans_affine::inverse_transform(double* x, double* y) const { double d = determinant_reciprocal(); double a = (*x - tx) * d; double b = (*y - ty) * d; *x = a * sy - b * shx; *y = b * sx - a * shy; } //------------------------------------------------------------------------ inline double trans_affine::scale() const { double x = 0.707106781 * sx + 0.707106781 * shx; double y = 0.707106781 * shy + 0.707106781 * sy; return std::sqrt(x*x + y*y); } //------------------------------------------------------------------------ inline const trans_affine& trans_affine::translate(double x, double y) { tx += x; ty += y; return *this; } //------------------------------------------------------------------------ inline const trans_affine& trans_affine::rotate(double a) { double ca = std::cos(a); double sa = std::sin(a); double t0 = sx * ca - shy * sa; double t2 = shx * ca - sy * sa; double t4 = tx * ca - ty * sa; shy = sx * sa + shy * ca; sy = shx * sa + sy * ca; ty = tx * sa + ty * ca; sx = t0; shx = t2; tx = t4; return *this; } //------------------------------------------------------------------------ inline const trans_affine& trans_affine::scale(double x, double y) { double mm0 = x; // Possible hint for the optimizer double mm3 = y; sx *= mm0; shx *= mm0; tx *= mm0; shy *= mm3; sy *= mm3; ty *= mm3; return *this; } //------------------------------------------------------------------------ inline const trans_affine& trans_affine::scale(double s) { double m = s; // Possible hint for the optimizer sx *= m; shx *= m; tx *= m; shy *= m; sy *= m; ty *= m; return *this; } //------------------------------------------------------------------------ inline const trans_affine& trans_affine::premultiply(const trans_affine& m) { trans_affine t = m; return *this = t.multiply(*this); } //------------------------------------------------------------------------ inline const trans_affine& trans_affine::multiply_inv(const trans_affine& m) { trans_affine t = m; t.invert(); return multiply(t); } //------------------------------------------------------------------------ inline const trans_affine& trans_affine::premultiply_inv(const trans_affine& m) { trans_affine t = m; t.invert(); return *this = t.multiply(*this); } //------------------------------------------------------------------------ inline void trans_affine::scaling_abs(double* x, double* y) const { // Used to calculate scaling coefficients in image resampling. // When there is considerable shear this method gives us much // better estimation than just sx, sy. *x = std::sqrt(sx * sx + shx * shx); *y = std::sqrt(shy * shy + sy * sy); } //====================================================trans_affine_rotation // Rotation matrix. sin() and cos() are calculated twice for the same angle. // There's no harm because the performance of sin()/cos() is very good on all // modern processors. Besides, this operation is not going to be invoked too // often. class trans_affine_rotation : public trans_affine { public: trans_affine_rotation(double a) : trans_affine(std::cos(a), std::sin(a), -std::sin(a), std::cos(a), 0.0, 0.0) {} }; //====================================================trans_affine_scaling // Scaling matrix. x, y - scale coefficients by X and Y respectively class trans_affine_scaling : public trans_affine { public: trans_affine_scaling(double x, double y) : trans_affine(x, 0.0, 0.0, y, 0.0, 0.0) {} trans_affine_scaling(double s) : trans_affine(s, 0.0, 0.0, s, 0.0, 0.0) {} }; //================================================trans_affine_translation // Translation matrix class trans_affine_translation : public trans_affine { public: trans_affine_translation(double x, double y) : trans_affine(1.0, 0.0, 0.0, 1.0, x, y) {} }; //====================================================trans_affine_skewing // Sckewing (shear) matrix class trans_affine_skewing : public trans_affine { public: trans_affine_skewing(double x, double y) : trans_affine(1.0, std::tan(y), std::tan(x), 1.0, 0.0, 0.0) {} }; //===============================================trans_affine_line_segment // Rotate, Scale and Translate, associating 0...dist with line segment // x1,y1,x2,y2 class trans_affine_line_segment : public trans_affine { public: trans_affine_line_segment(double x1, double y1, double x2, double y2, double dist) { double dx = x2 - x1; double dy = y2 - y1; if(dist > 0.0) { multiply(trans_affine_scaling(std::sqrt(dx * dx + dy * dy) / dist)); } multiply(trans_affine_rotation(std::atan2(dy, dx))); multiply(trans_affine_translation(x1, y1)); } }; //============================================trans_affine_reflection_unit // Reflection matrix. Reflect coordinates across the line through // the origin containing the unit vector (ux, uy). // Contributed by John Horigan class trans_affine_reflection_unit : public trans_affine { public: trans_affine_reflection_unit(double ux, double uy) : trans_affine(2.0 * ux * ux - 1.0, 2.0 * ux * uy, 2.0 * ux * uy, 2.0 * uy * uy - 1.0, 0.0, 0.0) {} }; //=================================================trans_affine_reflection // Reflection matrix. Reflect coordinates across the line through // the origin at the angle a or containing the non-unit vector (x, y). // Contributed by John Horigan class trans_affine_reflection : public trans_affine_reflection_unit { public: trans_affine_reflection(double a) : trans_affine_reflection_unit(std::cos(a), std::sin(a)) {} trans_affine_reflection(double x, double y) : trans_affine_reflection_unit(x / std::sqrt(x * x + y * y), y / std::sqrt(x * x + y * y)) {} }; } #endif ragg/src/agg/include/agg_trans_double_path.h0000644000176200001440000001013313504406270020625 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_TRANS_DOUBLE_PATH_INCLUDED #define AGG_TRANS_DOUBLE_PATH_INCLUDED #include "agg_basics.h" #include "agg_vertex_sequence.h" namespace agg { // See also: agg_trans_double_path.cpp // //-------------------------------------------------------trans_double_path class trans_double_path { enum status_e { initial, making_path, ready }; public: typedef vertex_sequence vertex_storage; trans_double_path(); //-------------------------------------------------------------------- void base_length(double v) { m_base_length = v; } double base_length() const { return m_base_length; } //-------------------------------------------------------------------- void base_height(double v) { m_base_height = v; } double base_height() const { return m_base_height; } //-------------------------------------------------------------------- void preserve_x_scale(bool f) { m_preserve_x_scale = f; } bool preserve_x_scale() const { return m_preserve_x_scale; } //-------------------------------------------------------------------- void reset(); void move_to1(double x, double y); void line_to1(double x, double y); void move_to2(double x, double y); void line_to2(double x, double y); void finalize_paths(); //-------------------------------------------------------------------- template void add_paths(VertexSource1& vs1, VertexSource2& vs2, unsigned path1_id=0, unsigned path2_id=0) { double x; double y; unsigned cmd; vs1.rewind(path1_id); while(!is_stop(cmd = vs1.vertex(&x, &y))) { if(is_move_to(cmd)) { move_to1(x, y); } else { if(is_vertex(cmd)) { line_to1(x, y); } } } vs2.rewind(path2_id); while(!is_stop(cmd = vs2.vertex(&x, &y))) { if(is_move_to(cmd)) { move_to2(x, y); } else { if(is_vertex(cmd)) { line_to2(x, y); } } } finalize_paths(); } //-------------------------------------------------------------------- double total_length1() const; double total_length2() const; void transform(double *x, double *y) const; private: double finalize_path(vertex_storage& vertices); void transform1(const vertex_storage& vertices, double kindex, double kx, double *x, double* y) const; vertex_storage m_src_vertices1; vertex_storage m_src_vertices2; double m_base_length; double m_base_height; double m_kindex1; double m_kindex2; status_e m_status1; status_e m_status2; bool m_preserve_x_scale; }; } #endif ragg/src/agg/include/agg_renderer_outline_aa.h0000644000176200001440000017417213504406270021154 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_RENDERER_OUTLINE_AA_INCLUDED #define AGG_RENDERER_OUTLINE_AA_INCLUDED #include #include "agg_array.h" #include "agg_math.h" #include "agg_line_aa_basics.h" #include "agg_dda_line.h" #include "agg_ellipse_bresenham.h" #include "agg_renderer_base.h" #include "agg_gamma_functions.h" #include "agg_clip_liang_barsky.h" namespace agg { //===================================================distance_interpolator0 class distance_interpolator0 { public: //--------------------------------------------------------------------- distance_interpolator0() {} distance_interpolator0(int x1, int y1, int x2, int y2, int x, int y) : m_dx(line_mr(x2) - line_mr(x1)), m_dy(line_mr(y2) - line_mr(y1)), m_dist((line_mr(x + line_subpixel_scale/2) - line_mr(x2)) * m_dy - (line_mr(y + line_subpixel_scale/2) - line_mr(y2)) * m_dx) { m_dx <<= line_mr_subpixel_shift; m_dy <<= line_mr_subpixel_shift; } //--------------------------------------------------------------------- void inc_x() { m_dist += m_dy; } int dist() const { return m_dist; } private: //--------------------------------------------------------------------- int m_dx; int m_dy; int m_dist; }; //==================================================distance_interpolator00 class distance_interpolator00 { public: //--------------------------------------------------------------------- distance_interpolator00() {} distance_interpolator00(int xc, int yc, int x1, int y1, int x2, int y2, int x, int y) : m_dx1(line_mr(x1) - line_mr(xc)), m_dy1(line_mr(y1) - line_mr(yc)), m_dx2(line_mr(x2) - line_mr(xc)), m_dy2(line_mr(y2) - line_mr(yc)), m_dist1((line_mr(x + line_subpixel_scale/2) - line_mr(x1)) * m_dy1 - (line_mr(y + line_subpixel_scale/2) - line_mr(y1)) * m_dx1), m_dist2((line_mr(x + line_subpixel_scale/2) - line_mr(x2)) * m_dy2 - (line_mr(y + line_subpixel_scale/2) - line_mr(y2)) * m_dx2) { m_dx1 <<= line_mr_subpixel_shift; m_dy1 <<= line_mr_subpixel_shift; m_dx2 <<= line_mr_subpixel_shift; m_dy2 <<= line_mr_subpixel_shift; } //--------------------------------------------------------------------- void inc_x() { m_dist1 += m_dy1; m_dist2 += m_dy2; } int dist1() const { return m_dist1; } int dist2() const { return m_dist2; } private: //--------------------------------------------------------------------- int m_dx1; int m_dy1; int m_dx2; int m_dy2; int m_dist1; int m_dist2; }; //===================================================distance_interpolator1 class distance_interpolator1 { public: //--------------------------------------------------------------------- distance_interpolator1() {} distance_interpolator1(int x1, int y1, int x2, int y2, int x, int y) : m_dx(x2 - x1), m_dy(y2 - y1), m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) - double(y + line_subpixel_scale/2 - y2) * double(m_dx))) { m_dx <<= line_subpixel_shift; m_dy <<= line_subpixel_shift; } //--------------------------------------------------------------------- void inc_x() { m_dist += m_dy; } void dec_x() { m_dist -= m_dy; } void inc_y() { m_dist -= m_dx; } void dec_y() { m_dist += m_dx; } //--------------------------------------------------------------------- void inc_x(int dy) { m_dist += m_dy; if(dy > 0) m_dist -= m_dx; if(dy < 0) m_dist += m_dx; } //--------------------------------------------------------------------- void dec_x(int dy) { m_dist -= m_dy; if(dy > 0) m_dist -= m_dx; if(dy < 0) m_dist += m_dx; } //--------------------------------------------------------------------- void inc_y(int dx) { m_dist -= m_dx; if(dx > 0) m_dist += m_dy; if(dx < 0) m_dist -= m_dy; } void dec_y(int dx) //--------------------------------------------------------------------- { m_dist += m_dx; if(dx > 0) m_dist += m_dy; if(dx < 0) m_dist -= m_dy; } //--------------------------------------------------------------------- int dist() const { return m_dist; } int dx() const { return m_dx; } int dy() const { return m_dy; } private: //--------------------------------------------------------------------- int m_dx; int m_dy; int m_dist; }; //===================================================distance_interpolator2 class distance_interpolator2 { public: //--------------------------------------------------------------------- distance_interpolator2() {} distance_interpolator2(int x1, int y1, int x2, int y2, int sx, int sy, int x, int y) : m_dx(x2 - x1), m_dy(y2 - y1), m_dx_start(line_mr(sx) - line_mr(x1)), m_dy_start(line_mr(sy) - line_mr(y1)), m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) - double(y + line_subpixel_scale/2 - y2) * double(m_dx))), m_dist_start((line_mr(x + line_subpixel_scale/2) - line_mr(sx)) * m_dy_start - (line_mr(y + line_subpixel_scale/2) - line_mr(sy)) * m_dx_start) { m_dx <<= line_subpixel_shift; m_dy <<= line_subpixel_shift; m_dx_start <<= line_mr_subpixel_shift; m_dy_start <<= line_mr_subpixel_shift; } distance_interpolator2(int x1, int y1, int x2, int y2, int ex, int ey, int x, int y, int) : m_dx(x2 - x1), m_dy(y2 - y1), m_dx_start(line_mr(ex) - line_mr(x2)), m_dy_start(line_mr(ey) - line_mr(y2)), m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) - double(y + line_subpixel_scale/2 - y2) * double(m_dx))), m_dist_start((line_mr(x + line_subpixel_scale/2) - line_mr(ex)) * m_dy_start - (line_mr(y + line_subpixel_scale/2) - line_mr(ey)) * m_dx_start) { m_dx <<= line_subpixel_shift; m_dy <<= line_subpixel_shift; m_dx_start <<= line_mr_subpixel_shift; m_dy_start <<= line_mr_subpixel_shift; } //--------------------------------------------------------------------- void inc_x() { m_dist += m_dy; m_dist_start += m_dy_start; } void dec_x() { m_dist -= m_dy; m_dist_start -= m_dy_start; } void inc_y() { m_dist -= m_dx; m_dist_start -= m_dx_start; } void dec_y() { m_dist += m_dx; m_dist_start += m_dx_start; } //--------------------------------------------------------------------- void inc_x(int dy) { m_dist += m_dy; m_dist_start += m_dy_start; if(dy > 0) { m_dist -= m_dx; m_dist_start -= m_dx_start; } if(dy < 0) { m_dist += m_dx; m_dist_start += m_dx_start; } } //--------------------------------------------------------------------- void dec_x(int dy) { m_dist -= m_dy; m_dist_start -= m_dy_start; if(dy > 0) { m_dist -= m_dx; m_dist_start -= m_dx_start; } if(dy < 0) { m_dist += m_dx; m_dist_start += m_dx_start; } } //--------------------------------------------------------------------- void inc_y(int dx) { m_dist -= m_dx; m_dist_start -= m_dx_start; if(dx > 0) { m_dist += m_dy; m_dist_start += m_dy_start; } if(dx < 0) { m_dist -= m_dy; m_dist_start -= m_dy_start; } } //--------------------------------------------------------------------- void dec_y(int dx) { m_dist += m_dx; m_dist_start += m_dx_start; if(dx > 0) { m_dist += m_dy; m_dist_start += m_dy_start; } if(dx < 0) { m_dist -= m_dy; m_dist_start -= m_dy_start; } } //--------------------------------------------------------------------- int dist() const { return m_dist; } int dist_start() const { return m_dist_start; } int dist_end() const { return m_dist_start; } //--------------------------------------------------------------------- int dx() const { return m_dx; } int dy() const { return m_dy; } int dx_start() const { return m_dx_start; } int dy_start() const { return m_dy_start; } int dx_end() const { return m_dx_start; } int dy_end() const { return m_dy_start; } private: //--------------------------------------------------------------------- int m_dx; int m_dy; int m_dx_start; int m_dy_start; int m_dist; int m_dist_start; }; //===================================================distance_interpolator3 class distance_interpolator3 { public: //--------------------------------------------------------------------- distance_interpolator3() {} distance_interpolator3(int x1, int y1, int x2, int y2, int sx, int sy, int ex, int ey, int x, int y) : m_dx(x2 - x1), m_dy(y2 - y1), m_dx_start(line_mr(sx) - line_mr(x1)), m_dy_start(line_mr(sy) - line_mr(y1)), m_dx_end(line_mr(ex) - line_mr(x2)), m_dy_end(line_mr(ey) - line_mr(y2)), m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) - double(y + line_subpixel_scale/2 - y2) * double(m_dx))), m_dist_start((line_mr(x + line_subpixel_scale/2) - line_mr(sx)) * m_dy_start - (line_mr(y + line_subpixel_scale/2) - line_mr(sy)) * m_dx_start), m_dist_end((line_mr(x + line_subpixel_scale/2) - line_mr(ex)) * m_dy_end - (line_mr(y + line_subpixel_scale/2) - line_mr(ey)) * m_dx_end) { m_dx <<= line_subpixel_shift; m_dy <<= line_subpixel_shift; m_dx_start <<= line_mr_subpixel_shift; m_dy_start <<= line_mr_subpixel_shift; m_dx_end <<= line_mr_subpixel_shift; m_dy_end <<= line_mr_subpixel_shift; } //--------------------------------------------------------------------- void inc_x() { m_dist += m_dy; m_dist_start += m_dy_start; m_dist_end += m_dy_end; } void dec_x() { m_dist -= m_dy; m_dist_start -= m_dy_start; m_dist_end -= m_dy_end; } void inc_y() { m_dist -= m_dx; m_dist_start -= m_dx_start; m_dist_end -= m_dx_end; } void dec_y() { m_dist += m_dx; m_dist_start += m_dx_start; m_dist_end += m_dx_end; } //--------------------------------------------------------------------- void inc_x(int dy) { m_dist += m_dy; m_dist_start += m_dy_start; m_dist_end += m_dy_end; if(dy > 0) { m_dist -= m_dx; m_dist_start -= m_dx_start; m_dist_end -= m_dx_end; } if(dy < 0) { m_dist += m_dx; m_dist_start += m_dx_start; m_dist_end += m_dx_end; } } //--------------------------------------------------------------------- void dec_x(int dy) { m_dist -= m_dy; m_dist_start -= m_dy_start; m_dist_end -= m_dy_end; if(dy > 0) { m_dist -= m_dx; m_dist_start -= m_dx_start; m_dist_end -= m_dx_end; } if(dy < 0) { m_dist += m_dx; m_dist_start += m_dx_start; m_dist_end += m_dx_end; } } //--------------------------------------------------------------------- void inc_y(int dx) { m_dist -= m_dx; m_dist_start -= m_dx_start; m_dist_end -= m_dx_end; if(dx > 0) { m_dist += m_dy; m_dist_start += m_dy_start; m_dist_end += m_dy_end; } if(dx < 0) { m_dist -= m_dy; m_dist_start -= m_dy_start; m_dist_end -= m_dy_end; } } //--------------------------------------------------------------------- void dec_y(int dx) { m_dist += m_dx; m_dist_start += m_dx_start; m_dist_end += m_dx_end; if(dx > 0) { m_dist += m_dy; m_dist_start += m_dy_start; m_dist_end += m_dy_end; } if(dx < 0) { m_dist -= m_dy; m_dist_start -= m_dy_start; m_dist_end -= m_dy_end; } } //--------------------------------------------------------------------- int dist() const { return m_dist; } int dist_start() const { return m_dist_start; } int dist_end() const { return m_dist_end; } //--------------------------------------------------------------------- int dx() const { return m_dx; } int dy() const { return m_dy; } int dx_start() const { return m_dx_start; } int dy_start() const { return m_dy_start; } int dx_end() const { return m_dx_end; } int dy_end() const { return m_dy_end; } private: //--------------------------------------------------------------------- int m_dx; int m_dy; int m_dx_start; int m_dy_start; int m_dx_end; int m_dy_end; int m_dist; int m_dist_start; int m_dist_end; }; //================================================line_interpolator_aa_base template class line_interpolator_aa_base { public: typedef Renderer renderer_type; typedef typename Renderer::color_type color_type; //--------------------------------------------------------------------- enum max_half_width_e { max_half_width = 64 }; //--------------------------------------------------------------------- line_interpolator_aa_base(renderer_type& ren, line_parameters& lp) : m_lp(&lp), m_li(lp.vertical ? line_dbl_hr(lp.x2 - lp.x1) : line_dbl_hr(lp.y2 - lp.y1), lp.vertical ? std::abs(lp.y2 - lp.y1) : std::abs(lp.x2 - lp.x1) + 1), m_ren(ren), m_len((lp.vertical == (lp.inc > 0)) ? -lp.len : lp.len), m_x(lp.x1 >> line_subpixel_shift), m_y(lp.y1 >> line_subpixel_shift), m_old_x(m_x), m_old_y(m_y), m_count((lp.vertical ? std::abs((lp.y2 >> line_subpixel_shift) - m_y) : std::abs((lp.x2 >> line_subpixel_shift) - m_x))), m_width(ren.subpixel_width()), //m_max_extent(m_width >> (line_subpixel_shift - 2)), m_max_extent((m_width + line_subpixel_mask) >> line_subpixel_shift), m_step(0) { agg::dda2_line_interpolator li(0, lp.vertical ? (lp.dy << agg::line_subpixel_shift) : (lp.dx << agg::line_subpixel_shift), lp.len); unsigned i; int stop = m_width + line_subpixel_scale * 2; for(i = 0; i < max_half_width; ++i) { m_dist[i] = li.y(); if(m_dist[i] >= stop) break; ++li; } m_dist[i++] = 0x7FFF0000; } //--------------------------------------------------------------------- template int step_hor_base(DI& di) { ++m_li; m_x += m_lp->inc; m_y = (m_lp->y1 + m_li.y()) >> line_subpixel_shift; if(m_lp->inc > 0) di.inc_x(m_y - m_old_y); else di.dec_x(m_y - m_old_y); m_old_y = m_y; return di.dist() / m_len; } //--------------------------------------------------------------------- template int step_ver_base(DI& di) { ++m_li; m_y += m_lp->inc; m_x = (m_lp->x1 + m_li.y()) >> line_subpixel_shift; if(m_lp->inc > 0) di.inc_y(m_x - m_old_x); else di.dec_y(m_x - m_old_x); m_old_x = m_x; return di.dist() / m_len; } //--------------------------------------------------------------------- bool vertical() const { return m_lp->vertical; } int width() const { return m_width; } int count() const { return m_count; } private: line_interpolator_aa_base(const line_interpolator_aa_base&); const line_interpolator_aa_base& operator = (const line_interpolator_aa_base&); protected: line_parameters* m_lp; dda2_line_interpolator m_li; renderer_type& m_ren; int m_len; int m_x; int m_y; int m_old_x; int m_old_y; int m_count; int m_width; int m_max_extent; int m_step; int m_dist[max_half_width + 1]; cover_type m_covers[max_half_width * 2 + 4]; }; //====================================================line_interpolator_aa0 template class line_interpolator_aa0 : public line_interpolator_aa_base { public: typedef Renderer renderer_type; typedef typename Renderer::color_type color_type; typedef line_interpolator_aa_base base_type; //--------------------------------------------------------------------- line_interpolator_aa0(renderer_type& ren, line_parameters& lp) : line_interpolator_aa_base(ren, lp), m_di(lp.x1, lp.y1, lp.x2, lp.y2, lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask) { base_type::m_li.adjust_forward(); } //--------------------------------------------------------------------- bool step_hor() { int dist; int dy; int s1 = base_type::step_hor_base(m_di); cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; cover_type* p1 = p0; *p1++ = (cover_type)base_type::m_ren.cover(s1); dy = 1; while((dist = base_type::m_dist[dy] - s1) <= base_type::m_width) { *p1++ = (cover_type)base_type::m_ren.cover(dist); ++dy; } dy = 1; while((dist = base_type::m_dist[dy] + s1) <= base_type::m_width) { *--p0 = (cover_type)base_type::m_ren.cover(dist); ++dy; } base_type::m_ren.blend_solid_vspan(base_type::m_x, base_type::m_y - dy + 1, unsigned(p1 - p0), p0); return ++base_type::m_step < base_type::m_count; } //--------------------------------------------------------------------- bool step_ver() { int dist; int dx; int s1 = base_type::step_ver_base(m_di); cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; cover_type* p1 = p0; *p1++ = (cover_type)base_type::m_ren.cover(s1); dx = 1; while((dist = base_type::m_dist[dx] - s1) <= base_type::m_width) { *p1++ = (cover_type)base_type::m_ren.cover(dist); ++dx; } dx = 1; while((dist = base_type::m_dist[dx] + s1) <= base_type::m_width) { *--p0 = (cover_type)base_type::m_ren.cover(dist); ++dx; } base_type::m_ren.blend_solid_hspan(base_type::m_x - dx + 1, base_type::m_y, unsigned(p1 - p0), p0); return ++base_type::m_step < base_type::m_count; } private: line_interpolator_aa0(const line_interpolator_aa0&); const line_interpolator_aa0& operator = (const line_interpolator_aa0&); //--------------------------------------------------------------------- distance_interpolator1 m_di; }; //====================================================line_interpolator_aa1 template class line_interpolator_aa1 : public line_interpolator_aa_base { public: typedef Renderer renderer_type; typedef typename Renderer::color_type color_type; typedef line_interpolator_aa_base base_type; //--------------------------------------------------------------------- line_interpolator_aa1(renderer_type& ren, line_parameters& lp, int sx, int sy) : line_interpolator_aa_base(ren, lp), m_di(lp.x1, lp.y1, lp.x2, lp.y2, sx, sy, lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask) { int dist1_start; int dist2_start; int npix = 1; if(lp.vertical) { do { --base_type::m_li; base_type::m_y -= lp.inc; base_type::m_x = (base_type::m_lp->x1 + base_type::m_li.y()) >> line_subpixel_shift; if(lp.inc > 0) m_di.dec_y(base_type::m_x - base_type::m_old_x); else m_di.inc_y(base_type::m_x - base_type::m_old_x); base_type::m_old_x = base_type::m_x; dist1_start = dist2_start = m_di.dist_start(); int dx = 0; if(dist1_start < 0) ++npix; do { dist1_start += m_di.dy_start(); dist2_start -= m_di.dy_start(); if(dist1_start < 0) ++npix; if(dist2_start < 0) ++npix; ++dx; } while(base_type::m_dist[dx] <= base_type::m_width); --base_type::m_step; if(npix == 0) break; npix = 0; } while(base_type::m_step >= -base_type::m_max_extent); } else { do { --base_type::m_li; base_type::m_x -= lp.inc; base_type::m_y = (base_type::m_lp->y1 + base_type::m_li.y()) >> line_subpixel_shift; if(lp.inc > 0) m_di.dec_x(base_type::m_y - base_type::m_old_y); else m_di.inc_x(base_type::m_y - base_type::m_old_y); base_type::m_old_y = base_type::m_y; dist1_start = dist2_start = m_di.dist_start(); int dy = 0; if(dist1_start < 0) ++npix; do { dist1_start -= m_di.dx_start(); dist2_start += m_di.dx_start(); if(dist1_start < 0) ++npix; if(dist2_start < 0) ++npix; ++dy; } while(base_type::m_dist[dy] <= base_type::m_width); --base_type::m_step; if(npix == 0) break; npix = 0; } while(base_type::m_step >= -base_type::m_max_extent); } base_type::m_li.adjust_forward(); } //--------------------------------------------------------------------- bool step_hor() { int dist_start; int dist; int dy; int s1 = base_type::step_hor_base(m_di); dist_start = m_di.dist_start(); cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; cover_type* p1 = p0; *p1 = 0; if(dist_start <= 0) { *p1 = (cover_type)base_type::m_ren.cover(s1); } ++p1; dy = 1; while((dist = base_type::m_dist[dy] - s1) <= base_type::m_width) { dist_start -= m_di.dx_start(); *p1 = 0; if(dist_start <= 0) { *p1 = (cover_type)base_type::m_ren.cover(dist); } ++p1; ++dy; } dy = 1; dist_start = m_di.dist_start(); while((dist = base_type::m_dist[dy] + s1) <= base_type::m_width) { dist_start += m_di.dx_start(); *--p0 = 0; if(dist_start <= 0) { *p0 = (cover_type)base_type::m_ren.cover(dist); } ++dy; } base_type::m_ren.blend_solid_vspan(base_type::m_x, base_type::m_y - dy + 1, unsigned(p1 - p0), p0); return ++base_type::m_step < base_type::m_count; } //--------------------------------------------------------------------- bool step_ver() { int dist_start; int dist; int dx; int s1 = base_type::step_ver_base(m_di); cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; cover_type* p1 = p0; dist_start = m_di.dist_start(); *p1 = 0; if(dist_start <= 0) { *p1 = (cover_type)base_type::m_ren.cover(s1); } ++p1; dx = 1; while((dist = base_type::m_dist[dx] - s1) <= base_type::m_width) { dist_start += m_di.dy_start(); *p1 = 0; if(dist_start <= 0) { *p1 = (cover_type)base_type::m_ren.cover(dist); } ++p1; ++dx; } dx = 1; dist_start = m_di.dist_start(); while((dist = base_type::m_dist[dx] + s1) <= base_type::m_width) { dist_start -= m_di.dy_start(); *--p0 = 0; if(dist_start <= 0) { *p0 = (cover_type)base_type::m_ren.cover(dist); } ++dx; } base_type::m_ren.blend_solid_hspan(base_type::m_x - dx + 1, base_type::m_y, unsigned(p1 - p0), p0); return ++base_type::m_step < base_type::m_count; } private: line_interpolator_aa1(const line_interpolator_aa1&); const line_interpolator_aa1& operator = (const line_interpolator_aa1&); //--------------------------------------------------------------------- distance_interpolator2 m_di; }; //====================================================line_interpolator_aa2 template class line_interpolator_aa2 : public line_interpolator_aa_base { public: typedef Renderer renderer_type; typedef typename Renderer::color_type color_type; typedef line_interpolator_aa_base base_type; //--------------------------------------------------------------------- line_interpolator_aa2(renderer_type& ren, line_parameters& lp, int ex, int ey) : line_interpolator_aa_base(ren, lp), m_di(lp.x1, lp.y1, lp.x2, lp.y2, ex, ey, lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask, 0) { base_type::m_li.adjust_forward(); base_type::m_step -= base_type::m_max_extent; } //--------------------------------------------------------------------- bool step_hor() { int dist_end; int dist; int dy; int s1 = base_type::step_hor_base(m_di); cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; cover_type* p1 = p0; dist_end = m_di.dist_end(); int npix = 0; *p1 = 0; if(dist_end > 0) { *p1 = (cover_type)base_type::m_ren.cover(s1); ++npix; } ++p1; dy = 1; while((dist = base_type::m_dist[dy] - s1) <= base_type::m_width) { dist_end -= m_di.dx_end(); *p1 = 0; if(dist_end > 0) { *p1 = (cover_type)base_type::m_ren.cover(dist); ++npix; } ++p1; ++dy; } dy = 1; dist_end = m_di.dist_end(); while((dist = base_type::m_dist[dy] + s1) <= base_type::m_width) { dist_end += m_di.dx_end(); *--p0 = 0; if(dist_end > 0) { *p0 = (cover_type)base_type::m_ren.cover(dist); ++npix; } ++dy; } base_type::m_ren.blend_solid_vspan(base_type::m_x, base_type::m_y - dy + 1, unsigned(p1 - p0), p0); return npix && ++base_type::m_step < base_type::m_count; } //--------------------------------------------------------------------- bool step_ver() { int dist_end; int dist; int dx; int s1 = base_type::step_ver_base(m_di); cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; cover_type* p1 = p0; dist_end = m_di.dist_end(); int npix = 0; *p1 = 0; if(dist_end > 0) { *p1 = (cover_type)base_type::m_ren.cover(s1); ++npix; } ++p1; dx = 1; while((dist = base_type::m_dist[dx] - s1) <= base_type::m_width) { dist_end += m_di.dy_end(); *p1 = 0; if(dist_end > 0) { *p1 = (cover_type)base_type::m_ren.cover(dist); ++npix; } ++p1; ++dx; } dx = 1; dist_end = m_di.dist_end(); while((dist = base_type::m_dist[dx] + s1) <= base_type::m_width) { dist_end -= m_di.dy_end(); *--p0 = 0; if(dist_end > 0) { *p0 = (cover_type)base_type::m_ren.cover(dist); ++npix; } ++dx; } base_type::m_ren.blend_solid_hspan(base_type::m_x - dx + 1, base_type::m_y, unsigned(p1 - p0), p0); return npix && ++base_type::m_step < base_type::m_count; } private: line_interpolator_aa2(const line_interpolator_aa2&); const line_interpolator_aa2& operator = (const line_interpolator_aa2&); //--------------------------------------------------------------------- distance_interpolator2 m_di; }; //====================================================line_interpolator_aa3 template class line_interpolator_aa3 : public line_interpolator_aa_base { public: typedef Renderer renderer_type; typedef typename Renderer::color_type color_type; typedef line_interpolator_aa_base base_type; //--------------------------------------------------------------------- line_interpolator_aa3(renderer_type& ren, line_parameters& lp, int sx, int sy, int ex, int ey) : line_interpolator_aa_base(ren, lp), m_di(lp.x1, lp.y1, lp.x2, lp.y2, sx, sy, ex, ey, lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask) { int dist1_start; int dist2_start; int npix = 1; if(lp.vertical) { do { --base_type::m_li; base_type::m_y -= lp.inc; base_type::m_x = (base_type::m_lp->x1 + base_type::m_li.y()) >> line_subpixel_shift; if(lp.inc > 0) m_di.dec_y(base_type::m_x - base_type::m_old_x); else m_di.inc_y(base_type::m_x - base_type::m_old_x); base_type::m_old_x = base_type::m_x; dist1_start = dist2_start = m_di.dist_start(); int dx = 0; if(dist1_start < 0) ++npix; do { dist1_start += m_di.dy_start(); dist2_start -= m_di.dy_start(); if(dist1_start < 0) ++npix; if(dist2_start < 0) ++npix; ++dx; } while(base_type::m_dist[dx] <= base_type::m_width); if(npix == 0) break; npix = 0; } while(--base_type::m_step >= -base_type::m_max_extent); } else { do { --base_type::m_li; base_type::m_x -= lp.inc; base_type::m_y = (base_type::m_lp->y1 + base_type::m_li.y()) >> line_subpixel_shift; if(lp.inc > 0) m_di.dec_x(base_type::m_y - base_type::m_old_y); else m_di.inc_x(base_type::m_y - base_type::m_old_y); base_type::m_old_y = base_type::m_y; dist1_start = dist2_start = m_di.dist_start(); int dy = 0; if(dist1_start < 0) ++npix; do { dist1_start -= m_di.dx_start(); dist2_start += m_di.dx_start(); if(dist1_start < 0) ++npix; if(dist2_start < 0) ++npix; ++dy; } while(base_type::m_dist[dy] <= base_type::m_width); if(npix == 0) break; npix = 0; } while(--base_type::m_step >= -base_type::m_max_extent); } base_type::m_li.adjust_forward(); base_type::m_step -= base_type::m_max_extent; } //--------------------------------------------------------------------- bool step_hor() { int dist_start; int dist_end; int dist; int dy; int s1 = base_type::step_hor_base(m_di); cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; cover_type* p1 = p0; dist_start = m_di.dist_start(); dist_end = m_di.dist_end(); int npix = 0; *p1 = 0; if(dist_end > 0) { if(dist_start <= 0) { *p1 = (cover_type)base_type::m_ren.cover(s1); } ++npix; } ++p1; dy = 1; while((dist = base_type::m_dist[dy] - s1) <= base_type::m_width) { dist_start -= m_di.dx_start(); dist_end -= m_di.dx_end(); *p1 = 0; if(dist_end > 0 && dist_start <= 0) { *p1 = (cover_type)base_type::m_ren.cover(dist); ++npix; } ++p1; ++dy; } dy = 1; dist_start = m_di.dist_start(); dist_end = m_di.dist_end(); while((dist = base_type::m_dist[dy] + s1) <= base_type::m_width) { dist_start += m_di.dx_start(); dist_end += m_di.dx_end(); *--p0 = 0; if(dist_end > 0 && dist_start <= 0) { *p0 = (cover_type)base_type::m_ren.cover(dist); ++npix; } ++dy; } base_type::m_ren.blend_solid_vspan(base_type::m_x, base_type::m_y - dy + 1, unsigned(p1 - p0), p0); return npix && ++base_type::m_step < base_type::m_count; } //--------------------------------------------------------------------- bool step_ver() { int dist_start; int dist_end; int dist; int dx; int s1 = base_type::step_ver_base(m_di); cover_type* p0 = base_type::m_covers + base_type::max_half_width + 2; cover_type* p1 = p0; dist_start = m_di.dist_start(); dist_end = m_di.dist_end(); int npix = 0; *p1 = 0; if(dist_end > 0) { if(dist_start <= 0) { *p1 = (cover_type)base_type::m_ren.cover(s1); } ++npix; } ++p1; dx = 1; while((dist = base_type::m_dist[dx] - s1) <= base_type::m_width) { dist_start += m_di.dy_start(); dist_end += m_di.dy_end(); *p1 = 0; if(dist_end > 0 && dist_start <= 0) { *p1 = (cover_type)base_type::m_ren.cover(dist); ++npix; } ++p1; ++dx; } dx = 1; dist_start = m_di.dist_start(); dist_end = m_di.dist_end(); while((dist = base_type::m_dist[dx] + s1) <= base_type::m_width) { dist_start -= m_di.dy_start(); dist_end -= m_di.dy_end(); *--p0 = 0; if(dist_end > 0 && dist_start <= 0) { *p0 = (cover_type)base_type::m_ren.cover(dist); ++npix; } ++dx; } base_type::m_ren.blend_solid_hspan(base_type::m_x - dx + 1, base_type::m_y, unsigned(p1 - p0), p0); return npix && ++base_type::m_step < base_type::m_count; } private: line_interpolator_aa3(const line_interpolator_aa3&); const line_interpolator_aa3& operator = (const line_interpolator_aa3&); //--------------------------------------------------------------------- distance_interpolator3 m_di; }; //==========================================================line_profile_aa // // See Implementation agg_line_profile_aa.cpp // class line_profile_aa { public: //--------------------------------------------------------------------- typedef int8u value_type; enum subpixel_scale_e { subpixel_shift = line_subpixel_shift, subpixel_scale = 1 << subpixel_shift, subpixel_mask = subpixel_scale - 1 }; enum aa_scale_e { aa_shift = 8, aa_scale = 1 << aa_shift, aa_mask = aa_scale - 1 }; //--------------------------------------------------------------------- line_profile_aa() : m_subpixel_width(0), m_min_width(1.0), m_smoother_width(1.0) { int i; for(i = 0; i < aa_scale; i++) m_gamma[i] = (value_type)i; } //--------------------------------------------------------------------- template line_profile_aa(double w, const GammaF& gamma_function) : m_subpixel_width(0), m_min_width(1.0), m_smoother_width(1.0) { gamma(gamma_function); width(w); } //--------------------------------------------------------------------- void min_width(double w) { m_min_width = w; } void smoother_width(double w) { m_smoother_width = w; } //--------------------------------------------------------------------- template void gamma(const GammaF& gamma_function) { int i; for(i = 0; i < aa_scale; i++) { m_gamma[i] = value_type( uround(gamma_function(double(i) / aa_mask) * aa_mask)); } } void width(double w); unsigned profile_size() const { return m_profile.size(); } int subpixel_width() const { return m_subpixel_width; } //--------------------------------------------------------------------- double min_width() const { return m_min_width; } double smoother_width() const { return m_smoother_width; } //--------------------------------------------------------------------- value_type value(int dist) const { return m_profile[dist + subpixel_scale*2]; } private: line_profile_aa(const line_profile_aa&); const line_profile_aa& operator = (const line_profile_aa&); value_type* profile(double w); void set(double center_width, double smoother_width); //--------------------------------------------------------------------- pod_array m_profile; value_type m_gamma[aa_scale]; int m_subpixel_width; double m_min_width; double m_smoother_width; }; //======================================================renderer_outline_aa template class renderer_outline_aa { public: //--------------------------------------------------------------------- typedef BaseRenderer base_ren_type; typedef renderer_outline_aa self_type; typedef typename base_ren_type::color_type color_type; //--------------------------------------------------------------------- renderer_outline_aa(base_ren_type& ren, line_profile_aa& prof) : m_ren(&ren), m_profile(&prof), m_clip_box(0,0,0,0), m_clipping(false) {} void attach(base_ren_type& ren) { m_ren = &ren; } //--------------------------------------------------------------------- void color(const color_type& c) { m_color = c; } const color_type& color() const { return m_color; } //--------------------------------------------------------------------- void profile(line_profile_aa& prof) { m_profile = &prof; } const line_profile_aa& profile() const { return *m_profile; } line_profile_aa& profile() { return *m_profile; } //--------------------------------------------------------------------- int subpixel_width() const { return m_profile->subpixel_width(); } //--------------------------------------------------------------------- void reset_clipping() { m_clipping = false; } void clip_box(double x1, double y1, double x2, double y2) { m_clip_box.x1 = line_coord_sat::conv(x1); m_clip_box.y1 = line_coord_sat::conv(y1); m_clip_box.x2 = line_coord_sat::conv(x2); m_clip_box.y2 = line_coord_sat::conv(y2); m_clipping = true; } //--------------------------------------------------------------------- int cover(int d) const { return m_profile->value(d); } //------------------------------------------------------------------------- void blend_solid_hspan(int x, int y, unsigned len, const cover_type* covers) { m_ren->blend_solid_hspan(x, y, len, m_color, covers); } //------------------------------------------------------------------------- void blend_solid_vspan(int x, int y, unsigned len, const cover_type* covers) { m_ren->blend_solid_vspan(x, y, len, m_color, covers); } //------------------------------------------------------------------------- static bool accurate_join_only() { return false; } //------------------------------------------------------------------------- template void semidot_hline(Cmp cmp, int xc1, int yc1, int xc2, int yc2, int x1, int y1, int x2) { cover_type covers[line_interpolator_aa_base::max_half_width * 2 + 4]; cover_type* p0 = covers; cover_type* p1 = covers; int x = x1 << line_subpixel_shift; int y = y1 << line_subpixel_shift; int w = subpixel_width(); distance_interpolator0 di(xc1, yc1, xc2, yc2, x, y); x += line_subpixel_scale/2; y += line_subpixel_scale/2; int x0 = x1; int dx = x - xc1; int dy = y - yc1; do { int d = int(fast_sqrt(dx*dx + dy*dy)); *p1 = 0; if(cmp(di.dist()) && d <= w) { *p1 = (cover_type)cover(d); } ++p1; dx += line_subpixel_scale; di.inc_x(); } while(++x1 <= x2); m_ren->blend_solid_hspan(x0, y1, unsigned(p1 - p0), color(), p0); } //------------------------------------------------------------------------- template void semidot(Cmp cmp, int xc1, int yc1, int xc2, int yc2) { if(m_clipping && clipping_flags(xc1, yc1, m_clip_box)) return; int r = ((subpixel_width() + line_subpixel_mask) >> line_subpixel_shift); if(r < 1) r = 1; ellipse_bresenham_interpolator ei(r, r); int dx = 0; int dy = -r; int dy0 = dy; int dx0 = dx; int x = xc1 >> line_subpixel_shift; int y = yc1 >> line_subpixel_shift; do { dx += ei.dx(); dy += ei.dy(); if(dy != dy0) { semidot_hline(cmp, xc1, yc1, xc2, yc2, x-dx0, y+dy0, x+dx0); semidot_hline(cmp, xc1, yc1, xc2, yc2, x-dx0, y-dy0, x+dx0); } dx0 = dx; dy0 = dy; ++ei; } while(dy < 0); semidot_hline(cmp, xc1, yc1, xc2, yc2, x-dx0, y+dy0, x+dx0); } //------------------------------------------------------------------------- void pie_hline(int xc, int yc, int xp1, int yp1, int xp2, int yp2, int xh1, int yh1, int xh2) { if(m_clipping && clipping_flags(xc, yc, m_clip_box)) return; cover_type covers[line_interpolator_aa_base::max_half_width * 2 + 4]; cover_type* p0 = covers; cover_type* p1 = covers; int x = xh1 << line_subpixel_shift; int y = yh1 << line_subpixel_shift; int w = subpixel_width(); distance_interpolator00 di(xc, yc, xp1, yp1, xp2, yp2, x, y); x += line_subpixel_scale/2; y += line_subpixel_scale/2; int xh0 = xh1; int dx = x - xc; int dy = y - yc; do { int d = int(fast_sqrt(dx*dx + dy*dy)); *p1 = 0; if(di.dist1() <= 0 && di.dist2() > 0 && d <= w) { *p1 = (cover_type)cover(d); } ++p1; dx += line_subpixel_scale; di.inc_x(); } while(++xh1 <= xh2); m_ren->blend_solid_hspan(xh0, yh1, unsigned(p1 - p0), color(), p0); } //------------------------------------------------------------------------- void pie(int xc, int yc, int x1, int y1, int x2, int y2) { int r = ((subpixel_width() + line_subpixel_mask) >> line_subpixel_shift); if(r < 1) r = 1; ellipse_bresenham_interpolator ei(r, r); int dx = 0; int dy = -r; int dy0 = dy; int dx0 = dx; int x = xc >> line_subpixel_shift; int y = yc >> line_subpixel_shift; do { dx += ei.dx(); dy += ei.dy(); if(dy != dy0) { pie_hline(xc, yc, x1, y1, x2, y2, x-dx0, y+dy0, x+dx0); pie_hline(xc, yc, x1, y1, x2, y2, x-dx0, y-dy0, x+dx0); } dx0 = dx; dy0 = dy; ++ei; } while(dy < 0); pie_hline(xc, yc, x1, y1, x2, y2, x-dx0, y+dy0, x+dx0); } //------------------------------------------------------------------------- void line0_no_clip(line_parameters& lp) { if(lp.len > line_max_length) { line_parameters lp1, lp2; lp.divide(lp1, lp2); line0_no_clip(lp1); line0_no_clip(lp2); return; } line_interpolator_aa0 li(*this, lp); if(li.count()) { if(li.vertical()) { while(li.step_ver()); } else { while(li.step_hor()); } } } //------------------------------------------------------------------------- void line0(line_parameters& lp) { if(m_clipping) { int x1 = lp.x1; int y1 = lp.y1; int x2 = lp.x2; int y2 = lp.y2; unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box); if((flags & 4) == 0) { if(flags) { line_parameters lp2(x1, y1, x2, y2, uround(calc_distance(x1, y1, x2, y2))); line0_no_clip(lp2); } else { line0_no_clip(lp); } } } else { line0_no_clip(lp); } } //------------------------------------------------------------------------- void line1_no_clip(line_parameters& lp, int sx, int sy) { if(lp.len > line_max_length) { line_parameters lp1, lp2; lp.divide(lp1, lp2); line1_no_clip(lp1, (lp.x1 + sx) >> 1, (lp.y1 + sy) >> 1); line1_no_clip(lp2, lp1.x2 + (lp1.y2 - lp1.y1), lp1.y2 - (lp1.x2 - lp1.x1)); return; } fix_degenerate_bisectrix_start(lp, &sx, &sy); line_interpolator_aa1 li(*this, lp, sx, sy); if(li.vertical()) { while(li.step_ver()); } else { while(li.step_hor()); } } //------------------------------------------------------------------------- void line1(line_parameters& lp, int sx, int sy) { if(m_clipping) { int x1 = lp.x1; int y1 = lp.y1; int x2 = lp.x2; int y2 = lp.y2; unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box); if((flags & 4) == 0) { if(flags) { line_parameters lp2(x1, y1, x2, y2, uround(calc_distance(x1, y1, x2, y2))); if(flags & 1) { sx = x1 + (y2 - y1); sy = y1 - (x2 - x1); } else { while(std::abs(sx - lp.x1) + std::abs(sy - lp.y1) > lp2.len) { sx = (lp.x1 + sx) >> 1; sy = (lp.y1 + sy) >> 1; } } line1_no_clip(lp2, sx, sy); } else { line1_no_clip(lp, sx, sy); } } } else { line1_no_clip(lp, sx, sy); } } //------------------------------------------------------------------------- void line2_no_clip(line_parameters& lp, int ex, int ey) { if(lp.len > line_max_length) { line_parameters lp1, lp2; lp.divide(lp1, lp2); line2_no_clip(lp1, lp1.x2 + (lp1.y2 - lp1.y1), lp1.y2 - (lp1.x2 - lp1.x1)); line2_no_clip(lp2, (lp.x2 + ex) >> 1, (lp.y2 + ey) >> 1); return; } fix_degenerate_bisectrix_end(lp, &ex, &ey); line_interpolator_aa2 li(*this, lp, ex, ey); if(li.vertical()) { while(li.step_ver()); } else { while(li.step_hor()); } } //------------------------------------------------------------------------- void line2(line_parameters& lp, int ex, int ey) { if(m_clipping) { int x1 = lp.x1; int y1 = lp.y1; int x2 = lp.x2; int y2 = lp.y2; unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box); if((flags & 4) == 0) { if(flags) { line_parameters lp2(x1, y1, x2, y2, uround(calc_distance(x1, y1, x2, y2))); if(flags & 2) { ex = x2 + (y2 - y1); ey = y2 - (x2 - x1); } else { while(std::abs(ex - lp.x2) + std::abs(ey - lp.y2) > lp2.len) { ex = (lp.x2 + ex) >> 1; ey = (lp.y2 + ey) >> 1; } } line2_no_clip(lp2, ex, ey); } else { line2_no_clip(lp, ex, ey); } } } else { line2_no_clip(lp, ex, ey); } } //------------------------------------------------------------------------- void line3_no_clip(line_parameters& lp, int sx, int sy, int ex, int ey) { if(lp.len > line_max_length) { line_parameters lp1, lp2; lp.divide(lp1, lp2); int mx = lp1.x2 + (lp1.y2 - lp1.y1); int my = lp1.y2 - (lp1.x2 - lp1.x1); line3_no_clip(lp1, (lp.x1 + sx) >> 1, (lp.y1 + sy) >> 1, mx, my); line3_no_clip(lp2, mx, my, (lp.x2 + ex) >> 1, (lp.y2 + ey) >> 1); return; } fix_degenerate_bisectrix_start(lp, &sx, &sy); fix_degenerate_bisectrix_end(lp, &ex, &ey); line_interpolator_aa3 li(*this, lp, sx, sy, ex, ey); if(li.vertical()) { while(li.step_ver()); } else { while(li.step_hor()); } } //------------------------------------------------------------------------- void line3(line_parameters& lp, int sx, int sy, int ex, int ey) { if(m_clipping) { int x1 = lp.x1; int y1 = lp.y1; int x2 = lp.x2; int y2 = lp.y2; unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box); if((flags & 4) == 0) { if(flags) { line_parameters lp2(x1, y1, x2, y2, uround(calc_distance(x1, y1, x2, y2))); if(flags & 1) { sx = x1 + (y2 - y1); sy = y1 - (x2 - x1); } else { while(std::abs(sx - lp.x1) + std::abs(sy - lp.y1) > lp2.len) { sx = (lp.x1 + sx) >> 1; sy = (lp.y1 + sy) >> 1; } } if(flags & 2) { ex = x2 + (y2 - y1); ey = y2 - (x2 - x1); } else { while(std::abs(ex - lp.x2) + std::abs(ey - lp.y2) > lp2.len) { ex = (lp.x2 + ex) >> 1; ey = (lp.y2 + ey) >> 1; } } line3_no_clip(lp2, sx, sy, ex, ey); } else { line3_no_clip(lp, sx, sy, ex, ey); } } } else { line3_no_clip(lp, sx, sy, ex, ey); } } private: base_ren_type* m_ren; line_profile_aa* m_profile; color_type m_color; rect_i m_clip_box; bool m_clipping; }; } #endif ragg/src/agg/include/agg_rasterizer_scanline_aa_nogamma.h0000644000176200001440000004015213504406270023342 0ustar liggesusers//---------------------------------------------------------------------------- // 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_SCANLINE_AA_NOGAMMA_INCLUDED #define AGG_RASTERIZER_SCANLINE_AA_NOGAMMA_INCLUDED #include #include "agg_rasterizer_cells_aa.h" #include "agg_rasterizer_sl_clip.h" namespace agg { //-----------------------------------------------------------------cell_aa // A pixel cell. There're no constructors defined and it was done // intentionally in order to avoid extra overhead when allocating an // array of cells. struct cell_aa { int x; int y; int cover; int area; void initial() { x = std::numeric_limits::max(); y = std::numeric_limits::max(); cover = 0; area = 0; } void style(const cell_aa&) {} int not_equal(int ex, int ey, const cell_aa&) const { return ((unsigned)ex - (unsigned)x) | ((unsigned)ey - (unsigned)y); } }; //==================================================rasterizer_scanline_aa_nogamma // Polygon rasterizer that is used to render filled polygons with // high-quality Anti-Aliasing. Internally, by default, the class uses // integer coordinates in format 24.8, i.e. 24 bits for integer part // and 8 bits for fractional - see poly_subpixel_shift. This class can be // used in the following way: // // 1. filling_rule(filling_rule_e ft) - optional. // // 2. gamma() - optional. // // 3. reset() // // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create // more than one contour, but each contour must consist of at least 3 // vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3); // is the absolute minimum of vertices that define a triangle. // The algorithm does not check either the number of vertices nor // coincidence of their coordinates, but in the worst case it just // won't draw anything. // The orger of the vertices (clockwise or counterclockwise) // is important when using the non-zero filling rule (fill_non_zero). // In this case the vertex order of all the contours must be the same // if you want your intersecting polygons to be without "holes". // You actually can use different vertices order. If the contours do not // intersect each other the order is not important anyway. If they do, // contours with the same vertex order will be rendered without "holes" // while the intersecting contours with different orders will have "holes". // // filling_rule() and gamma() can be called anytime before "sweeping". //------------------------------------------------------------------------ template class rasterizer_scanline_aa_nogamma { enum status { status_initial, status_move_to, status_line_to, status_closed }; public: typedef Clip clip_type; typedef typename Clip::conv_type conv_type; typedef typename Clip::coord_type coord_type; enum aa_scale_e { aa_shift = 8, aa_scale = 1 << aa_shift, aa_mask = aa_scale - 1, aa_scale2 = aa_scale * 2, aa_mask2 = aa_scale2 - 1 }; //-------------------------------------------------------------------- rasterizer_scanline_aa_nogamma(unsigned cell_block_limit=1024) : m_outline(cell_block_limit), m_clipper(), m_filling_rule(fill_non_zero), m_auto_close(true), m_start_x(0), m_start_y(0), m_status(status_initial) { } //-------------------------------------------------------------------- void reset(); void reset_clipping(); void clip_box(double x1, double y1, double x2, double y2); void filling_rule(filling_rule_e filling_rule); void auto_close(bool flag) { m_auto_close = flag; } //-------------------------------------------------------------------- unsigned apply_gamma(unsigned cover) const { return cover; } //-------------------------------------------------------------------- void move_to(int x, int y); void line_to(int x, int y); void move_to_d(double x, double y); void line_to_d(double x, double y); void close_polygon(); void add_vertex(double x, double y, unsigned cmd); void edge(int x1, int y1, int x2, int y2); void edge_d(double x1, double y1, double x2, double y2); //------------------------------------------------------------------- template void add_path(VertexSource& vs, unsigned path_id=0) { double x; double y; unsigned cmd; vs.rewind(path_id); if(m_outline.sorted()) reset(); while(!is_stop(cmd = vs.vertex(&x, &y))) { add_vertex(x, y, cmd); } } //-------------------------------------------------------------------- int min_x() const { return m_outline.min_x(); } int min_y() const { return m_outline.min_y(); } int max_x() const { return m_outline.max_x(); } int max_y() const { return m_outline.max_y(); } //-------------------------------------------------------------------- void sort(); bool rewind_scanlines(); bool navigate_scanline(int y); //-------------------------------------------------------------------- AGG_INLINE unsigned calculate_alpha(int area) const { int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift); if(cover < 0) cover = -cover; if(m_filling_rule == fill_even_odd) { cover &= aa_mask2; if(cover > aa_scale) { cover = aa_scale2 - cover; } } if(cover > aa_mask) cover = aa_mask; return cover; } //-------------------------------------------------------------------- template bool sweep_scanline(Scanline& sl) { for(;;) { if(m_scan_y > m_outline.max_y()) return false; sl.reset_spans(); unsigned num_cells = m_outline.scanline_num_cells(m_scan_y); const cell_aa* const* cells = m_outline.scanline_cells(m_scan_y); int cover = 0; while(num_cells) { const cell_aa* cur_cell = *cells; int x = cur_cell->x; int area = cur_cell->area; unsigned alpha; cover += cur_cell->cover; //accumulate all cells with the same X while(--num_cells) { cur_cell = *++cells; if(cur_cell->x != x) break; area += cur_cell->area; cover += cur_cell->cover; } if(area) { alpha = calculate_alpha((cover << (poly_subpixel_shift + 1)) - area); if(alpha) { sl.add_cell(x, alpha); } x++; } if(num_cells && cur_cell->x > x) { alpha = calculate_alpha(cover << (poly_subpixel_shift + 1)); if(alpha) { sl.add_span(x, cur_cell->x - x, alpha); } } } if(sl.num_spans()) break; ++m_scan_y; } sl.finalize(m_scan_y); ++m_scan_y; return true; } //-------------------------------------------------------------------- bool hit_test(int tx, int ty); private: //-------------------------------------------------------------------- // Disable copying rasterizer_scanline_aa_nogamma(const rasterizer_scanline_aa_nogamma&); const rasterizer_scanline_aa_nogamma& operator = (const rasterizer_scanline_aa_nogamma&); private: rasterizer_cells_aa m_outline; clip_type m_clipper; filling_rule_e m_filling_rule; bool m_auto_close; coord_type m_start_x; coord_type m_start_y; unsigned m_status; int m_scan_y; }; //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::reset() { m_outline.reset(); m_status = status_initial; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::filling_rule(filling_rule_e filling_rule) { m_filling_rule = filling_rule; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::clip_box(double x1, double y1, double x2, double y2) { reset(); m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), conv_type::upscale(x2), conv_type::upscale(y2)); } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::reset_clipping() { reset(); m_clipper.reset_clipping(); } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::close_polygon() { if(m_status == status_line_to) { m_clipper.line_to(m_outline, m_start_x, m_start_y); m_status = status_closed; } } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::move_to(int x, int y) { if(m_outline.sorted()) reset(); if(m_auto_close) close_polygon(); m_clipper.move_to(m_start_x = conv_type::downscale(x), m_start_y = conv_type::downscale(y)); m_status = status_move_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::line_to(int x, int y) { m_clipper.line_to(m_outline, conv_type::downscale(x), conv_type::downscale(y)); m_status = status_line_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::move_to_d(double x, double y) { if(m_outline.sorted()) reset(); if(m_auto_close) close_polygon(); m_clipper.move_to(m_start_x = conv_type::upscale(x), m_start_y = conv_type::upscale(y)); m_status = status_move_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::line_to_d(double x, double y) { m_clipper.line_to(m_outline, conv_type::upscale(x), conv_type::upscale(y)); m_status = status_line_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::add_vertex(double x, double y, unsigned cmd) { if(is_move_to(cmd)) { move_to_d(x, y); } else if(is_vertex(cmd)) { line_to_d(x, y); } else if(is_close(cmd)) { close_polygon(); } } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::edge(int x1, int y1, int x2, int y2) { if(m_outline.sorted()) reset(); m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1)); m_clipper.line_to(m_outline, conv_type::downscale(x2), conv_type::downscale(y2)); m_status = status_move_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::edge_d(double x1, double y1, double x2, double y2) { if(m_outline.sorted()) reset(); m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); m_clipper.line_to(m_outline, conv_type::upscale(x2), conv_type::upscale(y2)); m_status = status_move_to; } //------------------------------------------------------------------------ template void rasterizer_scanline_aa_nogamma::sort() { if(m_auto_close) close_polygon(); m_outline.sort_cells(); } //------------------------------------------------------------------------ template AGG_INLINE bool rasterizer_scanline_aa_nogamma::rewind_scanlines() { if(m_auto_close) close_polygon(); m_outline.sort_cells(); if(m_outline.total_cells() == 0) { return false; } m_scan_y = m_outline.min_y(); return true; } //------------------------------------------------------------------------ template AGG_INLINE bool rasterizer_scanline_aa_nogamma::navigate_scanline(int y) { if(m_auto_close) close_polygon(); m_outline.sort_cells(); if(m_outline.total_cells() == 0 || y < m_outline.min_y() || y > m_outline.max_y()) { return false; } m_scan_y = y; return true; } //------------------------------------------------------------------------ template bool rasterizer_scanline_aa_nogamma::hit_test(int tx, int ty) { if(!navigate_scanline(ty)) return false; scanline_hit_test sl(tx); sweep_scanline(sl); return sl.hit(); } } #endif ragg/src/agg/include/agg_span_image_filter.h0000644000176200001440000002175013504406270020607 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Image transformations with filtering. Span generator base class // //---------------------------------------------------------------------------- #ifndef AGG_SPAN_IMAGE_FILTER_INCLUDED #define AGG_SPAN_IMAGE_FILTER_INCLUDED #include "agg_basics.h" #include "agg_image_filters.h" #include "agg_span_interpolator_linear.h" namespace agg { //-------------------------------------------------------span_image_filter template class span_image_filter { public: typedef Source source_type; typedef Interpolator interpolator_type; //-------------------------------------------------------------------- span_image_filter() {} span_image_filter(source_type& src, interpolator_type& interpolator, image_filter_lut* filter) : m_src(&src), m_interpolator(&interpolator), m_filter(filter), m_dx_dbl(0.5), m_dy_dbl(0.5), m_dx_int(image_subpixel_scale / 2), m_dy_int(image_subpixel_scale / 2) {} void attach(source_type& v) { m_src = &v; } //-------------------------------------------------------------------- source_type& source() { return *m_src; } const source_type& source() const { return *m_src; } const image_filter_lut& filter() const { return *m_filter; } int filter_dx_int() const { return m_dx_int; } int filter_dy_int() const { return m_dy_int; } double filter_dx_dbl() const { return m_dx_dbl; } double filter_dy_dbl() const { return m_dy_dbl; } //-------------------------------------------------------------------- void interpolator(interpolator_type& v) { m_interpolator = &v; } void filter(image_filter_lut& v) { m_filter = &v; } void filter_offset(double dx, double dy) { m_dx_dbl = dx; m_dy_dbl = dy; m_dx_int = iround(dx * image_subpixel_scale); m_dy_int = iround(dy * image_subpixel_scale); } void filter_offset(double d) { filter_offset(d, d); } //-------------------------------------------------------------------- interpolator_type& interpolator() { return *m_interpolator; } //-------------------------------------------------------------------- void prepare() {} //-------------------------------------------------------------------- private: source_type* m_src; interpolator_type* m_interpolator; image_filter_lut* m_filter; double m_dx_dbl; double m_dy_dbl; unsigned m_dx_int; unsigned m_dy_int; }; //==============================================span_image_resample_affine template class span_image_resample_affine : public span_image_filter > { public: typedef Source source_type; typedef span_interpolator_linear interpolator_type; typedef span_image_filter base_type; //-------------------------------------------------------------------- span_image_resample_affine() : m_scale_limit(200.0), m_blur_x(1.0), m_blur_y(1.0) {} //-------------------------------------------------------------------- span_image_resample_affine(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, &filter), m_scale_limit(200.0), m_blur_x(1.0), m_blur_y(1.0) {} //-------------------------------------------------------------------- int scale_limit() const { return uround(m_scale_limit); } void scale_limit(int v) { m_scale_limit = v; } //-------------------------------------------------------------------- double blur_x() const { return m_blur_x; } double blur_y() const { return m_blur_y; } void blur_x(double v) { m_blur_x = v; } void blur_y(double v) { m_blur_y = v; } void blur(double v) { m_blur_x = m_blur_y = v; } //-------------------------------------------------------------------- void prepare() { double scale_x; double scale_y; base_type::interpolator().transformer().scaling_abs(&scale_x, &scale_y); double scale_xy = scale_x * scale_y; if (scale_xy > m_scale_limit) { scale_x = scale_x * m_scale_limit / scale_xy; scale_y = scale_y * m_scale_limit / scale_xy; } if(scale_x < 1) scale_x = 1; if(scale_y < 1) scale_y = 1; if(scale_x > m_scale_limit) scale_x = m_scale_limit; if(scale_y > m_scale_limit) scale_y = m_scale_limit; scale_x *= m_blur_x; scale_y *= m_blur_y; if(scale_x < 1) scale_x = 1; if(scale_y < 1) scale_y = 1; m_rx = uround( scale_x * double(image_subpixel_scale)); m_rx_inv = uround(1.0/scale_x * double(image_subpixel_scale)); m_ry = uround( scale_y * double(image_subpixel_scale)); m_ry_inv = uround(1.0/scale_y * double(image_subpixel_scale)); } protected: int m_rx; int m_ry; int m_rx_inv; int m_ry_inv; private: double m_scale_limit; double m_blur_x; double m_blur_y; }; //=====================================================span_image_resample template class span_image_resample : public span_image_filter { public: typedef Source source_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; //-------------------------------------------------------------------- span_image_resample() : m_scale_limit(20), m_blur_x(image_subpixel_scale), m_blur_y(image_subpixel_scale) {} //-------------------------------------------------------------------- span_image_resample(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, &filter), m_scale_limit(20), m_blur_x(image_subpixel_scale), m_blur_y(image_subpixel_scale) {} //-------------------------------------------------------------------- int scale_limit() const { return m_scale_limit; } void scale_limit(int v) { m_scale_limit = v; } //-------------------------------------------------------------------- double blur_x() const { return double(m_blur_x) / double(image_subpixel_scale); } double blur_y() const { return double(m_blur_y) / double(image_subpixel_scale); } void blur_x(double v) { m_blur_x = uround(v * double(image_subpixel_scale)); } void blur_y(double v) { m_blur_y = uround(v * double(image_subpixel_scale)); } void blur(double v) { m_blur_x = m_blur_y = uround(v * double(image_subpixel_scale)); } protected: AGG_INLINE void adjust_scale(int* rx, int* ry) { if(*rx < image_subpixel_scale) *rx = image_subpixel_scale; if(*ry < image_subpixel_scale) *ry = image_subpixel_scale; if(*rx > image_subpixel_scale * m_scale_limit) { *rx = image_subpixel_scale * m_scale_limit; } if(*ry > image_subpixel_scale * m_scale_limit) { *ry = image_subpixel_scale * m_scale_limit; } *rx = (*rx * m_blur_x) >> image_subpixel_shift; *ry = (*ry * m_blur_y) >> image_subpixel_shift; if(*rx < image_subpixel_scale) *rx = image_subpixel_scale; if(*ry < image_subpixel_scale) *ry = image_subpixel_scale; } int m_scale_limit; int m_blur_x; int m_blur_y; }; } #endif ragg/src/agg/include/agg_span_interpolator_trans.h0000644000176200001440000000603413504406270022107 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Horizontal span interpolator for use with an arbitrary transformer // The efficiency highly depends on the operations done in the transformer // //---------------------------------------------------------------------------- #ifndef AGG_SPAN_INTERPOLATOR_TRANS_INCLUDED #define AGG_SPAN_INTERPOLATOR_TRANS_INCLUDED #include "agg_basics.h" namespace agg { //=================================================span_interpolator_trans template class span_interpolator_trans { public: typedef Transformer trans_type; enum subpixel_scale_e { subpixel_shift = SubpixelShift, subpixel_scale = 1 << subpixel_shift }; //-------------------------------------------------------------------- span_interpolator_trans() {} span_interpolator_trans(trans_type& trans) : m_trans(&trans) {} span_interpolator_trans(trans_type& trans, double x, double y, unsigned) : m_trans(&trans) { begin(x, y, 0); } //---------------------------------------------------------------- const trans_type& transformer() const { return *m_trans; } void transformer(const trans_type& trans) { m_trans = &trans; } //---------------------------------------------------------------- void begin(double x, double y, unsigned) { m_x = x; m_y = y; m_trans->transform(&x, &y); m_ix = iround(x * subpixel_scale); m_iy = iround(y * subpixel_scale); } //---------------------------------------------------------------- void operator++() { m_x += 1.0; double x = m_x; double y = m_y; m_trans->transform(&x, &y); m_ix = iround(x * subpixel_scale); m_iy = iround(y * subpixel_scale); } //---------------------------------------------------------------- void coordinates(int* x, int* y) const { *x = m_ix; *y = m_iy; } private: trans_type* m_trans; double m_x; double m_y; int m_ix; int m_iy; }; } #endif ragg/src/agg/include/agg_vertex_sequence.h0000644000176200001440000001207213504406270020341 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // vertex_sequence container and vertex_dist struct // //---------------------------------------------------------------------------- #ifndef AGG_VERTEX_SEQUENCE_INCLUDED #define AGG_VERTEX_SEQUENCE_INCLUDED #include "agg_basics.h" #include "agg_array.h" #include "agg_math.h" namespace agg { //----------------------------------------------------------vertex_sequence // Modified agg::pod_bvector. The data is interpreted as a sequence // of vertices. It means that the type T must expose: // // bool T::operator() (const T& val) // // that is called every time new vertex is being added. The main purpose // of this operator is the possibility to calculate some values during // adding and to return true if the vertex fits some criteria or false if // it doesn't. In the last case the new vertex is not added. // // The simple example is filtering coinciding vertices with calculation // of the distance between the current and previous ones: // // struct vertex_dist // { // double x; // double y; // double dist; // // vertex_dist() {} // vertex_dist(double x_, double y_) : // x(x_), // y(y_), // dist(0.0) // { // } // // bool operator () (const vertex_dist& val) // { // return (dist = calc_distance(x, y, val.x, val.y)) > EPSILON; // } // }; // // Function close() calls this operator and removes the last vertex if // necessary. //------------------------------------------------------------------------ template class vertex_sequence : public pod_bvector { public: typedef pod_bvector base_type; void add(const T& val); void modify_last(const T& val); void close(bool remove_flag); }; //------------------------------------------------------------------------ template void vertex_sequence::add(const T& val) { if(base_type::size() > 1) { if(!(*this)[base_type::size() - 2]((*this)[base_type::size() - 1])) { base_type::remove_last(); } } base_type::add(val); } //------------------------------------------------------------------------ template void vertex_sequence::modify_last(const T& val) { base_type::remove_last(); add(val); } //------------------------------------------------------------------------ template void vertex_sequence::close(bool closed) { while(base_type::size() > 1) { if((*this)[base_type::size() - 2]((*this)[base_type::size() - 1])) break; T t = (*this)[base_type::size() - 1]; base_type::remove_last(); modify_last(t); } if(closed) { while(base_type::size() > 1) { if((*this)[base_type::size() - 1]((*this)[0])) break; base_type::remove_last(); } } } //-------------------------------------------------------------vertex_dist // Vertex (x, y) with the distance to the next one. The last vertex has // distance between the last and the first points if the polygon is closed // and 0.0 if it's a polyline. struct vertex_dist { double x; double y; double dist; vertex_dist() {} vertex_dist(double x_, double y_) : x(x_), y(y_), dist(0.0) { } bool operator () (const vertex_dist& val) { bool ret = (dist = calc_distance(x, y, val.x, val.y)) > vertex_dist_epsilon; if(!ret) dist = 1.0 / vertex_dist_epsilon; return ret; } }; //--------------------------------------------------------vertex_dist_cmd // Save as the above but with additional "command" value struct vertex_dist_cmd : public vertex_dist { unsigned cmd; vertex_dist_cmd() {} vertex_dist_cmd(double x_, double y_, unsigned cmd_) : vertex_dist(x_, y_), cmd(cmd_) { } }; } #endif ragg/src/agg/include/agg_renderer_base.h0000644000176200001440000006147213504406270017744 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // class renderer_base // //---------------------------------------------------------------------------- #ifndef AGG_RENDERER_BASE_INCLUDED #define AGG_RENDERER_BASE_INCLUDED #include "agg_basics.h" #include "agg_rendering_buffer.h" namespace agg { //-----------------------------------------------------------renderer_base template class renderer_base { public: typedef PixelFormat pixfmt_type; typedef typename pixfmt_type::color_type color_type; typedef typename pixfmt_type::row_data row_data; //-------------------------------------------------------------------- renderer_base() : m_ren(0), m_clip_box(1, 1, 0, 0) {} explicit renderer_base(pixfmt_type& ren) : m_ren(&ren), m_clip_box(0, 0, ren.width() - 1, ren.height() - 1) {} void attach(pixfmt_type& ren) { m_ren = &ren; m_clip_box = rect_i(0, 0, ren.width() - 1, ren.height() - 1); } //-------------------------------------------------------------------- const pixfmt_type& ren() const { return *m_ren; } pixfmt_type& ren() { return *m_ren; } //-------------------------------------------------------------------- unsigned width() const { return m_ren->width(); } unsigned height() const { return m_ren->height(); } //-------------------------------------------------------------------- bool clip_box(int x1, int y1, int x2, int y2) { rect_i cb(x1, y1, x2, y2); cb.normalize(); if(cb.clip(rect_i(0, 0, width() - 1, height() - 1))) { m_clip_box = cb; return true; } m_clip_box.x1 = 1; m_clip_box.y1 = 1; m_clip_box.x2 = 0; m_clip_box.y2 = 0; return false; } //-------------------------------------------------------------------- void reset_clipping(bool visibility) { if(visibility) { m_clip_box.x1 = 0; m_clip_box.y1 = 0; m_clip_box.x2 = width() - 1; m_clip_box.y2 = height() - 1; } else { m_clip_box.x1 = 1; m_clip_box.y1 = 1; m_clip_box.x2 = 0; m_clip_box.y2 = 0; } } //-------------------------------------------------------------------- void clip_box_naked(int x1, int y1, int x2, int y2) { m_clip_box.x1 = x1; m_clip_box.y1 = y1; m_clip_box.x2 = x2; m_clip_box.y2 = y2; } //-------------------------------------------------------------------- bool inbox(int x, int y) const { return x >= m_clip_box.x1 && y >= m_clip_box.y1 && x <= m_clip_box.x2 && y <= m_clip_box.y2; } //-------------------------------------------------------------------- const rect_i& clip_box() const { return m_clip_box; } int xmin() const { return m_clip_box.x1; } int ymin() const { return m_clip_box.y1; } int xmax() const { return m_clip_box.x2; } int ymax() const { return m_clip_box.y2; } //-------------------------------------------------------------------- const rect_i& bounding_clip_box() const { return m_clip_box; } int bounding_xmin() const { return m_clip_box.x1; } int bounding_ymin() const { return m_clip_box.y1; } int bounding_xmax() const { return m_clip_box.x2; } int bounding_ymax() const { return m_clip_box.y2; } //-------------------------------------------------------------------- void clear(const color_type& c) { unsigned y; if(width()) { for(y = 0; y < height(); y++) { m_ren->copy_hline(0, y, width(), c); } } } //-------------------------------------------------------------------- void fill(const color_type& c) { unsigned y; if(width()) { for(y = 0; y < height(); y++) { m_ren->blend_hline(0, y, width(), c, cover_mask); } } } //-------------------------------------------------------------------- void copy_pixel(int x, int y, const color_type& c) { if(inbox(x, y)) { m_ren->copy_pixel(x, y, c); } } //-------------------------------------------------------------------- void blend_pixel(int x, int y, const color_type& c, cover_type cover) { if(inbox(x, y)) { m_ren->blend_pixel(x, y, c, cover); } } //-------------------------------------------------------------------- color_type pixel(int x, int y) const { return inbox(x, y) ? m_ren->pixel(x, y) : color_type::no_color(); } //-------------------------------------------------------------------- void copy_hline(int x1, int y, int x2, const color_type& c) { if(x1 > x2) { int t = x2; x2 = x1; x1 = t; } if(y > ymax()) return; if(y < ymin()) return; if(x1 > xmax()) return; if(x2 < xmin()) return; if(x1 < xmin()) x1 = xmin(); if(x2 > xmax()) x2 = xmax(); m_ren->copy_hline(x1, y, x2 - x1 + 1, c); } //-------------------------------------------------------------------- void copy_vline(int x, int y1, int y2, const color_type& c) { if(y1 > y2) { int t = y2; y2 = y1; y1 = t; } if(x > xmax()) return; if(x < xmin()) return; if(y1 > ymax()) return; if(y2 < ymin()) return; if(y1 < ymin()) y1 = ymin(); if(y2 > ymax()) y2 = ymax(); m_ren->copy_vline(x, y1, y2 - y1 + 1, c); } //-------------------------------------------------------------------- void blend_hline(int x1, int y, int x2, const color_type& c, cover_type cover) { if(x1 > x2) { int t = x2; x2 = x1; x1 = t; } if(y > ymax()) return; if(y < ymin()) return; if(x1 > xmax()) return; if(x2 < xmin()) return; if(x1 < xmin()) x1 = xmin(); if(x2 > xmax()) x2 = xmax(); m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover); } //-------------------------------------------------------------------- void blend_vline(int x, int y1, int y2, const color_type& c, cover_type cover) { if(y1 > y2) { int t = y2; y2 = y1; y1 = t; } if(x > xmax()) return; if(x < xmin()) return; if(y1 > ymax()) return; if(y2 < ymin()) return; if(y1 < ymin()) y1 = ymin(); if(y2 > ymax()) y2 = ymax(); m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover); } //-------------------------------------------------------------------- void copy_bar(int x1, int y1, int x2, int y2, const color_type& c) { rect_i rc(x1, y1, x2, y2); rc.normalize(); if(rc.clip(clip_box())) { int y; for(y = rc.y1; y <= rc.y2; y++) { m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c); } } } //-------------------------------------------------------------------- void blend_bar(int x1, int y1, int x2, int y2, const color_type& c, cover_type cover) { rect_i rc(x1, y1, x2, y2); rc.normalize(); if(rc.clip(clip_box())) { int y; for(y = rc.y1; y <= rc.y2; y++) { m_ren->blend_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c, cover); } } } //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, int len, const color_type& c, const cover_type* covers) { if(y > ymax()) return; if(y < ymin()) return; if(x < xmin()) { len -= xmin() - x; if(len <= 0) return; covers += xmin() - x; x = xmin(); } if(x + len > xmax()) { len = xmax() - x + 1; if(len <= 0) return; } m_ren->blend_solid_hspan(x, y, len, c, covers); } //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, int len, const color_type& c, const cover_type* covers) { if(x > xmax()) return; if(x < xmin()) return; if(y < ymin()) { len -= ymin() - y; if(len <= 0) return; covers += ymin() - y; y = ymin(); } if(y + len > ymax()) { len = ymax() - y + 1; if(len <= 0) return; } m_ren->blend_solid_vspan(x, y, len, c, covers); } //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, int len, const color_type* colors) { if(y > ymax()) return; if(y < ymin()) return; if(x < xmin()) { int d = xmin() - x; len -= d; if(len <= 0) return; colors += d; x = xmin(); } if(x + len > xmax()) { len = xmax() - x + 1; if(len <= 0) return; } m_ren->copy_color_hspan(x, y, len, colors); } //-------------------------------------------------------------------- void copy_color_vspan(int x, int y, int len, const color_type* colors) { if(x > xmax()) return; if(x < xmin()) return; if(y < ymin()) { int d = ymin() - y; len -= d; if(len <= 0) return; colors += d; y = ymin(); } if(y + len > ymax()) { len = ymax() - y + 1; if(len <= 0) return; } m_ren->copy_color_vspan(x, y, len, colors); } //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, int len, const color_type* colors, const cover_type* covers, cover_type cover = agg::cover_full) { if(y > ymax()) return; if(y < ymin()) return; if(x < xmin()) { int d = xmin() - x; len -= d; if(len <= 0) return; if(covers) covers += d; colors += d; x = xmin(); } if(x + len > xmax()) { len = xmax() - x + 1; if(len <= 0) return; } m_ren->blend_color_hspan(x, y, len, colors, covers, cover); } //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, int len, const color_type* colors, const cover_type* covers, cover_type cover = agg::cover_full) { if(x > xmax()) return; if(x < xmin()) return; if(y < ymin()) { int d = ymin() - y; len -= d; if(len <= 0) return; if(covers) covers += d; colors += d; y = ymin(); } if(y + len > ymax()) { len = ymax() - y + 1; if(len <= 0) return; } m_ren->blend_color_vspan(x, y, len, colors, covers, cover); } //-------------------------------------------------------------------- rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const { rect_i rc(0,0,0,0); rect_i cb = clip_box(); ++cb.x2; ++cb.y2; if(src.x1 < 0) { dst.x1 -= src.x1; src.x1 = 0; } if(src.y1 < 0) { dst.y1 -= src.y1; src.y1 = 0; } if(src.x2 > wsrc) src.x2 = wsrc; if(src.y2 > hsrc) src.y2 = hsrc; if(dst.x1 < cb.x1) { src.x1 += cb.x1 - dst.x1; dst.x1 = cb.x1; } if(dst.y1 < cb.y1) { src.y1 += cb.y1 - dst.y1; dst.y1 = cb.y1; } if(dst.x2 > cb.x2) dst.x2 = cb.x2; if(dst.y2 > cb.y2) dst.y2 = cb.y2; rc.x2 = dst.x2 - dst.x1; rc.y2 = dst.y2 - dst.y1; if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1; if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1; return rc; } //-------------------------------------------------------------------- template void copy_from(const RenBuf& src, const rect_i* rect_src_ptr = 0, int dx = 0, int dy = 0) { rect_i rsrc(0, 0, src.width(), src.height()); if(rect_src_ptr) { rsrc.x1 = rect_src_ptr->x1; rsrc.y1 = rect_src_ptr->y1; rsrc.x2 = rect_src_ptr->x2 + 1; rsrc.y2 = rect_src_ptr->y2 + 1; } // Version with xdst, ydst (absolute positioning) //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); // Version with dx, dy (relative positioning) rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); if(rc.x2 > 0) { int incy = 1; if(rdst.y1 > rsrc.y1) { rsrc.y1 += rc.y2 - 1; rdst.y1 += rc.y2 - 1; incy = -1; } while(rc.y2 > 0) { m_ren->copy_from(src, rdst.x1, rdst.y1, rsrc.x1, rsrc.y1, rc.x2); rdst.y1 += incy; rsrc.y1 += incy; --rc.y2; } } } //-------------------------------------------------------------------- template void blend_from(const SrcPixelFormatRenderer& src, const rect_i* rect_src_ptr = 0, int dx = 0, int dy = 0, cover_type cover = agg::cover_full) { rect_i rsrc(0, 0, src.width(), src.height()); if(rect_src_ptr) { rsrc.x1 = rect_src_ptr->x1; rsrc.y1 = rect_src_ptr->y1; rsrc.x2 = rect_src_ptr->x2 + 1; rsrc.y2 = rect_src_ptr->y2 + 1; } // Version with xdst, ydst (absolute positioning) //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); // Version with dx, dy (relative positioning) rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); if(rc.x2 > 0) { int incy = 1; if(rdst.y1 > rsrc.y1) { rsrc.y1 += rc.y2 - 1; rdst.y1 += rc.y2 - 1; incy = -1; } while(rc.y2 > 0) { typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); if(rw.ptr) { int x1src = rsrc.x1; int x1dst = rdst.x1; int len = rc.x2; if(rw.x1 > x1src) { x1dst += rw.x1 - x1src; len -= rw.x1 - x1src; x1src = rw.x1; } if(len > 0) { if(x1src + len-1 > rw.x2) { len -= x1src + len - rw.x2 - 1; } if(len > 0) { m_ren->blend_from(src, x1dst, rdst.y1, x1src, rsrc.y1, len, cover); } } } rdst.y1 += incy; rsrc.y1 += incy; --rc.y2; } } } //-------------------------------------------------------------------- template void blend_from_color(const SrcPixelFormatRenderer& src, const color_type& color, const rect_i* rect_src_ptr = 0, int dx = 0, int dy = 0, cover_type cover = agg::cover_full) { rect_i rsrc(0, 0, src.width(), src.height()); if(rect_src_ptr) { rsrc.x1 = rect_src_ptr->x1; rsrc.y1 = rect_src_ptr->y1; rsrc.x2 = rect_src_ptr->x2 + 1; rsrc.y2 = rect_src_ptr->y2 + 1; } // Version with xdst, ydst (absolute positioning) //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); // Version with dx, dy (relative positioning) rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); if(rc.x2 > 0) { int incy = 1; if(rdst.y1 > rsrc.y1) { rsrc.y1 += rc.y2 - 1; rdst.y1 += rc.y2 - 1; incy = -1; } while(rc.y2 > 0) { typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); if(rw.ptr) { int x1src = rsrc.x1; int x1dst = rdst.x1; int len = rc.x2; if(rw.x1 > x1src) { x1dst += rw.x1 - x1src; len -= rw.x1 - x1src; x1src = rw.x1; } if(len > 0) { if(x1src + len-1 > rw.x2) { len -= x1src + len - rw.x2 - 1; } if(len > 0) { m_ren->blend_from_color(src, color, x1dst, rdst.y1, x1src, rsrc.y1, len, cover); } } } rdst.y1 += incy; rsrc.y1 += incy; --rc.y2; } } } //-------------------------------------------------------------------- template void blend_from_lut(const SrcPixelFormatRenderer& src, const color_type* color_lut, const rect_i* rect_src_ptr = 0, int dx = 0, int dy = 0, cover_type cover = agg::cover_full) { rect_i rsrc(0, 0, src.width(), src.height()); if(rect_src_ptr) { rsrc.x1 = rect_src_ptr->x1; rsrc.y1 = rect_src_ptr->y1; rsrc.x2 = rect_src_ptr->x2 + 1; rsrc.y2 = rect_src_ptr->y2 + 1; } // Version with xdst, ydst (absolute positioning) //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); // Version with dx, dy (relative positioning) rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); if(rc.x2 > 0) { int incy = 1; if(rdst.y1 > rsrc.y1) { rsrc.y1 += rc.y2 - 1; rdst.y1 += rc.y2 - 1; incy = -1; } while(rc.y2 > 0) { typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); if(rw.ptr) { int x1src = rsrc.x1; int x1dst = rdst.x1; int len = rc.x2; if(rw.x1 > x1src) { x1dst += rw.x1 - x1src; len -= rw.x1 - x1src; x1src = rw.x1; } if(len > 0) { if(x1src + len-1 > rw.x2) { len -= x1src + len - rw.x2 - 1; } if(len > 0) { m_ren->blend_from_lut(src, color_lut, x1dst, rdst.y1, x1src, rsrc.y1, len, cover); } } } rdst.y1 += incy; rsrc.y1 += incy; --rc.y2; } } } private: pixfmt_type* m_ren; rect_i m_clip_box; }; } #endif ragg/src/agg/include/agg_pattern_filters_rgba.h0000644000176200001440000001021413504406270021330 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_PATTERN_FILTERS_RGBA8_INCLUDED #define AGG_PATTERN_FILTERS_RGBA8_INCLUDED #include "agg_basics.h" #include "agg_line_aa_basics.h" #include "agg_color_rgba.h" namespace agg { //=======================================================pattern_filter_nn template struct pattern_filter_nn { typedef ColorT color_type; static unsigned dilation() { return 0; } static void AGG_INLINE pixel_low_res(color_type const* const* buf, color_type* p, int x, int y) { *p = buf[y][x]; } static void AGG_INLINE pixel_high_res(color_type const* const* buf, color_type* p, int x, int y) { *p = buf[y >> line_subpixel_shift] [x >> line_subpixel_shift]; } }; typedef pattern_filter_nn pattern_filter_nn_rgba8; typedef pattern_filter_nn pattern_filter_nn_rgba16; //===========================================pattern_filter_bilinear_rgba template struct pattern_filter_bilinear_rgba { typedef ColorT color_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; static unsigned dilation() { return 1; } static AGG_INLINE void pixel_low_res(color_type const* const* buf, color_type* p, int x, int y) { *p = buf[y][x]; } static AGG_INLINE void pixel_high_res(color_type const* const* buf, color_type* p, int x, int y) { calc_type r, g, b, a; r = g = b = a = 0; calc_type weight; int x_lr = x >> line_subpixel_shift; int y_lr = y >> line_subpixel_shift; x &= line_subpixel_mask; y &= line_subpixel_mask; const color_type* ptr = buf[y_lr] + x_lr; weight = (line_subpixel_scale - x) * (line_subpixel_scale - y); r += weight * ptr->r; g += weight * ptr->g; b += weight * ptr->b; a += weight * ptr->a; ++ptr; weight = x * (line_subpixel_scale - y); r += weight * ptr->r; g += weight * ptr->g; b += weight * ptr->b; a += weight * ptr->a; ptr = buf[y_lr + 1] + x_lr; weight = (line_subpixel_scale - x) * y; r += weight * ptr->r; g += weight * ptr->g; b += weight * ptr->b; a += weight * ptr->a; ++ptr; weight = x * y; r += weight * ptr->r; g += weight * ptr->g; b += weight * ptr->b; a += weight * ptr->a; p->r = (value_type)color_type::downshift(r, line_subpixel_shift * 2); p->g = (value_type)color_type::downshift(g, line_subpixel_shift * 2); p->b = (value_type)color_type::downshift(b, line_subpixel_shift * 2); p->a = (value_type)color_type::downshift(a, line_subpixel_shift * 2); } }; typedef pattern_filter_bilinear_rgba pattern_filter_bilinear_rgba8; typedef pattern_filter_bilinear_rgba pattern_filter_bilinear_rgba16; typedef pattern_filter_bilinear_rgba pattern_filter_bilinear_rgba32; } #endif ragg/src/agg/include/agg_ellipse.h0000644000176200001440000000713013504406270016570 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // class ellipse // //---------------------------------------------------------------------------- #ifndef AGG_ELLIPSE_INCLUDED #define AGG_ELLIPSE_INCLUDED #include "agg_basics.h" #include namespace agg { //----------------------------------------------------------------ellipse class ellipse { public: ellipse() : m_x(0.0), m_y(0.0), m_rx(1.0), m_ry(1.0), m_scale(1.0), m_num(4), m_step(0), m_cw(false) {} ellipse(double x, double y, double rx, double ry, unsigned num_steps=0, bool cw=false) : m_x(x), m_y(y), m_rx(rx), m_ry(ry), m_scale(1.0), m_num(num_steps), m_step(0), m_cw(cw) { if(m_num == 0) calc_num_steps(); } void init(double x, double y, double rx, double ry, unsigned num_steps=0, bool cw=false); void approximation_scale(double scale); void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: void calc_num_steps(); double m_x; double m_y; double m_rx; double m_ry; double m_scale; unsigned m_num; unsigned m_step; bool m_cw; }; //------------------------------------------------------------------------ inline void ellipse::init(double x, double y, double rx, double ry, unsigned num_steps, bool cw) { m_x = x; m_y = y; m_rx = rx; m_ry = ry; m_num = num_steps; m_step = 0; m_cw = cw; if(m_num == 0) calc_num_steps(); } //------------------------------------------------------------------------ inline void ellipse::approximation_scale(double scale) { m_scale = scale; calc_num_steps(); } //------------------------------------------------------------------------ inline void ellipse::calc_num_steps() { double ra = (std::fabs(m_rx) + std::fabs(m_ry)) / 2; double da = std::acos(ra / (ra + 0.125 / m_scale)) * 2; m_num = uround(2*pi / da); } //------------------------------------------------------------------------ inline void ellipse::rewind(unsigned) { m_step = 0; } //------------------------------------------------------------------------ inline unsigned ellipse::vertex(double* x, double* y) { if(m_step == m_num) { ++m_step; return path_cmd_end_poly | path_flags_close | path_flags_ccw; } if(m_step > m_num) return path_cmd_stop; double angle = double(m_step) / double(m_num) * 2.0 * pi; if(m_cw) angle = 2.0 * pi - angle; *x = m_x + std::cos(angle) * m_rx; *y = m_y + std::sin(angle) * m_ry; m_step++; return ((m_step == 1) ? path_cmd_move_to : path_cmd_line_to); } } #endif ragg/src/agg/include/agg_image_filters.h0000644000176200001440000003520714004766742017764 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Image transformation filters, // Filtering classes (image_filter_lut, image_filter), // Basic filter shape classes //---------------------------------------------------------------------------- #ifndef AGG_IMAGE_FILTERS_INCLUDED #define AGG_IMAGE_FILTERS_INCLUDED #include "agg_array.h" #include "agg_math.h" namespace agg { // See Implementation agg_image_filters.cpp enum image_filter_scale_e { image_filter_shift = 14, //----image_filter_shift image_filter_scale = 1 << image_filter_shift, //----image_filter_scale image_filter_mask = image_filter_scale - 1 //----image_filter_mask }; enum image_subpixel_scale_e { image_subpixel_shift = 8, //----image_subpixel_shift image_subpixel_scale = 1 << image_subpixel_shift, //----image_subpixel_scale image_subpixel_mask = image_subpixel_scale - 1 //----image_subpixel_mask }; //-----------------------------------------------------image_filter_lut class image_filter_lut { public: template void calculate(const FilterF& filter, bool normalization=true) { //filter; // prevent erroneous C4100 in MSVC double r = filter.radius(); realloc_lut(r); unsigned i; unsigned pivot = diameter() << (image_subpixel_shift - 1); for(i = 0; i < pivot; i++) { double x = double(i) / double(image_subpixel_scale); double y = filter.calc_weight(x); m_weight_array[pivot + i] = m_weight_array[pivot - i] = (int16)iround(y * image_filter_scale); } unsigned end = (diameter() << image_subpixel_shift) - 1; m_weight_array[0] = m_weight_array[end]; if(normalization) { normalize(); } } image_filter_lut() : m_radius(0), m_diameter(0), m_start(0) {} template image_filter_lut(const FilterF& filter, bool normalization=true) { calculate(filter, normalization); } double radius() const { return m_radius; } unsigned diameter() const { return m_diameter; } int start() const { return m_start; } const int16* weight_array() const { return &m_weight_array[0]; } void normalize(); private: void realloc_lut(double radius); image_filter_lut(const image_filter_lut&); const image_filter_lut& operator = (const image_filter_lut&); double m_radius; unsigned m_diameter; int m_start; pod_array m_weight_array; }; //--------------------------------------------------------image_filter template class image_filter : public image_filter_lut { public: image_filter() { calculate(m_filter_function); } private: FilterF m_filter_function; }; //-----------------------------------------------image_filter_bilinear struct image_filter_bilinear { static double radius() { return 1.0; } static double calc_weight(double x) { return 1.0 - x; } }; //-----------------------------------------------image_filter_hanning struct image_filter_hanning { static double radius() { return 1.0; } static double calc_weight(double x) { return 0.5 + 0.5 * std::cos(pi * x); } }; //-----------------------------------------------image_filter_hamming struct image_filter_hamming { static double radius() { return 1.0; } static double calc_weight(double x) { return 0.54 + 0.46 * std::cos(pi * x); } }; //-----------------------------------------------image_filter_hermite struct image_filter_hermite { static double radius() { return 1.0; } static double calc_weight(double x) { return (2.0 * x - 3.0) * x * x + 1.0; } }; //------------------------------------------------image_filter_quadric struct image_filter_quadric { static double radius() { return 1.5; } static double calc_weight(double x) { double t; if(x < 0.5) return 0.75 - x * x; if(x < 1.5) {t = x - 1.5; return 0.5 * t * t;} return 0.0; } }; //------------------------------------------------image_filter_bicubic class image_filter_bicubic { static double pow3(double x) { return (x <= 0.0) ? 0.0 : x * x * x; } public: static double radius() { return 2.0; } static double calc_weight(double x) { return (1.0/6.0) * (pow3(x + 2) - 4 * pow3(x + 1) + 6 * pow3(x) - 4 * pow3(x - 1)); } }; //-------------------------------------------------image_filter_kaiser class image_filter_kaiser { double a; double i0a; double epsilon; public: image_filter_kaiser(double b = 6.33) : a(b), epsilon(1e-12) { i0a = 1.0 / bessel_i0(b); } static double radius() { return 1.0; } double calc_weight(double x) const { return bessel_i0(a * std::sqrt(1. - x * x)) * i0a; } private: double bessel_i0(double x) const { int i; double sum, y, t; sum = 1.; y = x * x / 4.; t = y; for(i = 2; t > epsilon; i++) { sum += t; t *= (double)y / (i * i); } return sum; } }; //----------------------------------------------image_filter_catrom struct image_filter_catrom { static double radius() { return 2.0; } static double calc_weight(double x) { if(x < 1.0) return 0.5 * (2.0 + x * x * (-5.0 + x * 3.0)); if(x < 2.0) return 0.5 * (4.0 + x * (-8.0 + x * (5.0 - x))); return 0.; } }; //---------------------------------------------image_filter_mitchell class image_filter_mitchell { double p0, p2, p3; double q0, q1, q2, q3; public: image_filter_mitchell(double b = 1.0/3.0, double c = 1.0/3.0) : p0((6.0 - 2.0 * b) / 6.0), p2((-18.0 + 12.0 * b + 6.0 * c) / 6.0), p3((12.0 - 9.0 * b - 6.0 * c) / 6.0), q0((8.0 * b + 24.0 * c) / 6.0), q1((-12.0 * b - 48.0 * c) / 6.0), q2((6.0 * b + 30.0 * c) / 6.0), q3((-b - 6.0 * c) / 6.0) {} static double radius() { return 2.0; } double calc_weight(double x) const { if(x < 1.0) return p0 + x * x * (p2 + x * p3); if(x < 2.0) return q0 + x * (q1 + x * (q2 + x * q3)); return 0.0; } }; //----------------------------------------------image_filter_spline16 struct image_filter_spline16 { static double radius() { return 2.0; } static double calc_weight(double x) { if(x < 1.0) { return ((x - 9.0/5.0 ) * x - 1.0/5.0 ) * x + 1.0; } return ((-1.0/3.0 * (x-1) + 4.0/5.0) * (x-1) - 7.0/15.0 ) * (x-1); } }; //---------------------------------------------image_filter_spline36 struct image_filter_spline36 { static double radius() { return 3.0; } static double calc_weight(double x) { if(x < 1.0) { return ((13.0/11.0 * x - 453.0/209.0) * x - 3.0/209.0) * x + 1.0; } if(x < 2.0) { return ((-6.0/11.0 * (x-1) + 270.0/209.0) * (x-1) - 156.0/ 209.0) * (x-1); } return ((1.0/11.0 * (x-2) - 45.0/209.0) * (x-2) + 26.0/209.0) * (x-2); } }; //----------------------------------------------image_filter_gaussian struct image_filter_gaussian { static double radius() { return 2.0; } static double calc_weight(double x) { return std::exp(-2.0 * x * x) * std::sqrt(2.0 / pi); } }; //------------------------------------------------image_filter_bessel struct image_filter_bessel { static double radius() { return 3.2383; } static double calc_weight(double x) { return (x == 0.0) ? pi / 4.0 : besj(pi * x, 1) / (2.0 * x); } }; //-------------------------------------------------image_filter_sinc class image_filter_sinc { public: image_filter_sinc(double r) : m_radius(r < 2.0 ? 2.0 : r) {} double radius() const { return m_radius; } double calc_weight(double x) const { if(x == 0.0) return 1.0; x *= pi; return std::sin(x) / x; } private: double m_radius; }; //-----------------------------------------------image_filter_lanczos class image_filter_lanczos { public: image_filter_lanczos(double r) : m_radius(r < 2.0 ? 2.0 : r) {} double radius() const { return m_radius; } double calc_weight(double x) const { if(x == 0.0) return 1.0; if(x > m_radius) return 0.0; x *= pi; double xr = x / m_radius; return (std::sin(x) / x) * (std::sin(xr) / xr); } private: double m_radius; }; //----------------------------------------------image_filter_blackman class image_filter_blackman { public: image_filter_blackman(double r) : m_radius(r < 2.0 ? 2.0 : r) {} double radius() const { return m_radius; } double calc_weight(double x) const { if(x == 0.0) return 1.0; if(x > m_radius) return 0.0; x *= pi; double xr = x / m_radius; return (std::sin(x) / x) * (0.42 + 0.5*std::cos(xr) + 0.08*std::cos(2*xr)); } private: double m_radius; }; //------------------------------------------------image_filter_sinc36 class image_filter_sinc36 : public image_filter_sinc { public: image_filter_sinc36() : image_filter_sinc(3.0){} }; //------------------------------------------------image_filter_sinc64 class image_filter_sinc64 : public image_filter_sinc { public: image_filter_sinc64() : image_filter_sinc(4.0){} }; //-----------------------------------------------image_filter_sinc100 class image_filter_sinc100 : public image_filter_sinc { public: image_filter_sinc100() : image_filter_sinc(5.0){} }; //-----------------------------------------------image_filter_sinc144 class image_filter_sinc144 : public image_filter_sinc { public: image_filter_sinc144() : image_filter_sinc(6.0){} }; //-----------------------------------------------image_filter_sinc196 class image_filter_sinc196 : public image_filter_sinc { public: image_filter_sinc196() : image_filter_sinc(7.0){} }; //-----------------------------------------------image_filter_sinc256 class image_filter_sinc256 : public image_filter_sinc { public: image_filter_sinc256() : image_filter_sinc(8.0){} }; //---------------------------------------------image_filter_lanczos36 class image_filter_lanczos36 : public image_filter_lanczos { public: image_filter_lanczos36() : image_filter_lanczos(3.0){} }; //---------------------------------------------image_filter_lanczos64 class image_filter_lanczos64 : public image_filter_lanczos { public: image_filter_lanczos64() : image_filter_lanczos(4.0){} }; //--------------------------------------------image_filter_lanczos100 class image_filter_lanczos100 : public image_filter_lanczos { public: image_filter_lanczos100() : image_filter_lanczos(5.0){} }; //--------------------------------------------image_filter_lanczos144 class image_filter_lanczos144 : public image_filter_lanczos { public: image_filter_lanczos144() : image_filter_lanczos(6.0){} }; //--------------------------------------------image_filter_lanczos196 class image_filter_lanczos196 : public image_filter_lanczos { public: image_filter_lanczos196() : image_filter_lanczos(7.0){} }; //--------------------------------------------image_filter_lanczos256 class image_filter_lanczos256 : public image_filter_lanczos { public: image_filter_lanczos256() : image_filter_lanczos(8.0){} }; //--------------------------------------------image_filter_blackman36 class image_filter_blackman36 : public image_filter_blackman { public: image_filter_blackman36() : image_filter_blackman(3.0){} }; //--------------------------------------------image_filter_blackman64 class image_filter_blackman64 : public image_filter_blackman { public: image_filter_blackman64() : image_filter_blackman(4.0){} }; //-------------------------------------------image_filter_blackman100 class image_filter_blackman100 : public image_filter_blackman { public: image_filter_blackman100() : image_filter_blackman(5.0){} }; //-------------------------------------------image_filter_blackman144 class image_filter_blackman144 : public image_filter_blackman { public: image_filter_blackman144() : image_filter_blackman(6.0){} }; //-------------------------------------------image_filter_blackman196 class image_filter_blackman196 : public image_filter_blackman { public: image_filter_blackman196() : image_filter_blackman(7.0){} }; //-------------------------------------------image_filter_blackman256 class image_filter_blackman256 : public image_filter_blackman { public: image_filter_blackman256() : image_filter_blackman(8.0){} }; } #endif ragg/src/agg/include/agg_conv_clip_polyline.h0000644000176200001440000000474413504406270021032 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // polyline clipping converter // There an optimized Liang-Basky algorithm is used. // The algorithm doesn't optimize the degenerate edges, i.e. it will never // break a closed polyline into two or more ones, instead, there will be // degenerate edges coinciding with the respective clipping boundaries. // This is a sub-optimal solution, because that optimization would require // extra, rather expensive math while the rasterizer tolerates it quite well, // without any considerable overhead. // //---------------------------------------------------------------------------- #ifndef AGG_CONV_CLIP_polyline_INCLUDED #define AGG_CONV_CLIP_polyline_INCLUDED #include "agg_basics.h" #include "agg_conv_adaptor_vpgen.h" #include "agg_vpgen_clip_polyline.h" namespace agg { //=======================================================conv_clip_polyline template struct conv_clip_polyline : public conv_adaptor_vpgen { typedef conv_adaptor_vpgen base_type; conv_clip_polyline(VertexSource& vs) : conv_adaptor_vpgen(vs) {} void clip_box(double x1, double y1, double x2, double y2) { base_type::vpgen().clip_box(x1, y1, x2, y2); } double x1() const { return base_type::vpgen().x1(); } double y1() const { return base_type::vpgen().y1(); } double x2() const { return base_type::vpgen().x2(); } double y2() const { return base_type::vpgen().y2(); } private: conv_clip_polyline(const conv_clip_polyline&); const conv_clip_polyline& operator = (const conv_clip_polyline&); }; } #endif ragg/src/agg/include/agg_color_gray.h0000644000176200001440000010206613504406270017277 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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. // //---------------------------------------------------------------------------- // // color types gray8, gray16 // //---------------------------------------------------------------------------- #ifndef AGG_COLOR_GRAY_INCLUDED #define AGG_COLOR_GRAY_INCLUDED #include "agg_basics.h" #include "agg_color_rgba.h" namespace agg { //===================================================================gray8 template struct gray8T { typedef int8u value_type; typedef int32u calc_type; typedef int32 long_type; enum base_scale_e { base_shift = 8, base_scale = 1 << base_shift, base_mask = base_scale - 1, base_MSB = 1 << (base_shift - 1) }; typedef gray8T self_type; value_type v; value_type a; static value_type luminance(const rgba& c) { // Calculate grayscale value as per ITU-R BT.709. return value_type(uround((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * base_mask)); } static value_type luminance(const rgba8& c) { // Calculate grayscale value as per ITU-R BT.709. return value_type((55u * c.r + 184u * c.g + 18u * c.b) >> 8); } static void convert(gray8T& dst, const gray8T& src) { dst.v = sRGB_conv::rgb_from_sRGB(src.v); dst.a = src.a; } static void convert(gray8T& dst, const gray8T& src) { dst.v = sRGB_conv::rgb_to_sRGB(src.v); dst.a = src.a; } static void convert(gray8T& dst, const rgba8& src) { dst.v = luminance(src); dst.a = src.a; } static void convert(gray8T& dst, const srgba8& src) { // The RGB weights are only valid for linear values. convert(dst, rgba8(src)); } static void convert(gray8T& dst, const rgba8& src) { dst.v = sRGB_conv::rgb_to_sRGB(luminance(src)); dst.a = src.a; } static void convert(gray8T& dst, const srgba8& src) { // The RGB weights are only valid for linear values. convert(dst, rgba8(src)); } //-------------------------------------------------------------------- gray8T() {} //-------------------------------------------------------------------- explicit gray8T(unsigned v_, unsigned a_ = base_mask) : v(int8u(v_)), a(int8u(a_)) {} //-------------------------------------------------------------------- gray8T(const self_type& c, unsigned a_) : v(c.v), a(value_type(a_)) {} //-------------------------------------------------------------------- gray8T(const rgba& c) : v(luminance(c)), a(value_type(uround(c.a * base_mask))) {} //-------------------------------------------------------------------- template gray8T(const gray8T& c) { convert(*this, c); } //-------------------------------------------------------------------- template gray8T(const rgba8T& c) { convert(*this, c); } //-------------------------------------------------------------------- template T convert_from_sRGB() const { typename T::value_type y = sRGB_conv::rgb_from_sRGB(v); return T(y, y, y, sRGB_conv::alpha_from_sRGB(a)); } template T convert_to_sRGB() const { typename T::value_type y = sRGB_conv::rgb_to_sRGB(v); return T(y, y, y, sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- rgba8 make_rgba8(const linear&) const { return rgba8(v, v, v, a); } rgba8 make_rgba8(const sRGB&) const { return convert_from_sRGB(); } operator rgba8() const { return make_rgba8(Colorspace()); } //-------------------------------------------------------------------- srgba8 make_srgba8(const linear&) const { return convert_to_sRGB(); } srgba8 make_srgba8(const sRGB&) const { return srgba8(v, v, v, a); } operator srgba8() const { return make_rgba8(Colorspace()); } //-------------------------------------------------------------------- rgba16 make_rgba16(const linear&) const { rgba16::value_type rgb = (v << 8) | v; return rgba16(rgb, rgb, rgb, (a << 8) | a); } rgba16 make_rgba16(const sRGB&) const { return convert_from_sRGB(); } operator rgba16() const { return make_rgba16(Colorspace()); } //-------------------------------------------------------------------- rgba32 make_rgba32(const linear&) const { rgba32::value_type v32 = v / 255.0f; return rgba32(v32, v32, v32, a / 255.0f); } rgba32 make_rgba32(const sRGB&) const { return convert_from_sRGB(); } operator rgba32() const { return make_rgba32(Colorspace()); } //-------------------------------------------------------------------- static AGG_INLINE double to_double(value_type a) { return double(a) / base_mask; } //-------------------------------------------------------------------- static AGG_INLINE value_type from_double(double a) { return value_type(uround(a * base_mask)); } //-------------------------------------------------------------------- static AGG_INLINE value_type empty_value() { return 0; } //-------------------------------------------------------------------- static AGG_INLINE value_type full_value() { return base_mask; } //-------------------------------------------------------------------- AGG_INLINE bool is_transparent() const { return a == 0; } //-------------------------------------------------------------------- AGG_INLINE bool is_opaque() const { return a == base_mask; } //-------------------------------------------------------------------- // Fixed-point multiply, exact over int8u. static AGG_INLINE value_type multiply(value_type a, value_type b) { calc_type t = a * b + base_MSB; return value_type(((t >> base_shift) + t) >> base_shift); } //-------------------------------------------------------------------- static AGG_INLINE value_type demultiply(value_type a, value_type b) { if (a * b == 0) { return 0; } else if (a >= b) { return base_mask; } else return value_type((a * base_mask + (b >> 1)) / b); } //-------------------------------------------------------------------- template static AGG_INLINE T downscale(T a) { return a >> base_shift; } //-------------------------------------------------------------------- template static AGG_INLINE T downshift(T a, unsigned n) { return a >> n; } //-------------------------------------------------------------------- // Fixed-point multiply, exact over int8u. // Specifically for multiplying a color component by a cover. static AGG_INLINE value_type mult_cover(value_type a, value_type b) { return multiply(a, b); } //-------------------------------------------------------------------- static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return multiply(b, a); } //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return p + q - multiply(p, a); } //-------------------------------------------------------------------- // Interpolate p to q by a. static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { int t = (q - p) * a + base_MSB - (p > q); return value_type(p + (((t >> base_shift) + t) >> base_shift)); } //-------------------------------------------------------------------- self_type& clear() { v = a = 0; return *this; } //-------------------------------------------------------------------- self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- self_type& opacity(double a_) { if (a_ < 0) a = 0; else if (a_ > 1) a = 1; else a = (value_type)uround(a_ * double(base_mask)); return *this; } //-------------------------------------------------------------------- double opacity() const { return double(a) / double(base_mask); } //-------------------------------------------------------------------- self_type& premultiply() { if (a < base_mask) { if (a == 0) v = 0; else v = multiply(v, a); } return *this; } //-------------------------------------------------------------------- self_type& demultiply() { if (a < base_mask) { if (a == 0) { v = 0; } else { calc_type v_ = (calc_type(v) * base_mask) / a; v = value_type((v_ > base_mask) ? (value_type)base_mask : v_); } } return *this; } //-------------------------------------------------------------------- self_type gradient(self_type c, double k) const { self_type ret; calc_type ik = uround(k * base_scale); ret.v = lerp(v, c.v, ik); ret.a = lerp(a, c.a, ik); return ret; } //-------------------------------------------------------------------- AGG_INLINE void add(const self_type& c, unsigned cover) { calc_type cv, ca; if (cover == cover_mask) { if (c.a == base_mask) { *this = c; return; } else { cv = v + c.v; ca = a + c.a; } } else { cv = v + mult_cover(c.v, cover); ca = a + mult_cover(c.a, cover); } v = (value_type)((cv > calc_type(base_mask)) ? calc_type(base_mask) : cv); a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca); } //-------------------------------------------------------------------- static self_type no_color() { return self_type(0,0); } }; typedef gray8T gray8; typedef gray8T sgray8; //==================================================================gray16 struct gray16 { typedef int16u value_type; typedef int32u calc_type; typedef int64 long_type; enum base_scale_e { base_shift = 16, base_scale = 1 << base_shift, base_mask = base_scale - 1, base_MSB = 1 << (base_shift - 1) }; typedef gray16 self_type; value_type v; value_type a; static value_type luminance(const rgba& c) { // Calculate grayscale value as per ITU-R BT.709. return value_type(uround((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * base_mask)); } static value_type luminance(const rgba16& c) { // Calculate grayscale value as per ITU-R BT.709. return value_type((13933u * c.r + 46872u * c.g + 4732u * c.b) >> 16); } static value_type luminance(const rgba8& c) { return luminance(rgba16(c)); } static value_type luminance(const srgba8& c) { return luminance(rgba16(c)); } static value_type luminance(const rgba32& c) { return luminance(rgba(c)); } //-------------------------------------------------------------------- gray16() {} //-------------------------------------------------------------------- explicit gray16(unsigned v_, unsigned a_ = base_mask) : v(int16u(v_)), a(int16u(a_)) {} //-------------------------------------------------------------------- gray16(const self_type& c, unsigned a_) : v(c.v), a(value_type(a_)) {} //-------------------------------------------------------------------- gray16(const rgba& c) : v(luminance(c)), a((value_type)uround(c.a * double(base_mask))) {} //-------------------------------------------------------------------- gray16(const rgba8& c) : v(luminance(c)), a((value_type(c.a) << 8) | c.a) {} //-------------------------------------------------------------------- gray16(const srgba8& c) : v(luminance(c)), a((value_type(c.a) << 8) | c.a) {} //-------------------------------------------------------------------- gray16(const rgba16& c) : v(luminance(c)), a(c.a) {} //-------------------------------------------------------------------- gray16(const gray8& c) : v((value_type(c.v) << 8) | c.v), a((value_type(c.a) << 8) | c.a) {} //-------------------------------------------------------------------- gray16(const sgray8& c) : v(sRGB_conv::rgb_from_sRGB(c.v)), a(sRGB_conv::alpha_from_sRGB(c.a)) {} //-------------------------------------------------------------------- operator rgba8() const { return rgba8(v >> 8, v >> 8, v >> 8, a >> 8); } //-------------------------------------------------------------------- operator srgba8() const { value_type y = sRGB_conv::rgb_to_sRGB(v); return srgba8(y, y, y, sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- operator rgba16() const { return rgba16(v, v, v, a); } //-------------------------------------------------------------------- operator rgba32() const { rgba32::value_type v32 = v / 65535.0f; return rgba32(v32, v32, v32, a / 65535.0f); } //-------------------------------------------------------------------- operator gray8() const { return gray8(v >> 8, a >> 8); } //-------------------------------------------------------------------- operator sgray8() const { return sgray8( sRGB_conv::rgb_to_sRGB(v), sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- static AGG_INLINE double to_double(value_type a) { return double(a) / base_mask; } //-------------------------------------------------------------------- static AGG_INLINE value_type from_double(double a) { return value_type(uround(a * base_mask)); } //-------------------------------------------------------------------- static AGG_INLINE value_type empty_value() { return 0; } //-------------------------------------------------------------------- static AGG_INLINE value_type full_value() { return base_mask; } //-------------------------------------------------------------------- AGG_INLINE bool is_transparent() const { return a == 0; } //-------------------------------------------------------------------- AGG_INLINE bool is_opaque() const { return a == base_mask; } //-------------------------------------------------------------------- // Fixed-point multiply, exact over int16u. static AGG_INLINE value_type multiply(value_type a, value_type b) { calc_type t = a * b + base_MSB; return value_type(((t >> base_shift) + t) >> base_shift); } //-------------------------------------------------------------------- static AGG_INLINE value_type demultiply(value_type a, value_type b) { if (a * b == 0) { return 0; } else if (a >= b) { return base_mask; } else return value_type((a * base_mask + (b >> 1)) / b); } //-------------------------------------------------------------------- template static AGG_INLINE T downscale(T a) { return a >> base_shift; } //-------------------------------------------------------------------- template static AGG_INLINE T downshift(T a, unsigned n) { return a >> n; } //-------------------------------------------------------------------- // Fixed-point multiply, almost exact over int16u. // Specifically for multiplying a color component by a cover. static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return multiply(a, b << 8 | b); } //-------------------------------------------------------------------- static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return mult_cover(b, a) >> 8; } //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return p + q - multiply(p, a); } //-------------------------------------------------------------------- // Interpolate p to q by a. static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { int t = (q - p) * a + base_MSB - (p > q); return value_type(p + (((t >> base_shift) + t) >> base_shift)); } //-------------------------------------------------------------------- self_type& clear() { v = a = 0; return *this; } //-------------------------------------------------------------------- self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- self_type& opacity(double a_) { if (a_ < 0) a = 0; else if(a_ > 1) a = 1; else a = (value_type)uround(a_ * double(base_mask)); return *this; } //-------------------------------------------------------------------- double opacity() const { return double(a) / double(base_mask); } //-------------------------------------------------------------------- self_type& premultiply() { if (a < base_mask) { if(a == 0) v = 0; else v = multiply(v, a); } return *this; } //-------------------------------------------------------------------- self_type& demultiply() { if (a < base_mask) { if (a == 0) { v = 0; } else { calc_type v_ = (calc_type(v) * base_mask) / a; v = (v_ > base_mask) ? value_type(base_mask) : value_type(v_); } } return *this; } //-------------------------------------------------------------------- self_type gradient(self_type c, double k) const { self_type ret; calc_type ik = uround(k * base_scale); ret.v = lerp(v, c.v, ik); ret.a = lerp(a, c.a, ik); return ret; } //-------------------------------------------------------------------- AGG_INLINE void add(const self_type& c, unsigned cover) { calc_type cv, ca; if (cover == cover_mask) { if (c.a == base_mask) { *this = c; return; } else { cv = v + c.v; ca = a + c.a; } } else { cv = v + mult_cover(c.v, cover); ca = a + mult_cover(c.a, cover); } v = (value_type)((cv > calc_type(base_mask)) ? calc_type(base_mask) : cv); a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca); } //-------------------------------------------------------------------- static self_type no_color() { return self_type(0,0); } }; //===================================================================gray32 struct gray32 { typedef float value_type; typedef double calc_type; typedef double long_type; typedef gray32 self_type; value_type v; value_type a; // Calculate grayscale value as per ITU-R BT.709. static value_type luminance(double r, double g, double b) { return value_type(0.2126 * r + 0.7152 * g + 0.0722 * b); } static value_type luminance(const rgba& c) { return luminance(c.r, c.g, c.b); } static value_type luminance(const rgba32& c) { return luminance(c.r, c.g, c.b); } static value_type luminance(const rgba8& c) { return luminance(c.r / 255.0, c.g / 255.0, c.g / 255.0); } static value_type luminance(const rgba16& c) { return luminance(c.r / 65535.0, c.g / 65535.0, c.g / 65535.0); } //-------------------------------------------------------------------- gray32() {} //-------------------------------------------------------------------- explicit gray32(value_type v_, value_type a_ = 1) : v(v_), a(a_) {} //-------------------------------------------------------------------- gray32(const self_type& c, value_type a_) : v(c.v), a(a_) {} //-------------------------------------------------------------------- gray32(const rgba& c) : v(luminance(c)), a(value_type(c.a)) {} //-------------------------------------------------------------------- gray32(const rgba8& c) : v(luminance(c)), a(value_type(c.a / 255.0)) {} //-------------------------------------------------------------------- gray32(const srgba8& c) : v(luminance(rgba32(c))), a(value_type(c.a / 255.0)) {} //-------------------------------------------------------------------- gray32(const rgba16& c) : v(luminance(c)), a(value_type(c.a / 65535.0)) {} //-------------------------------------------------------------------- gray32(const rgba32& c) : v(luminance(c)), a(value_type(c.a)) {} //-------------------------------------------------------------------- gray32(const gray8& c) : v(value_type(c.v / 255.0)), a(value_type(c.a / 255.0)) {} //-------------------------------------------------------------------- gray32(const sgray8& c) : v(sRGB_conv::rgb_from_sRGB(c.v)), a(sRGB_conv::alpha_from_sRGB(c.a)) {} //-------------------------------------------------------------------- gray32(const gray16& c) : v(value_type(c.v / 65535.0)), a(value_type(c.a / 65535.0)) {} //-------------------------------------------------------------------- operator rgba() const { return rgba(v, v, v, a); } //-------------------------------------------------------------------- operator gray8() const { return gray8(uround(v * 255.0), uround(a * 255.0)); } //-------------------------------------------------------------------- operator sgray8() const { // Return (non-premultiplied) sRGB values. return sgray8( sRGB_conv::rgb_to_sRGB(v), sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- operator gray16() const { return gray16(uround(v * 65535.0), uround(a * 65535.0)); } //-------------------------------------------------------------------- operator rgba8() const { rgba8::value_type y = uround(v * 255.0); return rgba8(y, y, y, uround(a * 255.0)); } //-------------------------------------------------------------------- operator srgba8() const { srgba8::value_type y = sRGB_conv::rgb_to_sRGB(v); return srgba8(y, y, y, sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- operator rgba16() const { rgba16::value_type y = uround(v * 65535.0); return rgba16(y, y, y, uround(a * 65535.0)); } //-------------------------------------------------------------------- operator rgba32() const { return rgba32(v, v, v, a); } //-------------------------------------------------------------------- static AGG_INLINE double to_double(value_type a) { return a; } //-------------------------------------------------------------------- static AGG_INLINE value_type from_double(double a) { return value_type(a); } //-------------------------------------------------------------------- static AGG_INLINE value_type empty_value() { return 0; } //-------------------------------------------------------------------- static AGG_INLINE value_type full_value() { return 1; } //-------------------------------------------------------------------- AGG_INLINE bool is_transparent() const { return a <= 0; } //-------------------------------------------------------------------- AGG_INLINE bool is_opaque() const { return a >= 1; } //-------------------------------------------------------------------- static AGG_INLINE value_type invert(value_type x) { return 1 - x; } //-------------------------------------------------------------------- static AGG_INLINE value_type multiply(value_type a, value_type b) { return value_type(a * b); } //-------------------------------------------------------------------- static AGG_INLINE value_type demultiply(value_type a, value_type b) { return (b == 0) ? 0 : value_type(a / b); } //-------------------------------------------------------------------- template static AGG_INLINE T downscale(T a) { return a; } //-------------------------------------------------------------------- template static AGG_INLINE T downshift(T a, unsigned n) { return n > 0 ? a / (1 << n) : a; } //-------------------------------------------------------------------- static AGG_INLINE value_type mult_cover(value_type a, cover_type b) { return value_type(a * b / cover_mask); } //-------------------------------------------------------------------- static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) { return cover_type(uround(a * b)); } //-------------------------------------------------------------------- // Interpolate p to q by a, assuming q is premultiplied by a. static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) { return (1 - a) * p + q; // more accurate than "p + q - p * a" } //-------------------------------------------------------------------- // Interpolate p to q by a. static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) { // The form "p + a * (q - p)" avoids a multiplication, but may produce an // inaccurate result. For example, "p + (q - p)" may not be exactly equal // to q. Therefore, stick to the basic expression, which at least produces // the correct result at either extreme. return (1 - a) * p + a * q; } //-------------------------------------------------------------------- self_type& clear() { v = a = 0; return *this; } //-------------------------------------------------------------------- self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- self_type& opacity(double a_) { if (a_ < 0) a = 0; else if (a_ > 1) a = 1; else a = value_type(a_); return *this; } //-------------------------------------------------------------------- double opacity() const { return a; } //-------------------------------------------------------------------- self_type& premultiply() { if (a < 0) v = 0; else if(a < 1) v *= a; return *this; } //-------------------------------------------------------------------- self_type& demultiply() { if (a < 0) v = 0; else if (a < 1) v /= a; return *this; } //-------------------------------------------------------------------- self_type gradient(self_type c, double k) const { return self_type( value_type(v + (c.v - v) * k), value_type(a + (c.a - a) * k)); } //-------------------------------------------------------------------- static self_type no_color() { return self_type(0,0); } }; } #endif ragg/src/agg/include/agg_vcgen_smooth_poly1.h0000644000176200001440000000500513504406270020751 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_VCGEN_SMOOTH_POLY1_INCLUDED #define AGG_VCGEN_SMOOTH_POLY1_INCLUDED #include "agg_basics.h" #include "agg_vertex_sequence.h" namespace agg { //======================================================vcgen_smooth_poly1 // // See Implementation agg_vcgen_smooth_poly1.cpp // Smooth polygon generator // //------------------------------------------------------------------------ class vcgen_smooth_poly1 { enum status_e { initial, ready, polygon, ctrl_b, ctrl_e, ctrl1, ctrl2, end_poly, stop }; public: typedef vertex_sequence vertex_storage; vcgen_smooth_poly1(); void smooth_value(double v) { m_smooth_value = v * 0.5; } double smooth_value() const { return m_smooth_value * 2.0; } // Vertex Generator Interface void remove_all(); void add_vertex(double x, double y, unsigned cmd); // Vertex Source Interface void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: vcgen_smooth_poly1(const vcgen_smooth_poly1&); const vcgen_smooth_poly1& operator = (const vcgen_smooth_poly1&); void calculate(const vertex_dist& v0, const vertex_dist& v1, const vertex_dist& v2, const vertex_dist& v3); vertex_storage m_src_vertices; double m_smooth_value; unsigned m_closed; status_e m_status; unsigned m_src_vertex; double m_ctrl1_x; double m_ctrl1_y; double m_ctrl2_x; double m_ctrl2_y; }; } #endif ragg/src/agg/include/agg_span_pattern_gray.h0000644000176200001440000000632413504406270020657 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_SPAN_PATTERN_GRAY_INCLUDED #define AGG_SPAN_PATTERN_GRAY_INCLUDED #include "agg_basics.h" namespace agg { //=======================================================span_pattern_gray template class span_pattern_gray { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; //-------------------------------------------------------------------- span_pattern_gray() {} span_pattern_gray(source_type& src, unsigned offset_x, unsigned offset_y) : m_src(&src), m_offset_x(offset_x), m_offset_y(offset_y), m_alpha(color_type::base_mask) {} //-------------------------------------------------------------------- void attach(source_type& v) { m_src = &v; } source_type& source() { return *m_src; } const source_type& source() const { return *m_src; } //-------------------------------------------------------------------- void offset_x(unsigned v) { m_offset_x = v; } void offset_y(unsigned v) { m_offset_y = v; } unsigned offset_x() const { return m_offset_x; } unsigned offset_y() const { return m_offset_y; } void alpha(value_type v) { m_alpha = v; } value_type alpha() const { return m_alpha; } //-------------------------------------------------------------------- void prepare() {} void generate(color_type* span, int x, int y, unsigned len) { x += m_offset_x; y += m_offset_y; const value_type* p = (const value_type*)m_src->span(x, y, len); do { span->v = *p; span->a = m_alpha; p = m_src->next_x(); ++span; } while(--len); } private: source_type* m_src; unsigned m_offset_x; unsigned m_offset_y; value_type m_alpha; }; } #endif ragg/src/agg/include/agg_conv_close_polygon.h0000644000176200001440000000702013504406270021032 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_CONV_CLOSE_POLYGON_INCLUDED #define AGG_CONV_CLOSE_POLYGON_INCLUDED #include "agg_basics.h" namespace agg { //======================================================conv_close_polygon template class conv_close_polygon { public: explicit conv_close_polygon(VertexSource& vs) : m_source(&vs) {} void attach(VertexSource& source) { m_source = &source; } void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: conv_close_polygon(const conv_close_polygon&); const conv_close_polygon& operator = (const conv_close_polygon&); VertexSource* m_source; unsigned m_cmd[2]; double m_x[2]; double m_y[2]; unsigned m_vertex; bool m_line_to; }; //------------------------------------------------------------------------ template void conv_close_polygon::rewind(unsigned path_id) { m_source->rewind(path_id); m_vertex = 2; m_line_to = false; } //------------------------------------------------------------------------ template unsigned conv_close_polygon::vertex(double* x, double* y) { unsigned cmd = path_cmd_stop; for(;;) { if(m_vertex < 2) { *x = m_x[m_vertex]; *y = m_y[m_vertex]; cmd = m_cmd[m_vertex]; ++m_vertex; break; } cmd = m_source->vertex(x, y); if(is_end_poly(cmd)) { cmd |= path_flags_close; break; } if(is_stop(cmd)) { if(m_line_to) { m_cmd[0] = path_cmd_end_poly | path_flags_close; m_cmd[1] = path_cmd_stop; m_vertex = 0; m_line_to = false; continue; } break; } if(is_move_to(cmd)) { if(m_line_to) { m_x[0] = 0.0; m_y[0] = 0.0; m_cmd[0] = path_cmd_end_poly | path_flags_close; m_x[1] = *x; m_y[1] = *y; m_cmd[1] = cmd; m_vertex = 0; m_line_to = false; continue; } break; } if(is_vertex(cmd)) { m_line_to = true; break; } } return cmd; } } #endif ragg/src/agg/include/agg_span_image_filter_rgb.h0000644000176200001440000010546013504406270021442 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_SPAN_IMAGE_FILTER_RGB_INCLUDED #define AGG_SPAN_IMAGE_FILTER_RGB_INCLUDED #include "agg_basics.h" #include "agg_color_rgba.h" #include "agg_span_image_filter.h" namespace agg { //===============================================span_image_filter_rgb_nn template class span_image_filter_rgb_nn : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgb_nn() {} span_image_filter_rgb_nn(source_type& src, interpolator_type& inter) : base_type(src, inter, 0) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); do { base_type::interpolator().coordinates(&x, &y); const value_type* fg_ptr = (const value_type*) base_type::source().span(x >> image_subpixel_shift, y >> image_subpixel_shift, 1); span->r = fg_ptr[order_type::R]; span->g = fg_ptr[order_type::G]; span->b = fg_ptr[order_type::B]; span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; //==========================================span_image_filter_rgb_bilinear template class span_image_filter_rgb_bilinear : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgb_bilinear() {} span_image_filter_rgb_bilinear(source_type& src, interpolator_type& inter) : base_type(src, inter, 0) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[3]; const value_type *fg_ptr; do { int x_hr; int y_hr; base_type::interpolator().coordinates(&x_hr, &y_hr); x_hr -= base_type::filter_dx_int(); y_hr -= base_type::filter_dy_int(); int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; unsigned weight; fg[0] = fg[1] = fg[2] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); weight = (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_x(); weight = x_hr * (image_subpixel_scale - y_hr); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_y(); weight = (image_subpixel_scale - x_hr) * y_hr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_x(); weight = x_hr * y_hr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr; span->r = color_type::downshift(fg[order_type::R], image_subpixel_shift * 2); span->g = color_type::downshift(fg[order_type::G], image_subpixel_shift * 2); span->b = color_type::downshift(fg[order_type::B], image_subpixel_shift * 2); span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; //=====================================span_image_filter_rgb_bilinear_clip template class span_image_filter_rgb_bilinear_clip : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgb_bilinear_clip() {} span_image_filter_rgb_bilinear_clip(source_type& src, const color_type& back_color, interpolator_type& inter) : base_type(src, inter, 0), m_back_color(back_color) {} const color_type& background_color() const { return m_back_color; } void background_color(const color_type& v) { m_back_color = v; } //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[3]; long_type src_alpha; value_type back_r = m_back_color.r; value_type back_g = m_back_color.g; value_type back_b = m_back_color.b; value_type back_a = m_back_color.a; const value_type *fg_ptr; int maxx = base_type::source().width() - 1; int maxy = base_type::source().height() - 1; do { int x_hr; int y_hr; base_type::interpolator().coordinates(&x_hr, &y_hr); x_hr -= base_type::filter_dx_int(); y_hr -= base_type::filter_dy_int(); int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; unsigned weight; if(x_lr >= 0 && y_lr >= 0 && x_lr < maxx && y_lr < maxy) { fg[0] = fg[1] = fg[2] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; weight = (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; weight = x_hr * (image_subpixel_scale - y_hr); fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; ++y_lr; fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; weight = (image_subpixel_scale - x_hr) * y_hr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; weight = x_hr * y_hr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2); fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2); fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2); src_alpha = color_type::full_value(); } else { if(x_lr < -1 || y_lr < -1 || x_lr > maxx || y_lr > maxy) { fg[order_type::R] = back_r; fg[order_type::G] = back_g; fg[order_type::B] = back_b; src_alpha = back_a; } else { fg[0] = fg[1] = fg[2] = src_alpha = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; weight = (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr); if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; src_alpha += weight * color_type::full_value(); } else { fg[order_type::R] += back_r * weight; fg[order_type::G] += back_g * weight; fg[order_type::B] += back_b * weight; src_alpha += back_a * weight; } x_lr++; weight = x_hr * (image_subpixel_scale - y_hr); if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; src_alpha += weight * color_type::full_value(); } else { fg[order_type::R] += back_r * weight; fg[order_type::G] += back_g * weight; fg[order_type::B] += back_b * weight; src_alpha += back_a * weight; } x_lr--; y_lr++; weight = (image_subpixel_scale - x_hr) * y_hr; if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; src_alpha += weight * color_type::full_value(); } else { fg[order_type::R] += back_r * weight; fg[order_type::G] += back_g * weight; fg[order_type::B] += back_b * weight; src_alpha += back_a * weight; } x_lr++; weight = x_hr * y_hr; if(x_lr >= 0 && y_lr >= 0 && x_lr <= maxx && y_lr <= maxy) { fg_ptr = (const value_type*) base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; src_alpha += weight * color_type::full_value(); } else { fg[order_type::R] += back_r * weight; fg[order_type::G] += back_g * weight; fg[order_type::B] += back_b * weight; src_alpha += back_a * weight; } fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2); fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2); fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2); src_alpha = color_type::downshift(src_alpha, image_subpixel_shift * 2); } } span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; span->a = (value_type)src_alpha; ++span; ++base_type::interpolator(); } while(--len); } private: color_type m_back_color; }; //===============================================span_image_filter_rgb_2x2 template class span_image_filter_rgb_2x2 : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgb_2x2() {} span_image_filter_rgb_2x2(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, &filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[3]; const value_type *fg_ptr; const int16* weight_array = base_type::filter().weight_array() + ((base_type::filter().diameter()/2 - 1) << image_subpixel_shift); do { int x_hr; int y_hr; base_type::interpolator().coordinates(&x_hr, &y_hr); x_hr -= base_type::filter_dx_int(); y_hr -= base_type::filter_dy_int(); int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; unsigned weight; fg[0] = fg[1] = fg[2] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2); weight = (weight_array[x_hr + image_subpixel_scale] * weight_array[y_hr + image_subpixel_scale] + image_filter_scale / 2) >> image_filter_shift; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_x(); weight = (weight_array[x_hr] * weight_array[y_hr + image_subpixel_scale] + image_filter_scale / 2) >> image_filter_shift; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_y(); weight = (weight_array[x_hr + image_subpixel_scale] * weight_array[y_hr] + image_filter_scale / 2) >> image_filter_shift; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr; fg_ptr = (const value_type*)base_type::source().next_x(); weight = (weight_array[x_hr] * weight_array[y_hr] + image_filter_scale / 2) >> image_filter_shift; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr; fg[0] = color_type::downshift(fg[0], image_filter_shift); fg[1] = color_type::downshift(fg[1], image_filter_shift); fg[2] = color_type::downshift(fg[2], image_filter_shift); if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value(); if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value(); if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value(); span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; //===================================================span_image_filter_rgb template class span_image_filter_rgb : public span_image_filter { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_filter base_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgb() {} span_image_filter_rgb(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, &filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[3]; const value_type *fg_ptr; unsigned diameter = base_type::filter().diameter(); int start = base_type::filter().start(); const int16* weight_array = base_type::filter().weight_array(); int x_count; int weight_y; do { base_type::interpolator().coordinates(&x, &y); x -= base_type::filter_dx_int(); y -= base_type::filter_dy_int(); int x_hr = x; int y_hr = y; int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; fg[0] = fg[1] = fg[2] = 0; int x_fract = x_hr & image_subpixel_mask; unsigned y_count = diameter; y_hr = image_subpixel_mask - (y_hr & image_subpixel_mask); fg_ptr = (const value_type*)base_type::source().span(x_lr + start, y_lr + start, diameter); for(;;) { x_count = diameter; weight_y = weight_array[y_hr]; x_hr = image_subpixel_mask - x_fract; for(;;) { int weight = (weight_y * weight_array[x_hr] + image_filter_scale / 2) >> image_filter_shift; fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr; if(--x_count == 0) break; x_hr += image_subpixel_scale; fg_ptr = (const value_type*)base_type::source().next_x(); } if(--y_count == 0) break; y_hr += image_subpixel_scale; fg_ptr = (const value_type*)base_type::source().next_y(); } fg[0] = color_type::downshift(fg[0], image_filter_shift); fg[1] = color_type::downshift(fg[1], image_filter_shift); fg[2] = color_type::downshift(fg[2], image_filter_shift); if(fg[0] < 0) fg[0] = 0; if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value(); if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value(); if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value(); span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; //==========================================span_image_resample_rgb_affine template class span_image_resample_rgb_affine : public span_image_resample_affine { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef span_image_resample_affine base_type; typedef typename base_type::interpolator_type interpolator_type; typedef typename color_type::value_type value_type; typedef typename color_type::long_type long_type; enum base_scale_e { downscale_shift = image_filter_shift }; //-------------------------------------------------------------------- span_image_resample_rgb_affine() {} span_image_resample_rgb_affine(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[3]; int diameter = base_type::filter().diameter(); int filter_scale = diameter << image_subpixel_shift; int radius_x = (diameter * base_type::m_rx) >> 1; int radius_y = (diameter * base_type::m_ry) >> 1; int len_x_lr = (diameter * base_type::m_rx + image_subpixel_mask) >> image_subpixel_shift; const int16* weight_array = base_type::filter().weight_array(); do { base_type::interpolator().coordinates(&x, &y); x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; fg[0] = fg[1] = fg[2] = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * base_type::m_ry_inv) >> image_subpixel_shift; int total_weight = 0; int x_lr = x >> image_subpixel_shift; int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * base_type::m_rx_inv) >> image_subpixel_shift; int x_hr2 = x_hr; const value_type* fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); for(;;) { int weight_y = weight_array[y_hr]; x_hr = x_hr2; for(;;) { int weight = (weight_y * weight_array[x_hr] + image_filter_scale / 2) >> downscale_shift; fg[0] += *fg_ptr++ * weight; fg[1] += *fg_ptr++ * weight; fg[2] += *fg_ptr * weight; total_weight += weight; x_hr += base_type::m_rx_inv; if(x_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_x(); } y_hr += base_type::m_ry_inv; if(y_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_y(); } fg[0] /= total_weight; fg[1] /= total_weight; fg[2] /= total_weight; if(fg[0] < 0) fg[0] = 0; if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value(); if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value(); if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value(); span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; //=================================================span_image_resample_rgb template class span_image_resample_rgb : public span_image_resample { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef Interpolator interpolator_type; typedef span_image_resample base_type; typedef typename color_type::value_type value_type; typedef typename color_type::long_type long_type; enum base_scale_e { downscale_shift = image_filter_shift }; //-------------------------------------------------------------------- span_image_resample_rgb() {} span_image_resample_rgb(source_type& src, interpolator_type& inter, image_filter_lut& filter) : base_type(src, inter, filter) {} //-------------------------------------------------------------------- void generate(color_type* span, int x, int y, unsigned len) { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); long_type fg[3]; int diameter = base_type::filter().diameter(); int filter_scale = diameter << image_subpixel_shift; const int16* weight_array = base_type::filter().weight_array(); do { int rx; int ry; int rx_inv = image_subpixel_scale; int ry_inv = image_subpixel_scale; base_type::interpolator().coordinates(&x, &y); base_type::interpolator().local_scale(&rx, &ry); base_type::adjust_scale(&rx, &ry); rx_inv = image_subpixel_scale * image_subpixel_scale / rx; ry_inv = image_subpixel_scale * image_subpixel_scale / ry; int radius_x = (diameter * rx) >> 1; int radius_y = (diameter * ry) >> 1; int len_x_lr = (diameter * rx + image_subpixel_mask) >> image_subpixel_shift; x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; fg[0] = fg[1] = fg[2] = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * ry_inv) >> image_subpixel_shift; int total_weight = 0; int x_lr = x >> image_subpixel_shift; int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) * rx_inv) >> image_subpixel_shift; int x_hr2 = x_hr; const value_type* fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr); for(;;) { int weight_y = weight_array[y_hr]; x_hr = x_hr2; for(;;) { int weight = (weight_y * weight_array[x_hr] + image_filter_scale / 2) >> downscale_shift; fg[0] += *fg_ptr++ * weight; fg[1] += *fg_ptr++ * weight; fg[2] += *fg_ptr * weight; total_weight += weight; x_hr += rx_inv; if(x_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_x(); } y_hr += ry_inv; if(y_hr >= filter_scale) break; fg_ptr = (const value_type*)base_type::source().next_y(); } fg[0] /= total_weight; fg[1] /= total_weight; fg[2] /= total_weight; if(fg[0] < 0) fg[0] = 0; if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value(); if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value(); if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value(); span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); } }; } #endif ragg/src/agg/include/agg_pixfmt_base.h0000644000176200001440000000553413504406270017442 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_PIXFMT_BASE_INCLUDED #define AGG_PIXFMT_BASE_INCLUDED #include "agg_basics.h" #include "agg_color_gray.h" #include "agg_color_rgba.h" namespace agg { struct pixfmt_gray_tag { }; struct pixfmt_rgb_tag { }; struct pixfmt_rgba_tag { }; //--------------------------------------------------------------blender_base template struct blender_base { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; static rgba get(value_type r, value_type g, value_type b, value_type a, cover_type cover = cover_full) { if (cover > cover_none) { rgba c( color_type::to_double(r), color_type::to_double(g), color_type::to_double(b), color_type::to_double(a)); if (cover < cover_full) { double x = double(cover) / cover_full; c.r *= x; c.g *= x; c.b *= x; c.a *= x; } return c; } else return rgba::no_color(); } static rgba get(const value_type* p, cover_type cover = cover_full) { return get( p[order_type::R], p[order_type::G], p[order_type::B], p[order_type::A], cover); } static void set(value_type* p, value_type r, value_type g, value_type b, value_type a) { p[order_type::R] = r; p[order_type::G] = g; p[order_type::B] = b; p[order_type::A] = a; } static void set(value_type* p, const rgba& c) { p[order_type::R] = color_type::from_double(c.r); p[order_type::G] = color_type::from_double(c.g); p[order_type::B] = color_type::from_double(c.b); p[order_type::A] = color_type::from_double(c.a); } }; } #endif ragg/src/agg/include/agg_vpgen_segmentator.h0000644000176200001440000000336713504406270020672 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_VPGEN_SEGMENTATOR_INCLUDED #define AGG_VPGEN_SEGMENTATOR_INCLUDED #include "agg_basics.h" namespace agg { //=======================================================vpgen_segmentator // // See Implementation agg_vpgen_segmentator.cpp // class vpgen_segmentator { public: vpgen_segmentator() : m_approximation_scale(1.0) {} void approximation_scale(double s) { m_approximation_scale = s; } double approximation_scale() const { return m_approximation_scale; } static bool auto_close() { return false; } static bool auto_unclose() { return false; } void reset() { m_cmd = path_cmd_stop; } void move_to(double x, double y); void line_to(double x, double y); unsigned vertex(double* x, double* y); private: double m_approximation_scale; double m_x1; double m_y1; double m_dx; double m_dy; double m_dl; double m_ddl; unsigned m_cmd; }; } #endif ragg/src/agg/include/agg_font_cache_manager.h0000644000176200001440000003465013777316063020741 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_FONT_CACHE_MANAGER_INCLUDED #define AGG_FONT_CACHE_MANAGER_INCLUDED #include #include "agg_array.h" namespace agg { //---------------------------------------------------------glyph_data_type enum glyph_data_type { glyph_data_invalid = 0, glyph_data_mono = 1, glyph_data_gray8 = 2, glyph_data_outline = 3, glyph_data_color = 4 }; //-------------------------------------------------------------glyph_cache struct glyph_cache { unsigned glyph_index; int8u* data; unsigned data_size; glyph_data_type data_type; rect_i bounds; double advance_x; double advance_y; }; //--------------------------------------------------------------font_cache class font_cache { public: enum block_size_e { block_size = 16384-16 }; //-------------------------------------------------------------------- font_cache() : m_allocator(block_size), m_font_signature(0) {} //-------------------------------------------------------------------- void signature(const char* font_signature) { m_font_signature = (char*)m_allocator.allocate(std::strlen(font_signature) + 1); std::strcpy(m_font_signature, font_signature); std::memset(m_glyphs, 0, sizeof(m_glyphs)); } //-------------------------------------------------------------------- bool font_is(const char* font_signature) const { return std::strcmp(font_signature, m_font_signature) == 0; } //-------------------------------------------------------------------- const glyph_cache* find_glyph(unsigned glyph_code) const { unsigned msb = (glyph_code >> 8) & 0xFF; if(m_glyphs[msb]) { return m_glyphs[msb][glyph_code & 0xFF]; } return 0; } //-------------------------------------------------------------------- glyph_cache* cache_glyph(unsigned glyph_code, unsigned glyph_index, unsigned data_size, glyph_data_type data_type, const rect_i& bounds, double advance_x, double advance_y) { unsigned msb = (glyph_code >> 8) & 0xFF; if(m_glyphs[msb] == 0) { m_glyphs[msb] = (glyph_cache**)m_allocator.allocate(sizeof(glyph_cache*) * 256, sizeof(glyph_cache*)); std::memset(m_glyphs[msb], 0, sizeof(glyph_cache*) * 256); } unsigned lsb = glyph_code & 0xFF; if(m_glyphs[msb][lsb]) return 0; // Already exists, do not overwrite glyph_cache* glyph = (glyph_cache*)m_allocator.allocate(sizeof(glyph_cache), sizeof(double)); glyph->glyph_index = glyph_index; glyph->data = m_allocator.allocate(data_size); glyph->data_size = data_size; glyph->data_type = data_type; glyph->bounds = bounds; glyph->advance_x = advance_x; glyph->advance_y = advance_y; return m_glyphs[msb][lsb] = glyph; } private: block_allocator m_allocator; glyph_cache** m_glyphs[256]; char* m_font_signature; }; //---------------------------------------------------------font_cache_pool class font_cache_pool { public: //-------------------------------------------------------------------- ~font_cache_pool() { unsigned i; for(i = 0; i < m_num_fonts; ++i) { obj_allocator::deallocate(m_fonts[i]); } pod_allocator::deallocate(m_fonts, m_max_fonts); } //-------------------------------------------------------------------- font_cache_pool(unsigned max_fonts=32) : m_fonts(pod_allocator::allocate(max_fonts)), m_max_fonts(max_fonts), m_num_fonts(0), m_cur_font(0) {} //-------------------------------------------------------------------- void font(const char* font_signature, bool reset_cache = false) { int idx = find_font(font_signature); if(idx >= 0) { if(reset_cache) { obj_allocator::deallocate(m_fonts[idx]); m_fonts[idx] = obj_allocator::allocate(); m_fonts[idx]->signature(font_signature); } m_cur_font = m_fonts[idx]; } else { if(m_num_fonts >= m_max_fonts) { obj_allocator::deallocate(m_fonts[0]); std::memcpy(m_fonts, m_fonts + 1, (m_max_fonts - 1) * sizeof(font_cache*)); m_num_fonts = m_max_fonts - 1; } m_fonts[m_num_fonts] = obj_allocator::allocate(); m_fonts[m_num_fonts]->signature(font_signature); m_cur_font = m_fonts[m_num_fonts]; ++m_num_fonts; } } //-------------------------------------------------------------------- const font_cache* font() const { return m_cur_font; } //-------------------------------------------------------------------- const glyph_cache* find_glyph(unsigned glyph_code) const { if(m_cur_font) return m_cur_font->find_glyph(glyph_code); return 0; } //-------------------------------------------------------------------- glyph_cache* cache_glyph(unsigned glyph_code, unsigned glyph_index, unsigned data_size, glyph_data_type data_type, const rect_i& bounds, double advance_x, double advance_y) { if(m_cur_font) { return m_cur_font->cache_glyph(glyph_code, glyph_index, data_size, data_type, bounds, advance_x, advance_y); } return 0; } //-------------------------------------------------------------------- int find_font(const char* font_signature) { unsigned i; for(i = 0; i < m_num_fonts; i++) { if(m_fonts[i]->font_is(font_signature)) return int(i); } return -1; } private: font_cache** m_fonts; unsigned m_max_fonts; unsigned m_num_fonts; font_cache* m_cur_font; }; //------------------------------------------------------------------------ enum glyph_rendering { glyph_ren_native_mono, glyph_ren_native_gray8, glyph_ren_outline, glyph_ren_agg_mono, glyph_ren_agg_gray8, glyph_ren_native_color }; //------------------------------------------------------font_cache_manager template class font_cache_manager { public: typedef FontEngine font_engine_type; typedef font_cache_manager self_type; typedef typename font_engine_type::path_adaptor_type path_adaptor_type; typedef typename font_engine_type::gray8_adaptor_type gray8_adaptor_type; typedef typename gray8_adaptor_type::embedded_scanline gray8_scanline_type; typedef typename font_engine_type::mono_adaptor_type mono_adaptor_type; typedef typename mono_adaptor_type::embedded_scanline mono_scanline_type; //-------------------------------------------------------------------- font_cache_manager(font_engine_type& engine, unsigned max_fonts=32) : m_fonts(max_fonts), m_engine(engine), m_change_stamp(-1), m_prev_glyph(0), m_last_glyph(0) {} //-------------------------------------------------------------------- void reset_last_glyph() { m_prev_glyph = m_last_glyph = 0; } //-------------------------------------------------------------------- const glyph_cache* glyph(unsigned glyph_code) { synchronize(); const glyph_cache* gl = m_fonts.find_glyph(glyph_code); if(gl) { m_prev_glyph = m_last_glyph; return m_last_glyph = gl; } else { if(m_engine.prepare_glyph(glyph_code)) { m_prev_glyph = m_last_glyph; m_last_glyph = m_fonts.cache_glyph(glyph_code, m_engine.glyph_index(), m_engine.data_size(), m_engine.data_type(), m_engine.bounds(), m_engine.advance_x(), m_engine.advance_y()); m_engine.write_glyph_to(m_last_glyph->data); return m_last_glyph; } } return 0; } //-------------------------------------------------------------------- void init_embedded_adaptors(const glyph_cache* gl, double x, double y, double scale=1.0) { if(gl) { switch(gl->data_type) { default: return; case glyph_data_mono: m_mono_adaptor.init(gl->data, gl->data_size, x, y); break; case glyph_data_gray8: m_gray8_adaptor.init(gl->data, gl->data_size, x, y); break; case glyph_data_outline: m_path_adaptor.init(gl->data, gl->data_size, x, y, scale); break; } } } //-------------------------------------------------------------------- path_adaptor_type& path_adaptor() { return m_path_adaptor; } gray8_adaptor_type& gray8_adaptor() { return m_gray8_adaptor; } gray8_scanline_type& gray8_scanline() { return m_gray8_scanline; } mono_adaptor_type& mono_adaptor() { return m_mono_adaptor; } mono_scanline_type& mono_scanline() { return m_mono_scanline; } //-------------------------------------------------------------------- const glyph_cache* prev_glyph() const { return m_prev_glyph; } const glyph_cache* last_glyph() const { return m_last_glyph; } //-------------------------------------------------------------------- bool add_kerning(double* x, double* y) { if(m_prev_glyph && m_last_glyph) { return m_engine.add_kerning(m_prev_glyph->glyph_index, m_last_glyph->glyph_index, x, y); } return false; } //-------------------------------------------------------------------- void precache(unsigned from, unsigned to) { for(; from <= to; ++from) glyph(from); } //-------------------------------------------------------------------- void reset_cache() { m_fonts.font(m_engine.font_signature(), true); m_change_stamp = m_engine.change_stamp(); m_prev_glyph = m_last_glyph = 0; } private: //-------------------------------------------------------------------- font_cache_manager(const self_type&); const self_type& operator = (const self_type&); //-------------------------------------------------------------------- void synchronize() { if(m_change_stamp != m_engine.change_stamp()) { m_fonts.font(m_engine.font_signature()); m_change_stamp = m_engine.change_stamp(); m_prev_glyph = m_last_glyph = 0; } } font_cache_pool m_fonts; font_engine_type& m_engine; int m_change_stamp; double m_dx; double m_dy; const glyph_cache* m_prev_glyph; const glyph_cache* m_last_glyph; path_adaptor_type m_path_adaptor; gray8_adaptor_type m_gray8_adaptor; gray8_scanline_type m_gray8_scanline; mono_adaptor_type m_mono_adaptor; mono_scanline_type m_mono_scanline; }; } #endif ragg/src/agg/include/agg_conv_marker.h0000644000176200001440000001066413504406270017447 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // conv_marker // //---------------------------------------------------------------------------- #ifndef AGG_CONV_MARKER_INCLUDED #define AGG_CONV_MARKER_INCLUDED #include #include "agg_basics.h" #include "agg_trans_affine.h" namespace agg { //-------------------------------------------------------------conv_marker template class conv_marker { public: conv_marker(MarkerLocator& ml, MarkerShapes& ms); trans_affine& transform() { return m_transform; } const trans_affine& transform() const { return m_transform; } void rewind(unsigned path_id); unsigned vertex(double* x, double* y); private: conv_marker(const conv_marker&); const conv_marker& operator = (const conv_marker&); enum status_e { initial, markers, polygon, stop }; MarkerLocator* m_marker_locator; MarkerShapes* m_marker_shapes; trans_affine m_transform; trans_affine m_mtx; status_e m_status; unsigned m_marker; unsigned m_num_markers; }; //------------------------------------------------------------------------ template conv_marker::conv_marker(MarkerLocator& ml, MarkerShapes& ms) : m_marker_locator(&ml), m_marker_shapes(&ms), m_status(initial), m_marker(0), m_num_markers(1) { } //------------------------------------------------------------------------ template void conv_marker::rewind(unsigned) { m_status = initial; m_marker = 0; m_num_markers = 1; } //------------------------------------------------------------------------ template unsigned conv_marker::vertex(double* x, double* y) { unsigned cmd = path_cmd_move_to; double x1, y1, x2, y2; while(!is_stop(cmd)) { switch(m_status) { case initial: if(m_num_markers == 0) { cmd = path_cmd_stop; break; } m_marker_locator->rewind(m_marker); ++m_marker; m_num_markers = 0; m_status = markers; case markers: if(is_stop(m_marker_locator->vertex(&x1, &y1))) { m_status = initial; break; } if(is_stop(m_marker_locator->vertex(&x2, &y2))) { m_status = initial; break; } ++m_num_markers; m_mtx = m_transform; m_mtx *= trans_affine_rotation(std::atan2(y2 - y1, x2 - x1)); m_mtx *= trans_affine_translation(x1, y1); m_marker_shapes->rewind(m_marker - 1); m_status = polygon; case polygon: cmd = m_marker_shapes->vertex(x, y); if(is_stop(cmd)) { cmd = path_cmd_move_to; m_status = markers; break; } m_mtx.transform(x, y); return cmd; case stop: cmd = path_cmd_stop; break; } } return cmd; } } #endif ragg/src/agg/include/agg_array.h0000644000176200001440000010312113504406270016246 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_ARRAY_INCLUDED #define AGG_ARRAY_INCLUDED #include #include #include "agg_basics.h" namespace agg { //-------------------------------------------------------pod_array_adaptor template class pod_array_adaptor { public: typedef T value_type; pod_array_adaptor(T* array, unsigned size) : m_array(array), m_size(size) {} unsigned size() const { return m_size; } const T& operator [] (unsigned i) const { return m_array[i]; } T& operator [] (unsigned i) { return m_array[i]; } const T& at(unsigned i) const { return m_array[i]; } T& at(unsigned i) { return m_array[i]; } T value_at(unsigned i) const { return m_array[i]; } private: T* m_array; unsigned m_size; }; //---------------------------------------------------------pod_auto_array template class pod_auto_array { public: typedef T value_type; typedef pod_auto_array self_type; pod_auto_array() {} explicit pod_auto_array(const T* c) { std::memcpy(m_array, c, sizeof(T) * Size); } const self_type& operator = (const T* c) { std::memcpy(m_array, c, sizeof(T) * Size); return *this; } static unsigned size() { return Size; } const T& operator [] (unsigned i) const { return m_array[i]; } T& operator [] (unsigned i) { return m_array[i]; } const T& at(unsigned i) const { return m_array[i]; } T& at(unsigned i) { return m_array[i]; } T value_at(unsigned i) const { return m_array[i]; } private: T m_array[Size]; }; //--------------------------------------------------------pod_auto_vector template class pod_auto_vector { public: typedef T value_type; typedef pod_auto_vector self_type; pod_auto_vector() : m_size(0) {} void remove_all() { m_size = 0; } void clear() { m_size = 0; } void add(const T& v) { m_array[m_size++] = v; } void push_back(const T& v) { m_array[m_size++] = v; } void inc_size(unsigned size) { m_size += size; } unsigned size() const { return m_size; } const T& operator [] (unsigned i) const { return m_array[i]; } T& operator [] (unsigned i) { return m_array[i]; } const T& at(unsigned i) const { return m_array[i]; } T& at(unsigned i) { return m_array[i]; } T value_at(unsigned i) const { return m_array[i]; } private: T m_array[Size]; unsigned m_size; }; //---------------------------------------------------------------pod_array template class pod_array { public: typedef T value_type; typedef pod_array self_type; ~pod_array() { pod_allocator::deallocate(m_array, m_size); } pod_array() : m_array(0), m_size(0) {} pod_array(unsigned size) : m_array(pod_allocator::allocate(size)), m_size(size) {} pod_array(const self_type& v) : m_array(pod_allocator::allocate(v.m_size)), m_size(v.m_size) { std::memcpy(m_array, v.m_array, sizeof(T) * m_size); } void resize(unsigned size) { if(size != m_size) { pod_allocator::deallocate(m_array, m_size); m_array = pod_allocator::allocate(m_size = size); } } const self_type& operator = (const self_type& v) { resize(v.size()); std::memcpy(m_array, v.m_array, sizeof(T) * m_size); return *this; } unsigned size() const { return m_size; } const T& operator [] (unsigned i) const { return m_array[i]; } T& operator [] (unsigned i) { return m_array[i]; } const T& at(unsigned i) const { return m_array[i]; } T& at(unsigned i) { return m_array[i]; } T value_at(unsigned i) const { return m_array[i]; } const T* data() const { return m_array; } T* data() { return m_array; } private: T* m_array; unsigned m_size; }; //--------------------------------------------------------------pod_vector // A simple class template to store Plain Old Data, a vector // of a fixed size. The data is continous in memory //------------------------------------------------------------------------ template class pod_vector { public: typedef T value_type; ~pod_vector() { pod_allocator::deallocate(m_array, m_capacity); } pod_vector() : m_size(0), m_capacity(0), m_array(0) {} pod_vector(unsigned cap, unsigned extra_tail=0); // Copying pod_vector(const pod_vector&); const pod_vector& operator = (const pod_vector&); // Set new capacity. All data is lost, size is set to zero. void capacity(unsigned cap, unsigned extra_tail=0); unsigned capacity() const { return m_capacity; } // Allocate n elements. All data is lost, // but elements can be accessed in range 0...size-1. void allocate(unsigned size, unsigned extra_tail=0); // Resize keeping the content. void resize(unsigned new_size); void zero() { std::memset(m_array, 0, sizeof(T) * m_size); } void add(const T& v) { m_array[m_size++] = v; } void push_back(const T& v) { m_array[m_size++] = v; } void insert_at(unsigned pos, const T& val); void inc_size(unsigned size) { m_size += size; } unsigned size() const { return m_size; } unsigned byte_size() const { return m_size * sizeof(T); } void serialize(int8u* ptr) const; void deserialize(const int8u* data, unsigned byte_size); const T& operator [] (unsigned i) const { return m_array[i]; } T& operator [] (unsigned i) { return m_array[i]; } const T& at(unsigned i) const { return m_array[i]; } T& at(unsigned i) { return m_array[i]; } T value_at(unsigned i) const { return m_array[i]; } const T* data() const { return m_array; } T* data() { return m_array; } void remove_all() { m_size = 0; } void clear() { m_size = 0; } void cut_at(unsigned num) { if(num < m_size) m_size = num; } private: unsigned m_size; unsigned m_capacity; T* m_array; }; //------------------------------------------------------------------------ template void pod_vector::capacity(unsigned cap, unsigned extra_tail) { m_size = 0; if(cap > m_capacity) { pod_allocator::deallocate(m_array, m_capacity); m_capacity = cap + extra_tail; m_array = m_capacity ? pod_allocator::allocate(m_capacity) : 0; } } //------------------------------------------------------------------------ template void pod_vector::allocate(unsigned size, unsigned extra_tail) { capacity(size, extra_tail); m_size = size; } //------------------------------------------------------------------------ template void pod_vector::resize(unsigned new_size) { if(new_size > m_size) { if(new_size > m_capacity) { T* data = pod_allocator::allocate(new_size); std::memcpy(data, m_array, m_size * sizeof(T)); pod_allocator::deallocate(m_array, m_capacity); m_array = data; } } else { m_size = new_size; } } //------------------------------------------------------------------------ template pod_vector::pod_vector(unsigned cap, unsigned extra_tail) : m_size(0), m_capacity(cap + extra_tail), m_array(pod_allocator::allocate(m_capacity)) {} //------------------------------------------------------------------------ template pod_vector::pod_vector(const pod_vector& v) : m_size(v.m_size), m_capacity(v.m_capacity), m_array(v.m_capacity ? pod_allocator::allocate(v.m_capacity) : 0) { std::memcpy(m_array, v.m_array, sizeof(T) * v.m_size); } //------------------------------------------------------------------------ template const pod_vector& pod_vector::operator = (const pod_vector&v) { allocate(v.m_size); if(v.m_size) std::memcpy(m_array, v.m_array, sizeof(T) * v.m_size); return *this; } //------------------------------------------------------------------------ template void pod_vector::serialize(int8u* ptr) const { if(m_size) std::memcpy(ptr, m_array, m_size * sizeof(T)); } //------------------------------------------------------------------------ template void pod_vector::deserialize(const int8u* data, unsigned byte_size) { byte_size /= sizeof(T); allocate(byte_size); if(byte_size) std::memcpy(m_array, data, byte_size * sizeof(T)); } //------------------------------------------------------------------------ template void pod_vector::insert_at(unsigned pos, const T& val) { if(pos >= m_size) { m_array[m_size] = val; } else { std::memmove(m_array + pos + 1, m_array + pos, (m_size - pos) * sizeof(T)); m_array[pos] = val; } ++m_size; } //---------------------------------------------------------------pod_bvector // A simple class template to store Plain Old Data, similar to std::deque // It doesn't reallocate memory but instead, uses blocks of data of size // of (1 << S), that is, power of two. The data is NOT contiguous in memory, // so the only valid access method is operator [] or curr(), prev(), next() // // There reallocs occure only when the pool of pointers to blocks needs // to be extended (it happens very rarely). You can control the value // of increment to reallocate the pointer buffer. See the second constructor. // By default, the incremeent value equals (1 << S), i.e., the block size. //------------------------------------------------------------------------ template class pod_bvector { public: enum block_scale_e { block_shift = S, block_size = 1 << block_shift, block_mask = block_size - 1 }; typedef T value_type; ~pod_bvector(); pod_bvector(); pod_bvector(unsigned block_ptr_inc); // Copying pod_bvector(const pod_bvector& v); const pod_bvector& operator = (const pod_bvector& v); void remove_all() { m_size = 0; } void clear() { m_size = 0; } void free_all() { free_tail(0); } void free_tail(unsigned size); void add(const T& val); void push_back(const T& val) { add(val); } void modify_last(const T& val); void remove_last(); int allocate_continuous_block(unsigned num_elements); void add_array(const T* ptr, unsigned num_elem) { while(num_elem--) { add(*ptr++); } } template void add_data(DataAccessor& data) { while(data.size()) { add(*data); ++data; } } void cut_at(unsigned size) { if(size < m_size) m_size = size; } unsigned size() const { return m_size; } const T& operator [] (unsigned i) const { return m_blocks[i >> block_shift][i & block_mask]; } T& operator [] (unsigned i) { return m_blocks[i >> block_shift][i & block_mask]; } const T& at(unsigned i) const { return m_blocks[i >> block_shift][i & block_mask]; } T& at(unsigned i) { return m_blocks[i >> block_shift][i & block_mask]; } T value_at(unsigned i) const { return m_blocks[i >> block_shift][i & block_mask]; } const T& curr(unsigned idx) const { return (*this)[idx]; } T& curr(unsigned idx) { return (*this)[idx]; } const T& prev(unsigned idx) const { return (*this)[(idx + m_size - 1) % m_size]; } T& prev(unsigned idx) { return (*this)[(idx + m_size - 1) % m_size]; } const T& next(unsigned idx) const { return (*this)[(idx + 1) % m_size]; } T& next(unsigned idx) { return (*this)[(idx + 1) % m_size]; } const T& last() const { return (*this)[m_size - 1]; } T& last() { return (*this)[m_size - 1]; } unsigned byte_size() const; void serialize(int8u* ptr) const; void deserialize(const int8u* data, unsigned byte_size); void deserialize(unsigned start, const T& empty_val, const int8u* data, unsigned byte_size); template void deserialize(ByteAccessor data) { remove_all(); unsigned elem_size = data.size() / sizeof(T); for(unsigned i = 0; i < elem_size; ++i) { int8u* ptr = (int8u*)data_ptr(); for(unsigned j = 0; j < sizeof(T); ++j) { *ptr++ = *data; ++data; } ++m_size; } } template void deserialize(unsigned start, const T& empty_val, ByteAccessor data) { while(m_size < start) { add(empty_val); } unsigned elem_size = data.size() / sizeof(T); for(unsigned i = 0; i < elem_size; ++i) { int8u* ptr; if(start + i < m_size) { ptr = (int8u*)(&((*this)[start + i])); } else { ptr = (int8u*)data_ptr(); ++m_size; } for(unsigned j = 0; j < sizeof(T); ++j) { *ptr++ = *data; ++data; } } } const T* block(unsigned nb) const { return m_blocks[nb]; } private: void allocate_block(unsigned nb); T* data_ptr(); unsigned m_size; unsigned m_num_blocks; unsigned m_max_blocks; T** m_blocks; unsigned m_block_ptr_inc; }; //------------------------------------------------------------------------ template pod_bvector::~pod_bvector() { if(m_num_blocks) { T** blk = m_blocks + m_num_blocks - 1; while(m_num_blocks--) { pod_allocator::deallocate(*blk, block_size); --blk; } } pod_allocator::deallocate(m_blocks, m_max_blocks); } //------------------------------------------------------------------------ template void pod_bvector::free_tail(unsigned size) { if(size < m_size) { unsigned nb = (size + block_mask) >> block_shift; while(m_num_blocks > nb) { pod_allocator::deallocate(m_blocks[--m_num_blocks], block_size); } if(m_num_blocks == 0) { pod_allocator::deallocate(m_blocks, m_max_blocks); m_blocks = 0; m_max_blocks = 0; } m_size = size; } } //------------------------------------------------------------------------ template pod_bvector::pod_bvector() : m_size(0), m_num_blocks(0), m_max_blocks(0), m_blocks(0), m_block_ptr_inc(block_size) { } //------------------------------------------------------------------------ template pod_bvector::pod_bvector(unsigned block_ptr_inc) : m_size(0), m_num_blocks(0), m_max_blocks(0), m_blocks(0), m_block_ptr_inc(block_ptr_inc) { } //------------------------------------------------------------------------ template pod_bvector::pod_bvector(const pod_bvector& v) : m_size(v.m_size), m_num_blocks(v.m_num_blocks), m_max_blocks(v.m_max_blocks), m_blocks(v.m_max_blocks ? pod_allocator::allocate(v.m_max_blocks) : 0), m_block_ptr_inc(v.m_block_ptr_inc) { unsigned i; for(i = 0; i < v.m_num_blocks; ++i) { m_blocks[i] = pod_allocator::allocate(block_size); std::memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T)); } } //------------------------------------------------------------------------ template const pod_bvector& pod_bvector::operator = (const pod_bvector& v) { unsigned i; for(i = m_num_blocks; i < v.m_num_blocks; ++i) { allocate_block(i); } for(i = 0; i < v.m_num_blocks; ++i) { std::memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T)); } m_size = v.m_size; return *this; } //------------------------------------------------------------------------ template void pod_bvector::allocate_block(unsigned nb) { if(nb >= m_max_blocks) { T** new_blocks = pod_allocator::allocate(m_max_blocks + m_block_ptr_inc); if(m_blocks) { std::memcpy(new_blocks, m_blocks, m_num_blocks * sizeof(T*)); pod_allocator::deallocate(m_blocks, m_max_blocks); } m_blocks = new_blocks; m_max_blocks += m_block_ptr_inc; } m_blocks[nb] = pod_allocator::allocate(block_size); m_num_blocks++; } //------------------------------------------------------------------------ template inline T* pod_bvector::data_ptr() { unsigned nb = m_size >> block_shift; if(nb >= m_num_blocks) { allocate_block(nb); } return m_blocks[nb] + (m_size & block_mask); } //------------------------------------------------------------------------ template inline void pod_bvector::add(const T& val) { *data_ptr() = val; ++m_size; } //------------------------------------------------------------------------ template inline void pod_bvector::remove_last() { if(m_size) --m_size; } //------------------------------------------------------------------------ template void pod_bvector::modify_last(const T& val) { remove_last(); add(val); } //------------------------------------------------------------------------ template int pod_bvector::allocate_continuous_block(unsigned num_elements) { if(num_elements < block_size) { data_ptr(); // Allocate initial block if necessary unsigned rest = block_size - (m_size & block_mask); unsigned index; if(num_elements <= rest) { // The rest of the block is good, we can use it //----------------- index = m_size; m_size += num_elements; return index; } // New block //--------------- m_size += rest; data_ptr(); index = m_size; m_size += num_elements; return index; } return -1; // Impossible to allocate } //------------------------------------------------------------------------ template unsigned pod_bvector::byte_size() const { return m_size * sizeof(T); } //------------------------------------------------------------------------ template void pod_bvector::serialize(int8u* ptr) const { unsigned i; for(i = 0; i < m_size; i++) { std::memcpy(ptr, &(*this)[i], sizeof(T)); ptr += sizeof(T); } } //------------------------------------------------------------------------ template void pod_bvector::deserialize(const int8u* data, unsigned byte_size) { remove_all(); byte_size /= sizeof(T); for(unsigned i = 0; i < byte_size; ++i) { T* ptr = data_ptr(); std::memcpy(ptr, data, sizeof(T)); ++m_size; data += sizeof(T); } } // Replace or add a number of elements starting from "start" position //------------------------------------------------------------------------ template void pod_bvector::deserialize(unsigned start, const T& empty_val, const int8u* data, unsigned byte_size) { while(m_size < start) { add(empty_val); } byte_size /= sizeof(T); for(unsigned i = 0; i < byte_size; ++i) { if(start + i < m_size) { std::memcpy(&((*this)[start + i]), data, sizeof(T)); } else { T* ptr = data_ptr(); std::memcpy(ptr, data, sizeof(T)); ++m_size; } data += sizeof(T); } } //---------------------------------------------------------block_allocator // Allocator for arbitrary POD data. Most usable in different cache // systems for efficient memory allocations. // Memory is allocated with blocks of fixed size ("block_size" in // the constructor). If required size exceeds the block size the allocator // creates a new block of the required size. However, the most efficient // use is when the average reqired size is much less than the block size. //------------------------------------------------------------------------ class block_allocator { struct block_type { int8u* data; unsigned size; }; public: void remove_all() { if(m_num_blocks) { block_type* blk = m_blocks + m_num_blocks - 1; while(m_num_blocks--) { pod_allocator::deallocate(blk->data, blk->size); --blk; } pod_allocator::deallocate(m_blocks, m_max_blocks); } m_num_blocks = 0; m_max_blocks = 0; m_blocks = 0; m_buf_ptr = 0; m_rest = 0; } ~block_allocator() { remove_all(); } block_allocator(unsigned block_size, unsigned block_ptr_inc=256-8) : m_block_size(block_size), m_block_ptr_inc(block_ptr_inc), m_num_blocks(0), m_max_blocks(0), m_blocks(0), m_buf_ptr(0), m_rest(0) { } int8u* allocate(unsigned size, unsigned alignment=1) { if(size == 0) return 0; if(size <= m_rest) { int8u* ptr = m_buf_ptr; if(alignment > 1) { unsigned align = (alignment - unsigned((std::size_t)ptr) % alignment) % alignment; size += align; ptr += align; if(size <= m_rest) { m_rest -= size; m_buf_ptr += size; return ptr; } allocate_block(size); return allocate(size - align, alignment); } m_rest -= size; m_buf_ptr += size; return ptr; } allocate_block(size + alignment - 1); return allocate(size, alignment); } private: void allocate_block(unsigned size) { if(size < m_block_size) size = m_block_size; if(m_num_blocks >= m_max_blocks) { block_type* new_blocks = pod_allocator::allocate(m_max_blocks + m_block_ptr_inc); if(m_blocks) { std::memcpy(new_blocks, m_blocks, m_num_blocks * sizeof(block_type)); pod_allocator::deallocate(m_blocks, m_max_blocks); } m_blocks = new_blocks; m_max_blocks += m_block_ptr_inc; } m_blocks[m_num_blocks].size = size; m_blocks[m_num_blocks].data = m_buf_ptr = pod_allocator::allocate(size); m_num_blocks++; m_rest = size; } unsigned m_block_size; unsigned m_block_ptr_inc; unsigned m_num_blocks; unsigned m_max_blocks; block_type* m_blocks; int8u* m_buf_ptr; unsigned m_rest; }; //------------------------------------------------------------------------ enum quick_sort_threshold_e { quick_sort_threshold = 9 }; //-----------------------------------------------------------swap_elements template inline void swap_elements(T& a, T& b) { T temp = a; a = b; b = temp; } //--------------------------------------------------------------quick_sort template void quick_sort(Array& arr, Less less) { if(arr.size() < 2) return; typename Array::value_type* e1; typename Array::value_type* e2; int stack[80]; int* top = stack; int limit = arr.size(); int base = 0; for(;;) { int len = limit - base; int i; int j; int pivot; if(len > quick_sort_threshold) { // we use base + len/2 as the pivot pivot = base + len / 2; swap_elements(arr[base], arr[pivot]); i = base + 1; j = limit - 1; // now ensure that *i <= *base <= *j e1 = &(arr[j]); e2 = &(arr[i]); if(less(*e1, *e2)) swap_elements(*e1, *e2); e1 = &(arr[base]); e2 = &(arr[i]); if(less(*e1, *e2)) swap_elements(*e1, *e2); e1 = &(arr[j]); e2 = &(arr[base]); if(less(*e1, *e2)) swap_elements(*e1, *e2); for(;;) { do i++; while( less(arr[i], arr[base]) ); do j--; while( less(arr[base], arr[j]) ); if( i > j ) { break; } swap_elements(arr[i], arr[j]); } swap_elements(arr[base], arr[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(; less(*(e1 = &(arr[j + 1])), *(e2 = &(arr[j]))); j--) { swap_elements(*e1, *e2); if(j == base) { break; } } } if(top > stack) { top -= 2; base = top[0]; limit = top[1]; } else { break; } } } } //------------------------------------------------------remove_duplicates // Remove duplicates from a sorted array. It doesn't cut the // tail of the array, it just returns the number of remaining elements. //----------------------------------------------------------------------- template unsigned remove_duplicates(Array& arr, Equal equal) { if(arr.size() < 2) return arr.size(); unsigned i, j; for(i = 1, j = 1; i < arr.size(); i++) { typename Array::value_type& e = arr[i]; if(!equal(e, arr[i - 1])) { arr[j++] = e; } } return j; } //--------------------------------------------------------invert_container template void invert_container(Array& arr) { int i = 0; int j = arr.size() - 1; while(i < j) { swap_elements(arr[i++], arr[j--]); } } //------------------------------------------------------binary_search_pos template unsigned binary_search_pos(const Array& arr, const Value& val, Less less) { if(arr.size() == 0) return 0; unsigned beg = 0; unsigned end = arr.size() - 1; if(less(val, arr[0])) return 0; if(less(arr[end], val)) return end + 1; while(end - beg > 1) { unsigned mid = (end + beg) >> 1; if(less(val, arr[mid])) end = mid; else beg = mid; } //if(beg <= 0 && less(val, arr[0])) return 0; //if(end >= arr.size() - 1 && less(arr[end], val)) ++end; return end; } //----------------------------------------------------------range_adaptor template class range_adaptor { public: typedef typename Array::value_type value_type; range_adaptor(Array& array, unsigned start, unsigned size) : m_array(array), m_start(start), m_size(size) {} unsigned size() const { return m_size; } const value_type& operator [] (unsigned i) const { return m_array[m_start + i]; } value_type& operator [] (unsigned i) { return m_array[m_start + i]; } const value_type& at(unsigned i) const { return m_array[m_start + i]; } value_type& at(unsigned i) { return m_array[m_start + i]; } value_type value_at(unsigned i) const { return m_array[m_start + i]; } private: Array& m_array; unsigned m_start; unsigned m_size; }; //---------------------------------------------------------------int_less inline bool int_less(int a, int b) { return a < b; } //------------------------------------------------------------int_greater inline bool int_greater(int a, int b) { return a > b; } //----------------------------------------------------------unsigned_less inline bool unsigned_less(unsigned a, unsigned b) { return a < b; } //-------------------------------------------------------unsigned_greater inline bool unsigned_greater(unsigned a, unsigned b) { return a > b; } } #endif ragg/src/agg/include/agg_span_pattern_rgb.h0000644000176200001440000000656113504406270020472 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_SPAN_PATTERN_RGB_INCLUDED #define AGG_SPAN_PATTERN_RGB_INCLUDED #include "agg_basics.h" namespace agg { //========================================================span_pattern_rgb template class span_pattern_rgb { public: typedef Source source_type; typedef typename source_type::color_type color_type; typedef typename source_type::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; //-------------------------------------------------------------------- span_pattern_rgb() {} span_pattern_rgb(source_type& src, unsigned offset_x, unsigned offset_y) : m_src(&src), m_offset_x(offset_x), m_offset_y(offset_y), m_alpha(color_type::base_mask) {} //-------------------------------------------------------------------- void attach(source_type& v) { m_src = &v; } source_type& source() { return *m_src; } const source_type& source() const { return *m_src; } //-------------------------------------------------------------------- void offset_x(unsigned v) { m_offset_x = v; } void offset_y(unsigned v) { m_offset_y = v; } unsigned offset_x() const { return m_offset_x; } unsigned offset_y() const { return m_offset_y; } void alpha(value_type v) { m_alpha = v; } value_type alpha() const { return m_alpha; } //-------------------------------------------------------------------- void prepare() {} void generate(color_type* span, int x, int y, unsigned len) { x += m_offset_x; y += m_offset_y; const value_type* p = (const value_type*)m_src->span(x, y, len); do { span->r = p[order_type::R]; span->g = p[order_type::G]; span->b = p[order_type::B]; span->a = m_alpha; p = m_src->next_x(); ++span; } while(--len); } private: source_type* m_src; unsigned m_offset_x; unsigned m_offset_y; value_type m_alpha; }; } #endif ragg/src/agg/include/agg_pixfmt_rgba.h0000644000176200001440000032172513504406270017446 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Adaptation for high precision colors 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_PIXFMT_RGBA_INCLUDED #define AGG_PIXFMT_RGBA_INCLUDED #include #include #include "agg_pixfmt_base.h" #include "agg_rendering_buffer.h" namespace agg { template inline T sd_min(T a, T b) { return (a < b) ? a : b; } template inline T sd_max(T a, T b) { return (a > b) ? a : b; } inline rgba & clip(rgba & c) { if (c.a > 1) c.a = 1; else if (c.a < 0) c.a = 0; if (c.r > c.a) c.r = c.a; else if (c.r < 0) c.r = 0; if (c.g > c.a) c.g = c.a; else if (c.g < 0) c.g = 0; if (c.b > c.a) c.b = c.a; else if (c.b < 0) c.b = 0; return c; } //=========================================================multiplier_rgba template struct multiplier_rgba { typedef ColorT color_type; typedef typename color_type::value_type value_type; //-------------------------------------------------------------------- static AGG_INLINE void premultiply(value_type* p) { value_type a = p[Order::A]; p[Order::R] = color_type::multiply(p[Order::R], a); p[Order::G] = color_type::multiply(p[Order::G], a); p[Order::B] = color_type::multiply(p[Order::B], a); } //-------------------------------------------------------------------- static AGG_INLINE void demultiply(value_type* p) { value_type a = p[Order::A]; p[Order::R] = color_type::demultiply(p[Order::R], a); p[Order::G] = color_type::demultiply(p[Order::G], a); p[Order::B] = color_type::demultiply(p[Order::B], a); } }; //=====================================================apply_gamma_dir_rgba template class apply_gamma_dir_rgba { public: typedef ColorT color_type; typedef typename color_type::value_type value_type; apply_gamma_dir_rgba(const GammaLut& gamma) : m_gamma(gamma) {} AGG_INLINE void operator () (value_type* p) { p[Order::R] = m_gamma.dir(p[Order::R]); p[Order::G] = m_gamma.dir(p[Order::G]); p[Order::B] = m_gamma.dir(p[Order::B]); } private: const GammaLut& m_gamma; }; //=====================================================apply_gamma_inv_rgba template class apply_gamma_inv_rgba { public: typedef ColorT color_type; typedef typename color_type::value_type value_type; apply_gamma_inv_rgba(const GammaLut& gamma) : m_gamma(gamma) {} AGG_INLINE void operator () (value_type* p) { p[Order::R] = m_gamma.inv(p[Order::R]); p[Order::G] = m_gamma.inv(p[Order::G]); p[Order::B] = m_gamma.inv(p[Order::B]); } private: const GammaLut& m_gamma; }; template struct conv_rgba_pre { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; //-------------------------------------------------------------------- static AGG_INLINE void set_plain_color(value_type* p, color_type c) { c.premultiply(); p[Order::R] = c.r; p[Order::G] = c.g; p[Order::B] = c.b; p[Order::A] = c.a; } //-------------------------------------------------------------------- static AGG_INLINE color_type get_plain_color(const value_type* p) { return color_type( p[Order::R], p[Order::G], p[Order::B], p[Order::A]).demultiply(); } }; template struct conv_rgba_plain { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; //-------------------------------------------------------------------- static AGG_INLINE void set_plain_color(value_type* p, color_type c) { p[Order::R] = c.r; p[Order::G] = c.g; p[Order::B] = c.b; p[Order::A] = c.a; } //-------------------------------------------------------------------- static AGG_INLINE color_type get_plain_color(const value_type* p) { return color_type( p[Order::R], p[Order::G], p[Order::B], p[Order::A]); } }; //=============================================================blender_rgba // Blends "plain" (i.e. non-premultiplied) colors into a premultiplied buffer. template struct blender_rgba : conv_rgba_pre { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; // Blend pixels using the non-premultiplied form of Alvy-Ray Smith's // compositing function. Since the render buffer is in fact premultiplied // we omit the initial premultiplication and final demultiplication. //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) { blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover)); } //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha) { p[Order::R] = color_type::lerp(p[Order::R], cr, alpha); p[Order::G] = color_type::lerp(p[Order::G], cg, alpha); p[Order::B] = color_type::lerp(p[Order::B], cb, alpha); p[Order::A] = color_type::prelerp(p[Order::A], alpha, alpha); } }; //========================================================blender_rgba_pre // Blends premultiplied colors into a premultiplied buffer. template struct blender_rgba_pre : conv_rgba_pre { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; // Blend pixels using the premultiplied form of Alvy-Ray Smith's // compositing function. //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) { blend_pix(p, color_type::mult_cover(cr, cover), color_type::mult_cover(cg, cover), color_type::mult_cover(cb, cover), color_type::mult_cover(alpha, cover)); } //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha) { p[Order::R] = color_type::prelerp(p[Order::R], cr, alpha); p[Order::G] = color_type::prelerp(p[Order::G], cg, alpha); p[Order::B] = color_type::prelerp(p[Order::B], cb, alpha); p[Order::A] = color_type::prelerp(p[Order::A], alpha, alpha); } }; //======================================================blender_rgba_plain // Blends "plain" (non-premultiplied) colors into a plain (non-premultiplied) buffer. template struct blender_rgba_plain : conv_rgba_plain { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; // Blend pixels using the non-premultiplied form of Alvy-Ray Smith's // compositing function. //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) { blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover)); } //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, value_type cr, value_type cg, value_type cb, value_type alpha) { if (alpha > color_type::empty_value()) { calc_type a = p[Order::A]; calc_type r = color_type::multiply(p[Order::R], a); calc_type g = color_type::multiply(p[Order::G], a); calc_type b = color_type::multiply(p[Order::B], a); p[Order::R] = color_type::lerp(r, cr, alpha); p[Order::G] = color_type::lerp(g, cg, alpha); p[Order::B] = color_type::lerp(b, cb, alpha); p[Order::A] = color_type::prelerp(a, alpha, alpha); multiplier_rgba::demultiply(p); } } }; // SVG compositing operations. // For specifications, see http://www.w3.org/TR/SVGCompositing/ //=========================================================comp_op_rgba_clear template struct comp_op_rgba_clear : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = 0 // Da' = 0 static AGG_INLINE void blend_pix(value_type* p, value_type, value_type, value_type, value_type, cover_type cover) { if (cover >= cover_full) { p[0] = p[1] = p[2] = p[3] = color_type::empty_value(); } else if (cover > cover_none) { set(p, get(p, cover_full - cover)); } } }; //===========================================================comp_op_rgba_src template struct comp_op_rgba_src : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Sca // Da' = Sa static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { if (cover >= cover_full) { set(p, r, g, b, a); } else { rgba s = get(r, g, b, a, cover); rgba d = get(p, cover_full - cover); d.r += s.r; d.g += s.g; d.b += s.b; d.a += s.a; set(p, d); } } }; //===========================================================comp_op_rgba_dst template struct comp_op_rgba_dst : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; // Dca' = Dca.Sa + Dca.(1 - Sa) = Dca // Da' = Da.Sa + Da.(1 - Sa) = Da static AGG_INLINE void blend_pix(value_type*, value_type, value_type, value_type, value_type, cover_type) { // Well, that was easy! } }; //======================================================comp_op_rgba_src_over template struct comp_op_rgba_src_over : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Sca + Dca.(1 - Sa) = Dca + Sca - Dca.Sa // Da' = Sa + Da - Sa.Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { #if 1 blender_rgba_pre::blend_pix(p, r, g, b, a, cover); #else rgba s = get(r, g, b, a, cover); rgba d = get(p); d.r += s.r - d.r * s.a; d.g += s.g - d.g * s.a; d.b += s.b - d.b * s.a; d.a += s.a - d.a * s.a; set(p, d); #endif } }; //======================================================comp_op_rgba_dst_over template struct comp_op_rgba_dst_over : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Dca + Sca.(1 - Da) // Da' = Sa + Da - Sa.Da = Da + Sa.(1 - Da) static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); rgba d = get(p); double d1a = 1 - d.a; d.r += s.r * d1a; d.g += s.g * d1a; d.b += s.b * d1a; d.a += s.a * d1a; set(p, d); } }; //======================================================comp_op_rgba_src_in template struct comp_op_rgba_src_in : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Sca.Da // Da' = Sa.Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { double da = ColorT::to_double(p[Order::A]); if (da > 0) { rgba s = get(r, g, b, a, cover); rgba d = get(p, cover_full - cover); d.r += s.r * da; d.g += s.g * da; d.b += s.b * da; d.a += s.a * da; set(p, d); } } }; //======================================================comp_op_rgba_dst_in template struct comp_op_rgba_dst_in : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Dca.Sa // Da' = Sa.Da static AGG_INLINE void blend_pix(value_type* p, value_type, value_type, value_type, value_type a, cover_type cover) { double sa = ColorT::to_double(a); rgba d = get(p, cover_full - cover); rgba d2 = get(p, cover); d.r += d2.r * sa; d.g += d2.g * sa; d.b += d2.b * sa; d.a += d2.a * sa; set(p, d); } }; //======================================================comp_op_rgba_src_out template struct comp_op_rgba_src_out : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Sca.(1 - Da) // Da' = Sa.(1 - Da) static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); rgba d = get(p, cover_full - cover); double d1a = 1 - ColorT::to_double(p[Order::A]); d.r += s.r * d1a; d.g += s.g * d1a; d.b += s.b * d1a; d.a += s.a * d1a; set(p, d); } }; //======================================================comp_op_rgba_dst_out template struct comp_op_rgba_dst_out : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Dca.(1 - Sa) // Da' = Da.(1 - Sa) static AGG_INLINE void blend_pix(value_type* p, value_type, value_type, value_type, value_type a, cover_type cover) { rgba d = get(p, cover_full - cover); rgba dc = get(p, cover); double s1a = 1 - ColorT::to_double(a); d.r += dc.r * s1a; d.g += dc.g * s1a; d.b += dc.b * s1a; d.a += dc.a * s1a; set(p, d); } }; //=====================================================comp_op_rgba_src_atop template struct comp_op_rgba_src_atop : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Sca.Da + Dca.(1 - Sa) // Da' = Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); rgba d = get(p); double s1a = 1 - s.a; d.r = s.r * d.a + d.r * s1a; d.g = s.g * d.a + d.g * s1a; d.b = s.b * d.a + d.g * s1a; set(p, d); } }; //=====================================================comp_op_rgba_dst_atop template struct comp_op_rgba_dst_atop : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Dca.Sa + Sca.(1 - Da) // Da' = Sa static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba sc = get(r, g, b, a, cover); rgba dc = get(p, cover); rgba d = get(p, cover_full - cover); double sa = ColorT::to_double(a); double d1a = 1 - ColorT::to_double(p[Order::A]); d.r += dc.r * sa + sc.r * d1a; d.g += dc.g * sa + sc.g * d1a; d.b += dc.b * sa + sc.b * d1a; d.a += sc.a; set(p, d); } }; //=========================================================comp_op_rgba_xor template struct comp_op_rgba_xor : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Sca.(1 - Da) + Dca.(1 - Sa) // Da' = Sa + Da - 2.Sa.Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); rgba d = get(p); double s1a = 1 - s.a; double d1a = 1 - ColorT::to_double(p[Order::A]); d.r = s.r * d1a + d.r * s1a; d.g = s.g * d1a + d.g * s1a; d.b = s.b * d1a + d.b * s1a; d.a = s.a + d.a - 2 * s.a * d.a; set(p, d); } }; //=========================================================comp_op_rgba_plus template struct comp_op_rgba_plus : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Sca + Dca // Da' = Sa + Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); d.a = sd_min(d.a + s.a, 1.0); d.r = sd_min(d.r + s.r, d.a); d.g = sd_min(d.g + s.g, d.a); d.b = sd_min(d.b + s.b, d.a); set(p, clip(d)); } } }; //========================================================comp_op_rgba_minus // Note: not included in SVG spec. template struct comp_op_rgba_minus : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Dca - Sca // Da' = 1 - (1 - Sa).(1 - Da) = Da + Sa - Sa.Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); d.a += s.a - s.a * d.a; d.r = sd_max(d.r - s.r, 0.0); d.g = sd_max(d.g - s.g, 0.0); d.b = sd_max(d.b - s.b, 0.0); set(p, clip(d)); } } }; //=====================================================comp_op_rgba_multiply template struct comp_op_rgba_multiply : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) // Da' = Sa + Da - Sa.Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); double s1a = 1 - s.a; double d1a = 1 - d.a; d.r = s.r * d.r + s.r * d1a + d.r * s1a; d.g = s.g * d.g + s.g * d1a + d.g * s1a; d.b = s.b * d.b + s.b * d1a + d.b * s1a; d.a += s.a - s.a * d.a; set(p, clip(d)); } } }; //=====================================================comp_op_rgba_screen template struct comp_op_rgba_screen : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Sca + Dca - Sca.Dca // Da' = Sa + Da - Sa.Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); d.r += s.r - s.r * d.r; d.g += s.g - s.g * d.g; d.b += s.b - s.b * d.b; d.a += s.a - s.a * d.a; set(p, clip(d)); } } }; //=====================================================comp_op_rgba_overlay template struct comp_op_rgba_overlay : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // if 2.Dca <= Da // Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) // otherwise // Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) // // Da' = Sa + Da - Sa.Da static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a) { return (2 * dca <= da) ? 2 * sca * dca + sca * d1a + dca * s1a : sada - 2 * (da - dca) * (sa - sca) + sca * d1a + dca * s1a; } static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); double d1a = 1 - d.a; double s1a = 1 - s.a; double sada = s.a * d.a; d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a); d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a); d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a); d.a += s.a - s.a * d.a; set(p, clip(d)); } } }; //=====================================================comp_op_rgba_darken template struct comp_op_rgba_darken : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) // Da' = Sa + Da - Sa.Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); double d1a = 1 - d.a; double s1a = 1 - s.a; d.r = sd_min(s.r * d.a, d.r * s.a) + s.r * d1a + d.r * s1a; d.g = sd_min(s.g * d.a, d.g * s.a) + s.g * d1a + d.g * s1a; d.b = sd_min(s.b * d.a, d.b * s.a) + s.b * d1a + d.b * s1a; d.a += s.a - s.a * d.a; set(p, clip(d)); } } }; //=====================================================comp_op_rgba_lighten template struct comp_op_rgba_lighten : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) // Da' = Sa + Da - Sa.Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); double d1a = 1 - d.a; double s1a = 1 - s.a; d.r = sd_max(s.r * d.a, d.r * s.a) + s.r * d1a + d.r * s1a; d.g = sd_max(s.g * d.a, d.g * s.a) + s.g * d1a + d.g * s1a; d.b = sd_max(s.b * d.a, d.b * s.a) + s.b * d1a + d.b * s1a; d.a += s.a - s.a * d.a; set(p, clip(d)); } } }; //=====================================================comp_op_rgba_color_dodge template struct comp_op_rgba_color_dodge : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // if Sca == Sa and Dca == 0 // Dca' = Sca.(1 - Da) + Dca.(1 - Sa) = Sca.(1 - Da) // otherwise if Sca == Sa // Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) // otherwise if Sca < Sa // Dca' = Sa.Da.min(1, Dca/Da.Sa/(Sa - Sca)) + Sca.(1 - Da) + Dca.(1 - Sa) // // Da' = Sa + Da - Sa.Da static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a) { if (sca < sa) return sada * sd_min(1.0, (dca / da) * sa / (sa - sca)) + sca * d1a + dca * s1a; if (dca > 0) return sada + sca * d1a + dca * s1a; return sca * d1a; } static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); if (d.a > 0) { double sada = s.a * d.a; double s1a = 1 - s.a; double d1a = 1 - d.a; d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a); d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a); d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a); d.a += s.a - s.a * d.a; set(p, clip(d)); } else set(p, s); } } }; //=====================================================comp_op_rgba_color_burn template struct comp_op_rgba_color_burn : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // if Sca == 0 and Dca == Da // Dca' = Sa.Da + Dca.(1 - Sa) // otherwise if Sca == 0 // Dca' = Dca.(1 - Sa) // otherwise if Sca > 0 // Dca' = Sa.Da.(1 - min(1, (1 - Dca/Da).Sa/Sca)) + Sca.(1 - Da) + Dca.(1 - Sa) static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a) { if (sca > 0) return sada * (1 - sd_min(1.0, (1 - dca / da) * sa / sca)) + sca * d1a + dca * s1a; if (dca > da) return sada + dca * s1a; return dca * s1a; } static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); if (d.a > 0) { double sada = s.a * d.a; double s1a = 1 - s.a; double d1a = 1 - d.a; d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a); d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a); d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a); d.a += s.a - sada; set(p, clip(d)); } else set(p, s); } } }; //=====================================================comp_op_rgba_hard_light template struct comp_op_rgba_hard_light : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // if 2.Sca < Sa // Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) // otherwise // Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) // // Da' = Sa + Da - Sa.Da static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a) { return (2 * sca < sa) ? 2 * sca * dca + sca * d1a + dca * s1a : sada - 2 * (da - dca) * (sa - sca) + sca * d1a + dca * s1a; } static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); double d1a = 1 - d.a; double s1a = 1 - s.a; double sada = s.a * d.a; d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a); d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a); d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a); d.a += s.a - sada; set(p, clip(d)); } } }; //=====================================================comp_op_rgba_soft_light template struct comp_op_rgba_soft_light : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // if 2.Sca <= Sa // Dca' = Dca.Sa - (Sa.Da - 2.Sca.Da).Dca.Sa.(Sa.Da - Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) // otherwise if 2.Sca > Sa and 4.Dca <= Da // Dca' = Dca.Sa + (2.Sca.Da - Sa.Da).((((16.Dsa.Sa - 12).Dsa.Sa + 4).Dsa.Da) - Dsa.Da) + Sca.(1 - Da) + Dca.(1 - Sa) // otherwise if 2.Sca > Sa and 4.Dca > Da // Dca' = Dca.Sa + (2.Sca.Da - Sa.Da).((Dca.Sa)^0.5 - Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) // // Da' = Sa + Da - Sa.Da static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a) { double dcasa = dca * sa; if (2 * sca <= sa) return dcasa - (sada - 2 * sca * da) * dcasa * (sada - dcasa) + sca * d1a + dca * s1a; if (4 * dca <= da) return dcasa + (2 * sca * da - sada) * ((((16 * dcasa - 12) * dcasa + 4) * dca * da) - dca * da) + sca * d1a + dca * s1a; return dcasa + (2 * sca * da - sada) * (std::sqrt(dcasa) - dcasa) + sca * d1a + dca * s1a; } static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); if (d.a > 0) { double sada = s.a * d.a; double s1a = 1 - s.a; double d1a = 1 - d.a; d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a); d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a); d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a); d.a += s.a - sada; set(p, clip(d)); } else set(p, s); } } }; //=====================================================comp_op_rgba_difference template struct comp_op_rgba_difference : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = Sca + Dca - 2.min(Sca.Da, Dca.Sa) // Da' = Sa + Da - Sa.Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); d.r += s.r - 2 * sd_min(s.r * d.a, d.r * s.a); d.g += s.g - 2 * sd_min(s.g * d.a, d.g * s.a); d.b += s.b - 2 * sd_min(s.b * d.a, d.b * s.a); d.a += s.a - s.a * d.a; set(p, clip(d)); } } }; //=====================================================comp_op_rgba_exclusion template struct comp_op_rgba_exclusion : blender_base { typedef ColorT color_type; typedef typename color_type::value_type value_type; using blender_base::get; using blender_base::set; // Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) // Da' = Sa + Da - Sa.Da static AGG_INLINE void blend_pix(value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { rgba s = get(r, g, b, a, cover); if (s.a > 0) { rgba d = get(p); double d1a = 1 - d.a; double s1a = 1 - s.a; d.r = (s.r * d.a + d.r * s.a - 2 * s.r * d.r) + s.r * d1a + d.r * s1a; d.g = (s.g * d.a + d.g * s.a - 2 * s.g * d.g) + s.g * d1a + d.g * s1a; d.b = (s.b * d.a + d.b * s.a - 2 * s.b * d.b) + s.b * d1a + d.b * s1a; d.a += s.a - s.a * d.a; set(p, clip(d)); } } }; #if 0 //=====================================================comp_op_rgba_contrast template struct comp_op_rgba_contrast { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; enum base_scale_e { base_shift = color_type::base_shift, base_mask = color_type::base_mask }; static AGG_INLINE void blend_pix(value_type* p, unsigned sr, unsigned sg, unsigned sb, unsigned sa, unsigned cover) { if (cover < 255) { sr = (sr * cover + 255) >> 8; sg = (sg * cover + 255) >> 8; sb = (sb * cover + 255) >> 8; sa = (sa * cover + 255) >> 8; } long_type dr = p[Order::R]; long_type dg = p[Order::G]; long_type db = p[Order::B]; int da = p[Order::A]; long_type d2a = da >> 1; unsigned s2a = sa >> 1; int r = (int)((((dr - d2a) * int((sr - s2a)*2 + base_mask)) >> base_shift) + d2a); int g = (int)((((dg - d2a) * int((sg - s2a)*2 + base_mask)) >> base_shift) + d2a); int b = (int)((((db - d2a) * int((sb - s2a)*2 + base_mask)) >> base_shift) + d2a); r = (r < 0) ? 0 : r; g = (g < 0) ? 0 : g; b = (b < 0) ? 0 : b; p[Order::R] = (value_type)((r > da) ? da : r); p[Order::G] = (value_type)((g > da) ? da : g); p[Order::B] = (value_type)((b > da) ? da : b); } }; //=====================================================comp_op_rgba_invert template struct comp_op_rgba_invert { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; enum base_scale_e { base_shift = color_type::base_shift, base_mask = color_type::base_mask }; // Dca' = (Da - Dca) * Sa + Dca.(1 - Sa) // Da' = Sa + Da - Sa.Da static AGG_INLINE void blend_pix(value_type* p, unsigned sr, unsigned sg, unsigned sb, unsigned sa, unsigned cover) { sa = (sa * cover + 255) >> 8; if (sa) { calc_type da = p[Order::A]; calc_type dr = ((da - p[Order::R]) * sa + base_mask) >> base_shift; calc_type dg = ((da - p[Order::G]) * sa + base_mask) >> base_shift; calc_type db = ((da - p[Order::B]) * sa + base_mask) >> base_shift; calc_type s1a = base_mask - sa; p[Order::R] = (value_type)(dr + ((p[Order::R] * s1a + base_mask) >> base_shift)); p[Order::G] = (value_type)(dg + ((p[Order::G] * s1a + base_mask) >> base_shift)); p[Order::B] = (value_type)(db + ((p[Order::B] * s1a + base_mask) >> base_shift)); p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); } } }; //=================================================comp_op_rgba_invert_rgb template struct comp_op_rgba_invert_rgb { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; enum base_scale_e { base_shift = color_type::base_shift, base_mask = color_type::base_mask }; // Dca' = (Da - Dca) * Sca + Dca.(1 - Sa) // Da' = Sa + Da - Sa.Da static AGG_INLINE void blend_pix(value_type* p, unsigned sr, unsigned sg, unsigned sb, unsigned sa, unsigned cover) { if (cover < 255) { sr = (sr * cover + 255) >> 8; sg = (sg * cover + 255) >> 8; sb = (sb * cover + 255) >> 8; sa = (sa * cover + 255) >> 8; } if (sa) { calc_type da = p[Order::A]; calc_type dr = ((da - p[Order::R]) * sr + base_mask) >> base_shift; calc_type dg = ((da - p[Order::G]) * sg + base_mask) >> base_shift; calc_type db = ((da - p[Order::B]) * sb + base_mask) >> base_shift; calc_type s1a = base_mask - sa; p[Order::R] = (value_type)(dr + ((p[Order::R] * s1a + base_mask) >> base_shift)); p[Order::G] = (value_type)(dg + ((p[Order::G] * s1a + base_mask) >> base_shift)); p[Order::B] = (value_type)(db + ((p[Order::B] * s1a + base_mask) >> base_shift)); p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); } } }; #endif //======================================================comp_op_table_rgba template struct comp_op_table_rgba { typedef typename ColorT::value_type value_type; typedef typename ColorT::calc_type calc_type; typedef void (*comp_op_func_type)(value_type* p, value_type cr, value_type cg, value_type cb, value_type ca, cover_type cover); static comp_op_func_type g_comp_op_func[]; }; //==========================================================g_comp_op_func template typename comp_op_table_rgba::comp_op_func_type comp_op_table_rgba::g_comp_op_func[] = { comp_op_rgba_clear ::blend_pix, comp_op_rgba_src ::blend_pix, comp_op_rgba_dst ::blend_pix, comp_op_rgba_src_over ::blend_pix, comp_op_rgba_dst_over ::blend_pix, comp_op_rgba_src_in ::blend_pix, comp_op_rgba_dst_in ::blend_pix, comp_op_rgba_src_out ::blend_pix, comp_op_rgba_dst_out ::blend_pix, comp_op_rgba_src_atop ::blend_pix, comp_op_rgba_dst_atop ::blend_pix, comp_op_rgba_xor ::blend_pix, comp_op_rgba_plus ::blend_pix, //comp_op_rgba_minus ::blend_pix, comp_op_rgba_multiply ::blend_pix, comp_op_rgba_screen ::blend_pix, comp_op_rgba_overlay ::blend_pix, comp_op_rgba_darken ::blend_pix, comp_op_rgba_lighten ::blend_pix, comp_op_rgba_color_dodge::blend_pix, comp_op_rgba_color_burn ::blend_pix, comp_op_rgba_hard_light ::blend_pix, comp_op_rgba_soft_light ::blend_pix, comp_op_rgba_difference ::blend_pix, comp_op_rgba_exclusion ::blend_pix, //comp_op_rgba_contrast ::blend_pix, //comp_op_rgba_invert ::blend_pix, //comp_op_rgba_invert_rgb ::blend_pix, 0 }; //==============================================================comp_op_e enum comp_op_e { comp_op_clear, //----comp_op_clear comp_op_src, //----comp_op_src comp_op_dst, //----comp_op_dst comp_op_src_over, //----comp_op_src_over comp_op_dst_over, //----comp_op_dst_over comp_op_src_in, //----comp_op_src_in comp_op_dst_in, //----comp_op_dst_in comp_op_src_out, //----comp_op_src_out comp_op_dst_out, //----comp_op_dst_out comp_op_src_atop, //----comp_op_src_atop comp_op_dst_atop, //----comp_op_dst_atop comp_op_xor, //----comp_op_xor comp_op_plus, //----comp_op_plus //comp_op_minus, //----comp_op_minus comp_op_multiply, //----comp_op_multiply comp_op_screen, //----comp_op_screen comp_op_overlay, //----comp_op_overlay comp_op_darken, //----comp_op_darken comp_op_lighten, //----comp_op_lighten comp_op_color_dodge, //----comp_op_color_dodge comp_op_color_burn, //----comp_op_color_burn comp_op_hard_light, //----comp_op_hard_light comp_op_soft_light, //----comp_op_soft_light comp_op_difference, //----comp_op_difference comp_op_exclusion, //----comp_op_exclusion //comp_op_contrast, //----comp_op_contrast //comp_op_invert, //----comp_op_invert //comp_op_invert_rgb, //----comp_op_invert_rgb end_of_comp_op_e }; //====================================================comp_op_adaptor_rgba template struct comp_op_adaptor_rgba { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned op, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { comp_op_table_rgba::g_comp_op_func[op](p, color_type::multiply(r, a), color_type::multiply(g, a), color_type::multiply(b, a), a, cover); } }; //=========================================comp_op_adaptor_clip_to_dst_rgba template struct comp_op_adaptor_clip_to_dst_rgba { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned op, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { r = color_type::multiply(r, a); g = color_type::multiply(g, a); b = color_type::multiply(b, a); value_type da = p[Order::A]; comp_op_table_rgba::g_comp_op_func[op](p, color_type::multiply(r, da), color_type::multiply(g, da), color_type::multiply(b, da), color_type::multiply(a, da), cover); } }; //================================================comp_op_adaptor_rgba_pre template struct comp_op_adaptor_rgba_pre { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned op, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { comp_op_table_rgba::g_comp_op_func[op](p, r, g, b, a, cover); } }; //=====================================comp_op_adaptor_clip_to_dst_rgba_pre template struct comp_op_adaptor_clip_to_dst_rgba_pre { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned op, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { value_type da = p[Order::A]; comp_op_table_rgba::g_comp_op_func[op](p, color_type::multiply(r, da), color_type::multiply(g, da), color_type::multiply(b, da), color_type::multiply(a, da), cover); } }; //====================================================comp_op_adaptor_rgba_plain template struct comp_op_adaptor_rgba_plain { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned op, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { multiplier_rgba::premultiply(p); comp_op_adaptor_rgba::blend_pix(op, p, r, g, b, a, cover); multiplier_rgba::demultiply(p); } }; //=========================================comp_op_adaptor_clip_to_dst_rgba_plain template struct comp_op_adaptor_clip_to_dst_rgba_plain { typedef ColorT color_type; typedef Order order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned op, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { multiplier_rgba::premultiply(p); comp_op_adaptor_clip_to_dst_rgba::blend_pix(op, p, r, g, b, a, cover); multiplier_rgba::demultiply(p); } }; //=======================================================comp_adaptor_rgba template struct comp_adaptor_rgba { typedef typename BlenderPre::color_type color_type; typedef typename BlenderPre::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { BlenderPre::blend_pix(p, color_type::multiply(r, a), color_type::multiply(g, a), color_type::multiply(b, a), a, cover); } }; //==========================================comp_adaptor_clip_to_dst_rgba template struct comp_adaptor_clip_to_dst_rgba { typedef typename BlenderPre::color_type color_type; typedef typename BlenderPre::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { r = color_type::multiply(r, a); g = color_type::multiply(g, a); b = color_type::multiply(b, a); value_type da = p[order_type::A]; BlenderPre::blend_pix(p, color_type::multiply(r, da), color_type::multiply(g, da), color_type::multiply(b, da), color_type::multiply(a, da), cover); } }; //=======================================================comp_adaptor_rgba_pre template struct comp_adaptor_rgba_pre { typedef typename BlenderPre::color_type color_type; typedef typename BlenderPre::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { BlenderPre::blend_pix(p, r, g, b, a, cover); } }; //======================================comp_adaptor_clip_to_dst_rgba_pre template struct comp_adaptor_clip_to_dst_rgba_pre { typedef typename BlenderPre::color_type color_type; typedef typename BlenderPre::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { unsigned da = p[order_type::A]; BlenderPre::blend_pix(p, color_type::multiply(r, da), color_type::multiply(g, da), color_type::multiply(b, da), color_type::multiply(a, da), cover); } }; //=======================================================comp_adaptor_rgba_plain template struct comp_adaptor_rgba_plain { typedef typename BlenderPre::color_type color_type; typedef typename BlenderPre::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned op, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { multiplier_rgba::premultiply(p); comp_adaptor_rgba::blend_pix(op, p, r, g, b, a, cover); multiplier_rgba::demultiply(p); } }; //==========================================comp_adaptor_clip_to_dst_rgba_plain template struct comp_adaptor_clip_to_dst_rgba_plain { typedef typename BlenderPre::color_type color_type; typedef typename BlenderPre::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; typedef typename color_type::long_type long_type; static AGG_INLINE void blend_pix(unsigned op, value_type* p, value_type r, value_type g, value_type b, value_type a, cover_type cover) { multiplier_rgba::premultiply(p); comp_adaptor_clip_to_dst_rgba::blend_pix(op, p, r, g, b, a, cover); multiplier_rgba::demultiply(p); } }; //=================================================pixfmt_alpha_blend_rgba template class pixfmt_alpha_blend_rgba { public: typedef pixfmt_rgba_tag pixfmt_category; typedef RenBuf rbuf_type; typedef typename rbuf_type::row_data row_data; typedef Blender blender_type; typedef typename blender_type::color_type color_type; typedef typename blender_type::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; enum { num_components = 4, pix_step = 4, pix_width = sizeof(value_type) * pix_step, }; struct pixel_type { value_type c[num_components]; void set(value_type r, value_type g, value_type b, value_type a) { c[order_type::R] = r; c[order_type::G] = g; c[order_type::B] = b; c[order_type::A] = a; } void set(const color_type& color) { set(color.r, color.g, color.b, color.a); } void get(value_type& r, value_type& g, value_type& b, value_type& a) const { r = c[order_type::R]; g = c[order_type::G]; b = c[order_type::B]; a = c[order_type::A]; } color_type get() const { return color_type( c[order_type::R], c[order_type::G], c[order_type::B], c[order_type::A]); } pixel_type* next() { return (pixel_type*)(c + pix_step); } const pixel_type* next() const { return (const pixel_type*)(c + pix_step); } pixel_type* advance(int n) { return (pixel_type*)(c + n * pix_step); } const pixel_type* advance(int n) const { return (const pixel_type*)(c + n * pix_step); } }; private: //-------------------------------------------------------------------- AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover) { m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a, cover); } //-------------------------------------------------------------------- AGG_INLINE void blend_pix(pixel_type* p, const color_type& c) { m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a); } //-------------------------------------------------------------------- AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover) { if (!c.is_transparent()) { if (c.is_opaque() && cover == cover_mask) { p->set(c.r, c.g, c.b, c.a); } else { m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a, cover); } } } //-------------------------------------------------------------------- AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c) { if (!c.is_transparent()) { if (c.is_opaque()) { p->set(c.r, c.g, c.b, c.a); } else { m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a); } } } public: //-------------------------------------------------------------------- pixfmt_alpha_blend_rgba() : m_rbuf(0) {} explicit pixfmt_alpha_blend_rgba(rbuf_type& rb) : m_rbuf(&rb) {} void attach(rbuf_type& rb) { m_rbuf = &rb; } //-------------------------------------------------------------------- template bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) { rect_i r(x1, y1, x2, y2); if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) { int stride = pixf.stride(); m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), (r.x2 - r.x1) + 1, (r.y2 - r.y1) + 1, stride); return true; } return false; } //-------------------------------------------------------------------- AGG_INLINE unsigned width() const { return m_rbuf->width(); } AGG_INLINE unsigned height() const { return m_rbuf->height(); } AGG_INLINE int stride() const { return m_rbuf->stride(); } //-------------------------------------------------------------------- AGG_INLINE int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } AGG_INLINE row_data row(int y) const { return m_rbuf->row(y); } //-------------------------------------------------------------------- AGG_INLINE int8u* pix_ptr(int x, int y) { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step); } AGG_INLINE const int8u* pix_ptr(int x, int y) const { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step); } // Return pointer to pixel value, forcing row to be allocated. AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len) { return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step)); } // Return pointer to pixel value, or null if row not allocated. AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const { int8u* p = m_rbuf->row_ptr(y); return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step)) : 0; } // Get pixel pointer from raw buffer pointer. AGG_INLINE static pixel_type* pix_value_ptr(void* p) { return (pixel_type*)p; } // Get pixel pointer from raw buffer pointer. AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) { return (const pixel_type*)p; } //-------------------------------------------------------------------- AGG_INLINE static void write_plain_color(void* p, color_type c) { blender_type::set_plain_color(pix_value_ptr(p)->c, c); } //-------------------------------------------------------------------- AGG_INLINE static color_type read_plain_color(const void* p) { return blender_type::get_plain_color(pix_value_ptr(p)->c); } //-------------------------------------------------------------------- AGG_INLINE static void make_pix(int8u* p, const color_type& c) { ((pixel_type*)p)->set(c); } //-------------------------------------------------------------------- AGG_INLINE color_type pixel(int x, int y) const { if (const pixel_type* p = pix_value_ptr(x, y)) { return p->get(); } return color_type::no_color(); } //-------------------------------------------------------------------- AGG_INLINE void copy_pixel(int x, int y, const color_type& c) { pix_value_ptr(x, y, 1)->set(c); } //-------------------------------------------------------------------- AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) { copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover); } //-------------------------------------------------------------------- AGG_INLINE void copy_hline(int x, int y, unsigned len, const color_type& c) { pixel_type v; v.set(c); pixel_type* p = pix_value_ptr(x, y, len); do { *p = v; p = p->next(); } while (--len); } //-------------------------------------------------------------------- AGG_INLINE void copy_vline(int x, int y, unsigned len, const color_type& c) { pixel_type v; v.set(c); do { *pix_value_ptr(x, y++, 1) = v; } while (--len); } //-------------------------------------------------------------------- void blend_hline(int x, int y, unsigned len, const color_type& c, int8u cover) { if (!c.is_transparent()) { pixel_type* p = pix_value_ptr(x, y, len); if (c.is_opaque() && cover == cover_mask) { pixel_type v; v.set(c); do { *p = v; p = p->next(); } while (--len); } else { if (cover == cover_mask) { do { blend_pix(p, c); p = p->next(); } while (--len); } else { do { blend_pix(p, c, cover); p = p->next(); } while (--len); } } } } //-------------------------------------------------------------------- void blend_vline(int x, int y, unsigned len, const color_type& c, int8u cover) { if (!c.is_transparent()) { if (c.is_opaque() && cover == cover_mask) { pixel_type v; v.set(c); do { *pix_value_ptr(x, y++, 1) = v; } while (--len); } else { if (cover == cover_mask) { do { blend_pix(pix_value_ptr(x, y++, 1), c, c.a); } while (--len); } else { do { blend_pix(pix_value_ptr(x, y++, 1), c, cover); } while (--len); } } } } //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { if (!c.is_transparent()) { pixel_type* p = pix_value_ptr(x, y, len); do { if (c.is_opaque() && *covers == cover_mask) { p->set(c); } else { blend_pix(p, c, *covers); } p = p->next(); ++covers; } while (--len); } } //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { if (!c.is_transparent()) { do { pixel_type* p = pix_value_ptr(x, y++, 1); if (c.is_opaque() && *covers == cover_mask) { p->set(c); } else { blend_pix(p, c, *covers); } ++covers; } while (--len); } } //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, unsigned len, const color_type* colors) { pixel_type* p = pix_value_ptr(x, y, len); do { p->set(*colors++); p = p->next(); } while (--len); } //-------------------------------------------------------------------- void copy_color_vspan(int x, int y, unsigned len, const color_type* colors) { do { pix_value_ptr(x, y++, 1)->set(*colors++); } while (--len); } //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { pixel_type* p = pix_value_ptr(x, y, len); if (covers) { do { copy_or_blend_pix(p, *colors++, *covers++); p = p->next(); } while (--len); } else { if (cover == cover_mask) { do { copy_or_blend_pix(p, *colors++); p = p->next(); } while (--len); } else { do { copy_or_blend_pix(p, *colors++, cover); p = p->next(); } while (--len); } } } //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { if (covers) { do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); } while (--len); } else { if (cover == cover_mask) { do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); } while (--len); } else { do { copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); } while (--len); } } } //-------------------------------------------------------------------- template void for_each_pixel(Function f) { for (unsigned y = 0; y < height(); ++y) { row_data r = m_rbuf->row(y); if (r.ptr) { unsigned len = r.x2 - r.x1 + 1; pixel_type* p = pix_value_ptr(r.x1, y, len); do { f(p->c); p = p->next(); } while (--len); } } } //-------------------------------------------------------------------- void premultiply() { for_each_pixel(multiplier_rgba::premultiply); } //-------------------------------------------------------------------- void demultiply() { for_each_pixel(multiplier_rgba::demultiply); } //-------------------------------------------------------------------- template void apply_gamma_dir(const GammaLut& g) { for_each_pixel(apply_gamma_dir_rgba(g)); } //-------------------------------------------------------------------- template void apply_gamma_inv(const GammaLut& g) { for_each_pixel(apply_gamma_inv_rgba(g)); } //-------------------------------------------------------------------- template void copy_from(const RenBuf2& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len) { if (const int8u* p = from.row_ptr(ysrc)) { std::memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, p + xsrc * pix_width, len * pix_width); } } //-------------------------------------------------------------------- // Blend from another RGBA surface. template void blend_from(const SrcPixelFormatRenderer& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); int srcinc = 1; int dstinc = 1; if (xdst > xsrc) { psrc = psrc->advance(len - 1); pdst = pdst->advance(len - 1); srcinc = -1; dstinc = -1; } if (cover == cover_mask) { do { copy_or_blend_pix(pdst, psrc->get()); psrc = psrc->advance(srcinc); pdst = pdst->advance(dstinc); } while (--len); } else { do { copy_or_blend_pix(pdst, psrc->get(), cover); psrc = psrc->advance(srcinc); pdst = pdst->advance(dstinc); } while (--len); } } } //-------------------------------------------------------------------- // Combine single color with grayscale surface and blend. template void blend_from_color(const SrcPixelFormatRenderer& from, const color_type& color, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; typedef typename SrcPixelFormatRenderer::color_type src_color_type; if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); do { copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); psrc = psrc->next(); pdst = pdst->next(); } while (--len); } } //-------------------------------------------------------------------- // Blend from color table, using grayscale surface as indexes into table. // Obviously, this only works for integer value types. template void blend_from_lut(const SrcPixelFormatRenderer& from, const color_type* color_lut, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); if (cover == cover_mask) { do { copy_or_blend_pix(pdst, color_lut[psrc->c[0]]); psrc = psrc->next(); pdst = pdst->next(); } while (--len); } else { do { copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); psrc = psrc->next(); pdst = pdst->next(); } while (--len); } } } private: rbuf_type* m_rbuf; Blender m_blender; }; //================================================pixfmt_custom_blend_rgba template class pixfmt_custom_blend_rgba { public: typedef pixfmt_rgba_tag pixfmt_category; typedef RenBuf rbuf_type; typedef typename rbuf_type::row_data row_data; typedef Blender blender_type; typedef typename blender_type::color_type color_type; typedef typename blender_type::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; enum { num_components = 4, pix_step = 4, pix_width = sizeof(value_type) * pix_step, }; struct pixel_type { value_type c[num_components]; void set(value_type r, value_type g, value_type b, value_type a) { c[order_type::R] = r; c[order_type::G] = g; c[order_type::B] = b; c[order_type::A] = a; } void set(const color_type& color) { set(color.r, color.g, color.b, color.a); } void get(value_type& r, value_type& g, value_type& b, value_type& a) const { r = c[order_type::R]; g = c[order_type::G]; b = c[order_type::B]; a = c[order_type::A]; } color_type get() const { return color_type( c[order_type::R], c[order_type::G], c[order_type::B], c[order_type::A]); } pixel_type* next() { return (pixel_type*)(c + pix_step); } const pixel_type* next() const { return (const pixel_type*)(c + pix_step); } pixel_type* advance(int n) { return (pixel_type*)(c + n * pix_step); } const pixel_type* advance(int n) const { return (const pixel_type*)(c + n * pix_step); } }; private: //-------------------------------------------------------------------- AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover = cover_full) { m_blender.blend_pix(m_comp_op, p->c, c.r, c.g, c.b, c.a, cover); } //-------------------------------------------------------------------- AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover = cover_full) { if (!c.is_transparent()) { if (c.is_opaque() && cover == cover_mask) { p->set(c.r, c.g, c.b, c.a); } else { blend_pix(p, c, cover); } } } public: //-------------------------------------------------------------------- pixfmt_custom_blend_rgba() : m_rbuf(0), m_comp_op(3) {} explicit pixfmt_custom_blend_rgba(rbuf_type& rb, unsigned comp_op=3) : m_rbuf(&rb), m_comp_op(comp_op) {} void attach(rbuf_type& rb) { m_rbuf = &rb; } //-------------------------------------------------------------------- template bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) { rect_i r(x1, y1, x2, y2); if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) { int stride = pixf.stride(); m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), (r.x2 - r.x1) + 1, (r.y2 - r.y1) + 1, stride); return true; } return false; } //-------------------------------------------------------------------- void comp_op(unsigned op) { m_comp_op = op; } unsigned comp_op() const { return m_comp_op; } //-------------------------------------------------------------------- AGG_INLINE unsigned width() const { return m_rbuf->width(); } AGG_INLINE unsigned height() const { return m_rbuf->height(); } AGG_INLINE int stride() const { return m_rbuf->stride(); } //-------------------------------------------------------------------- AGG_INLINE int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } AGG_INLINE row_data row(int y) const { return m_rbuf->row(y); } //-------------------------------------------------------------------- AGG_INLINE int8u* pix_ptr(int x, int y) { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step); } AGG_INLINE const int8u* pix_ptr(int x, int y) const { return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step); } // Return pointer to pixel value, forcing row to be allocated. AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len) { return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step)); } // Return pointer to pixel value, or null if row not allocated. AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const { int8u* p = m_rbuf->row_ptr(y); return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step)) : 0; } // Get pixel pointer from raw buffer pointer. AGG_INLINE static pixel_type* pix_value_ptr(void* p) { return (pixel_type*)p; } // Get pixel pointer from raw buffer pointer. AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) { return (const pixel_type*)p; } //-------------------------------------------------------------------- AGG_INLINE static void make_pix(int8u* p, const color_type& c) { ((pixel_type*)p)->set(c); } //-------------------------------------------------------------------- AGG_INLINE color_type pixel(int x, int y) const { if (const pixel_type* p = pix_value_ptr(x, y)) { return p->get(); } return color_type::no_color(); } //-------------------------------------------------------------------- AGG_INLINE void copy_pixel(int x, int y, const color_type& c) { make_pix(pix_value_ptr(x, y, 1), c); } //-------------------------------------------------------------------- AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) { blend_pix(pix_value_ptr(x, y, 1), c, cover); } //-------------------------------------------------------------------- AGG_INLINE void copy_hline(int x, int y, unsigned len, const color_type& c) { pixel_type v; v.set(c); pixel_type* p = pix_value_ptr(x, y, len); do { *p = v; p = p->next(); } while (--len); } //-------------------------------------------------------------------- AGG_INLINE void copy_vline(int x, int y, unsigned len, const color_type& c) { pixel_type v; v.set(c); do { *pix_value_ptr(x, y++, 1) = v; } while (--len); } //-------------------------------------------------------------------- void blend_hline(int x, int y, unsigned len, const color_type& c, int8u cover) { pixel_type* p = pix_value_ptr(x, y, len); do { blend_pix(p, c, cover); p = p->next(); } while (--len); } //-------------------------------------------------------------------- void blend_vline(int x, int y, unsigned len, const color_type& c, int8u cover) { do { blend_pix(pix_value_ptr(x, y++, 1), c, cover); } while (--len); } //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { pixel_type* p = pix_value_ptr(x, y, len); do { blend_pix(p, c, *covers++); p = p->next(); } while (--len); } //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { do { blend_pix(pix_value_ptr(x, y++, 1), c, *covers++); } while (--len); } //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, unsigned len, const color_type* colors) { pixel_type* p = pix_value_ptr(x, y, len); do { p->set(*colors++); p = p->next(); } while (--len); } //-------------------------------------------------------------------- void copy_color_vspan(int x, int y, unsigned len, const color_type* colors) { do { pix_value_ptr(x, y++, 1)->set(*colors++); } while (--len); } //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { pixel_type* p = pix_value_ptr(x, y, len); do { blend_pix(p, *colors++, covers ? *covers++ : cover); p = p->next(); } while (--len); } //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, unsigned len, const color_type* colors, const int8u* covers, int8u cover) { do { blend_pix(pix_value_ptr(x, y++, 1), *colors++, covers ? *covers++ : cover); } while (--len); } //-------------------------------------------------------------------- template void for_each_pixel(Function f) { unsigned y; for (y = 0; y < height(); ++y) { row_data r = m_rbuf->row(y); if (r.ptr) { unsigned len = r.x2 - r.x1 + 1; pixel_type* p = pix_value_ptr(r.x1, y, len); do { f(p->c); p = p->next(); } while (--len); } } } //-------------------------------------------------------------------- void premultiply() { for_each_pixel(multiplier_rgba::premultiply); } //-------------------------------------------------------------------- void demultiply() { for_each_pixel(multiplier_rgba::demultiply); } //-------------------------------------------------------------------- template void apply_gamma_dir(const GammaLut& g) { for_each_pixel(apply_gamma_dir_rgba(g)); } //-------------------------------------------------------------------- template void apply_gamma_inv(const GammaLut& g) { for_each_pixel(apply_gamma_inv_rgba(g)); } //-------------------------------------------------------------------- template void copy_from(const RenBuf2& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len) { if (const int8u* p = from.row_ptr(ysrc)) { std::memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, p + xsrc * pix_width, len * pix_width); } } //-------------------------------------------------------------------- // Blend from another RGBA surface. template void blend_from(const SrcPixelFormatRenderer& from, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); int srcinc = 1; int dstinc = 1; if (xdst > xsrc) { psrc = psrc->advance(len - 1); pdst = pdst->advance(len - 1); srcinc = -1; dstinc = -1; } do { blend_pix(pdst, psrc->get(), cover); psrc = psrc->advance(srcinc); pdst = pdst->advance(dstinc); } while (--len); } } //-------------------------------------------------------------------- // Blend from single color, using grayscale surface as alpha channel. template void blend_from_color(const SrcPixelFormatRenderer& from, const color_type& color, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; typedef typename SrcPixelFormatRenderer::color_type src_color_type; if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); do { blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); psrc = psrc->next(); pdst = pdst->next(); } while (--len); } } //-------------------------------------------------------------------- // Blend from color table, using grayscale surface as indexes into table. // Obviously, this only works for integer value types. template void blend_from_lut(const SrcPixelFormatRenderer& from, const color_type* color_lut, int xdst, int ydst, int xsrc, int ysrc, unsigned len, int8u cover) { typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { pixel_type* pdst = pix_value_ptr(xdst, ydst, len); do { blend_pix(pdst, color_lut[psrc->c[0]], cover); psrc = psrc->next(); pdst = pdst->next(); } while (--len); } } private: rbuf_type* m_rbuf; Blender m_blender; unsigned m_comp_op; }; //----------------------------------------------------------------------- typedef blender_rgba blender_rgba32; typedef blender_rgba blender_argb32; typedef blender_rgba blender_abgr32; typedef blender_rgba blender_bgra32; typedef blender_rgba blender_srgba32; typedef blender_rgba blender_sargb32; typedef blender_rgba blender_sabgr32; typedef blender_rgba blender_sbgra32; typedef blender_rgba_pre blender_rgba32_pre; typedef blender_rgba_pre blender_argb32_pre; typedef blender_rgba_pre blender_abgr32_pre; typedef blender_rgba_pre blender_bgra32_pre; typedef blender_rgba_pre blender_srgba32_pre; typedef blender_rgba_pre blender_sargb32_pre; typedef blender_rgba_pre blender_sabgr32_pre; typedef blender_rgba_pre blender_sbgra32_pre; typedef blender_rgba_plain blender_rgba32_plain; typedef blender_rgba_plain blender_argb32_plain; typedef blender_rgba_plain blender_abgr32_plain; typedef blender_rgba_plain blender_bgra32_plain; typedef blender_rgba_plain blender_srgba32_plain; typedef blender_rgba_plain blender_sargb32_plain; typedef blender_rgba_plain blender_sabgr32_plain; typedef blender_rgba_plain blender_sbgra32_plain; typedef blender_rgba blender_rgba64; typedef blender_rgba blender_argb64; typedef blender_rgba blender_abgr64; typedef blender_rgba blender_bgra64; typedef blender_rgba_pre blender_rgba64_pre; typedef blender_rgba_pre blender_argb64_pre; typedef blender_rgba_pre blender_abgr64_pre; typedef blender_rgba_pre blender_bgra64_pre; typedef blender_rgba_plain blender_rgba64_plain; typedef blender_rgba_plain blender_argb64_plain; typedef blender_rgba_plain blender_abgr64_plain; typedef blender_rgba_plain blender_bgra64_plain; typedef blender_rgba blender_rgba128; typedef blender_rgba blender_argb128; typedef blender_rgba blender_abgr128; typedef blender_rgba blender_bgra128; typedef blender_rgba_pre blender_rgba128_pre; typedef blender_rgba_pre blender_argb128_pre; typedef blender_rgba_pre blender_abgr128_pre; typedef blender_rgba_pre blender_bgra128_pre; typedef blender_rgba_plain blender_rgba128_plain; typedef blender_rgba_plain blender_argb128_plain; typedef blender_rgba_plain blender_abgr128_plain; typedef blender_rgba_plain blender_bgra128_plain; //----------------------------------------------------------------------- typedef pixfmt_alpha_blend_rgba pixfmt_rgba32; typedef pixfmt_alpha_blend_rgba pixfmt_argb32; typedef pixfmt_alpha_blend_rgba pixfmt_abgr32; typedef pixfmt_alpha_blend_rgba pixfmt_bgra32; typedef pixfmt_alpha_blend_rgba pixfmt_srgba32; typedef pixfmt_alpha_blend_rgba pixfmt_sargb32; typedef pixfmt_alpha_blend_rgba pixfmt_sabgr32; typedef pixfmt_alpha_blend_rgba pixfmt_sbgra32; typedef pixfmt_alpha_blend_rgba pixfmt_rgba32_pre; typedef pixfmt_alpha_blend_rgba pixfmt_argb32_pre; typedef pixfmt_alpha_blend_rgba pixfmt_abgr32_pre; typedef pixfmt_alpha_blend_rgba pixfmt_bgra32_pre; typedef pixfmt_alpha_blend_rgba pixfmt_srgba32_pre; typedef pixfmt_alpha_blend_rgba pixfmt_sargb32_pre; typedef pixfmt_alpha_blend_rgba pixfmt_sabgr32_pre; typedef pixfmt_alpha_blend_rgba pixfmt_sbgra32_pre; typedef pixfmt_alpha_blend_rgba pixfmt_rgba32_plain; typedef pixfmt_alpha_blend_rgba pixfmt_argb32_plain; typedef pixfmt_alpha_blend_rgba pixfmt_abgr32_plain; typedef pixfmt_alpha_blend_rgba pixfmt_bgra32_plain; typedef pixfmt_alpha_blend_rgba pixfmt_srgba32_plain; typedef pixfmt_alpha_blend_rgba pixfmt_sargb32_plain; typedef pixfmt_alpha_blend_rgba pixfmt_sabgr32_plain; typedef pixfmt_alpha_blend_rgba pixfmt_sbgra32_plain; typedef pixfmt_alpha_blend_rgba pixfmt_rgba64; typedef pixfmt_alpha_blend_rgba pixfmt_argb64; typedef pixfmt_alpha_blend_rgba pixfmt_abgr64; typedef pixfmt_alpha_blend_rgba pixfmt_bgra64; typedef pixfmt_alpha_blend_rgba pixfmt_rgba64_pre; typedef pixfmt_alpha_blend_rgba pixfmt_argb64_pre; typedef pixfmt_alpha_blend_rgba pixfmt_abgr64_pre; typedef pixfmt_alpha_blend_rgba pixfmt_bgra64_pre; typedef pixfmt_alpha_blend_rgba pixfmt_rgba64_plain; typedef pixfmt_alpha_blend_rgba pixfmt_argb64_plain; typedef pixfmt_alpha_blend_rgba pixfmt_abgr64_plain; typedef pixfmt_alpha_blend_rgba pixfmt_bgra64_plain; typedef pixfmt_alpha_blend_rgba pixfmt_rgba128; typedef pixfmt_alpha_blend_rgba pixfmt_argb128; typedef pixfmt_alpha_blend_rgba pixfmt_abgr128; typedef pixfmt_alpha_blend_rgba pixfmt_bgra128; typedef pixfmt_alpha_blend_rgba pixfmt_rgba128_pre; typedef pixfmt_alpha_blend_rgba pixfmt_argb128_pre; typedef pixfmt_alpha_blend_rgba pixfmt_abgr128_pre; typedef pixfmt_alpha_blend_rgba pixfmt_bgra128_pre; typedef pixfmt_alpha_blend_rgba pixfmt_rgba128_plain; typedef pixfmt_alpha_blend_rgba pixfmt_argb128_plain; typedef pixfmt_alpha_blend_rgba pixfmt_abgr128_plain; typedef pixfmt_alpha_blend_rgba pixfmt_bgra128_plain; } #endif ragg/src/agg/include/agg_rasterizer_outline.h0000644000176200001440000001024413504406270021064 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_RASTERIZER_OUTLINE_INCLUDED #define AGG_RASTERIZER_OUTLINE_INCLUDED #include "agg_basics.h" namespace agg { //======================================================rasterizer_outline template class rasterizer_outline { public: explicit rasterizer_outline(Renderer& ren) : m_ren(&ren), m_start_x(0), m_start_y(0), m_vertices(0) {} void attach(Renderer& ren) { m_ren = &ren; } //-------------------------------------------------------------------- void move_to(int x, int y) { m_vertices = 1; m_ren->move_to(m_start_x = x, m_start_y = y); } //-------------------------------------------------------------------- void line_to(int x, int y) { ++m_vertices; m_ren->line_to(x, y); } //-------------------------------------------------------------------- void move_to_d(double x, double y) { move_to(m_ren->coord(x), m_ren->coord(y)); } //-------------------------------------------------------------------- void line_to_d(double x, double y) { line_to(m_ren->coord(x), m_ren->coord(y)); } //-------------------------------------------------------------------- void close() { if(m_vertices > 2) { line_to(m_start_x, m_start_y); } m_vertices = 0; } //-------------------------------------------------------------------- void add_vertex(double x, double y, unsigned cmd) { if(is_move_to(cmd)) { move_to_d(x, y); } else { if(is_end_poly(cmd)) { if(is_closed(cmd)) close(); } else { line_to_d(x, y); } } } //-------------------------------------------------------------------- template void add_path(VertexSource& vs, unsigned path_id=0) { double x; double y; unsigned cmd; vs.rewind(path_id); while(!is_stop(cmd = vs.vertex(&x, &y))) { add_vertex(x, y, cmd); } } //-------------------------------------------------------------------- template void render_all_paths(VertexSource& vs, const ColorStorage& colors, const PathId& path_id, unsigned num_paths) { for(unsigned i = 0; i < num_paths; i++) { m_ren->line_color(colors[i]); add_path(vs, path_id[i]); } } //-------------------------------------------------------------------- template void render_ctrl(Ctrl& c) { unsigned i; for(i = 0; i < c.num_paths(); i++) { m_ren->line_color(c.color(i)); add_path(c, i); } } private: Renderer* m_ren; int m_start_x; int m_start_y; unsigned m_vertices; }; } #endif ragg/src/agg/include/agg_gradient_lut.h0000644000176200001440000001663113504406270017622 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_GRADIENT_LUT_INCLUDED #define AGG_GRADIENT_LUT_INCLUDED #include "agg_array.h" #include "agg_dda_line.h" #include "agg_color_rgba.h" #include "agg_color_gray.h" namespace agg { //======================================================color_interpolator template struct color_interpolator { public: typedef ColorT color_type; color_interpolator(const color_type& c1, const color_type& c2, unsigned len) : m_c1(c1), m_c2(c2), m_len(len), m_count(0) {} void operator ++ () { ++m_count; } color_type color() const { return m_c1.gradient(m_c2, double(m_count) / m_len); } private: color_type m_c1; color_type m_c2; unsigned m_len; unsigned m_count; }; //======================================================================== // Fast specialization for rgba8 template<> struct color_interpolator { public: typedef rgba8 color_type; color_interpolator(const color_type& c1, const color_type& c2, unsigned len) : r(c1.r, c2.r, len), g(c1.g, c2.g, len), b(c1.b, c2.b, len), a(c1.a, c2.a, len) {} void operator ++ () { ++r; ++g; ++b; ++a; } color_type color() const { return color_type(r.y(), g.y(), b.y(), a.y()); } private: agg::dda_line_interpolator<14> r, g, b, a; }; //======================================================================== // Fast specialization for gray8 template<> struct color_interpolator { public: typedef gray8 color_type; color_interpolator(const color_type& c1, const color_type& c2, unsigned len) : v(c1.v, c2.v, len), a(c1.a, c2.a, len) {} void operator ++ () { ++v; ++a; } color_type color() const { return color_type(v.y(), a.y()); } private: agg::dda_line_interpolator<14> v,a; }; //============================================================gradient_lut template class gradient_lut { public: typedef ColorInterpolator interpolator_type; typedef typename interpolator_type::color_type color_type; enum { color_lut_size = ColorLutSize }; //-------------------------------------------------------------------- gradient_lut() : m_color_lut(color_lut_size) {} // Build Gradient Lut // First, call remove_all(), then add_color() at least twice, // then build_lut(). Argument "offset" in add_color must be // in range [0...1] and defines a color stop as it is described // in SVG specification, section Gradients and Patterns. // The simplest linear gradient is: // gradient_lut.add_color(0.0, start_color); // gradient_lut.add_color(1.0, end_color); //-------------------------------------------------------------------- void remove_all(); void add_color(double offset, const color_type& color); void build_lut(); // Size-index Interface. This class can be used directly as the // ColorF in span_gradient. All it needs is two access methods // size() and operator []. //-------------------------------------------------------------------- static unsigned size() { return color_lut_size; } const color_type& operator [] (unsigned i) const { return m_color_lut[i]; } private: //-------------------------------------------------------------------- struct color_point { double offset; color_type color; color_point() {} color_point(double off, const color_type& c) : offset(off), color(c) { if(offset < 0.0) offset = 0.0; if(offset > 1.0) offset = 1.0; } }; typedef agg::pod_bvector color_profile_type; typedef agg::pod_array color_lut_type; static bool offset_less(const color_point& a, const color_point& b) { return a.offset < b.offset; } static bool offset_equal(const color_point& a, const color_point& b) { return a.offset == b.offset; } //-------------------------------------------------------------------- color_profile_type m_color_profile; color_lut_type m_color_lut; }; //------------------------------------------------------------------------ template void gradient_lut::remove_all() { m_color_profile.remove_all(); } //------------------------------------------------------------------------ template void gradient_lut::add_color(double offset, const color_type& color) { m_color_profile.add(color_point(offset, color)); } //------------------------------------------------------------------------ template void gradient_lut::build_lut() { quick_sort(m_color_profile, offset_less); m_color_profile.cut_at(remove_duplicates(m_color_profile, offset_equal)); if(m_color_profile.size() >= 2) { unsigned i; unsigned start = uround(m_color_profile[0].offset * color_lut_size); unsigned end; color_type c = m_color_profile[0].color; for(i = 0; i < start; i++) { m_color_lut[i] = c; } for(i = 1; i < m_color_profile.size(); i++) { end = uround(m_color_profile[i].offset * color_lut_size); interpolator_type ci(m_color_profile[i-1].color, m_color_profile[i ].color, end - start + 1); while(start < end) { m_color_lut[start] = ci.color(); ++ci; ++start; } } c = m_color_profile.last().color; for(; end < m_color_lut.size(); end++) { m_color_lut[end] = c; } } } } #endif ragg/src/agg/include/agg_path_storage.h0000644000176200001440000014461413504406270017624 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_PATH_STORAGE_INCLUDED #define AGG_PATH_STORAGE_INCLUDED #include #include "agg_math.h" #include "agg_array.h" #include "agg_bezier_arc.h" namespace agg { //----------------------------------------------------vertex_block_storage template class vertex_block_storage { public: // Allocation parameters enum block_scale_e { block_shift = BlockShift, block_size = 1 << block_shift, block_mask = block_size - 1, block_pool = BlockPool }; typedef T value_type; typedef vertex_block_storage self_type; ~vertex_block_storage(); vertex_block_storage(); vertex_block_storage(const self_type& v); const self_type& operator = (const self_type& ps); void remove_all(); void free_all(); void add_vertex(double x, double y, unsigned cmd); void modify_vertex(unsigned idx, double x, double y); void modify_vertex(unsigned idx, double x, double y, unsigned cmd); void modify_command(unsigned idx, unsigned cmd); void swap_vertices(unsigned v1, unsigned v2); unsigned last_command() const; unsigned last_vertex(double* x, double* y) const; unsigned prev_vertex(double* x, double* y) const; double last_x() const; double last_y() const; unsigned total_vertices() const; unsigned vertex(unsigned idx, double* x, double* y) const; unsigned command(unsigned idx) const; private: void allocate_block(unsigned nb); int8u* storage_ptrs(T** xy_ptr); private: unsigned m_total_vertices; unsigned m_total_blocks; unsigned m_max_blocks; T** m_coord_blocks; int8u** m_cmd_blocks; }; //------------------------------------------------------------------------ template void vertex_block_storage::free_all() { if(m_total_blocks) { T** coord_blk = m_coord_blocks + m_total_blocks - 1; while(m_total_blocks--) { pod_allocator::deallocate( *coord_blk, block_size * 2 + block_size / (sizeof(T) / sizeof(unsigned char))); --coord_blk; } pod_allocator::deallocate(m_coord_blocks, m_max_blocks * 2); m_total_blocks = 0; m_max_blocks = 0; m_coord_blocks = 0; m_cmd_blocks = 0; m_total_vertices = 0; } } //------------------------------------------------------------------------ template vertex_block_storage::~vertex_block_storage() { free_all(); } //------------------------------------------------------------------------ template vertex_block_storage::vertex_block_storage() : m_total_vertices(0), m_total_blocks(0), m_max_blocks(0), m_coord_blocks(0), m_cmd_blocks(0) { } //------------------------------------------------------------------------ template vertex_block_storage::vertex_block_storage(const vertex_block_storage& v) : m_total_vertices(0), m_total_blocks(0), m_max_blocks(0), m_coord_blocks(0), m_cmd_blocks(0) { *this = v; } //------------------------------------------------------------------------ template const vertex_block_storage& vertex_block_storage::operator = (const vertex_block_storage& v) { remove_all(); unsigned i; for(i = 0; i < v.total_vertices(); i++) { double x, y; unsigned cmd = v.vertex(i, &x, &y); add_vertex(x, y, cmd); } return *this; } //------------------------------------------------------------------------ template inline void vertex_block_storage::remove_all() { m_total_vertices = 0; } //------------------------------------------------------------------------ template inline void vertex_block_storage::add_vertex(double x, double y, unsigned cmd) { T* coord_ptr = 0; *storage_ptrs(&coord_ptr) = (int8u)cmd; coord_ptr[0] = T(x); coord_ptr[1] = T(y); m_total_vertices++; } //------------------------------------------------------------------------ template inline void vertex_block_storage::modify_vertex(unsigned idx, double x, double y) { T* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1); pv[0] = T(x); pv[1] = T(y); } //------------------------------------------------------------------------ template inline void vertex_block_storage::modify_vertex(unsigned idx, double x, double y, unsigned cmd) { unsigned block = idx >> block_shift; unsigned offset = idx & block_mask; T* pv = m_coord_blocks[block] + (offset << 1); pv[0] = T(x); pv[1] = T(y); m_cmd_blocks[block][offset] = (int8u)cmd; } //------------------------------------------------------------------------ template inline void vertex_block_storage::modify_command(unsigned idx, unsigned cmd) { m_cmd_blocks[idx >> block_shift][idx & block_mask] = (int8u)cmd; } //------------------------------------------------------------------------ template inline void vertex_block_storage::swap_vertices(unsigned v1, unsigned v2) { unsigned b1 = v1 >> block_shift; unsigned b2 = v2 >> block_shift; unsigned o1 = v1 & block_mask; unsigned o2 = v2 & block_mask; T* pv1 = m_coord_blocks[b1] + (o1 << 1); T* pv2 = m_coord_blocks[b2] + (o2 << 1); T val; val = pv1[0]; pv1[0] = pv2[0]; pv2[0] = val; val = pv1[1]; pv1[1] = pv2[1]; pv2[1] = val; int8u cmd = m_cmd_blocks[b1][o1]; m_cmd_blocks[b1][o1] = m_cmd_blocks[b2][o2]; m_cmd_blocks[b2][o2] = cmd; } //------------------------------------------------------------------------ template inline unsigned vertex_block_storage::last_command() const { if(m_total_vertices) return command(m_total_vertices - 1); return path_cmd_stop; } //------------------------------------------------------------------------ template inline unsigned vertex_block_storage::last_vertex(double* x, double* y) const { if(m_total_vertices) return vertex(m_total_vertices - 1, x, y); return path_cmd_stop; } //------------------------------------------------------------------------ template inline unsigned vertex_block_storage::prev_vertex(double* x, double* y) const { if(m_total_vertices > 1) return vertex(m_total_vertices - 2, x, y); return path_cmd_stop; } //------------------------------------------------------------------------ template inline double vertex_block_storage::last_x() const { if(m_total_vertices) { unsigned idx = m_total_vertices - 1; return m_coord_blocks[idx >> block_shift][(idx & block_mask) << 1]; } return 0.0; } //------------------------------------------------------------------------ template inline double vertex_block_storage::last_y() const { if(m_total_vertices) { unsigned idx = m_total_vertices - 1; return m_coord_blocks[idx >> block_shift][((idx & block_mask) << 1) + 1]; } return 0.0; } //------------------------------------------------------------------------ template inline unsigned vertex_block_storage::total_vertices() const { return m_total_vertices; } //------------------------------------------------------------------------ template inline unsigned vertex_block_storage::vertex(unsigned idx, double* x, double* y) const { unsigned nb = idx >> block_shift; const T* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1); *x = pv[0]; *y = pv[1]; return m_cmd_blocks[nb][idx & block_mask]; } //------------------------------------------------------------------------ template inline unsigned vertex_block_storage::command(unsigned idx) const { return m_cmd_blocks[idx >> block_shift][idx & block_mask]; } //------------------------------------------------------------------------ template void vertex_block_storage::allocate_block(unsigned nb) { if(nb >= m_max_blocks) { T** new_coords = pod_allocator::allocate((m_max_blocks + block_pool) * 2); unsigned char** new_cmds = (unsigned char**)(new_coords + m_max_blocks + block_pool); if(m_coord_blocks) { std::memcpy(new_coords, m_coord_blocks, m_max_blocks * sizeof(T*)); std::memcpy(new_cmds, m_cmd_blocks, m_max_blocks * sizeof(unsigned char*)); pod_allocator::deallocate(m_coord_blocks, m_max_blocks * 2); } m_coord_blocks = new_coords; m_cmd_blocks = new_cmds; m_max_blocks += block_pool; } m_coord_blocks[nb] = pod_allocator::allocate(block_size * 2 + block_size / (sizeof(T) / sizeof(unsigned char))); m_cmd_blocks[nb] = (unsigned char*)(m_coord_blocks[nb] + block_size * 2); m_total_blocks++; } //------------------------------------------------------------------------ template int8u* vertex_block_storage::storage_ptrs(T** xy_ptr) { unsigned nb = m_total_vertices >> block_shift; if(nb >= m_total_blocks) { allocate_block(nb); } *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1); return m_cmd_blocks[nb] + (m_total_vertices & block_mask); } //-----------------------------------------------------poly_plain_adaptor template class poly_plain_adaptor { public: typedef T value_type; poly_plain_adaptor() : m_data(0), m_ptr(0), m_end(0), m_closed(false), m_stop(false) {} poly_plain_adaptor(const T* data, unsigned num_points, bool closed) : m_data(data), m_ptr(data), m_end(data + num_points * 2), m_closed(closed), m_stop(false) {} void init(const T* data, unsigned num_points, bool closed) { m_data = data; m_ptr = data; m_end = data + num_points * 2; m_closed = closed; m_stop = false; } void rewind(unsigned) { m_ptr = m_data; m_stop = false; } unsigned vertex(double* x, double* y) { if(m_ptr < m_end) { bool first = m_ptr == m_data; *x = *m_ptr++; *y = *m_ptr++; return first ? path_cmd_move_to : path_cmd_line_to; } *x = *y = 0.0; if(m_closed && !m_stop) { m_stop = true; return path_cmd_end_poly | path_flags_close; } return path_cmd_stop; } private: const T* m_data; const T* m_ptr; const T* m_end; bool m_closed; bool m_stop; }; //-------------------------------------------------poly_container_adaptor template class poly_container_adaptor { public: typedef typename Container::value_type vertex_type; poly_container_adaptor() : m_container(0), m_index(0), m_closed(false), m_stop(false) {} poly_container_adaptor(const Container& data, bool closed) : m_container(&data), m_index(0), m_closed(closed), m_stop(false) {} void init(const Container& data, bool closed) { m_container = &data; m_index = 0; m_closed = closed; m_stop = false; } void rewind(unsigned) { m_index = 0; m_stop = false; } unsigned vertex(double* x, double* y) { if(m_index < m_container->size()) { bool first = m_index == 0; const vertex_type& v = (*m_container)[m_index++]; *x = v.x; *y = v.y; return first ? path_cmd_move_to : path_cmd_line_to; } *x = *y = 0.0; if(m_closed && !m_stop) { m_stop = true; return path_cmd_end_poly | path_flags_close; } return path_cmd_stop; } private: const Container* m_container; unsigned m_index; bool m_closed; bool m_stop; }; //-----------------------------------------poly_container_reverse_adaptor template class poly_container_reverse_adaptor { public: typedef typename Container::value_type vertex_type; poly_container_reverse_adaptor() : m_container(0), m_index(-1), m_closed(false), m_stop(false) {} poly_container_reverse_adaptor(Container& data, bool closed) : m_container(&data), m_index(-1), m_closed(closed), m_stop(false) {} void init(Container& data, bool closed) { m_container = &data; m_index = m_container->size() - 1; m_closed = closed; m_stop = false; } void rewind(unsigned) { m_index = m_container->size() - 1; m_stop = false; } unsigned vertex(double* x, double* y) { if(m_index >= 0) { bool first = m_index == int(m_container->size() - 1); const vertex_type& v = (*m_container)[m_index--]; *x = v.x; *y = v.y; return first ? path_cmd_move_to : path_cmd_line_to; } *x = *y = 0.0; if(m_closed && !m_stop) { m_stop = true; return path_cmd_end_poly | path_flags_close; } return path_cmd_stop; } private: Container* m_container; int m_index; bool m_closed; bool m_stop; }; //--------------------------------------------------------line_adaptor class line_adaptor { public: typedef double value_type; line_adaptor() : m_line(m_coord, 2, false) {} line_adaptor(double x1, double y1, double x2, double y2) : m_line(m_coord, 2, false) { m_coord[0] = x1; m_coord[1] = y1; m_coord[2] = x2; m_coord[3] = y2; } void init(double x1, double y1, double x2, double y2) { m_coord[0] = x1; m_coord[1] = y1; m_coord[2] = x2; m_coord[3] = y2; m_line.rewind(0); } void rewind(unsigned) { m_line.rewind(0); } unsigned vertex(double* x, double* y) { return m_line.vertex(x, y); } private: double m_coord[4]; poly_plain_adaptor m_line; }; //---------------------------------------------------------------path_base // A container to store vertices with their flags. // A path consists of a number of contours separated with "move_to" // commands. The path storage can keep and maintain more than one // path. // To navigate to the beginning of a particular path, use rewind(path_id); // Where path_id is what start_new_path() returns. So, when you call // start_new_path() you need to store its return value somewhere else // to navigate to the path afterwards. // // See also: vertex_source concept //------------------------------------------------------------------------ template class path_base { public: typedef VertexContainer container_type; typedef path_base self_type; //-------------------------------------------------------------------- path_base() : m_vertices(), m_iterator(0) {} void remove_all() { m_vertices.remove_all(); m_iterator = 0; } void free_all() { m_vertices.free_all(); m_iterator = 0; } // Make path functions //-------------------------------------------------------------------- unsigned start_new_path(); void move_to(double x, double y); void move_rel(double dx, double dy); void line_to(double x, double y); void line_rel(double dx, double dy); void hline_to(double x); void hline_rel(double dx); void vline_to(double y); void vline_rel(double dy); void arc_to(double rx, double ry, double angle, bool large_arc_flag, bool sweep_flag, double x, double y); void arc_rel(double rx, double ry, double angle, bool large_arc_flag, bool sweep_flag, double dx, double dy); void curve3(double x_ctrl, double y_ctrl, double x_to, double y_to); void curve3_rel(double dx_ctrl, double dy_ctrl, double dx_to, double dy_to); void curve3(double x_to, double y_to); void curve3_rel(double dx_to, double dy_to); void curve4(double x_ctrl1, double y_ctrl1, double x_ctrl2, double y_ctrl2, double x_to, double y_to); void curve4_rel(double dx_ctrl1, double dy_ctrl1, double dx_ctrl2, double dy_ctrl2, double dx_to, double dy_to); void curve4(double x_ctrl2, double y_ctrl2, double x_to, double y_to); void curve4_rel(double x_ctrl2, double y_ctrl2, double x_to, double y_to); void end_poly(unsigned flags = path_flags_close); void close_polygon(unsigned flags = path_flags_none); // Accessors //-------------------------------------------------------------------- const container_type& vertices() const { return m_vertices; } container_type& vertices() { return m_vertices; } unsigned total_vertices() const; void rel_to_abs(double* x, double* y) const; unsigned last_vertex(double* x, double* y) const; unsigned prev_vertex(double* x, double* y) const; double last_x() const; double last_y() const; unsigned vertex(unsigned idx, double* x, double* y) const; unsigned command(unsigned idx) const; void modify_vertex(unsigned idx, double x, double y); void modify_vertex(unsigned idx, double x, double y, unsigned cmd); void modify_command(unsigned idx, unsigned cmd); // VertexSource interface //-------------------------------------------------------------------- void rewind(unsigned path_id); unsigned vertex(double* x, double* y); // Arrange the orientation of a polygon, all polygons in a path, // or in all paths. After calling arrange_orientations() or // arrange_orientations_all_paths(), all the polygons will have // the same orientation, i.e. path_flags_cw or path_flags_ccw //-------------------------------------------------------------------- unsigned arrange_polygon_orientation(unsigned start, path_flags_e orientation); unsigned arrange_orientations(unsigned path_id, path_flags_e orientation); void arrange_orientations_all_paths(path_flags_e orientation); void invert_polygon(unsigned start); // Flip all vertices horizontally or vertically, // between x1 and x2, or between y1 and y2 respectively //-------------------------------------------------------------------- void flip_x(double x1, double x2); void flip_y(double y1, double y2); // Concatenate path. The path is added as is. //-------------------------------------------------------------------- template void concat_path(VertexSource& vs, unsigned path_id = 0) { double x, y; unsigned cmd; vs.rewind(path_id); while(!is_stop(cmd = vs.vertex(&x, &y))) { m_vertices.add_vertex(x, y, cmd); } } //-------------------------------------------------------------------- // Join path. The path is joined with the existing one, that is, // it behaves as if the pen of a plotter was always down (drawing) template void join_path(VertexSource& vs, unsigned path_id = 0) { double x, y; unsigned cmd; vs.rewind(path_id); cmd = vs.vertex(&x, &y); if(!is_stop(cmd)) { if(is_vertex(cmd)) { double x0, y0; unsigned cmd0 = last_vertex(&x0, &y0); if(is_vertex(cmd0)) { if(calc_distance(x, y, x0, y0) > vertex_dist_epsilon) { if(is_move_to(cmd)) cmd = path_cmd_line_to; m_vertices.add_vertex(x, y, cmd); } } else { if(is_stop(cmd0)) { cmd = path_cmd_move_to; } else { if(is_move_to(cmd)) cmd = path_cmd_line_to; } m_vertices.add_vertex(x, y, cmd); } } while(!is_stop(cmd = vs.vertex(&x, &y))) { m_vertices.add_vertex(x, y, is_move_to(cmd) ? unsigned(path_cmd_line_to) : cmd); } } } // Concatenate polygon/polyline. //-------------------------------------------------------------------- template void concat_poly(const T* data, unsigned num_points, bool closed) { poly_plain_adaptor poly(data, num_points, closed); concat_path(poly); } // Join polygon/polyline continuously. //-------------------------------------------------------------------- template void join_poly(const T* data, unsigned num_points, bool closed) { poly_plain_adaptor poly(data, num_points, closed); join_path(poly); } //-------------------------------------------------------------------- void translate(double dx, double dy, unsigned path_id=0); void translate_all_paths(double dx, double dy); //-------------------------------------------------------------------- template void transform(const Trans& trans, unsigned path_id=0) { unsigned num_ver = m_vertices.total_vertices(); for(; path_id < num_ver; path_id++) { double x, y; unsigned cmd = m_vertices.vertex(path_id, &x, &y); if(is_stop(cmd)) break; if(is_vertex(cmd)) { trans.transform(&x, &y); m_vertices.modify_vertex(path_id, x, y); } } } //-------------------------------------------------------------------- template void transform_all_paths(const Trans& trans) { unsigned idx; unsigned num_ver = m_vertices.total_vertices(); for(idx = 0; idx < num_ver; idx++) { double x, y; if(is_vertex(m_vertices.vertex(idx, &x, &y))) { trans.transform(&x, &y); m_vertices.modify_vertex(idx, x, y); } } } //-------------------------------------------------------------------- // If the end points of a path are very, very close then make them // exactly equal so that the stroke converter is not confused. //-------------------------------------------------------------------- unsigned align_path(unsigned idx = 0) { if (idx >= total_vertices() || !is_move_to(command(idx))) { return total_vertices(); } double start_x, start_y; for (; idx < total_vertices() && is_move_to(command(idx)); ++idx) { vertex(idx, &start_x, &start_y); } while (idx < total_vertices() && is_drawing(command(idx))) ++idx; double x, y; if (is_drawing(vertex(idx - 1, &x, &y)) && is_equal_eps(x, start_x, 1e-8) && is_equal_eps(y, start_y, 1e-8)) { modify_vertex(idx - 1, start_x, start_y); } while (idx < total_vertices() && !is_move_to(command(idx))) ++idx; return idx; } void align_all_paths() { for (unsigned i = 0; i < total_vertices(); i = align_path(i)); } private: unsigned perceive_polygon_orientation(unsigned start, unsigned end); void invert_polygon(unsigned start, unsigned end); VertexContainer m_vertices; unsigned m_iterator; }; //------------------------------------------------------------------------ template unsigned path_base::start_new_path() { if(!is_stop(m_vertices.last_command())) { m_vertices.add_vertex(0.0, 0.0, path_cmd_stop); } return m_vertices.total_vertices(); } //------------------------------------------------------------------------ template inline void path_base::rel_to_abs(double* x, double* y) const { if(m_vertices.total_vertices()) { double x2; double y2; if(is_vertex(m_vertices.last_vertex(&x2, &y2))) { *x += x2; *y += y2; } } } //------------------------------------------------------------------------ template inline void path_base::move_to(double x, double y) { m_vertices.add_vertex(x, y, path_cmd_move_to); } //------------------------------------------------------------------------ template inline void path_base::move_rel(double dx, double dy) { rel_to_abs(&dx, &dy); m_vertices.add_vertex(dx, dy, path_cmd_move_to); } //------------------------------------------------------------------------ template inline void path_base::line_to(double x, double y) { m_vertices.add_vertex(x, y, path_cmd_line_to); } //------------------------------------------------------------------------ template inline void path_base::line_rel(double dx, double dy) { rel_to_abs(&dx, &dy); m_vertices.add_vertex(dx, dy, path_cmd_line_to); } //------------------------------------------------------------------------ template inline void path_base::hline_to(double x) { m_vertices.add_vertex(x, last_y(), path_cmd_line_to); } //------------------------------------------------------------------------ template inline void path_base::hline_rel(double dx) { double dy = 0; rel_to_abs(&dx, &dy); m_vertices.add_vertex(dx, dy, path_cmd_line_to); } //------------------------------------------------------------------------ template inline void path_base::vline_to(double y) { m_vertices.add_vertex(last_x(), y, path_cmd_line_to); } //------------------------------------------------------------------------ template inline void path_base::vline_rel(double dy) { double dx = 0; rel_to_abs(&dx, &dy); m_vertices.add_vertex(dx, dy, path_cmd_line_to); } //------------------------------------------------------------------------ template void path_base::arc_to(double rx, double ry, double angle, bool large_arc_flag, bool sweep_flag, double x, double y) { if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command())) { const double epsilon = 1e-30; double x0 = 0.0; double y0 = 0.0; m_vertices.last_vertex(&x0, &y0); rx = std::fabs(rx); ry = std::fabs(ry); // Ensure radii are valid //------------------------- if(rx < epsilon || ry < epsilon) { line_to(x, y); return; } if(calc_distance(x0, y0, x, y) < epsilon) { // If the endpoints (x, y) and (x0, y0) are identical, then this // is equivalent to omitting the elliptical arc segment entirely. return; } bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y); if(a.radii_ok()) { join_path(a); } else { line_to(x, y); } } else { move_to(x, y); } } //------------------------------------------------------------------------ template void path_base::arc_rel(double rx, double ry, double angle, bool large_arc_flag, bool sweep_flag, double dx, double dy) { rel_to_abs(&dx, &dy); arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy); } //------------------------------------------------------------------------ template void path_base::curve3(double x_ctrl, double y_ctrl, double x_to, double y_to) { m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3); m_vertices.add_vertex(x_to, y_to, path_cmd_curve3); } //------------------------------------------------------------------------ template void path_base::curve3_rel(double dx_ctrl, double dy_ctrl, double dx_to, double dy_to) { rel_to_abs(&dx_ctrl, &dy_ctrl); rel_to_abs(&dx_to, &dy_to); m_vertices.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3); m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve3); } //------------------------------------------------------------------------ template void path_base::curve3(double x_to, double y_to) { double x0; double y0; if(is_vertex(m_vertices.last_vertex(&x0, &y0))) { double x_ctrl; double y_ctrl; unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl); if(is_curve(cmd)) { x_ctrl = x0 + x0 - x_ctrl; y_ctrl = y0 + y0 - y_ctrl; } else { x_ctrl = x0; y_ctrl = y0; } curve3(x_ctrl, y_ctrl, x_to, y_to); } } //------------------------------------------------------------------------ template void path_base::curve3_rel(double dx_to, double dy_to) { rel_to_abs(&dx_to, &dy_to); curve3(dx_to, dy_to); } //------------------------------------------------------------------------ template void path_base::curve4(double x_ctrl1, double y_ctrl1, double x_ctrl2, double y_ctrl2, double x_to, double y_to) { m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4); m_vertices.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4); m_vertices.add_vertex(x_to, y_to, path_cmd_curve4); } //------------------------------------------------------------------------ template void path_base::curve4_rel(double dx_ctrl1, double dy_ctrl1, double dx_ctrl2, double dy_ctrl2, double dx_to, double dy_to) { rel_to_abs(&dx_ctrl1, &dy_ctrl1); rel_to_abs(&dx_ctrl2, &dy_ctrl2); rel_to_abs(&dx_to, &dy_to); m_vertices.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4); m_vertices.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4); m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve4); } //------------------------------------------------------------------------ template void path_base::curve4(double x_ctrl2, double y_ctrl2, double x_to, double y_to) { double x0; double y0; if(is_vertex(last_vertex(&x0, &y0))) { double x_ctrl1; double y_ctrl1; unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1); if(is_curve(cmd)) { x_ctrl1 = x0 + x0 - x_ctrl1; y_ctrl1 = y0 + y0 - y_ctrl1; } else { x_ctrl1 = x0; y_ctrl1 = y0; } curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to); } } //------------------------------------------------------------------------ template void path_base::curve4_rel(double dx_ctrl2, double dy_ctrl2, double dx_to, double dy_to) { rel_to_abs(&dx_ctrl2, &dy_ctrl2); rel_to_abs(&dx_to, &dy_to); curve4(dx_ctrl2, dy_ctrl2, dx_to, dy_to); } //------------------------------------------------------------------------ template inline void path_base::end_poly(unsigned flags) { if(is_vertex(m_vertices.last_command())) { m_vertices.add_vertex(0.0, 0.0, path_cmd_end_poly | flags); } } //------------------------------------------------------------------------ template inline void path_base::close_polygon(unsigned flags) { end_poly(path_flags_close | flags); } //------------------------------------------------------------------------ template inline unsigned path_base::total_vertices() const { return m_vertices.total_vertices(); } //------------------------------------------------------------------------ template inline unsigned path_base::last_vertex(double* x, double* y) const { return m_vertices.last_vertex(x, y); } //------------------------------------------------------------------------ template inline unsigned path_base::prev_vertex(double* x, double* y) const { return m_vertices.prev_vertex(x, y); } //------------------------------------------------------------------------ template inline double path_base::last_x() const { return m_vertices.last_x(); } //------------------------------------------------------------------------ template inline double path_base::last_y() const { return m_vertices.last_y(); } //------------------------------------------------------------------------ template inline unsigned path_base::vertex(unsigned idx, double* x, double* y) const { return m_vertices.vertex(idx, x, y); } //------------------------------------------------------------------------ template inline unsigned path_base::command(unsigned idx) const { return m_vertices.command(idx); } //------------------------------------------------------------------------ template void path_base::modify_vertex(unsigned idx, double x, double y) { m_vertices.modify_vertex(idx, x, y); } //------------------------------------------------------------------------ template void path_base::modify_vertex(unsigned idx, double x, double y, unsigned cmd) { m_vertices.modify_vertex(idx, x, y, cmd); } //------------------------------------------------------------------------ template void path_base::modify_command(unsigned idx, unsigned cmd) { m_vertices.modify_command(idx, cmd); } //------------------------------------------------------------------------ template inline void path_base::rewind(unsigned path_id) { m_iterator = path_id; } //------------------------------------------------------------------------ template inline unsigned path_base::vertex(double* x, double* y) { if(m_iterator >= m_vertices.total_vertices()) return path_cmd_stop; return m_vertices.vertex(m_iterator++, x, y); } //------------------------------------------------------------------------ template unsigned path_base::perceive_polygon_orientation(unsigned start, unsigned end) { // Calculate signed area (double area to be exact) //--------------------- unsigned np = end - start; double area = 0.0; unsigned i; for(i = 0; i < np; i++) { double x1, y1, x2, y2; m_vertices.vertex(start + i, &x1, &y1); m_vertices.vertex(start + (i + 1) % np, &x2, &y2); area += x1 * y2 - y1 * x2; } return (area < 0.0) ? path_flags_cw : path_flags_ccw; } //------------------------------------------------------------------------ template void path_base::invert_polygon(unsigned start, unsigned end) { unsigned i; unsigned tmp_cmd = m_vertices.command(start); --end; // Make "end" inclusive // Shift all commands to one position for(i = start; i < end; i++) { m_vertices.modify_command(i, m_vertices.command(i + 1)); } // Assign starting command to the ending command m_vertices.modify_command(end, tmp_cmd); // Reverse the polygon while(end > start) { m_vertices.swap_vertices(start++, end--); } } //------------------------------------------------------------------------ template void path_base::invert_polygon(unsigned start) { // Skip all non-vertices at the beginning while(start < m_vertices.total_vertices() && !is_vertex(m_vertices.command(start))) ++start; // Skip all insignificant move_to while(start+1 < m_vertices.total_vertices() && is_move_to(m_vertices.command(start)) && is_move_to(m_vertices.command(start+1))) ++start; // Find the last vertex unsigned end = start + 1; while(end < m_vertices.total_vertices() && !is_next_poly(m_vertices.command(end))) ++end; invert_polygon(start, end); } //------------------------------------------------------------------------ template unsigned path_base::arrange_polygon_orientation(unsigned start, path_flags_e orientation) { if(orientation == path_flags_none) return start; // Skip all non-vertices at the beginning while(start < m_vertices.total_vertices() && !is_vertex(m_vertices.command(start))) ++start; // Skip all insignificant move_to while(start+1 < m_vertices.total_vertices() && is_move_to(m_vertices.command(start)) && is_move_to(m_vertices.command(start+1))) ++start; // Find the last vertex unsigned end = start + 1; while(end < m_vertices.total_vertices() && !is_next_poly(m_vertices.command(end))) ++end; if(end - start > 2) { if(perceive_polygon_orientation(start, end) != unsigned(orientation)) { // Invert polygon, set orientation flag, and skip all end_poly invert_polygon(start, end); unsigned cmd; while(end < m_vertices.total_vertices() && is_end_poly(cmd = m_vertices.command(end))) { m_vertices.modify_command(end++, set_orientation(cmd, orientation)); } } } return end; } //------------------------------------------------------------------------ template unsigned path_base::arrange_orientations(unsigned start, path_flags_e orientation) { if(orientation != path_flags_none) { while(start < m_vertices.total_vertices()) { start = arrange_polygon_orientation(start, orientation); if(is_stop(m_vertices.command(start))) { ++start; break; } } } return start; } //------------------------------------------------------------------------ template void path_base::arrange_orientations_all_paths(path_flags_e orientation) { if(orientation != path_flags_none) { unsigned start = 0; while(start < m_vertices.total_vertices()) { start = arrange_orientations(start, orientation); } } } //------------------------------------------------------------------------ template void path_base::flip_x(double x1, double x2) { unsigned i; double x, y; for(i = 0; i < m_vertices.total_vertices(); i++) { unsigned cmd = m_vertices.vertex(i, &x, &y); if(is_vertex(cmd)) { m_vertices.modify_vertex(i, x2 - x + x1, y); } } } //------------------------------------------------------------------------ template void path_base::flip_y(double y1, double y2) { unsigned i; double x, y; for(i = 0; i < m_vertices.total_vertices(); i++) { unsigned cmd = m_vertices.vertex(i, &x, &y); if(is_vertex(cmd)) { m_vertices.modify_vertex(i, x, y2 - y + y1); } } } //------------------------------------------------------------------------ template void path_base::translate(double dx, double dy, unsigned path_id) { unsigned num_ver = m_vertices.total_vertices(); for(; path_id < num_ver; path_id++) { double x, y; unsigned cmd = m_vertices.vertex(path_id, &x, &y); if(is_stop(cmd)) break; if(is_vertex(cmd)) { x += dx; y += dy; m_vertices.modify_vertex(path_id, x, y); } } } //------------------------------------------------------------------------ template void path_base::translate_all_paths(double dx, double dy) { unsigned idx; unsigned num_ver = m_vertices.total_vertices(); for(idx = 0; idx < num_ver; idx++) { double x, y; if(is_vertex(m_vertices.vertex(idx, &x, &y))) { x += dx; y += dy; m_vertices.modify_vertex(idx, x, y); } } } //-----------------------------------------------------vertex_stl_storage template class vertex_stl_storage { public: typedef typename Container::value_type vertex_type; typedef typename vertex_type::value_type value_type; void remove_all() { m_vertices.clear(); } void free_all() { m_vertices.clear(); } void add_vertex(double x, double y, unsigned cmd) { m_vertices.push_back(vertex_type(value_type(x), value_type(y), int8u(cmd))); } void modify_vertex(unsigned idx, double x, double y) { vertex_type& v = m_vertices[idx]; v.x = value_type(x); v.y = value_type(y); } void modify_vertex(unsigned idx, double x, double y, unsigned cmd) { vertex_type& v = m_vertices[idx]; v.x = value_type(x); v.y = value_type(y); v.cmd = int8u(cmd); } void modify_command(unsigned idx, unsigned cmd) { m_vertices[idx].cmd = int8u(cmd); } void swap_vertices(unsigned v1, unsigned v2) { vertex_type t = m_vertices[v1]; m_vertices[v1] = m_vertices[v2]; m_vertices[v2] = t; } unsigned last_command() const { return m_vertices.size() ? m_vertices[m_vertices.size() - 1].cmd : path_cmd_stop; } unsigned last_vertex(double* x, double* y) const { if(m_vertices.size() == 0) { *x = *y = 0.0; return path_cmd_stop; } return vertex(m_vertices.size() - 1, x, y); } unsigned prev_vertex(double* x, double* y) const { if(m_vertices.size() < 2) { *x = *y = 0.0; return path_cmd_stop; } return vertex(m_vertices.size() - 2, x, y); } double last_x() const { return m_vertices.size() ? m_vertices[m_vertices.size() - 1].x : 0.0; } double last_y() const { return m_vertices.size() ? m_vertices[m_vertices.size() - 1].y : 0.0; } unsigned total_vertices() const { return m_vertices.size(); } unsigned vertex(unsigned idx, double* x, double* y) const { const vertex_type& v = m_vertices[idx]; *x = v.x; *y = v.y; return v.cmd; } unsigned command(unsigned idx) const { return m_vertices[idx].cmd; } private: Container m_vertices; }; //-----------------------------------------------------------path_storage typedef path_base > path_storage; // Example of declarations path_storage with pod_bvector as a container //----------------------------------------------------------------------- //typedef path_base > > path_storage; } // Example of declarations path_storage with std::vector as a container //--------------------------------------------------------------------------- //#include //namespace agg //{ // typedef path_base > > stl_path_storage; //} #endif ragg/src/agg/include/agg_image_accessors.h0000644000176200001440000003151413506353306020270 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_IMAGE_ACCESSORS_INCLUDED #define AGG_IMAGE_ACCESSORS_INCLUDED #include "agg_basics.h" namespace agg { //-----------------------------------------------------image_accessor_clip template class image_accessor_clip { public: typedef PixFmt pixfmt_type; typedef typename pixfmt_type::color_type color_type; typedef typename pixfmt_type::order_type order_type; typedef typename pixfmt_type::value_type value_type; enum pix_width_e { pix_width = pixfmt_type::pix_width }; image_accessor_clip() {} explicit image_accessor_clip(pixfmt_type& pixf, const color_type& bk) : m_pixf(&pixf) { pixfmt_type::make_pix(m_bk_buf, bk); } void attach(pixfmt_type& pixf) { m_pixf = &pixf; } void background_color(const color_type& bk) { pixfmt_type::make_pix(m_bk_buf, bk); } private: AGG_INLINE const int8u* pixel() const { if(m_y >= 0 && m_y < (int)m_pixf->height() && m_x >= 0 && m_x < (int)m_pixf->width()) { return m_pixf->pix_ptr(m_x, m_y); } return m_bk_buf; } public: AGG_INLINE const int8u* span(int x, int y, unsigned len) { m_x = m_x0 = x; m_y = y; if(y >= 0 && y < (int)m_pixf->height() && x >= 0 && x+(int)len <= (int)m_pixf->width()) { return m_pix_ptr = m_pixf->pix_ptr(x, y); } m_pix_ptr = 0; return pixel(); } AGG_INLINE const int8u* next_x() { if(m_pix_ptr) return m_pix_ptr += pix_width; ++m_x; return pixel(); } AGG_INLINE const int8u* next_y() { ++m_y; m_x = m_x0; if(m_pix_ptr && m_y >= 0 && m_y < (int)m_pixf->height()) { return m_pix_ptr = m_pixf->pix_ptr(m_x, m_y); } m_pix_ptr = 0; return pixel(); } private: const pixfmt_type* m_pixf; int8u m_bk_buf[pix_width]; int m_x, m_x0, m_y; const int8u* m_pix_ptr; }; //--------------------------------------------------image_accessor_no_clip template class image_accessor_no_clip { public: typedef PixFmt pixfmt_type; typedef typename pixfmt_type::color_type color_type; typedef typename pixfmt_type::order_type order_type; typedef typename pixfmt_type::value_type value_type; enum pix_width_e { pix_width = pixfmt_type::pix_width }; image_accessor_no_clip() {} explicit image_accessor_no_clip(pixfmt_type& pixf) : m_pixf(&pixf) {} void attach(pixfmt_type& pixf) { m_pixf = &pixf; } AGG_INLINE const int8u* span(int x, int y, unsigned) { m_x = x; m_y = y; return m_pix_ptr = m_pixf->pix_ptr(x, y); } AGG_INLINE const int8u* next_x() { return m_pix_ptr += pix_width; } AGG_INLINE const int8u* next_y() { ++m_y; return m_pix_ptr = m_pixf->pix_ptr(m_x, m_y); } private: const pixfmt_type* m_pixf; int m_x, m_y; const int8u* m_pix_ptr; }; //----------------------------------------------------image_accessor_clone template class image_accessor_clone { public: typedef PixFmt pixfmt_type; typedef typename pixfmt_type::color_type color_type; typedef typename pixfmt_type::order_type order_type; typedef typename pixfmt_type::value_type value_type; enum pix_width_e { pix_width = pixfmt_type::pix_width }; image_accessor_clone() {} explicit image_accessor_clone(pixfmt_type& pixf) : m_pixf(&pixf) {} void attach(pixfmt_type& pixf) { m_pixf = &pixf; } private: AGG_INLINE const int8u* pixel() const { int x = m_x; int y = m_y; if(x < 0) x = 0; if(y < 0) y = 0; if(x >= (int)m_pixf->width()) x = m_pixf->width() - 1; if(y >= (int)m_pixf->height()) y = m_pixf->height() - 1; return m_pixf->pix_ptr(x, y); } public: AGG_INLINE const int8u* span(int x, int y, unsigned len) { m_x = m_x0 = x; m_y = y; if(y >= 0 && y < (int)m_pixf->height() && x >= 0 && x+(int)len <= (int)m_pixf->width()) { return m_pix_ptr = m_pixf->pix_ptr(x, y); } m_pix_ptr = 0; return pixel(); } AGG_INLINE const int8u* next_x() { if(m_pix_ptr) return m_pix_ptr += pix_width; ++m_x; return pixel(); } AGG_INLINE const int8u* next_y() { ++m_y; m_x = m_x0; if(m_pix_ptr && m_y >= 0 && m_y < (int)m_pixf->height()) { return m_pix_ptr = m_pixf->pix_ptr(m_x, m_y); } m_pix_ptr = 0; return pixel(); } private: const pixfmt_type* m_pixf; int m_x, m_x0, m_y; const int8u* m_pix_ptr; }; //-----------------------------------------------------image_accessor_wrap template class image_accessor_wrap { public: typedef PixFmt pixfmt_type; typedef typename pixfmt_type::color_type color_type; typedef typename pixfmt_type::order_type order_type; typedef typename pixfmt_type::value_type value_type; enum pix_width_e { pix_width = pixfmt_type::pix_width }; image_accessor_wrap() {} explicit image_accessor_wrap(pixfmt_type& pixf) : m_pixf(&pixf), m_wrap_x(pixf.width()), m_wrap_y(pixf.height()) {} void attach(pixfmt_type& pixf) { m_pixf = &pixf; } AGG_INLINE const int8u* span(int x, int y, unsigned) { m_x = x; m_row_ptr = m_pixf->pix_ptr(0, m_wrap_y(y)); return m_row_ptr + m_wrap_x(x) * pix_width; } AGG_INLINE const int8u* next_x() { int x = ++m_wrap_x; return m_row_ptr + x * pix_width; } AGG_INLINE const int8u* next_y() { m_row_ptr = m_pixf->pix_ptr(0, ++m_wrap_y); return m_row_ptr + m_wrap_x(m_x) * pix_width; } private: const pixfmt_type* m_pixf; const int8u* m_row_ptr; int m_x; WrapX m_wrap_x; WrapY m_wrap_y; }; //--------------------------------------------------------wrap_mode_repeat class wrap_mode_repeat { public: wrap_mode_repeat() {} wrap_mode_repeat(unsigned size) : m_size(size), m_add(size * (0x3FFFFFFF / size)), m_value(0) {} AGG_INLINE unsigned operator() (int v) { return m_value = (unsigned(v) + m_add) % m_size; } AGG_INLINE unsigned operator++ () { ++m_value; if(m_value >= m_size) m_value = 0; return m_value; } private: unsigned m_size; unsigned m_add; unsigned m_value; }; //---------------------------------------------------wrap_mode_repeat_pow2 class wrap_mode_repeat_pow2 { public: wrap_mode_repeat_pow2() {} wrap_mode_repeat_pow2(unsigned size) : m_value(0) { m_mask = 1; while(m_mask < size) m_mask = (m_mask << 1) | 1; m_mask >>= 1; } AGG_INLINE unsigned operator() (int v) { return m_value = unsigned(v) & m_mask; } AGG_INLINE unsigned operator++ () { ++m_value; if(m_value > m_mask) m_value = 0; return m_value; } private: unsigned m_mask; unsigned m_value; }; //----------------------------------------------wrap_mode_repeat_auto_pow2 class wrap_mode_repeat_auto_pow2 { public: wrap_mode_repeat_auto_pow2() {} wrap_mode_repeat_auto_pow2(unsigned size) : m_size(size), m_add(size * (0x3FFFFFFF / size)), m_mask((m_size & (m_size-1)) ? 0 : m_size-1), m_value(0) {} AGG_INLINE unsigned operator() (int v) { if(m_mask) return m_value = unsigned(v) & m_mask; return m_value = (unsigned(v) + m_add) % m_size; } AGG_INLINE unsigned operator++ () { ++m_value; if(m_value >= m_size) m_value = 0; return m_value; } private: unsigned m_size; unsigned m_add; unsigned m_mask; unsigned m_value; }; //-------------------------------------------------------wrap_mode_reflect class wrap_mode_reflect { public: wrap_mode_reflect() {} wrap_mode_reflect(unsigned size) : m_size(size), m_size2(size * 2), m_add(m_size2 * (0x3FFFFFFF / m_size2)), m_value(0) {} AGG_INLINE unsigned operator() (int v) { m_value = (unsigned(v) + m_add) % m_size2; if(m_value >= m_size) return m_size2 - m_value - 1; return m_value; } AGG_INLINE unsigned operator++ () { ++m_value; if(m_value >= m_size2) m_value = 0; if(m_value >= m_size) return m_size2 - m_value - 1; return m_value; } private: unsigned m_size; unsigned m_size2; unsigned m_add; unsigned m_value; }; //--------------------------------------------------wrap_mode_reflect_pow2 class wrap_mode_reflect_pow2 { public: wrap_mode_reflect_pow2() {} wrap_mode_reflect_pow2(unsigned size) : m_value(0) { m_mask = 1; m_size = 1; while(m_mask < size) { m_mask = (m_mask << 1) | 1; m_size <<= 1; } } AGG_INLINE unsigned operator() (int v) { m_value = unsigned(v) & m_mask; if(m_value >= m_size) return m_mask - m_value; return m_value; } AGG_INLINE unsigned operator++ () { ++m_value; m_value &= m_mask; if(m_value >= m_size) return m_mask - m_value; return m_value; } private: unsigned m_size; unsigned m_mask; unsigned m_value; }; //---------------------------------------------wrap_mode_reflect_auto_pow2 class wrap_mode_reflect_auto_pow2 { public: wrap_mode_reflect_auto_pow2() {} wrap_mode_reflect_auto_pow2(unsigned size) : m_size(size), m_size2(size * 2), m_add(m_size2 * (0x3FFFFFFF / m_size2)), m_mask((m_size2 & (m_size2-1)) ? 0 : m_size2-1), m_value(0) {} AGG_INLINE unsigned operator() (int v) { m_value = m_mask ? unsigned(v) & m_mask : (unsigned(v) + m_add) % m_size2; if(m_value >= m_size) return m_size2 - m_value - 1; return m_value; } AGG_INLINE unsigned operator++ () { ++m_value; if(m_value >= m_size2) m_value = 0; if(m_value >= m_size) return m_size2 - m_value - 1; return m_value; } private: unsigned m_size; unsigned m_size2; unsigned m_add; unsigned m_mask; unsigned m_value; }; } #endif ragg/src/agg/AUTHORS0000644000176200001440000000012713504406270013570 0ustar liggesusersAnti-Grain Geometry - Version 2.4 Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) ragg/src/agg/src/0000755000176200001440000000000014153422062013305 5ustar liggesusersragg/src/agg/src/agg_trans_affine.cpp0000644000176200001440000001411113504406270017266 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Affine transformations // //---------------------------------------------------------------------------- #include "agg_trans_affine.h" namespace agg { //------------------------------------------------------------------------ const trans_affine& trans_affine::parl_to_parl(const double* src, const double* dst) { sx = src[2] - src[0]; shy = src[3] - src[1]; shx = src[4] - src[0]; sy = src[5] - src[1]; tx = src[0]; ty = src[1]; invert(); multiply(trans_affine(dst[2] - dst[0], dst[3] - dst[1], dst[4] - dst[0], dst[5] - dst[1], dst[0], dst[1])); return *this; } //------------------------------------------------------------------------ const trans_affine& trans_affine::rect_to_parl(double x1, double y1, double x2, double y2, const double* parl) { double src[6]; src[0] = x1; src[1] = y1; src[2] = x2; src[3] = y1; src[4] = x2; src[5] = y2; parl_to_parl(src, parl); return *this; } //------------------------------------------------------------------------ const trans_affine& trans_affine::parl_to_rect(const double* parl, double x1, double y1, double x2, double y2) { double dst[6]; dst[0] = x1; dst[1] = y1; dst[2] = x2; dst[3] = y1; dst[4] = x2; dst[5] = y2; parl_to_parl(parl, dst); return *this; } //------------------------------------------------------------------------ const trans_affine& trans_affine::multiply(const trans_affine& m) { double t0 = sx * m.sx + shy * m.shx; double t2 = shx * m.sx + sy * m.shx; double t4 = tx * m.sx + ty * m.shx + m.tx; shy = sx * m.shy + shy * m.sy; sy = shx * m.shy + sy * m.sy; ty = tx * m.shy + ty * m.sy + m.ty; sx = t0; shx = t2; tx = t4; return *this; } //------------------------------------------------------------------------ const trans_affine& trans_affine::invert() { double d = determinant_reciprocal(); double t0 = sy * d; sy = sx * d; shy = -shy * d; shx = -shx * d; double t4 = -tx * t0 - ty * shx; ty = -tx * shy - ty * sy; sx = t0; tx = t4; return *this; } //------------------------------------------------------------------------ const trans_affine& trans_affine::flip_x() { sx = -sx; shy = -shy; tx = -tx; return *this; } //------------------------------------------------------------------------ const trans_affine& trans_affine::flip_y() { shx = -shx; sy = -sy; ty = -ty; return *this; } //------------------------------------------------------------------------ const trans_affine& trans_affine::reset() { sx = sy = 1.0; shy = shx = tx = ty = 0.0; return *this; } //------------------------------------------------------------------------ bool trans_affine::is_identity(double epsilon) const { return is_equal_eps(sx, 1.0, epsilon) && is_equal_eps(shy, 0.0, epsilon) && is_equal_eps(shx, 0.0, epsilon) && is_equal_eps(sy, 1.0, epsilon) && is_equal_eps(tx, 0.0, epsilon) && is_equal_eps(ty, 0.0, epsilon); } //------------------------------------------------------------------------ bool trans_affine::is_valid(double epsilon) const { return std::fabs(sx) > epsilon && std::fabs(sy) > epsilon; } //------------------------------------------------------------------------ bool trans_affine::is_equal(const trans_affine& m, double epsilon) const { return is_equal_eps(sx, m.sx, epsilon) && is_equal_eps(shy, m.shy, epsilon) && is_equal_eps(shx, m.shx, epsilon) && is_equal_eps(sy, m.sy, epsilon) && is_equal_eps(tx, m.tx, epsilon) && is_equal_eps(ty, m.ty, epsilon); } //------------------------------------------------------------------------ double trans_affine::rotation() const { double x1 = 0.0; double y1 = 0.0; double x2 = 1.0; double y2 = 0.0; transform(&x1, &y1); transform(&x2, &y2); return std::atan2(y2-y1, x2-x1); } //------------------------------------------------------------------------ void trans_affine::translation(double* dx, double* dy) const { *dx = tx; *dy = ty; } //------------------------------------------------------------------------ void trans_affine::scaling(double* x, double* y) const { double x1 = 0.0; double y1 = 0.0; double x2 = 1.0; double y2 = 1.0; trans_affine t(*this); t *= trans_affine_rotation(-rotation()); t.transform(&x1, &y1); t.transform(&x2, &y2); *x = x2 - x1; *y = y2 - y1; } } ragg/src/agg/src/agg_curves.cpp0000644000176200001440000004641013506714016016147 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #include #include "agg_curves.h" #include "agg_math.h" namespace agg { //------------------------------------------------------------------------ //const double curve_distance_epsilon = 1e-30; const double curve_collinearity_epsilon = 1e-30; const double curve_angle_tolerance_epsilon = 0.01; enum curve_recursion_limit_e { curve_recursion_limit = 32 }; //------------------------------------------------------------------------ void curve3_inc::approximation_scale(double s) { m_scale = s; } //------------------------------------------------------------------------ double curve3_inc::approximation_scale() const { return m_scale; } //------------------------------------------------------------------------ void curve3_inc::init(double x1, double y1, double x2, double y2, double x3, double y3) { m_start_x = x1; m_start_y = y1; m_end_x = x3; m_end_y = y3; double dx1 = x2 - x1; double dy1 = y2 - y1; double dx2 = x3 - x2; double dy2 = y3 - y2; double len = std::sqrt(dx1 * dx1 + dy1 * dy1) + std::sqrt(dx2 * dx2 + dy2 * dy2); m_num_steps = uround(len * 0.25 * m_scale); if(m_num_steps < 4) { m_num_steps = 4; } double subdivide_step = 1.0 / m_num_steps; double subdivide_step2 = subdivide_step * subdivide_step; double tmpx = (x1 - x2 * 2.0 + x3) * subdivide_step2; double tmpy = (y1 - y2 * 2.0 + y3) * subdivide_step2; m_saved_fx = m_fx = x1; m_saved_fy = m_fy = y1; m_saved_dfx = m_dfx = tmpx + (x2 - x1) * (2.0 * subdivide_step); m_saved_dfy = m_dfy = tmpy + (y2 - y1) * (2.0 * subdivide_step); m_ddfx = tmpx * 2.0; m_ddfy = tmpy * 2.0; m_step = m_num_steps; } //------------------------------------------------------------------------ void curve3_inc::rewind(unsigned) { if(m_num_steps == 0) { m_step = -1; return; } m_step = m_num_steps; m_fx = m_saved_fx; m_fy = m_saved_fy; m_dfx = m_saved_dfx; m_dfy = m_saved_dfy; } //------------------------------------------------------------------------ unsigned curve3_inc::vertex(double* x, double* y) { if(m_step < 0) return path_cmd_stop; if(m_step == m_num_steps) { *x = m_start_x; *y = m_start_y; --m_step; return path_cmd_move_to; } if(m_step == 0) { *x = m_end_x; *y = m_end_y; --m_step; return path_cmd_line_to; } m_fx += m_dfx; m_fy += m_dfy; m_dfx += m_ddfx; m_dfy += m_ddfy; *x = m_fx; *y = m_fy; --m_step; return path_cmd_line_to; } //------------------------------------------------------------------------ void curve3_div::init(double x1, double y1, double x2, double y2, double x3, double y3) { m_points.remove_all(); m_distance_tolerance_square = 0.5 / m_approximation_scale; m_distance_tolerance_square *= m_distance_tolerance_square; bezier(x1, y1, x2, y2, x3, y3); m_count = 0; } //------------------------------------------------------------------------ void curve3_div::recursive_bezier(double x1, double y1, double x2, double y2, double x3, double y3, unsigned level) { if(level > curve_recursion_limit) { return; } // Calculate all the mid-points of the line segments //---------------------- double x12 = (x1 + x2) / 2; double y12 = (y1 + y2) / 2; double x23 = (x2 + x3) / 2; double y23 = (y2 + y3) / 2; double x123 = (x12 + x23) / 2; double y123 = (y12 + y23) / 2; double dx = x3-x1; double dy = y3-y1; double d = std::fabs(((x2 - x3) * dy - (y2 - y3) * dx)); double da; if(d > curve_collinearity_epsilon) { // Regular case //----------------- if(d * d <= m_distance_tolerance_square * (dx*dx + dy*dy)) { // If the curvature doesn't exceed the distance_tolerance value // we tend to finish subdivisions. //---------------------- if(m_angle_tolerance < curve_angle_tolerance_epsilon) { m_points.add(point_d(x123, y123)); return; } // Angle & Cusp Condition //---------------------- da = std::fabs(std::atan2(y3 - y2, x3 - x2) - std::atan2(y2 - y1, x2 - x1)); if(da >= pi) da = 2*pi - da; if(da < m_angle_tolerance) { // Finally we can stop the recursion //---------------------- m_points.add(point_d(x123, y123)); return; } } } else { // Collinear case //------------------ da = dx*dx + dy*dy; if(da == 0) { d = calc_sq_distance(x1, y1, x2, y2); } else { d = ((x2 - x1)*dx + (y2 - y1)*dy) / da; if(d > 0 && d < 1) { // Simple collinear case, 1---2---3 // We can leave just two endpoints return; } if(d <= 0) d = calc_sq_distance(x2, y2, x1, y1); else if(d >= 1) d = calc_sq_distance(x2, y2, x3, y3); else d = calc_sq_distance(x2, y2, x1 + d*dx, y1 + d*dy); } if(d < m_distance_tolerance_square) { m_points.add(point_d(x2, y2)); return; } } // Continue subdivision //---------------------- recursive_bezier(x1, y1, x12, y12, x123, y123, level + 1); recursive_bezier(x123, y123, x23, y23, x3, y3, level + 1); } //------------------------------------------------------------------------ void curve3_div::bezier(double x1, double y1, double x2, double y2, double x3, double y3) { m_points.add(point_d(x1, y1)); recursive_bezier(x1, y1, x2, y2, x3, y3, 0); m_points.add(point_d(x3, y3)); } //------------------------------------------------------------------------ void curve4_inc::approximation_scale(double s) { m_scale = s; } //------------------------------------------------------------------------ double curve4_inc::approximation_scale() const { return m_scale; } #if defined(_MSC_VER) && _MSC_VER <= 1200 //------------------------------------------------------------------------ static double MSC60_fix_ICE(double v) { return v; } #endif //------------------------------------------------------------------------ void curve4_inc::init(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { m_start_x = x1; m_start_y = y1; m_end_x = x4; m_end_y = y4; double dx1 = x2 - x1; double dy1 = y2 - y1; double dx2 = x3 - x2; double dy2 = y3 - y2; double dx3 = x4 - x3; double dy3 = y4 - y3; double len = (std::sqrt(dx1 * dx1 + dy1 * dy1) + std::sqrt(dx2 * dx2 + dy2 * dy2) + std::sqrt(dx3 * dx3 + dy3 * dy3)) * 0.25 * m_scale; #if defined(_MSC_VER) && _MSC_VER <= 1200 m_num_steps = uround(MSC60_fix_ICE(len)); #else m_num_steps = uround(len); #endif if(m_num_steps < 4) { m_num_steps = 4; } double subdivide_step = 1.0 / m_num_steps; double subdivide_step2 = subdivide_step * subdivide_step; double subdivide_step3 = subdivide_step * subdivide_step * subdivide_step; double pre1 = 3.0 * subdivide_step; double pre2 = 3.0 * subdivide_step2; double pre4 = 6.0 * subdivide_step2; double pre5 = 6.0 * subdivide_step3; double tmp1x = x1 - x2 * 2.0 + x3; double tmp1y = y1 - y2 * 2.0 + y3; double tmp2x = (x2 - x3) * 3.0 - x1 + x4; double tmp2y = (y2 - y3) * 3.0 - y1 + y4; m_saved_fx = m_fx = x1; m_saved_fy = m_fy = y1; m_saved_dfx = m_dfx = (x2 - x1) * pre1 + tmp1x * pre2 + tmp2x * subdivide_step3; m_saved_dfy = m_dfy = (y2 - y1) * pre1 + tmp1y * pre2 + tmp2y * subdivide_step3; m_saved_ddfx = m_ddfx = tmp1x * pre4 + tmp2x * pre5; m_saved_ddfy = m_ddfy = tmp1y * pre4 + tmp2y * pre5; m_dddfx = tmp2x * pre5; m_dddfy = tmp2y * pre5; m_step = m_num_steps; } //------------------------------------------------------------------------ void curve4_inc::rewind(unsigned) { if(m_num_steps == 0) { m_step = -1; return; } m_step = m_num_steps; m_fx = m_saved_fx; m_fy = m_saved_fy; m_dfx = m_saved_dfx; m_dfy = m_saved_dfy; m_ddfx = m_saved_ddfx; m_ddfy = m_saved_ddfy; } //------------------------------------------------------------------------ unsigned curve4_inc::vertex(double* x, double* y) { if(m_step < 0) return path_cmd_stop; if(m_step == m_num_steps) { *x = m_start_x; *y = m_start_y; --m_step; return path_cmd_move_to; } if(m_step == 0) { *x = m_end_x; *y = m_end_y; --m_step; return path_cmd_line_to; } m_fx += m_dfx; m_fy += m_dfy; m_dfx += m_ddfx; m_dfy += m_ddfy; m_ddfx += m_dddfx; m_ddfy += m_dddfy; *x = m_fx; *y = m_fy; --m_step; return path_cmd_line_to; } //------------------------------------------------------------------------ void curve4_div::init(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { m_points.remove_all(); m_distance_tolerance_square = 0.5 / m_approximation_scale; m_distance_tolerance_square *= m_distance_tolerance_square; bezier(x1, y1, x2, y2, x3, y3, x4, y4); m_count = 0; } //------------------------------------------------------------------------ void curve4_div::recursive_bezier(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, unsigned level) { if(level > curve_recursion_limit) { return; } // Calculate all the mid-points of the line segments //---------------------- double x12 = (x1 + x2) / 2; double y12 = (y1 + y2) / 2; double x23 = (x2 + x3) / 2; double y23 = (y2 + y3) / 2; double x34 = (x3 + x4) / 2; double y34 = (y3 + y4) / 2; double x123 = (x12 + x23) / 2; double y123 = (y12 + y23) / 2; double x234 = (x23 + x34) / 2; double y234 = (y23 + y34) / 2; double x1234 = (x123 + x234) / 2; double y1234 = (y123 + y234) / 2; // Try to approximate the full cubic curve by a single straight line //------------------ double dx = x4-x1; double dy = y4-y1; double d2 = std::fabs(((x2 - x4) * dy - (y2 - y4) * dx)); double d3 = std::fabs(((x3 - x4) * dy - (y3 - y4) * dx)); double da1, da2, k; switch((int(d2 > curve_collinearity_epsilon) << 1) + int(d3 > curve_collinearity_epsilon)) { case 0: // All collinear OR p1==p4 //---------------------- k = dx*dx + dy*dy; if(k == 0) { d2 = calc_sq_distance(x1, y1, x2, y2); d3 = calc_sq_distance(x4, y4, x3, y3); } else { k = 1 / k; da1 = x2 - x1; da2 = y2 - y1; d2 = k * (da1*dx + da2*dy); da1 = x3 - x1; da2 = y3 - y1; d3 = k * (da1*dx + da2*dy); if(d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1) { // Simple collinear case, 1---2---3---4 // We can leave just two endpoints return; } if(d2 <= 0) d2 = calc_sq_distance(x2, y2, x1, y1); else if(d2 >= 1) d2 = calc_sq_distance(x2, y2, x4, y4); else d2 = calc_sq_distance(x2, y2, x1 + d2*dx, y1 + d2*dy); if(d3 <= 0) d3 = calc_sq_distance(x3, y3, x1, y1); else if(d3 >= 1) d3 = calc_sq_distance(x3, y3, x4, y4); else d3 = calc_sq_distance(x3, y3, x1 + d3*dx, y1 + d3*dy); } if(d2 > d3) { if(d2 < m_distance_tolerance_square) { m_points.add(point_d(x2, y2)); return; } } else { if(d3 < m_distance_tolerance_square) { m_points.add(point_d(x3, y3)); return; } } break; case 1: // p1,p2,p4 are collinear, p3 is significant //---------------------- if(d3 * d3 <= m_distance_tolerance_square * (dx*dx + dy*dy)) { if(m_angle_tolerance < curve_angle_tolerance_epsilon) { m_points.add(point_d(x23, y23)); return; } // Angle Condition //---------------------- da1 = std::fabs(std::atan2(y4 - y3, x4 - x3) - std::atan2(y3 - y2, x3 - x2)); if(da1 >= pi) da1 = 2*pi - da1; if(da1 < m_angle_tolerance) { m_points.add(point_d(x2, y2)); m_points.add(point_d(x3, y3)); return; } if(m_cusp_limit != 0.0) { if(da1 > m_cusp_limit) { m_points.add(point_d(x3, y3)); return; } } } break; case 2: // p1,p3,p4 are collinear, p2 is significant //---------------------- if(d2 * d2 <= m_distance_tolerance_square * (dx*dx + dy*dy)) { if(m_angle_tolerance < curve_angle_tolerance_epsilon) { m_points.add(point_d(x23, y23)); return; } // Angle Condition //---------------------- da1 = std::fabs(std::atan2(y3 - y2, x3 - x2) - std::atan2(y2 - y1, x2 - x1)); if(da1 >= pi) da1 = 2*pi - da1; if(da1 < m_angle_tolerance) { m_points.add(point_d(x2, y2)); m_points.add(point_d(x3, y3)); return; } if(m_cusp_limit != 0.0) { if(da1 > m_cusp_limit) { m_points.add(point_d(x2, y2)); return; } } } break; case 3: // Regular case //----------------- if((d2 + d3)*(d2 + d3) <= m_distance_tolerance_square * (dx*dx + dy*dy)) { // If the curvature doesn't exceed the distance_tolerance value // we tend to finish subdivisions. //---------------------- if(m_angle_tolerance < curve_angle_tolerance_epsilon) { m_points.add(point_d(x23, y23)); return; } // Angle & Cusp Condition //---------------------- k = std::atan2(y3 - y2, x3 - x2); da1 = std::fabs(k - std::atan2(y2 - y1, x2 - x1)); da2 = std::fabs(std::atan2(y4 - y3, x4 - x3) - k); if(da1 >= pi) da1 = 2*pi - da1; if(da2 >= pi) da2 = 2*pi - da2; if(da1 + da2 < m_angle_tolerance) { // Finally we can stop the recursion //---------------------- m_points.add(point_d(x23, y23)); return; } if(m_cusp_limit != 0.0) { if(da1 > m_cusp_limit) { m_points.add(point_d(x2, y2)); return; } if(da2 > m_cusp_limit) { m_points.add(point_d(x3, y3)); return; } } } break; } // Continue subdivision //---------------------- recursive_bezier(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1); recursive_bezier(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1); } //------------------------------------------------------------------------ void curve4_div::bezier(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { m_points.add(point_d(x1, y1)); recursive_bezier(x1, y1, x2, y2, x3, y3, x4, y4, 0); m_points.add(point_d(x4, y4)); } } ragg/src/agg/src/agg_vcgen_stroke.cpp0000644000176200001440000001543713504406270017334 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Stroke generator // //---------------------------------------------------------------------------- #include "agg_vcgen_stroke.h" #include "agg_shorten_path.h" namespace agg { //------------------------------------------------------------------------ vcgen_stroke::vcgen_stroke() : m_stroker(), m_src_vertices(), m_out_vertices(), m_shorten(0.0), m_closed(0), m_status(initial), m_src_vertex(0), m_out_vertex(0) { } //------------------------------------------------------------------------ void vcgen_stroke::remove_all() { m_src_vertices.remove_all(); m_closed = 0; m_status = initial; } //------------------------------------------------------------------------ void vcgen_stroke::add_vertex(double x, double y, unsigned cmd) { m_status = initial; if(is_move_to(cmd)) { m_src_vertices.modify_last(vertex_dist(x, y)); } else { if(is_vertex(cmd)) { m_src_vertices.add(vertex_dist(x, y)); } else { m_closed = get_close_flag(cmd); } } } //------------------------------------------------------------------------ void vcgen_stroke::rewind(unsigned) { if(m_status == initial) { m_src_vertices.close(m_closed != 0); shorten_path(m_src_vertices, m_shorten, m_closed); if(m_src_vertices.size() < 3) m_closed = 0; } m_status = ready; m_src_vertex = 0; m_out_vertex = 0; } //------------------------------------------------------------------------ unsigned vcgen_stroke::vertex(double* x, double* y) { unsigned cmd = path_cmd_line_to; while(!is_stop(cmd)) { switch(m_status) { case initial: rewind(0); case ready: if(m_src_vertices.size() < 2 + unsigned(m_closed != 0)) { cmd = path_cmd_stop; break; } m_status = m_closed ? outline1 : cap1; cmd = path_cmd_move_to; m_src_vertex = 0; m_out_vertex = 0; break; case cap1: m_stroker.calc_cap(m_out_vertices, m_src_vertices[0], m_src_vertices[1], m_src_vertices[0].dist); m_src_vertex = 1; m_prev_status = outline1; m_status = out_vertices; m_out_vertex = 0; break; case cap2: m_stroker.calc_cap(m_out_vertices, m_src_vertices[m_src_vertices.size() - 1], m_src_vertices[m_src_vertices.size() - 2], m_src_vertices[m_src_vertices.size() - 2].dist); m_prev_status = outline2; m_status = out_vertices; m_out_vertex = 0; break; case outline1: if(m_closed) { if(m_src_vertex >= m_src_vertices.size()) { m_prev_status = close_first; m_status = end_poly1; break; } } else { if(m_src_vertex >= m_src_vertices.size() - 1) { m_status = cap2; break; } } m_stroker.calc_join(m_out_vertices, m_src_vertices.prev(m_src_vertex), m_src_vertices.curr(m_src_vertex), m_src_vertices.next(m_src_vertex), m_src_vertices.prev(m_src_vertex).dist, m_src_vertices.curr(m_src_vertex).dist); ++m_src_vertex; m_prev_status = m_status; m_status = out_vertices; m_out_vertex = 0; break; case close_first: m_status = outline2; cmd = path_cmd_move_to; case outline2: if(m_src_vertex <= unsigned(m_closed == 0)) { m_status = end_poly2; m_prev_status = stop; break; } --m_src_vertex; m_stroker.calc_join(m_out_vertices, m_src_vertices.next(m_src_vertex), m_src_vertices.curr(m_src_vertex), m_src_vertices.prev(m_src_vertex), m_src_vertices.curr(m_src_vertex).dist, m_src_vertices.prev(m_src_vertex).dist); m_prev_status = m_status; m_status = out_vertices; m_out_vertex = 0; break; case out_vertices: if(m_out_vertex >= m_out_vertices.size()) { m_status = m_prev_status; } else { const point_d& c = m_out_vertices[m_out_vertex++]; *x = c.x; *y = c.y; return cmd; } break; case end_poly1: m_status = m_prev_status; return path_cmd_end_poly | path_flags_close | path_flags_ccw; case end_poly2: m_status = m_prev_status; return path_cmd_end_poly | path_flags_close | path_flags_cw; case stop: cmd = path_cmd_stop; break; } } return cmd; } } ragg/src/agg/src/agg_vcgen_dash.cpp0000644000176200001440000001564513504406270016745 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Line dash generator // //---------------------------------------------------------------------------- #include #include "agg_vcgen_dash.h" #include "agg_shorten_path.h" namespace agg { //------------------------------------------------------------------------ vcgen_dash::vcgen_dash() : m_total_dash_len(0.0), m_num_dashes(0), m_dash_start(0.0), m_shorten(0.0), m_curr_dash_start(0.0), m_curr_dash(0), m_src_vertices(), m_closed(0), m_status(initial), m_src_vertex(0) { } //------------------------------------------------------------------------ void vcgen_dash::remove_all_dashes() { m_total_dash_len = 0.0; m_num_dashes = 0; m_curr_dash_start = 0.0; m_curr_dash = 0; } //------------------------------------------------------------------------ void vcgen_dash::add_dash(double dash_len, double gap_len) { if(m_num_dashes < max_dashes) { m_total_dash_len += dash_len + gap_len; m_dashes[m_num_dashes++] = dash_len; m_dashes[m_num_dashes++] = gap_len; } } //------------------------------------------------------------------------ void vcgen_dash::dash_start(double ds) { m_dash_start = ds; calc_dash_start(std::fabs(ds)); } //------------------------------------------------------------------------ void vcgen_dash::calc_dash_start(double ds) { m_curr_dash = 0; m_curr_dash_start = 0.0; while(ds > 0.0) { if(ds > m_dashes[m_curr_dash]) { ds -= m_dashes[m_curr_dash]; ++m_curr_dash; m_curr_dash_start = 0.0; if(m_curr_dash >= m_num_dashes) m_curr_dash = 0; } else { m_curr_dash_start = ds; ds = 0.0; } } } //------------------------------------------------------------------------ void vcgen_dash::remove_all() { m_status = initial; m_src_vertices.remove_all(); m_closed = 0; } //------------------------------------------------------------------------ void vcgen_dash::add_vertex(double x, double y, unsigned cmd) { m_status = initial; if(is_move_to(cmd)) { m_src_vertices.modify_last(vertex_dist(x, y)); } else { if(is_vertex(cmd)) { m_src_vertices.add(vertex_dist(x, y)); } else { m_closed = get_close_flag(cmd); } } } //------------------------------------------------------------------------ void vcgen_dash::rewind(unsigned) { if(m_status == initial) { m_src_vertices.close(m_closed != 0); shorten_path(m_src_vertices, m_shorten, m_closed); } m_status = ready; m_src_vertex = 0; } //------------------------------------------------------------------------ unsigned vcgen_dash::vertex(double* x, double* y) { unsigned cmd = path_cmd_move_to; while(!is_stop(cmd)) { switch(m_status) { case initial: rewind(0); case ready: if(m_num_dashes < 2 || m_src_vertices.size() < 2) { cmd = path_cmd_stop; break; } m_status = polyline; m_src_vertex = 1; m_v1 = &m_src_vertices[0]; m_v2 = &m_src_vertices[1]; m_curr_rest = m_v1->dist; *x = m_v1->x; *y = m_v1->y; if(m_dash_start >= 0.0) calc_dash_start(m_dash_start); return path_cmd_move_to; case polyline: { double dash_rest = m_dashes[m_curr_dash] - m_curr_dash_start; unsigned cmd = (m_curr_dash & 1) ? path_cmd_move_to : path_cmd_line_to; if(m_curr_rest > dash_rest) { m_curr_rest -= dash_rest; ++m_curr_dash; if(m_curr_dash >= m_num_dashes) m_curr_dash = 0; m_curr_dash_start = 0.0; *x = m_v2->x - (m_v2->x - m_v1->x) * m_curr_rest / m_v1->dist; *y = m_v2->y - (m_v2->y - m_v1->y) * m_curr_rest / m_v1->dist; } else { m_curr_dash_start += m_curr_rest; *x = m_v2->x; *y = m_v2->y; ++m_src_vertex; m_v1 = m_v2; m_curr_rest = m_v1->dist; if(m_closed) { if(m_src_vertex > m_src_vertices.size()) { m_status = stop; } else { m_v2 = &m_src_vertices [ (m_src_vertex >= m_src_vertices.size()) ? 0 : m_src_vertex ]; } } else { if(m_src_vertex >= m_src_vertices.size()) { m_status = stop; } else { m_v2 = &m_src_vertices[m_src_vertex]; } } } return cmd; } break; case stop: cmd = path_cmd_stop; break; } } return path_cmd_stop; } } ragg/src/agg/src/agg_image_filters.cpp0000644000176200001440000000676011063417155017456 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // Filtering class image_filter_lut implemantation // //---------------------------------------------------------------------------- #include "agg_image_filters.h" namespace agg { //-------------------------------------------------------------------- void image_filter_lut::realloc_lut(double radius) { m_radius = radius; m_diameter = uceil(radius) * 2; m_start = -int(m_diameter / 2 - 1); unsigned size = m_diameter << image_subpixel_shift; if(size > m_weight_array.size()) { m_weight_array.resize(size); } } //-------------------------------------------------------------------- // This function normalizes integer values and corrects the rounding // errors. It doesn't do anything with the source floating point values // (m_weight_array_dbl), it corrects only integers according to the rule // of 1.0 which means that any sum of pixel weights must be equal to 1.0. // So, the filter function must produce a graph of the proper shape. //-------------------------------------------------------------------- void image_filter_lut::normalize() { unsigned i; int flip = 1; for(i = 0; i < image_subpixel_scale; i++) { for(;;) { int sum = 0; unsigned j; for(j = 0; j < m_diameter; j++) { sum += m_weight_array[j * image_subpixel_scale + i]; } if(sum == image_filter_scale) break; double k = double(image_filter_scale) / double(sum); sum = 0; for(j = 0; j < m_diameter; j++) { sum += m_weight_array[j * image_subpixel_scale + i] = iround(m_weight_array[j * image_subpixel_scale + i] * k); } sum -= image_filter_scale; int inc = (sum > 0) ? -1 : 1; for(j = 0; j < m_diameter && sum; j++) { flip ^= 1; unsigned idx = flip ? m_diameter/2 + j/2 : m_diameter/2 - j/2; int v = m_weight_array[idx * image_subpixel_scale + i]; if(v < image_filter_scale) { m_weight_array[idx * image_subpixel_scale + i] += inc; sum += inc; } } } } unsigned pivot = m_diameter << (image_subpixel_shift - 1); for(i = 0; i < pivot; i++) { m_weight_array[pivot + i] = m_weight_array[pivot - i]; } unsigned end = (diameter() << image_subpixel_shift) - 1; m_weight_array[0] = m_weight_array[end]; } } ragg/src/agg/src/agg_font_freetype.cpp0000644000176200001440000013527014136210153017505 0ustar liggesusers//---------------------------------------------------------------------------- // 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. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #include #include #include "agg_font_freetype.h" #include "agg_bitset_iterator.h" #include "agg_renderer_scanline.h" namespace agg { //------------------------------------------------------------------------------ // // This code implements the AUTODIN II polynomial // The variable corresponding to the macro argument "crc" should // be an unsigned long. // Oroginal code by Spencer Garrett // // generated using the AUTODIN II polynomial // x^32 + x^26 + x^23 + x^22 + x^16 + // x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 // //------------------------------------------------------------------------------ static const unsigned crc32tab[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, }; //------------------------------------------------------------------------------ static unsigned calc_crc32(const unsigned char* buf, unsigned size) { unsigned crc = (unsigned)~0; const unsigned char* p; unsigned len = 0; unsigned nr = size; for (len += nr, p = buf; nr--; ++p) { crc = (crc >> 8) ^ crc32tab[(crc ^ *p) & 0xff]; } return ~crc; } //------------------------------------------------------------------------ static inline int dbl_to_plain_fx(double d) { return int(d * 65536.0); } //------------------------------------------------------------------------ static inline double int26p6_to_dbl(int p) { return double(p) / 64.0; } //------------------------------------------------------------------------ static inline int dbl_to_int26p6(double p) { return int(p * 64.0 + 0.5); } //------------------------------------------------------------------------ template bool decompose_ft_outline(const FT_Outline& outline, bool flip_y, const trans_affine& mtx, PathStorage& path) { typedef typename PathStorage::value_type value_type; FT_Vector v_last; FT_Vector v_control; FT_Vector v_start; double x1, y1, x2, y2, x3, y3; FT_Vector* point; FT_Vector* limit; char* tags; int n; // index of contour in outline int first; // index of first point in contour char tag; // current point's state first = 0; for(n = 0; n < outline.n_contours; n++) { int last; // index of last point in contour last = outline.contours[n]; limit = outline.points + last; v_start = outline.points[first]; v_last = outline.points[last]; v_control = v_start; point = outline.points + first; tags = outline.tags + first; tag = FT_CURVE_TAG(tags[0]); // A contour cannot start with a cubic control point! if(tag == FT_CURVE_TAG_CUBIC) return false; // check first point to determine origin if( tag == FT_CURVE_TAG_CONIC) { // first point is conic control. Yes, this happens. if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) { // start at last point if it is on the curve v_start = v_last; limit--; } else { // if both first and last points are conic, // start at their middle and record its position // for closure v_start.x = (v_start.x + v_last.x) / 2; v_start.y = (v_start.y + v_last.y) / 2; v_last = v_start; } point--; tags--; } x1 = int26p6_to_dbl(v_start.x); y1 = int26p6_to_dbl(v_start.y); if(flip_y) y1 = -y1; mtx.transform(&x1, &y1); path.move_to(value_type(dbl_to_int26p6(x1)), value_type(dbl_to_int26p6(y1))); while(point < limit) { point++; tags++; tag = FT_CURVE_TAG(tags[0]); switch(tag) { case FT_CURVE_TAG_ON: // emit a single line_to { x1 = int26p6_to_dbl(point->x); y1 = int26p6_to_dbl(point->y); if(flip_y) y1 = -y1; mtx.transform(&x1, &y1); path.line_to(value_type(dbl_to_int26p6(x1)), value_type(dbl_to_int26p6(y1))); //path.line_to(conv(point->x), flip_y ? -conv(point->y) : conv(point->y)); continue; } case FT_CURVE_TAG_CONIC: // consume conic arcs { v_control.x = point->x; v_control.y = point->y; Do_Conic: if(point < limit) { FT_Vector vec; FT_Vector v_middle; point++; tags++; tag = FT_CURVE_TAG(tags[0]); vec.x = point->x; vec.y = point->y; if(tag == FT_CURVE_TAG_ON) { x1 = int26p6_to_dbl(v_control.x); y1 = int26p6_to_dbl(v_control.y); x2 = int26p6_to_dbl(vec.x); y2 = int26p6_to_dbl(vec.y); if(flip_y) { y1 = -y1; y2 = -y2; } mtx.transform(&x1, &y1); mtx.transform(&x2, &y2); path.curve3(value_type(dbl_to_int26p6(x1)), value_type(dbl_to_int26p6(y1)), value_type(dbl_to_int26p6(x2)), value_type(dbl_to_int26p6(y2))); continue; } if(tag != FT_CURVE_TAG_CONIC) return false; v_middle.x = (v_control.x + vec.x) / 2; v_middle.y = (v_control.y + vec.y) / 2; x1 = int26p6_to_dbl(v_control.x); y1 = int26p6_to_dbl(v_control.y); x2 = int26p6_to_dbl(v_middle.x); y2 = int26p6_to_dbl(v_middle.y); if(flip_y) { y1 = -y1; y2 = -y2; } mtx.transform(&x1, &y1); mtx.transform(&x2, &y2); path.curve3(value_type(dbl_to_int26p6(x1)), value_type(dbl_to_int26p6(y1)), value_type(dbl_to_int26p6(x2)), value_type(dbl_to_int26p6(y2))); //path.curve3(conv(v_control.x), // flip_y ? -conv(v_control.y) : conv(v_control.y), // conv(v_middle.x), // flip_y ? -conv(v_middle.y) : conv(v_middle.y)); v_control = vec; goto Do_Conic; } x1 = int26p6_to_dbl(v_control.x); y1 = int26p6_to_dbl(v_control.y); x2 = int26p6_to_dbl(v_start.x); y2 = int26p6_to_dbl(v_start.y); if(flip_y) { y1 = -y1; y2 = -y2; } mtx.transform(&x1, &y1); mtx.transform(&x2, &y2); path.curve3(value_type(dbl_to_int26p6(x1)), value_type(dbl_to_int26p6(y1)), value_type(dbl_to_int26p6(x2)), value_type(dbl_to_int26p6(y2))); //path.curve3(conv(v_control.x), // flip_y ? -conv(v_control.y) : conv(v_control.y), // conv(v_start.x), // flip_y ? -conv(v_start.y) : conv(v_start.y)); goto Close; } default: // FT_CURVE_TAG_CUBIC { FT_Vector vec1, vec2; if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC) { return false; } vec1.x = point[0].x; vec1.y = point[0].y; vec2.x = point[1].x; vec2.y = point[1].y; point += 2; tags += 2; if(point <= limit) { FT_Vector vec; vec.x = point->x; vec.y = point->y; x1 = int26p6_to_dbl(vec1.x); y1 = int26p6_to_dbl(vec1.y); x2 = int26p6_to_dbl(vec2.x); y2 = int26p6_to_dbl(vec2.y); x3 = int26p6_to_dbl(vec.x); y3 = int26p6_to_dbl(vec.y); if(flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; } mtx.transform(&x1, &y1); mtx.transform(&x2, &y2); mtx.transform(&x3, &y3); path.curve4(value_type(dbl_to_int26p6(x1)), value_type(dbl_to_int26p6(y1)), value_type(dbl_to_int26p6(x2)), value_type(dbl_to_int26p6(y2)), value_type(dbl_to_int26p6(x3)), value_type(dbl_to_int26p6(y3))); //path.curve4(conv(vec1.x), // flip_y ? -conv(vec1.y) : conv(vec1.y), // conv(vec2.x), // flip_y ? -conv(vec2.y) : conv(vec2.y), // conv(vec.x), // flip_y ? -conv(vec.y) : conv(vec.y)); continue; } x1 = int26p6_to_dbl(vec1.x); y1 = int26p6_to_dbl(vec1.y); x2 = int26p6_to_dbl(vec2.x); y2 = int26p6_to_dbl(vec2.y); x3 = int26p6_to_dbl(v_start.x); y3 = int26p6_to_dbl(v_start.y); if(flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; } mtx.transform(&x1, &y1); mtx.transform(&x2, &y2); mtx.transform(&x3, &y3); path.curve4(value_type(dbl_to_int26p6(x1)), value_type(dbl_to_int26p6(y1)), value_type(dbl_to_int26p6(x2)), value_type(dbl_to_int26p6(y2)), value_type(dbl_to_int26p6(x3)), value_type(dbl_to_int26p6(y3))); //path.curve4(conv(vec1.x), // flip_y ? -conv(vec1.y) : conv(vec1.y), // conv(vec2.x), // flip_y ? -conv(vec2.y) : conv(vec2.y), // conv(v_start.x), // flip_y ? -conv(v_start.y) : conv(v_start.y)); goto Close; } } } path.close_polygon(); Close: first = last + 1; } return true; } //------------------------------------------------------------------------ template void decompose_ft_bitmap_mono(const FT_Bitmap& bitmap, int x, int y, bool flip_y, Scanline& sl, ScanlineStorage& storage) { unsigned int i; const int8u* buf = (const int8u*)bitmap.buffer; int pitch = bitmap.pitch; sl.reset(x, x + bitmap.width); storage.prepare(); if(flip_y) { buf += bitmap.pitch * (bitmap.rows - 1); y += bitmap.rows; pitch = -pitch; } for(i = 0; i < bitmap.rows; i++) { sl.reset_spans(); bitset_iterator bits(buf, 0); unsigned int j; for(j = 0; j < bitmap.width; j++) { if(bits.bit()) sl.add_cell(x + j, cover_full); ++bits; } buf += pitch; if(sl.num_spans()) { sl.finalize(y - i - 1); storage.render(sl); } } } //------------------------------------------------------------------------ template void decompose_ft_bitmap_gray8(const FT_Bitmap& bitmap, int x, int y, bool flip_y, Rasterizer& ras, Scanline& sl, ScanlineStorage& storage) { unsigned int i, j; const int8u* buf = (const int8u*)bitmap.buffer; int pitch = bitmap.pitch; sl.reset(x, x + bitmap.width); storage.prepare(); if(flip_y) { buf += bitmap.pitch * (bitmap.rows - 1); y += bitmap.rows; pitch = -pitch; } for(i = 0; i < bitmap.rows; i++) { sl.reset_spans(); const int8u* p = buf; for(j = 0; j < bitmap.width; j++) { if(*p) sl.add_cell(x + j, ras.apply_gamma(*p)); ++p; } buf += pitch; if(sl.num_spans()) { sl.finalize(y - i - 1); storage.render(sl); } } } //------------------------------------------------------------------------ template void decompose_ft_bitmap_color(const FT_Bitmap& bitmap, int x, int y, bool flip_y, Rasterizer& ras, Scanline& sl, ScanlineStorage& storage) { unsigned int i, j; const int8u* buf = (const int8u*)bitmap.buffer; int pitch = bitmap.pitch; sl.reset(x, x + bitmap.width*4); storage.prepare(); if(flip_y) { buf += bitmap.pitch * (bitmap.rows - 1); y += bitmap.rows; pitch = -pitch; } for(i = 0; i < bitmap.rows; i++) { sl.reset_spans(); const int8u* p = buf; for(j = 0; j < bitmap.width*4; j++) { if(*p) sl.add_cell(x + j, *p); ++p; } buf += pitch; if(sl.num_spans()) { sl.finalize(y - i - 1); storage.render(sl); } } } //------------------------------------------------------------------------ font_engine_freetype_base::~font_engine_freetype_base() { unsigned i; for(i = 0; i < m_num_faces; ++i) { delete [] m_face_names[i]; FT_Done_Face(m_faces[i]); } delete [] m_face_names; delete [] m_face_indices; delete [] m_faces; delete [] m_signature; if(m_library_initialized) FT_Done_FreeType(m_library); } //------------------------------------------------------------------------ font_engine_freetype_base::font_engine_freetype_base(bool flag32, unsigned max_faces) : m_flag32(flag32), m_change_stamp(0), m_last_error(0), m_name(0), m_name_len(256-16-1), m_face_index(0), m_char_map(FT_ENCODING_NONE), m_signature(new char [256+256-16]), m_height(0), m_width(0), m_hinting(true), m_flip_y(false), m_library_initialized(false), m_library(0), m_faces(new FT_Face [max_faces]), m_face_names(new char* [max_faces]), m_face_indices(new unsigned [max_faces]), m_num_faces(0), m_max_faces(max_faces), m_cur_face(0), m_resolution(0), m_glyph_rendering(glyph_ren_native_gray8), m_glyph_index(0), m_data_size(0), m_data_type(glyph_data_invalid), m_bounds(1,1,0,0), m_advance_x(0.0), m_advance_y(0.0), m_path16(), m_path32(), m_curves16(m_path16), m_curves32(m_path32), m_scanline_aa(), m_scanline_bin(), m_scanlines_aa(), m_scanlines_bin(), m_rasterizer() { m_curves16.approximation_scale(4.0); m_curves32.approximation_scale(4.0); m_last_error = FT_Init_FreeType(&m_library); if(m_last_error == 0) m_library_initialized = true; } //------------------------------------------------------------------------ void font_engine_freetype_base::resolution(unsigned dpi) { m_resolution = dpi; update_char_size(); } //------------------------------------------------------------------------ int font_engine_freetype_base::find_face(const char* face_name, unsigned face_index) const { unsigned i; for(i = 0; i < m_num_faces; ++i) { if(face_index == m_face_indices[i] && std::strcmp(face_name, m_face_names[i]) == 0) return i; } return -1; } //------------------------------------------------------------------------ double font_engine_freetype_base::ascender() const { if(m_cur_face) { return m_cur_face->ascender * height() / m_cur_face->height; } return 0.0; } //------------------------------------------------------------------------ double font_engine_freetype_base::descender() const { if(m_cur_face) { return m_cur_face->descender * height() / m_cur_face->height; } return 0.0; } //------------------------------------------------------------------------ bool font_engine_freetype_base::load_font(const char* font_name, unsigned face_index, glyph_rendering ren_type, const char* font_mem, const long font_mem_size) { bool ret = false; if(m_library_initialized) { m_last_error = 0; int idx = find_face(font_name, face_index); if(idx >= 0) { m_cur_face = m_faces[idx]; m_name = m_face_names[idx]; m_face_index = m_face_indices[idx]; } else { if(m_num_faces >= m_max_faces) { delete [] m_face_names[0]; FT_Done_Face(m_faces[0]); std::memcpy(m_faces, m_faces + 1, (m_max_faces - 1) * sizeof(FT_Face)); std::memcpy(m_face_names, m_face_names + 1, (m_max_faces - 1) * sizeof(char*)); std::memcpy(m_face_indices, m_face_indices + 1, (m_max_faces - 1) * sizeof(unsigned)); m_num_faces = m_max_faces - 1; } if (font_mem && font_mem_size) { m_last_error = FT_New_Memory_Face(m_library, (const FT_Byte*)font_mem, font_mem_size, face_index, &m_faces[m_num_faces]); } else { m_last_error = FT_New_Face(m_library, font_name, face_index, &m_faces[m_num_faces]); } if(m_last_error == 0) { m_face_names[m_num_faces] = new char [std::strlen(font_name) + 1]; std::strcpy(m_face_names[m_num_faces], font_name); m_face_indices[m_num_faces] = face_index; m_cur_face = m_faces[m_num_faces]; m_name = m_face_names[m_num_faces]; m_face_index = face_index; ++m_num_faces; } else { m_face_names[m_num_faces] = 0; m_face_indices[m_num_faces] = 0; m_cur_face = 0; m_name = 0; m_face_index = 0; } } if(m_last_error == 0) { ret = true; if (FT_HAS_COLOR(m_cur_face)) { m_glyph_rendering = glyph_ren_native_color; } else { switch(ren_type) { case glyph_ren_native_mono: m_glyph_rendering = glyph_ren_native_mono; break; case glyph_ren_native_gray8: m_glyph_rendering = glyph_ren_native_gray8; break; case glyph_ren_native_color: // Not a color font so use gray8 m_glyph_rendering = glyph_ren_native_gray8; break; case glyph_ren_outline: if(FT_IS_SCALABLE(m_cur_face)) { m_glyph_rendering = glyph_ren_outline; } else { m_glyph_rendering = glyph_ren_native_gray8; } break; case glyph_ren_agg_mono: if(FT_IS_SCALABLE(m_cur_face)) { m_glyph_rendering = glyph_ren_agg_mono; } else { m_glyph_rendering = glyph_ren_native_mono; } break; case glyph_ren_agg_gray8: if(FT_IS_SCALABLE(m_cur_face)) { m_glyph_rendering = glyph_ren_agg_gray8; } else { m_glyph_rendering = glyph_ren_native_gray8; } break; } } update_signature(); } } return ret; } //------------------------------------------------------------------------ bool font_engine_freetype_base::attach(const char* file_name) { if(m_cur_face) { m_last_error = FT_Attach_File(m_cur_face, file_name); return m_last_error == 0; } return false; } //------------------------------------------------------------------------ unsigned font_engine_freetype_base::num_faces() const { if(m_cur_face) { return m_cur_face->num_faces; } return 0; } //------------------------------------------------------------------------ bool font_engine_freetype_base::char_map(FT_Encoding map) { if(m_cur_face) { m_last_error = FT_Select_Charmap(m_cur_face, map); if(m_last_error == 0) { m_char_map = map; update_signature(); return true; } } return false; } //------------------------------------------------------------------------ bool font_engine_freetype_base::height(double h) { m_height = int(h * 64.0); if(m_cur_face) { update_char_size(); return true; } return false; } //------------------------------------------------------------------------ bool font_engine_freetype_base::width(double w) { m_width = int(w * 64.0); if(m_cur_face) { update_char_size(); return true; } return false; } //------------------------------------------------------------------------ void font_engine_freetype_base::hinting(bool h) { m_hinting = h; if(m_cur_face) { update_signature(); } } //------------------------------------------------------------------------ void font_engine_freetype_base::flip_y(bool f) { m_flip_y = f; if(m_cur_face) { update_signature(); } } //------------------------------------------------------------------------ void font_engine_freetype_base::transform(const trans_affine& affine) { m_affine = affine; if(m_cur_face) { update_signature(); } } //------------------------------------------------------------------------ void font_engine_freetype_base::update_signature() { if(m_cur_face && m_name) { unsigned name_len = std::strlen(m_name); if(name_len > m_name_len) { delete [] m_signature; m_signature = new char [name_len + 32 + 256]; m_name_len = name_len + 32 - 1; } unsigned gamma_hash = 0; if(m_glyph_rendering == glyph_ren_native_gray8 || m_glyph_rendering == glyph_ren_native_color || m_glyph_rendering == glyph_ren_agg_mono || m_glyph_rendering == glyph_ren_agg_gray8) { unsigned char gamma_table[rasterizer_scanline_aa<>::aa_scale]; unsigned i; for(i = 0; i < rasterizer_scanline_aa<>::aa_scale; ++i) { gamma_table[i] = m_rasterizer.apply_gamma(i); } gamma_hash = calc_crc32(gamma_table, sizeof(gamma_table)); } std::sprintf(m_signature, "%s,%u,%d,%d,%d:%dx%d,%d,%d,%08X", m_name, m_char_map, m_face_index, int(m_glyph_rendering), m_resolution, m_height, m_width, int(m_hinting), int(m_flip_y), gamma_hash); if(m_glyph_rendering == glyph_ren_outline || m_glyph_rendering == glyph_ren_agg_mono || m_glyph_rendering == glyph_ren_agg_gray8) { double mtx[6]; char buf[100]; m_affine.store_to(mtx); std::sprintf(buf, ",%08X%08X%08X%08X%08X%08X", dbl_to_plain_fx(mtx[0]), dbl_to_plain_fx(mtx[1]), dbl_to_plain_fx(mtx[2]), dbl_to_plain_fx(mtx[3]), dbl_to_plain_fx(mtx[4]), dbl_to_plain_fx(mtx[5])); std::strcat(m_signature, buf); } ++m_change_stamp; } } //------------------------------------------------------------------------ void font_engine_freetype_base::update_char_size() { if(m_cur_face) { if(!FT_IS_SCALABLE(m_cur_face)) { int best_match = 0; int diff = 1e6; unsigned largest_size = 0; int largest_ind = -1; bool found_match = false; for (int i = 0; i < m_cur_face->num_fixed_sizes; ++i) { if (m_cur_face->available_sizes[i].size > largest_size) { largest_ind = i; } int ndiff = m_cur_face->available_sizes[i].size - m_height; if (ndiff >= 0 && ndiff < diff) { best_match = i; diff = ndiff; found_match = true; } } if (!found_match && m_height >= largest_size) { best_match = largest_ind; } FT_Select_Size(m_cur_face, best_match); m_height = m_cur_face->size->metrics.height; } else if(m_resolution) { FT_Set_Char_Size(m_cur_face, m_width, // char_width in 1/64th of points m_height, // char_height in 1/64th of points m_resolution, // horizontal device resolution m_resolution); // vertical device resolution } else { FT_Set_Pixel_Sizes(m_cur_face, m_width >> 6, // pixel_width m_height >> 6); // pixel_height } update_signature(); } } //------------------------------------------------------------------------ unsigned font_engine_freetype_base::get_glyph_index(unsigned glyph_code) { return FT_Get_Char_Index(m_cur_face, glyph_code); } //------------------------------------------------------------------------ bool font_engine_freetype_base::prepare_glyph(unsigned glyph_index) { m_glyph_index = glyph_index; m_last_error = FT_Load_Glyph(m_cur_face, m_glyph_index, m_glyph_rendering == glyph_ren_native_color ? FT_LOAD_COLOR : (m_hinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING)); if(m_last_error == 0) { switch(m_glyph_rendering) { case glyph_ren_native_mono: m_last_error = FT_Render_Glyph(m_cur_face->glyph, FT_RENDER_MODE_MONO); if(m_last_error == 0) { decompose_ft_bitmap_mono(m_cur_face->glyph->bitmap, m_cur_face->glyph->bitmap_left, m_flip_y ? -m_cur_face->glyph->bitmap_top : m_cur_face->glyph->bitmap_top, m_flip_y, m_scanline_bin, m_scanlines_bin); m_bounds.x1 = m_scanlines_bin.min_x(); m_bounds.y1 = m_scanlines_bin.min_y(); m_bounds.x2 = m_scanlines_bin.max_x() + 1; m_bounds.y2 = m_scanlines_bin.max_y() + 1; m_data_size = m_scanlines_bin.byte_size(); m_data_type = glyph_data_mono; m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x); m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y); return true; } break; case glyph_ren_native_color: m_last_error = FT_Render_Glyph(m_cur_face->glyph, FT_RENDER_MODE_NORMAL); if(m_last_error == 0) { m_bounds.x1 = m_cur_face->glyph->bitmap_left; m_bounds.y1 = m_cur_face->glyph->bitmap_top; m_bounds.x2 = m_bounds.x1 + m_cur_face->glyph->bitmap.width; m_bounds.y2 = m_bounds.y1 - m_cur_face->glyph->bitmap.rows; m_data_size = m_cur_face->glyph->bitmap.rows * m_cur_face->glyph->bitmap.pitch; m_data_type = glyph_data_color; m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x); m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y); return true; } break; case glyph_ren_native_gray8: m_last_error = FT_Render_Glyph(m_cur_face->glyph, FT_RENDER_MODE_NORMAL); if(m_last_error == 0) { decompose_ft_bitmap_gray8(m_cur_face->glyph->bitmap, m_cur_face->glyph->bitmap_left, m_flip_y ? -m_cur_face->glyph->bitmap_top : m_cur_face->glyph->bitmap_top, m_flip_y, m_rasterizer, m_scanline_aa, m_scanlines_aa); m_bounds.x1 = m_scanlines_aa.min_x(); m_bounds.y1 = m_scanlines_aa.min_y(); m_bounds.x2 = m_scanlines_aa.max_x() + 1; m_bounds.y2 = m_scanlines_aa.max_y() + 1; m_data_size = m_scanlines_aa.byte_size(); m_data_type = glyph_data_gray8; m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x); m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y); return true; } break; case glyph_ren_outline: if(m_last_error == 0) { if(m_flag32) { m_path32.remove_all(); if(decompose_ft_outline(m_cur_face->glyph->outline, m_flip_y, m_affine, m_path32)) { rect_d bnd = m_path32.bounding_rect(); m_data_size = m_path32.byte_size(); m_data_type = glyph_data_outline; m_bounds.x1 = int(floor(bnd.x1)); m_bounds.y1 = int(floor(bnd.y1)); m_bounds.x2 = int(ceil(bnd.x2)); m_bounds.y2 = int(ceil(bnd.y2)); m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x); m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y); m_affine.transform(&m_advance_x, &m_advance_y); return true; } } else { m_path16.remove_all(); if(decompose_ft_outline(m_cur_face->glyph->outline, m_flip_y, m_affine, m_path16)) { rect_d bnd = m_path16.bounding_rect(); m_data_size = m_path16.byte_size(); m_data_type = glyph_data_outline; m_bounds.x1 = int(floor(bnd.x1)); m_bounds.y1 = int(floor(bnd.y1)); m_bounds.x2 = int(ceil(bnd.x2)); m_bounds.y2 = int(ceil(bnd.y2)); m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x); m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y); m_affine.transform(&m_advance_x, &m_advance_y); return true; } } } return false; case glyph_ren_agg_mono: if(m_last_error == 0) { m_rasterizer.reset(); if(m_flag32) { m_path32.remove_all(); decompose_ft_outline(m_cur_face->glyph->outline, m_flip_y, m_affine, m_path32); m_rasterizer.add_path(m_curves32); } else { m_path16.remove_all(); decompose_ft_outline(m_cur_face->glyph->outline, m_flip_y, m_affine, m_path16); m_rasterizer.add_path(m_curves16); } m_scanlines_bin.prepare(); // Remove all render_scanlines(m_rasterizer, m_scanline_bin, m_scanlines_bin); m_bounds.x1 = m_scanlines_bin.min_x(); m_bounds.y1 = m_scanlines_bin.min_y(); m_bounds.x2 = m_scanlines_bin.max_x() + 1; m_bounds.y2 = m_scanlines_bin.max_y() + 1; m_data_size = m_scanlines_bin.byte_size(); m_data_type = glyph_data_mono; m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x); m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y); m_affine.transform(&m_advance_x, &m_advance_y); return true; } return false; case glyph_ren_agg_gray8: if(m_last_error == 0) { m_rasterizer.reset(); if(m_flag32) { m_path32.remove_all(); decompose_ft_outline(m_cur_face->glyph->outline, m_flip_y, m_affine, m_path32); m_rasterizer.add_path(m_curves32); } else { m_path16.remove_all(); decompose_ft_outline(m_cur_face->glyph->outline, m_flip_y, m_affine, m_path16); m_rasterizer.add_path(m_curves16); } m_scanlines_aa.prepare(); // Remove all render_scanlines(m_rasterizer, m_scanline_aa, m_scanlines_aa); m_bounds.x1 = m_scanlines_aa.min_x(); m_bounds.y1 = m_scanlines_aa.min_y(); m_bounds.x2 = m_scanlines_aa.max_x() + 1; m_bounds.y2 = m_scanlines_aa.max_y() + 1; m_data_size = m_scanlines_aa.byte_size(); m_data_type = glyph_data_gray8; m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x); m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y); m_affine.transform(&m_advance_x, &m_advance_y); return true; } return false; } } return false; } //------------------------------------------------------------------------ void font_engine_freetype_base::write_glyph_to(int8u* data) const { if(data && m_data_size) { switch(m_data_type) { default: return; case glyph_data_mono: m_scanlines_bin.serialize(data); break; case glyph_data_color: memcpy(data, m_cur_face->glyph->bitmap.buffer, m_data_size); break; case glyph_data_gray8: m_scanlines_aa.serialize(data); break; case glyph_data_outline: if(m_flag32) { m_path32.serialize(data); } else { m_path16.serialize(data); } break; case glyph_data_invalid: break; } } } //------------------------------------------------------------------------ bool font_engine_freetype_base::add_kerning(unsigned first, unsigned second, double* x, double* y) { if(m_cur_face && first && second && FT_HAS_KERNING(m_cur_face)) { FT_Vector delta; FT_Get_Kerning(m_cur_face, first, second, FT_KERNING_DEFAULT, &delta); double dx = int26p6_to_dbl(delta.x); double dy = int26p6_to_dbl(delta.y); if(m_glyph_rendering == glyph_ren_outline || m_glyph_rendering == glyph_ren_agg_mono || m_glyph_rendering == glyph_ren_agg_gray8) { m_affine.transform_2x2(&dx, &dy); } *x += dx; *y += dy; return true; } return false; } } ragg/src/agg/copying0000644000176200001440000000505513504406270014120 0ustar liggesusersThe Anti-Grain Geometry Project A high quality rendering engine for C++ http://antigrain.com Anti-Grain Geometry has dual licensing model. The Modified BSD License was first added in version v2.4 just for convenience. It is a simple, permissive non-copyleft free software license, compatible with the GNU GPL. It's well proven and recognizable. See http://www.fsf.org/licensing/licenses/index_html#ModifiedBSD for details. Note that the Modified BSD license DOES NOT restrict your rights if you choose the Anti-Grain Geometry Public License. Anti-Grain Geometry Public License ==================================================== Anti-Grain Geometry - Version 2.4 Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) 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. Modified BSD License ==================================================== Anti-Grain Geometry - Version 2.4 Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ragg/src/init.cpp0000644000176200001440000000121013665770132013434 0ustar liggesusers#define R_NO_REMAP #include #include // for NULL #include #include #include "ragg.h" static const R_CallMethodDef CallEntries[] = { {"agg_ppm_c", (DL_FUNC) &agg_ppm_c, 7}, {"agg_png_c", (DL_FUNC) &agg_png_c, 8}, {"agg_supertransparent_c", (DL_FUNC) &agg_supertransparent_c, 8}, {"agg_tiff_c", (DL_FUNC) &agg_tiff_c, 10}, {"agg_jpeg_c", (DL_FUNC) &agg_jpeg_c, 10}, {"agg_capture_c", (DL_FUNC) &agg_capture_c, 7}, {NULL, NULL, 0} }; extern "C" void R_init_ragg(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } ragg/src/png_dev.cpp0000644000176200001440000000544714127312027014120 0ustar liggesusers#include "ragg.h" #include "init_device.h" #include "AggDevicePng.h" // [[export]] SEXP agg_png_c(SEXP file, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling, SEXP bit) { bool bit8 = INTEGER(bit)[0] == 8; int bgCol = RGBpar(bg, 0); BEGIN_CPP if (bit8) { if (R_OPAQUE(bgCol)) { // Opaque bg... no need for alpha channel AggDevicePngNoAlpha* device = new AggDevicePngNoAlpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0] ); makeDevice(device, "agg_png"); } else { AggDevicePngAlpha* device = new AggDevicePngAlpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0] ); makeDevice(device, "agg_png"); } } else { if (R_OPAQUE(bgCol)) { // Opaque bg... no need for alpha channel AggDevicePng16NoAlpha* device = new AggDevicePng16NoAlpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0] ); makeDevice(device, "agg_png"); } else { AggDevicePng16Alpha* device = new AggDevicePng16Alpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0] ); makeDevice(device, "agg_png"); } } END_CPP return R_NilValue; } SEXP agg_supertransparent_c(SEXP file, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling, SEXP alpha_mod) { int bgCol = RGBpar(bg, 0); BEGIN_CPP if (R_OPAQUE(bgCol)) { // Opaque bg... no need for alpha channel AggDevicePng16NoAlpha* device = new AggDevicePng16NoAlpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0], REAL(alpha_mod)[0] ); makeDevice(device, "agg_png"); } else { AggDevicePng16Alpha* device = new AggDevicePng16Alpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0], REAL(alpha_mod)[0] ); makeDevice(device, "agg_png"); } END_CPP return R_NilValue; } ragg/src/AggDeviceCapture.h0000644000176200001440000000177514127250576015317 0ustar liggesusers#pragma once #include "ragg.h" #include "AggDevice.h" template class AggDeviceCapture : public AggDevice { public: bool can_capture = true; AggDeviceCapture(const char* fp, int w, int h, double ps, int bg, double res, double scaling) : AggDevice(fp, w, h, ps, bg, res, scaling) { } // Behaviour bool savePage() { return true; } SEXP capture() { SEXP raster = PROTECT(Rf_allocVector(INTSXP, this->width * this->height)); agg::rendering_buffer caprbuf(reinterpret_cast(INTEGER(raster)), this->width, this->height, this->width * 4); agg::convert(&caprbuf, &this->rbuf); SEXP dims = PROTECT(Rf_allocVector(INTSXP, 2)); INTEGER(dims)[0] = this->height; INTEGER(dims)[1] = this->width; Rf_setAttrib(raster, R_DimSymbol, dims); UNPROTECT(2); return raster; } }; typedef AggDeviceCapture AggDeviceCaptureAlpha; ragg/src/AggDeviceTiff.h0000644000176200001440000001125714153356753014603 0ustar liggesusers#pragma once #include "ragg.h" #include "AggDevice.h" #include "AggDevice16.h" #include template class AggDeviceTiff : public AggDevice { int compression; int encoding; public: AggDeviceTiff(const char* fp, int w, int h, double ps, int bg, double res, double scaling, int comp = 0, int enc = 0) : AggDevice(fp, w, h, ps, bg, res, scaling), compression(comp), encoding(enc) { } // Behaviour bool savePage() { char buf[PATH_MAX+1]; snprintf(buf, PATH_MAX, this->file.c_str(), this->pageno); buf[PATH_MAX] = '\0'; TIFF *out= TIFFOpen(buf, "w"); if (!out) return false; // Image dims TIFFSetField (out, TIFFTAG_IMAGEWIDTH, this->width); TIFFSetField(out, TIFFTAG_IMAGELENGTH, this->height); TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, PIXFMT::num_components); if (PIXFMT::num_components == 4) { short extras[] = {EXTRASAMPLE_ASSOCALPHA}; TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, extras); } TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(out, TIFFTAG_XRESOLUTION, this->res_real); TIFFSetField(out, TIFFTAG_YRESOLUTION, this->res_real); TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, 2); // Inches // Compression if (compression) TIFFSetField(out, TIFFTAG_COMPRESSION, compression); if (encoding) TIFFSetField(out, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); // Required TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); // Strip equals scanline TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, this->width * PIXFMT::num_components)); agg::row_ptr_cache buffer_rows( this->buffer, this->width, this->height, this->rbuf.stride_abs() ); //Now writing image to the file one strip at a time for (int32_t row = 0; row < this->height; row++) { if (TIFFWriteScanline(out, buffer_rows.row_ptr(row), row, 0) < 0) { (void) TIFFClose(out); return false; } } (void) TIFFClose(out); return true; } }; typedef AggDeviceTiff AggDeviceTiffNoAlpha; typedef AggDeviceTiff AggDeviceTiffAlpha; // This is more or less a complete copy of the above 8bit implementation, // but subclassing AggDevice16. There is probably a better setup template class AggDeviceTiff16 : public AggDevice16 { int compression; int encoding; public: AggDeviceTiff16(const char* fp, int w, int h, double ps, int bg, double res, double scaling, int comp = 0, int enc = 0) : AggDevice16(fp, w, h, ps, bg, res, scaling), compression(comp), encoding(enc) { } // Behaviour bool savePage() { char buf[PATH_MAX+1]; snprintf(buf, PATH_MAX, this->file.c_str(), this->pageno); buf[PATH_MAX] = '\0'; TIFF *out= TIFFOpen(buf, "w"); if (!out) return false; // Image dims TIFFSetField (out, TIFFTAG_IMAGEWIDTH, this->width); TIFFSetField(out, TIFFTAG_IMAGELENGTH, this->height); TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, PIXFMT::num_components); if (PIXFMT::num_components == 4) { TIFFSetField(out, TIFFTAG_EXTRASAMPLES, EXTRASAMPLE_ASSOCALPHA); } TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 16); TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(out, TIFFTAG_XRESOLUTION, this->res_real); TIFFSetField(out, TIFFTAG_YRESOLUTION, this->res_real); TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, 2); // Inches // Compression if (compression) TIFFSetField(out, TIFFTAG_COMPRESSION, compression); if (encoding) TIFFSetField(out, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); // Required TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); // Strip equals scanline TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, this->width * PIXFMT::num_components)); agg::row_ptr_cache buffer_rows( this->buffer, this->width, this->height, this->rbuf.stride_abs() ); //Now writing image to the file one strip at a time for (int32_t row = 0; row < this->height; row++) { if (TIFFWriteScanline(out, buffer_rows.row_ptr(row), row, 0) < 0) { (void) TIFFClose(out); return false; } } (void) TIFFClose(out); return true; } }; typedef AggDeviceTiff16 AggDeviceTiff16NoAlpha; typedef AggDeviceTiff16 AggDeviceTiff16Alpha; ragg/src/AggDevice.h0000644000176200001440000011104214153414623013752 0ustar liggesusers#pragma once #include "ragg.h" #include "rendering.h" #include "text_renderer.h" #include "RenderBuffer.h" #include "pattern.h" #include "agg_math_stroke.h" #include "agg_ellipse.h" #include "agg_path_storage.h" #include "agg_conv_stroke.h" #include "agg_conv_dash.h" // #include "agg_span_interpolator_linear.h" #include "agg_image_accessors.h" #include "agg_span_image_filter_rgba.h" #include "agg_span_allocator.h" // #include "agg_rasterizer_scanline_aa.h" #include "agg_scanline_p.h" #include "agg_scanline_u.h" #include "agg_scanline_boolean_algebra.h" #include "util/agg_color_conv.h" #include static const int MAX_CELLS = 1 << 20; /* Base class for graphic device interface to AGG. See AggDevice.cpp for * implementation details. * * Specific devices should subclass this and provide their own buffer and * savePage() methods (at least), while the drawing methods should work * regardless. The base class outputs images in ppm format which is not realy * a usable format. See png and tiff versions for actual usable classes. */ template class AggDevice { public: typedef PIXFMT pixfmt_type; typedef agg::renderer_base renbase_type; typedef agg::renderer_scanline_aa_solid renderer_solid; typedef agg::renderer_scanline_bin_solid renderer_bin; static const int bytes_per_pixel = pixfmt_type::pix_width; bool can_capture = false; int width; int height; double clip_left; double clip_right; double clip_top; double clip_bottom; unsigned int device_id; renbase_type renderer; renderer_solid solid_renderer; pixfmt_type* pixf; agg::rendering_buffer rbuf; unsigned char* buffer; int pageno; std::string file; R_COLOR background; int background_int; double pointsize; double res_real; double res_mod; double lwd_mod; double x_trans; double y_trans; TextRenderer t_ren; // Caches std::unordered_map, bool> > clip_cache; unsigned int clip_cache_next_id; agg::path_storage* recording_clip; agg::path_storage* current_clip; bool current_clip_rule_is_evenodd; std::unordered_map > mask_cache; unsigned int mask_cache_next_id; MaskBuffer* recording_mask; MaskBuffer* current_mask; std::unordered_map > > pattern_cache; unsigned int pattern_cache_next_id; RenderBuffer* recording_pattern; // Lifecycle methods AggDevice(const char* fp, int w, int h, double ps, int bg, double res, double scaling); virtual ~AggDevice(); void newPage(unsigned int bg); void close(); virtual bool savePage(); SEXP capture(); // Behaviour void clipRect(double x0, double y0, double x1, double y1); double stringWidth(const char *str, const char *family, int face, double size); void charMetric(int c, const char *family, int face, double size, double *ascent, double *descent, double *width); SEXP createClipPath(SEXP path, SEXP ref); void removeClipPath(SEXP ref); SEXP createMask(SEXP mask, SEXP ref); void removeMask(SEXP ref); SEXP createPattern(SEXP pattern); void removePattern(SEXP ref); // Drawing Methods void drawCircle(double x, double y, double r, int fill, int col, double lwd, int lty, R_GE_lineend lend, int pattern); void drawRect(double x0, double y0, double x1, double y1, int fill, int col, double lwd, int lty, R_GE_lineend lend, int pattern); void drawPolygon(int n, double *x, double *y, int fill, int col, double lwd, int lty, R_GE_lineend lend, R_GE_linejoin ljoin, double lmitre, int pattern); void drawLine(double x1, double y1, double x2, double y2, int col, double lwd, int lty, R_GE_lineend lend); void drawPolyline(int n, double* x, double* y, int col, double lwd, int lty, R_GE_lineend lend, R_GE_linejoin ljoin, double lmitre); void drawPath(int npoly, int* nper, double* x, double* y, int col, int fill, double lwd, int lty, R_GE_lineend lend, R_GE_linejoin ljoin, double lmitre, bool evenodd, int pattern); void drawRaster(unsigned int *raster, int w, int h, double x, double y, double final_width, double final_height, double rot, bool interpolate); void drawText(double x, double y, const char *str, const char *family, int face, double size, double rot, double hadj, int col); private: virtual inline R_COLOR convertColour(unsigned int col) { return R_COLOR(R_RED(col), R_GREEN(col), R_BLUE(col), R_ALPHA(col)).premultiply(); } virtual inline agg::rgba32 convertMaskCol(unsigned int col) { return agg::rgba32(R_COLOR(R_RED(col), R_GREEN(col), R_BLUE(col), R_ALPHA(col))).premultiply(); } inline bool visibleColour(unsigned int col) { return (int) !R_TRANSPARENT(col); } inline agg::line_cap_e convertLineend(R_GE_lineend lend) { switch (lend) { case GE_ROUND_CAP: return agg::round_cap; case GE_BUTT_CAP: return agg::butt_cap; case GE_SQUARE_CAP: return agg::square_cap; } //should never happen return agg::square_cap; } inline agg::line_join_e convertLinejoin(R_GE_linejoin ljoin) { switch(ljoin) { case GE_ROUND_JOIN: return agg::round_join; case GE_MITRE_JOIN: return agg::miter_join; case GE_BEVEL_JOIN: return agg::bevel_join; } //should never happen return agg::round_join; } template void makeDash(T &dash_conv, int lty, double lwd) { dash_conv.remove_all_dashes(); double dash, gap; for(int i = 0 ; i < 8 && lty & 15 ; i += 2) { dash = (lty & 15) * lwd; lty = lty>>4; gap = (lty & 15) * lwd; lty = lty>>4; dash_conv.add_dash(dash, gap); } } template void setStroke(Raster &ras, Path &p, int lty, double lwd, R_GE_lineend lend, R_GE_linejoin ljoin) { if (lty == LTY_SOLID) { agg::conv_stroke pg(p); pg.width(lwd); pg.line_join(convertLinejoin(ljoin)); pg.line_cap(convertLineend(lend)); ras.add_path(pg); } else { agg::conv_dash pd(p); agg::conv_stroke< agg::conv_dash > pg(pd); makeDash(pd, lty, lwd); pg.width(lwd); pg.line_join(convertLinejoin(ljoin)); pg.line_cap(convertLineend(lend)); ras.add_path(pg); } } template void fillPattern(Raster &ras, Raster &ras_clip, Pattern& pattern) { agg::scanline_u8 sl; bool clip = current_clip != NULL; if (recording_mask == NULL && recording_pattern == NULL) { if (current_mask == NULL) { pattern.draw(ras, ras_clip, sl, renderer, clip); } else { pattern.draw(ras, ras_clip, current_mask->get_masked_scanline(), renderer, clip); } } else if (recording_pattern == NULL) { Pattern mask_pattern = pattern.convert_for_mask(); if (current_mask == NULL) { mask_pattern.draw(ras, ras_clip, sl, recording_mask->get_renderer(), clip); } else { mask_pattern.draw(ras, ras_clip, current_mask->get_masked_scanline(), recording_mask->get_renderer(), clip); } } else { if (current_mask == NULL) { pattern.draw(ras, ras_clip, sl, recording_pattern->get_renderer(), clip); } else { pattern.draw(ras, ras_clip, current_mask->get_masked_scanline(), recording_pattern->get_renderer(), clip); } } } template void drawShape(Raster &ras, Raster &ras_clip, Path &path, bool draw_fill, bool draw_stroke, int fill, int col, double lwd, int lty, R_GE_lineend lend, R_GE_linejoin ljoin = GE_ROUND_JOIN, int pattern = -1, bool evenodd = false) { agg::scanline_p8 slp; if (recording_clip != NULL) { recording_clip->concat_path(path); return; } if (current_clip != NULL) { ras_clip.add_path(*current_clip); if (current_clip_rule_is_evenodd) { ras_clip.filling_rule(agg::fill_even_odd); } } if (pattern != -1) { ras.add_path(path); if (evenodd) ras.filling_rule(agg::fill_even_odd); auto pat_it = pattern_cache.find(pattern); if (pat_it != pattern_cache.end()) { fillPattern(ras, ras_clip, *(pat_it->second)); } } else if (draw_fill) { ras.add_path(path); if (evenodd) ras.filling_rule(agg::fill_even_odd); if (recording_mask == NULL && recording_pattern == NULL) { solid_renderer.color(convertColour(fill)); if (current_mask == NULL) { render(ras, ras_clip, slp, solid_renderer, current_clip != NULL); } else { render(ras, ras_clip, current_mask->get_masked_scanline(), solid_renderer, current_clip != NULL); } } else if (recording_pattern == NULL) { recording_mask->set_colour(convertMaskCol(fill)); if (current_mask == NULL) { render(ras, ras_clip, slp, recording_mask->get_solid_renderer(), current_clip != NULL); } else { render(ras, ras_clip, current_mask->get_masked_scanline(), recording_mask->get_solid_renderer(), current_clip != NULL); } } else { recording_pattern->set_colour(convertColour(fill)); if (current_mask == NULL) { render(ras, ras_clip, slp, recording_pattern->get_solid_renderer(), current_clip != NULL); } else { render(ras, ras_clip, current_mask->get_masked_scanline(), recording_pattern->get_solid_renderer(), current_clip != NULL); } } } if (!draw_stroke) return; if (evenodd) ras.filling_rule(agg::fill_non_zero); agg::scanline_u8 slu; setStroke(ras, path, lty, lwd, lend, ljoin); if (recording_mask == NULL && recording_pattern == NULL) { solid_renderer.color(convertColour(col)); if (current_mask == NULL) { render(ras, ras_clip, slu, solid_renderer, current_clip != NULL); } else { render(ras, ras_clip, current_mask->get_masked_scanline(), solid_renderer, current_clip != NULL); } } else if (recording_pattern == NULL) { recording_mask->set_colour(convertMaskCol(col)); if (current_mask == NULL) { render(ras, ras_clip, slu, recording_mask->get_solid_renderer(), current_clip != NULL); } else { render(ras, ras_clip, current_mask->get_masked_scanline(), recording_mask->get_solid_renderer(), current_clip != NULL); } } else { recording_pattern->set_colour(convertMaskCol(col)); if (current_mask == NULL) { render(ras, ras_clip, slu, recording_pattern->get_solid_renderer(), current_clip != NULL); } else { render(ras, ras_clip, current_mask->get_masked_scanline(), recording_pattern->get_solid_renderer(), current_clip != NULL); } } } }; // IMPLIMENTATION -------------------------------------------------------------- // LIFECYCLE ------------------------------------------------------------------- /* The initialiser takes care of setting up the buffer, and caching a pixel * formatter and renderer. */ template AggDevice::AggDevice(const char* fp, int w, int h, double ps, int bg, double res, double scaling) : width(w), height(h), clip_left(0), clip_right(w), clip_top(0), clip_bottom(h), device_id(0), pageno(0), file(fp), background_int(bg), pointsize(ps), res_real(res), res_mod(scaling * res / 72.0), lwd_mod(scaling * res / 96.0), x_trans(0.0), y_trans(0.0), t_ren(), clip_cache_next_id(0), recording_clip(NULL), current_clip(NULL), current_clip_rule_is_evenodd(false), mask_cache_next_id(0), recording_mask(NULL), current_mask(NULL), pattern_cache_next_id(0), recording_pattern(NULL) { buffer = new unsigned char[width * height * bytes_per_pixel]; rbuf = agg::rendering_buffer(buffer, width, height, width * bytes_per_pixel); pixf = new pixfmt_type(rbuf); renderer = renbase_type(*pixf); solid_renderer = renderer_solid(renderer); background = convertColour(background_int); renderer.clear(background); } template AggDevice::~AggDevice() { delete pixf; delete [] buffer; } /* newPage() should not need to be overwritten as long the class have an * appropriate savePage() method. For screen devices it may make sense to change * it for performance */ template void AggDevice::newPage(unsigned int bg) { if (pageno != 0) { if (!savePage()) { Rf_warning("agg could not write to the given file"); } } renderer.reset_clipping(true); if (visibleColour(bg)) { renderer.clear(convertColour(bg)); } else { renderer.clear(background); } pageno++; } template void AggDevice::close() { if (pageno == 0) pageno++; if (!savePage()) { Rf_warning("agg could not write to the given file"); } } template SEXP AggDevice::capture() { return Rf_allocVector(INTSXP, 0); } /* This takes care of writing the buffer to an appropriate file. The filename * may be specified as a printf string with room for a page counter, so the * method should take care of resolving that together with the pageno field. */ template bool AggDevice::savePage() { return true; } // BEHAVIOUR ------------------------------------------------------------------- /* The clipRect method sets clipping on the renderer level, but for performance * gain the different drawing methods should set it on the rasterizer as well * to avoid unneccesary allocation and looping */ template void AggDevice::clipRect(double x0, double y0, double x1, double y1) { if (recording_pattern != NULL && x0 == 0.0 && y0 == height && x1 == width && y1 == 0.0) { // resetting clipping while recording a pattern // I hate this heuristic clip_left = 0.0; clip_right = recording_pattern->width; clip_top = 0.0; clip_bottom = recording_pattern->height; return; } clip_left = x0 + x_trans; clip_right = x1 + x_trans; clip_top = y0 + y_trans; clip_bottom = y1 + y_trans; renderer.clip_box(clip_left, clip_top, clip_right, clip_bottom); current_clip = NULL; current_clip_rule_is_evenodd = false; } /* These methods funnel all operations to the text_renderer. See text_renderer.h * for implementation details. * * They work on gray8 bitmap to speed it up as all metrixs are assumed to be in * horizontal mode only */ template double AggDevice::stringWidth(const char *str, const char *family, int face, double size) { size *= res_mod; agg::glyph_rendering gren = agg::glyph_ren_agg_gray8; if (!t_ren.load_font(gren, family, face, size, device_id)) { return 0.0; } return t_ren.get_text_width(str); } template void AggDevice::charMetric(int c, const char *family, int face, double size, double *ascent, double *descent, double *width) { if (c < 0) { c = -c; } size *= res_mod; agg::glyph_rendering gren = agg::glyph_ren_agg_gray8; if (!t_ren.load_font(gren, family, face, size, device_id)) { *ascent = 0.0; *descent = 0.0; *width = 0.0; return; } t_ren.get_char_metric(c, ascent, descent, width); } template SEXP AggDevice::createClipPath(SEXP path, SEXP ref) { int key; if (Rf_isNull(path)) { return Rf_ScalarInteger(-1); } if (Rf_isNull(ref)) { key = clip_cache_next_id; clip_cache_next_id++; } else { key = INTEGER(ref)[0]; if (key < 0) { return Rf_ScalarInteger(key); } } auto clip_cache_iter = clip_cache.find(key); // Check if path exists if (clip_cache_iter == clip_cache.end()) { // Path doesn't exist - create a new entry and get reference to it std::unique_ptr new_clip(new agg::path_storage()); bool new_clip_is_even_odd = false; #if R_GE_version >= 15 new_clip_is_even_odd = R_GE_clipPathFillRule(path) == R_GE_evenOddRule; #endif // Assign container pointer to device recording_clip = new_clip.get(); SEXP R_fcall = PROTECT(Rf_lang1(path)); Rf_eval(R_fcall, R_GlobalEnv); UNPROTECT(1); current_clip = recording_clip; current_clip_rule_is_evenodd = new_clip_is_even_odd; recording_clip = NULL; clip_cache[key] = {std::move(new_clip), new_clip_is_even_odd}; } else { current_clip = clip_cache_iter->second.first.get(); current_clip_rule_is_evenodd = clip_cache_iter->second.second; } clip_left = 0.0; clip_right = width; clip_top = 0.0; clip_bottom = height; renderer.reset_clipping(true); return Rf_ScalarInteger(key); } template void AggDevice::removeClipPath(SEXP ref) { if (Rf_isNull(ref)) { clip_cache.clear(); clip_cache_next_id = 0; return; } int key = INTEGER(ref)[0]; if (key < 0) { return; } auto it = clip_cache.find(key); // Check if path exists if (it != clip_cache.end()) { clip_cache.erase(it); } return; } template SEXP AggDevice::createMask(SEXP mask, SEXP ref) { int key; if (Rf_isNull(mask)) { current_mask = NULL; return Rf_ScalarInteger(-1); } if (Rf_isNull(ref)) { key = mask_cache_next_id; mask_cache_next_id++; } else { key = INTEGER(ref)[0]; if (key < 0) { current_mask = NULL; return Rf_ScalarInteger(key); } } auto mask_cache_iter = mask_cache.find(key); // Check if path exists if (mask_cache_iter == mask_cache.end()) { // Mask doesn't exist - create a new entry and get reference to it std::unique_ptr new_mask(new MaskBuffer()); new_mask->init(width, height); // Assign container pointer to device MaskBuffer* temp_mask = recording_mask; RenderBuffer* temp_pattern = recording_pattern; recording_mask = new_mask.get(); recording_pattern = NULL; SEXP R_fcall = PROTECT(Rf_lang1(mask)); Rf_eval(R_fcall, R_GlobalEnv); UNPROTECT(1); current_mask = recording_mask; recording_pattern = temp_pattern; recording_mask = temp_mask; mask_cache[key] = std::move(new_mask); } else { current_mask = mask_cache_iter->second.get(); } return Rf_ScalarInteger(key); } template void AggDevice::removeMask(SEXP ref) { if (Rf_isNull(ref)) { mask_cache.clear(); mask_cache_next_id = 0; return; } unsigned int key = INTEGER(ref)[0]; auto it = mask_cache.find(key); // Check if path exists if (it != mask_cache.end()) { mask_cache.erase(it); } return; } template SEXP AggDevice::createPattern(SEXP pattern) { if (Rf_isNull(pattern)) { return Rf_ScalarInteger(-1); } int key = pattern_cache_next_id; pattern_cache_next_id++; std::unique_ptr > new_pattern(new Pattern()); #if R_GE_version >= 13 ExtendType extend = ExtendNone; switch(R_GE_patternType(pattern)) { case R_GE_linearGradientPattern: switch(R_GE_linearGradientExtend(pattern)) { case R_GE_patternExtendNone: extend = ExtendNone; break; case R_GE_patternExtendPad: extend = ExtendPad; break; case R_GE_patternExtendReflect: extend = ExtendReflect; break; case R_GE_patternExtendRepeat: extend = ExtendRepeat; break; } new_pattern->init_linear(R_GE_linearGradientX1(pattern) + x_trans, R_GE_linearGradientY1(pattern) + y_trans, R_GE_linearGradientX2(pattern) + x_trans, R_GE_linearGradientY2(pattern) + y_trans, extend); for (int i = 0; i < R_GE_linearGradientNumStops(pattern); ++i) { R_COLOR col = convertColour(R_GE_linearGradientColour(pattern, i)); double stop = R_GE_linearGradientStop(pattern, i); new_pattern->add_color(stop, col); } new_pattern->finish_gradient(); break; case R_GE_radialGradientPattern: switch(R_GE_radialGradientExtend(pattern)) { case R_GE_patternExtendNone: extend = ExtendNone; break; case R_GE_patternExtendPad: extend = ExtendPad; break; case R_GE_patternExtendReflect: extend = ExtendReflect; break; case R_GE_patternExtendRepeat: extend = ExtendRepeat; break; } new_pattern->init_radial(R_GE_radialGradientCX1(pattern) + x_trans, R_GE_radialGradientCY1(pattern) + y_trans, R_GE_radialGradientR1(pattern), R_GE_radialGradientCX2(pattern) + x_trans, R_GE_radialGradientCY2(pattern) + y_trans, R_GE_radialGradientR2(pattern), extend); for (int i = 0; i < R_GE_radialGradientNumStops(pattern); ++i) { R_COLOR col = convertColour(R_GE_radialGradientColour(pattern, i)); double stop = R_GE_radialGradientStop(pattern, i); new_pattern->add_color(stop, col); } new_pattern->finish_gradient(); break; case R_GE_tilingPattern: switch(R_GE_tilingPatternExtend(pattern)) { case R_GE_patternExtendNone: extend = ExtendNone; break; case R_GE_patternExtendPad: extend = ExtendPad; break; case R_GE_patternExtendReflect: extend = ExtendReflect; break; case R_GE_patternExtendRepeat: extend = ExtendRepeat; break; } new_pattern->init_tile(R_GE_tilingPatternWidth(pattern), R_GE_tilingPatternHeight(pattern), R_GE_tilingPatternX(pattern) + x_trans, R_GE_tilingPatternY(pattern) + y_trans, extend); double temp_clip_left = clip_left; double temp_clip_right = clip_right; double temp_clip_top = clip_top; double temp_clip_bottom = clip_bottom; MaskBuffer* temp_mask = recording_mask; MaskBuffer* temp_current_mask = current_mask; RenderBuffer* temp_pattern = recording_pattern; x_trans += new_pattern->x_trans; y_trans += new_pattern->y_trans; clip_left = 0.0; clip_right = R_GE_tilingPatternWidth(pattern); clip_top = 0.0; clip_bottom = R_GE_tilingPatternHeight(pattern); if (clip_bottom < 0) clip_bottom = -clip_bottom; recording_mask = NULL; current_mask = NULL; recording_pattern = &(new_pattern->buffer); SEXP R_fcall = PROTECT(Rf_lang1(R_GE_tilingPatternFunction(pattern))); Rf_eval(R_fcall, R_GlobalEnv); UNPROTECT(1); clip_left = temp_clip_left; clip_right = temp_clip_right; clip_top = temp_clip_top; clip_bottom = temp_clip_bottom; x_trans -= new_pattern->x_trans; y_trans -= new_pattern->y_trans; recording_mask = temp_mask; current_mask = temp_current_mask; recording_pattern = temp_pattern; break; } #endif pattern_cache[key] = std::move(new_pattern); return Rf_ScalarInteger(key); } template void AggDevice::removePattern(SEXP ref) { if (Rf_isNull(ref)) { pattern_cache.clear(); pattern_cache_next_id = 0; return; } unsigned int key = INTEGER(ref)[0]; auto it = pattern_cache.find(key); // Check if path exists if (it != pattern_cache.end()) { pattern_cache.erase(it); } return; } // DRAWING --------------------------------------------------------------------- /* Draws a circle. Use for standard points as well as grid.circle etc. The * number of points around the circle is precalculated below a radius of 64 * pixels in order to speed up point rendering */ template void AggDevice::drawCircle(double x, double y, double r, int fill, int col, double lwd, int lty, R_GE_lineend lend, int pattern) { bool draw_fill = visibleColour(fill) || pattern != -1; bool draw_stroke = visibleColour(col) && lwd > 0.0 && lty != LTY_BLANK; if (!draw_fill && !draw_stroke) return; // Early exit lwd *= lwd_mod; agg::rasterizer_scanline_aa<> ras(MAX_CELLS); agg::rasterizer_scanline_aa<> ras_clip(MAX_CELLS); ras.clip_box(clip_left, clip_top, clip_right, clip_bottom); agg::ellipse e1; x += x_trans; y += y_trans; if (r < 1) { r = r < 0.5 ? 0.5 : r; e1.init(x, y, r, r, 4); } else if (r < 2.5) { e1.init(x, y, r, r, 8); } else if (r < 5) { e1.init(x, y, r, r, 16); } else if (r < 10) { e1.init(x, y, r, r, 32); } else if (r < 20) { e1.init(x, y, r, r, 64); } else { e1.init(x, y, r, r); } drawShape(ras, ras_clip, e1, draw_fill, draw_stroke, fill, col, lwd, lty, lend, GE_ROUND_JOIN, pattern); } template void AggDevice::drawRect(double x0, double y0, double x1, double y1, int fill, int col, double lwd, int lty, R_GE_lineend lend, int pattern) { bool draw_fill = visibleColour(fill) || pattern != -1; bool draw_stroke = visibleColour(col) && lwd > 0.0 && lty != LTY_BLANK; if (!draw_fill && !draw_stroke) return; // Early exit lwd *= lwd_mod; agg::rasterizer_scanline_aa<> ras(MAX_CELLS); agg::rasterizer_scanline_aa<> ras_clip(MAX_CELLS); ras.clip_box(clip_left, clip_top, clip_right, clip_bottom); agg::path_storage rect; x0 += x_trans; x1 += x_trans; y0 += y_trans; y1 += y_trans; rect.remove_all(); rect.move_to(x0, y0); rect.line_to(x0, y1); rect.line_to(x1, y1); rect.line_to(x1, y0); rect.close_polygon(); drawShape(ras, ras_clip, rect, draw_fill, draw_stroke, fill, col, lwd, lty, lend, GE_ROUND_JOIN, pattern); } template void AggDevice::drawPolygon(int n, double *x, double *y, int fill, int col, double lwd, int lty, R_GE_lineend lend, R_GE_linejoin ljoin, double lmitre, int pattern) { bool draw_fill = visibleColour(fill) || pattern != -1; bool draw_stroke = visibleColour(col) && lwd > 0.0 && lty != LTY_BLANK; if (n < 2 || (!draw_fill && !draw_stroke)) return; // Early exit lwd *= lwd_mod; agg::rasterizer_scanline_aa<> ras(MAX_CELLS); agg::rasterizer_scanline_aa<> ras_clip(MAX_CELLS); ras.clip_box(clip_left, clip_top, clip_right, clip_bottom); agg::path_storage poly; poly.remove_all(); poly.move_to(x[0] + x_trans, y[0] + y_trans); for (int i = 1; i < n; i++) { poly.line_to(x[i] + x_trans, y[i] + y_trans); } poly.close_polygon(); drawShape(ras, ras_clip, poly, draw_fill, draw_stroke, fill, col, lwd, lty, lend, ljoin, pattern); } template void AggDevice::drawLine(double x1, double y1, double x2, double y2, int col, double lwd, int lty, R_GE_lineend lend) { if (!visibleColour(col) || lwd == 0.0 || lty == LTY_BLANK) return; lwd *= lwd_mod; agg::rasterizer_scanline_aa<> ras(MAX_CELLS); agg::rasterizer_scanline_aa<> ras_clip(MAX_CELLS); ras.clip_box(clip_left, clip_top, clip_right, clip_bottom); agg::path_storage ps; ps.remove_all(); ps.move_to(x1 + x_trans, y1 + y_trans); ps.line_to(x2 + x_trans, y2 + y_trans); drawShape(ras, ras_clip, ps, false, true, 0, col, lwd, lty, lend); } template void AggDevice::drawPolyline(int n, double* x, double* y, int col, double lwd, int lty, R_GE_lineend lend, R_GE_linejoin ljoin, double lmitre) { if (!visibleColour(col) || lwd == 0.0 || lty == LTY_BLANK || n < 2) return; lwd *= lwd_mod; agg::rasterizer_scanline_aa<> ras(MAX_CELLS); agg::rasterizer_scanline_aa<> ras_clip(MAX_CELLS); ras.clip_box(clip_left, clip_top, clip_right, clip_bottom); agg::path_storage ps; ps.remove_all(); ps.move_to(x[0] + x_trans, y[0] + y_trans); for (int i = 1; i < n; i++) { ps.line_to(x[i] + x_trans, y[i] + y_trans); } drawShape(ras, ras_clip, ps, false, true, 0, col, lwd, lty, lend, ljoin); } template void AggDevice::drawPath(int npoly, int* nper, double* x, double* y, int col, int fill, double lwd, int lty, R_GE_lineend lend, R_GE_linejoin ljoin, double lmitre, bool evenodd, int pattern) { bool draw_fill = visibleColour(fill) || pattern != -1; bool draw_stroke = visibleColour(col) && lwd > 0.0 && lty != LTY_BLANK; if (!draw_fill && !draw_stroke) return; // Early exit lwd *= lwd_mod; agg::rasterizer_scanline_aa<> ras(MAX_CELLS); agg::rasterizer_scanline_aa<> ras_clip(MAX_CELLS); ras.clip_box(clip_left, clip_top, clip_right, clip_bottom); agg::scanline_p8 slp, slp_clip, slp_result; agg::path_storage path; path.remove_all(); int counter = 0; for (int i = 0; i < npoly; i++) { if (nper[i] < 2) { counter += nper[i]; continue; } path.move_to(x[counter] + x_trans, y[counter] + y_trans); counter++; for (int j = 1; j < nper[i]; j++) { path.line_to(x[counter] + x_trans, y[counter] + y_trans); counter++; }; path.close_polygon(); } drawShape(ras, ras_clip, path, draw_fill, draw_stroke, fill, col, lwd, lty, lend, ljoin, pattern, evenodd); } template void AggDevice::drawRaster(unsigned int *raster, int w, int h, double x, double y, double final_width, double final_height, double rot, bool interpolate) { agg::rendering_buffer rbuf(reinterpret_cast(raster), w, h, w * 4); x += x_trans; y += y_trans; double x_scale = final_width / double(w); double y_scale = final_height / double (h); agg::trans_affine img_mtx; img_mtx *= agg::trans_affine_reflection(0); img_mtx *= agg::trans_affine_translation(0, h); img_mtx *= agg::trans_affine_scaling(x_scale, y_scale); img_mtx *= agg::trans_affine_rotation(-rot * agg::pi / 180.0); img_mtx *= agg::trans_affine_translation(x, y); agg::trans_affine src_mtx = img_mtx; img_mtx.invert(); typedef agg::span_interpolator_linear<> interpolator_type; interpolator_type interpolator(img_mtx); agg::rasterizer_scanline_aa<> ras(MAX_CELLS); ras.clip_box(clip_left, clip_top, clip_right, clip_bottom); agg::rasterizer_scanline_aa<> ras_clip(MAX_CELLS); if (current_clip != NULL) { ras_clip.add_path(*current_clip); if (current_clip_rule_is_evenodd) { ras_clip.filling_rule(agg::fill_even_odd); } } agg::path_storage rect; rect.remove_all(); rect.move_to(0, 0); rect.line_to(0, h); rect.line_to(w, h); rect.line_to(w, 0); rect.close_polygon(); agg::conv_transform tr(rect, src_mtx); ras.add_path(tr); agg::scanline_u8 slu; if (recording_mask == NULL && recording_pattern == NULL) { if (current_mask == NULL) { render_raster(rbuf, w, h, ras, ras_clip, slu, interpolator, renderer, interpolate, current_clip != NULL, false); } else{ render_raster(rbuf, w, h, ras, ras_clip, current_mask->get_masked_scanline(), interpolator, renderer, interpolate, current_clip != NULL, false); } } else if (recording_pattern == NULL) { if (current_mask == NULL) { render_raster(rbuf, w, h, ras, ras_clip, slu, interpolator, recording_mask->get_renderer(), interpolate, current_clip != NULL, false); } else { render_raster(rbuf, w, h, ras, ras_clip, current_mask->get_masked_scanline(), interpolator, recording_mask->get_renderer(), interpolate, current_clip != NULL, false); } } else { if (current_mask == NULL) { render_raster(rbuf, w, h, ras, ras_clip, slu, interpolator, recording_pattern->get_renderer(), interpolate, current_clip != NULL, false); } else { render_raster(rbuf, w, h, ras, ras_clip, current_mask->get_masked_scanline(), interpolator, recording_pattern->get_renderer(), interpolate, current_clip != NULL, false); } } } template void AggDevice::drawText(double x, double y, const char *str, const char *family, int face, double size, double rot, double hadj, int col) { agg::glyph_rendering gren = std::fmod(rot, 90) == 0.0 && recording_clip == NULL ? agg::glyph_ren_agg_gray8 : agg::glyph_ren_outline; x += x_trans; y += y_trans; size *= res_mod; if (!t_ren.load_font(gren, family, face, size, device_id)) { return; } agg::rasterizer_scanline_aa<> ras_clip(MAX_CELLS); if (current_clip != NULL) { ras_clip.add_path(*current_clip); if (current_clip_rule_is_evenodd) { ras_clip.filling_rule(agg::fill_even_odd); } } agg::scanline_u8 slu; if (recording_mask == NULL && recording_pattern == NULL) { solid_renderer.color(convertColour(col)); if (current_mask == NULL) { t_ren.template plot_text(x, y, str, rot, hadj, solid_renderer, renderer, slu, device_id, ras_clip, current_clip != NULL, recording_clip); } else { t_ren.template plot_text(x, y, str, rot, hadj, solid_renderer, renderer, current_mask->get_masked_scanline(), device_id, ras_clip, current_clip != NULL, recording_clip); } } else if (recording_pattern == NULL) { recording_mask->set_colour(convertMaskCol(col)); if (current_mask == NULL) { t_ren.template plot_text(x, y, str, rot, hadj, recording_mask->get_solid_renderer(), recording_mask->get_renderer(), slu, device_id, ras_clip, current_clip != NULL, recording_clip); } else { t_ren.template plot_text(x, y, str, rot, hadj, recording_mask->get_solid_renderer(), recording_mask->get_renderer(), current_mask->get_masked_scanline(), device_id, ras_clip, current_clip != NULL, recording_clip); } } else { recording_pattern->set_colour(convertColour(col)); if (current_mask == NULL) { t_ren.template plot_text(x, y, str, rot, hadj, recording_pattern->get_solid_renderer(), recording_pattern->get_renderer(), slu, device_id, ras_clip, current_clip != NULL, recording_clip); } else { t_ren.template plot_text(x, y, str, rot, hadj, recording_pattern->get_solid_renderer(), recording_pattern->get_renderer(), current_mask->get_masked_scanline(), device_id, ras_clip, current_clip != NULL, recording_clip); } } } ragg/src/RenderBuffer.h0000644000176200001440000000621714136005375014515 0ustar liggesusers#pragma once // TODO: Consider if main render buffer should be a RenderBuffer object instead // of defined in the AggDevice class. #include "ragg.h" #include "agg_alpha_mask_u8.h" #include "agg_pixfmt_gray.h" #include "agg_scanline_u.h" #include "util/agg_color_conv.h" template class RenderBuffer { public: typedef PIXFMT pixfmt_type; typedef agg::renderer_base renbase_type; typedef agg::renderer_scanline_aa_solid rensolid_type; int width; int height; protected: unsigned char* buffer; agg::rendering_buffer rbuf; pixfmt_type* pixf; renbase_type renderer; rensolid_type renderer_solid; public: RenderBuffer() : width(0), height(0), rbuf() { buffer = new unsigned char[0]; rbuf.attach(buffer, 0, 0, 0); pixf = new pixfmt_type(rbuf); renderer = renbase_type(*pixf); renderer_solid = rensolid_type(renderer); } template RenderBuffer(int _width, int _height, COLOR bg) : width(_width), height(_height), rbuf() { buffer = new unsigned char[width * height * PIXFMT::pix_width]; rbuf.attach(buffer, width, height, width * PIXFMT::pix_width); pixf = new pixfmt_type(rbuf); renderer = renbase_type(*pixf); renderer_solid = rensolid_type(renderer); renderer.clear(bg); } ~RenderBuffer() { delete pixf; delete [] buffer; } template void init(int _width, int _height, COLOR bg) { delete pixf; delete [] buffer; width = _width; height = _height; buffer = new unsigned char[width * height * PIXFMT::pix_width]; rbuf.attach(buffer, width, height, width * PIXFMT::pix_width); pixf = new pixfmt_type(rbuf); renderer = renbase_type(*pixf); renderer_solid = rensolid_type(renderer); renderer.clear(bg); } renbase_type& get_renderer() { return renderer; } rensolid_type& get_solid_renderer() { return renderer_solid; } agg::rendering_buffer& get_buffer() { return rbuf; } template void set_colour(COLOR col) { renderer_solid.color(col); } template void copy_from(agg::rendering_buffer& copy_buffer) { agg::convert(&rbuf, ©_buffer); } }; class MaskBuffer : public RenderBuffer { public: typedef agg::scanline_u8_am scanline_type; private: agg::alpha_mask_rgba32a alpha_mask; scanline_type scanline; public: MaskBuffer() : RenderBuffer(), alpha_mask(rbuf), scanline(alpha_mask) { } MaskBuffer(int width, int height) : RenderBuffer(width, height, agg::rgba8(0, 0, 0, 0)), alpha_mask(rbuf), scanline(alpha_mask) { } void init(int _width, int _height) { delete pixf; delete [] buffer; width = _width; height = _height; buffer = new unsigned char[width * height * 4]; rbuf.attach(buffer, width, height, width * 4); pixf = new pixfmt_type_32(rbuf); renderer = renbase_type(*pixf); renderer_solid = rensolid_type(renderer); renderer.clear(agg::rgba8(0, 0, 0, 0)); } scanline_type& get_masked_scanline() { return scanline; } }; ragg/src/tiff_dev.cpp0000644000176200001440000000417514127312027014261 0ustar liggesusers#include "ragg.h" #include "init_device.h" #include "AggDeviceTiff.h" // [[export]] SEXP agg_tiff_c(SEXP file, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling, SEXP bit, SEXP compression, SEXP encoding) { bool bit8 = INTEGER(bit)[0] == 8; int bgCol = RGBpar(bg, 0); BEGIN_CPP if (bit8) { if (R_OPAQUE(bgCol)) { // Opaque bg... no need for alpha channel AggDeviceTiffNoAlpha* device = new AggDeviceTiffNoAlpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0], INTEGER(compression)[0], INTEGER(encoding)[0] ); makeDevice(device, "agg_tiff"); } else { AggDeviceTiffAlpha* device = new AggDeviceTiffAlpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0], INTEGER(compression)[0], INTEGER(encoding)[0] ); makeDevice(device, "agg_tiff"); } } else { if (R_OPAQUE(bgCol)) { // Opaque bg... no need for alpha channel AggDeviceTiff16NoAlpha* device = new AggDeviceTiff16NoAlpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0], INTEGER(compression)[0], INTEGER(encoding)[0] ); makeDevice(device, "agg_png"); } else { AggDeviceTiff16Alpha* device = new AggDeviceTiff16Alpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0], INTEGER(compression)[0], INTEGER(encoding)[0] ); makeDevice(device, "agg_png"); } } END_CPP return R_NilValue; } ragg/src/AggDevicePng.h0000644000176200001440000000766414131500414014423 0ustar liggesusers#pragma once extern "C" { #include } #include "ragg.h" #include "AggDevice.h" #include "AggDevice16.h" #include "files.h" template class AggDevicePng : public AggDevice { public: AggDevicePng(const char* fp, int w, int h, double ps, int bg, double res, double scaling) : AggDevice(fp, w, h, ps, bg, res, scaling) { } // Behaviour bool savePage() { char buf[PATH_MAX+1]; snprintf(buf, PATH_MAX, this->file.c_str(), this->pageno); buf[PATH_MAX] = '\0'; FILE* fd = unicode_fopen(buf, "wb"); if(!fd) return false; png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) return false; png_infop info = png_create_info_struct(png); if (!info) return false; if (setjmp(png_jmpbuf(png))) return false; png_init_io(png, fd); png_set_IHDR( png, info, this->width, this->height, 8, PIXFMT::num_components == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); // Write in physical dimensions unsigned int ppm = this->res_real / 0.0254; png_set_pHYs(png, info, ppm, ppm, 1); // Write prefered background, just because... png_color_16 background; background.red = this->background.r; background.green = this->background.g; background.blue = this->background.b; png_set_bKGD(png, info, &background); png_write_info(png, info); demultiply(this->pixf); agg::row_ptr_cache buffer_rows( this->buffer, this->width, this->height, this->rbuf.stride_abs() ); png_write_image(png, (png_byte **) buffer_rows.rows()); png_write_end(png, NULL); png_destroy_write_struct(&png, &info); fclose(fd); return true; } }; typedef AggDevicePng AggDevicePngNoAlpha; typedef AggDevicePng AggDevicePngAlpha; template class AggDevicePng16 : public AggDevice16 { public: AggDevicePng16(const char* fp, int w, int h, double ps, int bg, double res, double scaling, double alpha_mod = 1.0) : AggDevice16(fp, w, h, ps, bg, res, scaling, alpha_mod) { } // Behaviour bool savePage() { char buf[PATH_MAX+1]; snprintf(buf, PATH_MAX, this->file.c_str(), this->pageno); buf[PATH_MAX] = '\0'; FILE* fd = unicode_fopen(buf, "wb"); if(!fd) return false; png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) return false; png_infop info = png_create_info_struct(png); if (!info) return false; if (setjmp(png_jmpbuf(png))) return false; png_init_io(png, fd); png_set_IHDR( png, info, this->width, this->height, 16, PIXFMT::num_components == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); // Write in physical dimensions unsigned int ppm = this->res_real / 0.0254; png_set_pHYs(png, info, ppm, ppm, 1); // Write prefered background, just because... png_color_16 background; background.red = this->background.r; background.green = this->background.g; background.blue = this->background.b; png_set_bKGD(png, info, &background); png_write_info(png, info); demultiply(this->pixf); this->to_bigend(); agg::row_ptr_cache buffer_rows( this->buffer, this->width, this->height, this->rbuf.stride_abs() ); png_write_image(png, (png_byte **) buffer_rows.rows()); png_write_end(png, NULL); png_destroy_write_struct(&png, &info); fclose(fd); return true; } }; typedef AggDevicePng16 AggDevicePng16NoAlpha; typedef AggDevicePng16 AggDevicePng16Alpha; ragg/src/init_device.h0000644000176200001440000002107714132007605014421 0ustar liggesusers#pragma once #include "ragg.h" template void agg_metric_info(int c, const pGEcontext gc, double* ascent, double* descent, double* width, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP device->charMetric(c, gc->fontfamily, gc->fontface, gc->ps * gc->cex, ascent, descent, width); END_CPP return; } template void agg_clip(double x0, double x1, double y0, double y1, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP device->clipRect(x0, y0, x1, y1); END_CPP return; } template void agg_new_page(const pGEcontext gc, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP device->newPage(gc->fill); END_CPP return; } template void agg_close(pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP device->close(); delete device; END_CPP return; } template void agg_line(double x1, double y1, double x2, double y2, const pGEcontext gc, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP device->drawLine(x1, y1, x2, y2, gc->col, gc->lwd, gc->lty, gc->lend); END_CPP return; } template void agg_polyline(int n, double *x, double *y, const pGEcontext gc, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP device->drawPolyline(n, x, y, gc->col, gc->lwd, gc->lty, gc->lend, gc->ljoin, gc->lmitre); END_CPP return; } template void agg_polygon(int n, double *x, double *y, const pGEcontext gc, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; int pattern = -1; #if R_GE_version >= 13 pattern = gc->patternFill == R_NilValue ? -1 : INTEGER(gc->patternFill)[0]; #endif BEGIN_CPP device->drawPolygon(n, x, y, gc->fill, gc->col, gc->lwd, gc->lty, gc->lend, gc->ljoin, gc->lmitre, pattern); END_CPP return; } template void agg_path(double *x, double *y, int npoly, int *nper, Rboolean winding, const pGEcontext gc, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; int pattern = -1; #if R_GE_version >= 13 pattern = gc->patternFill == R_NilValue ? -1 : INTEGER(gc->patternFill)[0]; #endif BEGIN_CPP device->drawPath(npoly, nper, x, y, gc->col, gc->fill, gc->lwd, gc->lty, gc->lend, gc->ljoin, gc->lmitre, !winding, pattern); END_CPP return; } template double agg_strwidth(const char *str, const pGEcontext gc, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP return device->stringWidth(str, gc->fontfamily, gc->fontface, gc->ps * gc->cex); END_CPP } template void agg_rect(double x0, double y0, double x1, double y1, const pGEcontext gc, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; int pattern = -1; #if R_GE_version >= 13 pattern = gc->patternFill == R_NilValue ? -1 : INTEGER(gc->patternFill)[0]; #endif BEGIN_CPP device->drawRect(x0, y0, x1, y1, gc->fill, gc->col, gc->lwd, gc->lty, gc->lend, pattern); END_CPP return; } template void agg_circle(double x, double y, double r, const pGEcontext gc, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; int pattern = -1; #if R_GE_version >= 13 pattern = gc->patternFill == R_NilValue ? -1 : INTEGER(gc->patternFill)[0]; #endif BEGIN_CPP device->drawCircle(x, y, r, gc->fill, gc->col, gc->lwd, gc->lty, gc->lend, pattern); END_CPP return; } template void agg_text(double x, double y, const char *str, double rot, double hadj, const pGEcontext gc, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP device->drawText(x, y, str, gc->fontfamily, gc->fontface, gc->ps * gc->cex, rot, hadj, gc->col); END_CPP return; } template static inline void agg_size(double *left, double *right, double *bottom, double *top, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; *left = dd->left; *right = (double) device->width; *bottom = (double) device->height; *top = dd->top; } template void agg_raster(unsigned int *raster, int w, int h, double x, double y, double width, double height, double rot, Rboolean interpolate, const pGEcontext gc, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP device->drawRaster(raster, w, h, x, y, width, height, rot, interpolate); END_CPP return; } template SEXP agg_capture(pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP return device->capture(); END_CPP } template SEXP agg_setPattern(SEXP pattern, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP return device->createPattern(pattern); END_CPP return R_NilValue; } template void agg_releasePattern(SEXP ref, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP device->removePattern(ref); END_CPP } template SEXP agg_setClipPath(SEXP path, SEXP ref, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP return device->createClipPath(path, ref); END_CPP return R_NilValue; } template void agg_releaseClipPath(SEXP ref, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP device->removeClipPath(ref); END_CPP } template SEXP agg_setMask(SEXP path, SEXP ref, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP return device->createMask(path, ref); END_CPP return R_NilValue; } template void agg_releaseMask(SEXP ref, pDevDesc dd) { T * device = (T *) dd->deviceSpecific; BEGIN_CPP device->removeMask(ref); END_CPP } static unsigned int DEVICE_COUNTER = 0; template pDevDesc agg_device_new(T* device) { pDevDesc dd = (DevDesc*) calloc(1, sizeof(DevDesc)); if (dd == NULL) return dd; dd->startfill = device->background_int; dd->startcol = R_RGB(0, 0, 0); dd->startps = device->pointsize; dd->startlty = LTY_SOLID; dd->startfont = 1; dd->startgamma = 1; // Callbacks dd->activate = NULL; dd->deactivate = NULL; dd->close = agg_close; dd->clip = agg_clip; dd->size = agg_size; dd->newPage = agg_new_page; dd->line = agg_line; dd->text = agg_text; dd->strWidth = agg_strwidth; dd->rect = agg_rect; dd->circle = agg_circle; dd->polygon = agg_polygon; dd->polyline = agg_polyline; dd->path = agg_path; dd->mode = NULL; dd->metricInfo = agg_metric_info; if (device->can_capture) { dd->cap = agg_capture; } else { dd->cap = NULL; } dd->raster = agg_raster; #if R_GE_version >= 13 dd->setPattern = agg_setPattern; dd->releasePattern = agg_releasePattern; dd->setClipPath = agg_setClipPath; dd->releaseClipPath = agg_releaseClipPath; dd->setMask = agg_setMask; dd->releaseMask = agg_releaseMask; #endif // UTF-8 support dd->wantSymbolUTF8 = (Rboolean) 1; dd->hasTextUTF8 = (Rboolean) 1; dd->textUTF8 = agg_text; dd->strWidthUTF8 = agg_strwidth; // Screen Dimensions in pts dd->left = 0.0; dd->top = 0.0; dd->right = device->width; dd->bottom = device->height; // Magic constants copied from other graphics devices // nominal character sizes in pts dd->cra[0] = 0.9 * device->pointsize * device->res_mod; dd->cra[1] = 1.2 * device->pointsize * device->res_mod; // character alignment offsets dd->xCharOffset = 0.4900; dd->yCharOffset = 0.3333; dd->yLineBias = 0.2; // inches per pt dd->ipr[0] = 1.0 / (72 * device->res_mod); dd->ipr[1] = 1.0 / (72 * device->res_mod); // Capabilities dd->canClip = TRUE; #if R_GE_version >= 14 dd->deviceClip = TRUE; #endif dd->canHAdj = 2; dd->canChangeGamma = FALSE; dd->displayListOn = FALSE; dd->haveTransparency = 2; dd->haveTransparentBg = 2; dd->useRotatedTextInContour = (Rboolean) 1; #if R_GE_version >= 13 dd->deviceVersion = R_GE_definitions; #endif device->device_id = DEVICE_COUNTER++; dd->deviceSpecific = device; return dd; } template void makeDevice(T* device, const char *name) { R_GE_checkVersionOrDie(R_GE_version); R_CheckDeviceAvailable(); BEGIN_SUSPEND_INTERRUPTS { pDevDesc dev = agg_device_new(device); if (dev == NULL) Rf_error("agg device failed to open"); pGEDevDesc dd = GEcreateDevDesc(dev); GEaddDevice2(dd, name); GEinitDisplayList(dd); } END_SUSPEND_INTERRUPTS; } ragg/src/Makevars.win0000644000176200001440000000134514046470414014260 0ustar liggesusersVERSION = 2.7.4 RWINLIB = ../windows/harfbuzz-${VERSION} AGG_OBJECTS = agg/src/agg_curves.o agg/src/agg_font_freetype.o \ agg/src/agg_image_filters.o agg/src/agg_trans_affine.o \ agg/src/agg_vcgen_dash.o agg/src/agg_vcgen_stroke.o PKG_CPPFLAGS = -DSTRICT_R_HEADERS \ -I${RWINLIB}/include \ -I${RWINLIB}/include/freetype2 \ -I./agg/include \ PKG_LIBS = -Lagg -lstatagg \ -L${RWINLIB}/lib${R_ARCH}${CRT} \ -lfreetype -lharfbuzz -lfreetype -lpng -lz -ltiff -ljpeg \ -lbz2 -lgdi32 -lws2_32 STATLIB = agg/libstatagg.a all: clean winlibs $(SHLIB): $(STATLIB) $(STATLIB): $(AGG_OBJECTS) winlibs: "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" "../tools/winlibs.R" ${VERSION} clean: rm -f $(OBJECTS) $(STATLIB) $(SHLIB) $(AGG_OBJECTS) ragg/src/files.h0000644000176200001440000000165114131500213013225 0ustar liggesusers#pragma once #include #ifdef _WIN32 #include #include #endif // From vroom: https://github.com/r-lib/vroom/blob/master/src/unicode_fopen.h inline FILE* unicode_fopen(const char* path, const char* mode) { FILE* out; #ifdef _WIN32 // First conver the mode to the wide equivalent // Only usage is 2 characters so max 8 bytes + 2 byte null. wchar_t mode_w[10]; MultiByteToWideChar(CP_UTF8, 0, mode, -1, mode_w, 9); // Then convert the path wchar_t* buf; size_t len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); if (len <= 0) { Rf_error("Cannot convert file to Unicode: %s", path); } buf = (wchar_t*)R_alloc(len, sizeof(wchar_t)); if (buf == NULL) { Rf_error("Could not allocate buffer of size: %ll", len); } MultiByteToWideChar(CP_UTF8, 0, path, -1, buf, len); out = _wfopen(buf, mode_w); #else out = fopen(path, mode); #endif return out; } ragg/src/text_renderer.h0000644000176200001440000003222414127517571015021 0ustar liggesusers#pragma once #include #include #include #include #include "ragg.h" #include "rendering.h" #include "agg_font_freetype.h" #include "agg_span_interpolator_linear.h" #include "agg_image_accessors.h" #include "agg_span_image_filter_rgba.h" #include "agg_span_allocator.h" #include "agg_path_storage.h" #include "util/agg_color_conv.h" typedef agg::font_engine_freetype_int32 font_engine_type; typedef agg::font_cache_manager font_manager_type; /* Basic UTF-8 manipulation routines by Jeff Bezanson placed in the public domain Fall 2005 This code is designed to provide the utilities you need to manipulate UTF-8 as an internal string encoding. These functions do not perform the error checking normally needed when handling UTF-8 data, so if you happen to be from the Unicode Consortium you will want to flay me alive. I do this because error checking can be performed at the boundaries (I/O), with these routines reserved for higher performance on data known to be valid. Source: https://www.cprogramming.com/tutorial/utf8.c Modified 2019 by Thomas Lin Pedersen to work with const char* */ static const uint32_t offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; static const char trailingBytesForUTF8[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; /* conversions without error checking only works for valid UTF-8, i.e. no 5- or 6-byte sequences srcsz = source size in bytes, or -1 if 0-terminated sz = dest size in # of wide characters returns # characters converted dest will always be L'\0'-terminated, even if there isn't enough room for all the characters. if sz = srcsz+1 (i.e. 4*srcsz+4 bytes), there will always be enough space. */ static int u8_toucs(uint32_t *dest, int sz, const char *src, int srcsz) { uint32_t ch; const char *src_end = src + srcsz; int nb; int i=0; while (i < sz-1) { nb = trailingBytesForUTF8[(unsigned char)*src]; if (srcsz == -1) { if (*src == 0) goto done_toucs; } else { if (src + nb >= src_end) goto done_toucs; } ch = 0; switch (nb) { /* these fall through deliberately */ case 5: ch += (unsigned char)*src++; ch <<= 6; case 4: ch += (unsigned char)*src++; ch <<= 6; case 3: ch += (unsigned char)*src++; ch <<= 6; case 2: ch += (unsigned char)*src++; ch <<= 6; case 1: ch += (unsigned char)*src++; ch <<= 6; case 0: ch += (unsigned char)*src++; } ch -= offsetsFromUTF8[nb]; dest[i++] = ch; } done_toucs: dest[i] = 0; return i; } /* End of Basic UTF-8 manipulation routines by Jeff Bezanson */ class UTF_UCS { std::vector buffer; public: UTF_UCS() { // Allocate space in buffer buffer.resize(1024); } ~UTF_UCS() { } uint32_t * convert(const char * string, int &n_conv) { int n_bytes = strlen(string) + 1; unsigned int max_size = n_bytes * 4; if (buffer.size() < max_size) { buffer.resize(max_size); } n_conv = u8_toucs(buffer.data(), max_size, string, -1); return buffer.data(); } }; template class TextRenderer { UTF_UCS converter; FontSettings last_font; agg::glyph_rendering last_gren; std::vector loc_buffer; std::vector id_buffer; std::vector cluster_buffer; std::vector font_buffer; std::vector fallback_buffer; std::vector scaling_buffer; double current_font_height; double current_font_size; bool no_bearings; public: TextRenderer() : converter() { last_gren = agg::glyph_ren_native_mono; get_engine().hinting(true); get_engine().flip_y(true); get_engine().gamma(agg::gamma_power(1.6)); } bool load_font(agg::glyph_rendering gren, const char *family, int face, double size, unsigned int id = 0) { FontSettings font = get_font_file(family, face == 2 || face == 4, face == 3 || face == 4, face == 5); current_font_size = size; if (!load_font_from_file(font, gren, size, id)) { Rf_warning("Unable to load font: %s", family); current_font_height = 0; return false; } current_font_height = size; no_bearings = false; #if defined(_WIN32) // Windows emojis have weird right bearings if (strcmp("Segoe UI Emoji", get_engine().family()) == 0) { no_bearings = true; } #endif return true; } double get_text_width(const char* string) { double width = 0.0; int error = textshaping::string_width( string, last_font, current_font_size, 72.0, no_bearings ? 0 : 1, &width ); if (error) { return 0.0; } return width; } void get_char_metric(int c, double *ascent, double *descent, double *width) { unsigned index = get_engine().get_glyph_index(c); const agg::glyph_cache* glyph = get_manager().glyph(index); // This might also be relevant to non-colour fonts that are unscalable double mod = current_font_height / get_engine().height(); // Only use 77 glyph if found and not colour font // Last point is to guard against wrong line-heights based in M char in emoji fonts if (glyph && !(c == 77 && (index == 0 || glyph->data_type == agg::glyph_data_color))) { *ascent = mod * (double) -glyph->bounds.y1; *descent = mod * (double) glyph->bounds.y2; *width = mod * glyph->advance_x; #if defined(__APPLE__) // Apple emojis have no descender if (glyph->data_type == agg::glyph_data_color && strcmp("Apple Color Emoji", get_engine().family()) == 0) { double y_shift = double(glyph->bounds.y1 - glyph->bounds.y2) * 0.1; *descent += y_shift; *ascent += y_shift; } #endif } else { // Use global font metrics *ascent = mod * get_engine().ascent(); *descent = mod * get_engine().descent(); *width = mod * get_engine().max_advance(); } } template void plot_text(double x, double y, const char *string, double rot, double hadj, renderer_solid &ren_solid, renderer &ren, scanline &sl, unsigned int id, raster &ras_clip, bool clip, agg::path_storage* recording_clip) { agg::rasterizer_scanline_aa<> ras; agg::conv_curve curves(get_manager().path_adaptor()); curves.approximation_scale(2.0); double width = get_text_width(string); if (width == 0.0) { return; } int expected_max = strlen(string) * 16; loc_buffer.reserve(expected_max); id_buffer.reserve(expected_max); cluster_buffer.reserve(expected_max); font_buffer.reserve(expected_max); fallback_buffer.reserve(expected_max); scaling_buffer.reserve(expected_max); int err = textshaping::string_shape( string, last_font, current_font_size, 72.0, loc_buffer, id_buffer, cluster_buffer, font_buffer, fallback_buffer, scaling_buffer ); if (err != 0) { Rf_warning("textshaping failed to shape the string"); return; } int n_glyphs = loc_buffer.size(); if (n_glyphs == 0) { return; } if (rot != 0) { rot = agg::deg2rad(-rot); agg::trans_affine mtx; mtx *= agg::trans_affine_rotation(rot); get_engine().transform(mtx); } double cos_rot = cos(rot); double sin_rot = sin(rot); x -= (width * hadj) * cos_rot; y -= (width * hadj) * sin_rot; // Snap to pixel grid for vertical or horizontal text if (fmod(rot, 180) < 1e-6) { y = std::round(y); } else if (fmod(rot + 90, 180) < 1e-6) { x = std::round(x); } int text_run_start = 0; for (int j = 1; j <= n_glyphs; ++j) { if (j == n_glyphs || font_buffer[j] != font_buffer[j - 1]) { if (fallback_buffer.size() == 0 || // To guard against old textshaping version/solaris mock load_font_from_file(fallback_buffer[font_buffer[text_run_start]], last_gren, current_font_size, id)) { for (int i = text_run_start; i < j; ++i) { const agg::glyph_cache* glyph = get_manager().glyph(id_buffer[i]); if (glyph) { double x_offset = loc_buffer[i].x * cos_rot + loc_buffer[i].y * sin_rot; double y_offset = loc_buffer[i].y * cos_rot + loc_buffer[i].x * sin_rot; get_manager().init_embedded_adaptors(glyph, x + x_offset, y + y_offset); switch(glyph->data_type) { default: break; case agg::glyph_data_gray8: render(get_manager().gray8_adaptor(), ras_clip, sl, ren_solid, clip); break; case agg::glyph_data_color: renderColourGlyph(glyph, x + x_offset, y + y_offset, rot, ren, sl, scaling_buffer[font_buffer[text_run_start]], ras_clip, clip); break; case agg::glyph_data_outline: if (recording_clip != NULL) { recording_clip->concat_path(curves); break; } ras.reset(); ras.add_path(curves); render(ras, ras_clip, sl, ren_solid, clip); break; } } } } text_run_start = j; } } if (rot != 0) { get_engine().transform(agg::trans_affine()); } } private: inline font_engine_type& get_engine() { static font_engine_type engine; return engine; } inline font_manager_type& get_manager() { static font_manager_type manager(get_engine()); return manager; } FontSettings get_font_file(const char* family, int bold, int italic, int symbol) { const char* fontfamily = family; if (symbol) { fontfamily = "symbol"; } return locate_font_with_features(fontfamily, italic, bold); } bool load_font_from_file(FontSettings font, agg::glyph_rendering gren, double size, unsigned int id) { if (id != get_engine().id() || !(gren == last_gren && font.index == last_font.index && strncmp(font.file, last_font.file, PATH_MAX) == 0)) { if (!get_engine().load_font(font.file, font.index, gren)) { return false; } last_gren = gren; get_engine().height(size); get_engine().id(id); } else if (size != get_engine().height()) { get_engine().height(size); } last_font = font; return true; } template void renderColourGlyph(const agg::glyph_cache* glyph, double x, double y, double rot, ren &renderer, scanline &sl, double scaling, raster &ras_clip, bool clip) { int w = glyph->bounds.x2 - glyph->bounds.x1; int h = glyph->bounds.y1 - glyph->bounds.y2; agg::rendering_buffer rbuf(glyph->data, w, h, w * 4); agg::trans_affine img_mtx; img_mtx *= agg::trans_affine_translation(0, -glyph->bounds.y1); if (scaling > 0) { img_mtx *= agg::trans_affine_translation(-double(w)/2, 0); img_mtx *= agg::trans_affine_scaling(scaling); img_mtx *= agg::trans_affine_translation(scaling * double(w)/2, 0); } #if defined(__APPLE__) // Apple emojis have no descender if (strcmp("Apple Color Emoji", get_engine().family()) == 0) { if (scaling < 0) scaling = 1.0; //shouldn't happen as Apple emojis are not scalable img_mtx *= agg::trans_affine_translation(0, scaling * double(h) * 0.12); } #endif img_mtx *= agg::trans_affine_rotation(rot); img_mtx *= agg::trans_affine_translation(x, y); agg::trans_affine src_mtx = img_mtx; img_mtx.invert(); typedef agg::span_interpolator_linear<> interpolator_type; interpolator_type interpolator(img_mtx); agg::rasterizer_scanline_aa<> ras; agg::path_storage rect; rect.remove_all(); rect.move_to(0, 0); rect.line_to(0, h); rect.line_to(w, h); rect.line_to(w, 0); rect.close_polygon(); agg::conv_transform tr(rect, src_mtx); ras.add_path(tr); bool interpolate = scaling >= 1 || scaling < 0; render_raster(rbuf, w, h, ras, ras_clip, sl, interpolator, renderer, interpolate, clip, !interpolate); } }; ragg/src/AggDevicePpm.h0000644000176200001440000000143414131500365014425 0ustar liggesusers#pragma once #include "ragg.h" #include "AggDevice.h" #include "files.h" template class AggDevicePpm : public AggDevice { public: AggDevicePpm(const char* fp, int w, int h, double ps, int bg, double res, double scaling) : AggDevice(fp, w, h, ps, bg, res, scaling) { } // Behaviour bool savePage() { char buf[PATH_MAX+1]; snprintf(buf, PATH_MAX, this->file.c_str(), this->pageno); buf[PATH_MAX] = '\0'; FILE* fd = unicode_fopen(buf, "wb"); if(fd) { fprintf(fd, "P6 %d %d 255 ", this->width, this->height); fwrite(this->buffer, 1,this-> width * this->height * this->bytes_per_pixel, fd); fclose(fd); return true; } return false; }; }; typedef AggDevicePpm AggDevicePpmNoAlpha; ragg/src/pattern.h0000644000176200001440000002705214136210032013605 0ustar liggesusers#pragma once #include #include "ragg.h" #include "RenderBuffer.h" #include "rendering.h" #include "agg_span_gradient.h" #include "agg_gradient_lut.h" #include "agg_span_interpolator_linear.h" #include "agg_span_allocator.h" #include "agg_scanline_p.h" #include "agg_span_image_filter_rgba.h" enum PatternType { PatternLinearGradient, PatternRadialGradient, PatternTile }; enum ExtendType { ExtendPad, ExtendRepeat, ExtendReflect, ExtendNone }; template class Pattern { public: typedef agg::gradient_x linear_type; typedef agg::gradient_radial_focus radial_type; typedef agg::span_interpolator_linear<> interpolator_type; typedef agg::span_allocator span_allocator_type; typedef agg::gradient_lut< agg::color_interpolator, 512 > color_func_type; typedef agg::gradient_lut< agg::color_interpolator, 512 > color_func_type_mask; PatternType type; ExtendType extend; RenderBuffer buffer; color_func_type gradient; color_func_type_mask gradient_mask; linear_type linear; radial_type radial; span_allocator_type sa; double d2; int width; int height; agg::trans_affine mtx; double x_trans; double y_trans; Pattern() : buffer(), d2(0.0), width(0), height(0), x_trans(0.0), y_trans(0.0) { gradient.remove_all(); gradient_mask.remove_all(); mtx.reset(); } void init_linear(double x1, double y1, double x2, double y2, ExtendType e) { type = PatternLinearGradient; extend = e; double dx = x2 - x1; double dy = y2 - y1; d2 = std::sqrt(dx * dx + dy * dy); mtx *= agg::trans_affine_rotation(atan2(dy, dx)); mtx *= agg::trans_affine_translation(x1, y1); mtx.invert(); } void init_radial(double x1, double y1, double r1, double x2, double y2, double r2, ExtendType e) { type = PatternRadialGradient; extend = e; d2 = r2 + r1; mtx *= agg::trans_affine_translation(x2, y2); mtx.invert(); radial.init(r2, x1 - x2, y1 - y2); } void init_tile(int w, int h, double x, double y, ExtendType e) { type = PatternTile; extend = e; width = w < 0 ? -w : w; height = h < 0 ? -h : h; buffer.init(width, height, color(0, 0, 0, 0)); mtx *= agg::trans_affine_translation(0, h); mtx *= agg::trans_affine_translation(x, y); mtx.invert(); x_trans = -x; y_trans = -y + height; } bool is_gradient() { return type != PatternTile; } void add_color(double at, color &col) { gradient.add_color(at, col); gradient_mask.add_color(at, col); } void finish_gradient() { gradient.build_lut(); gradient_mask.build_lut(); } template void draw(Raster &ras, RasterClip &ras_clip, Scanline &sl, Render &renderer, bool clip) { switch (type) { case PatternLinearGradient: draw_linear(ras, ras_clip, sl, renderer, clip); break; case PatternRadialGradient: draw_radial(ras, ras_clip, sl, renderer, clip); break; case PatternTile: draw_tile(ras, ras_clip, sl, renderer, clip); break; } } Pattern convert_for_mask() { Pattern new_pattern; if (type == PatternTile) { new_pattern.init_tile(width, height, 0, 0, extend); new_pattern.buffer.copy_from(buffer.get_buffer()); } else{ new_pattern.type = type; new_pattern.extend = extend; new_pattern.d2 = d2; new_pattern.radial = radial; new_pattern.gradient = gradient_mask; } new_pattern.mtx = mtx; return new_pattern; } private: template void draw_linear(Raster &ras, RasterClip &ras_clip, Scanline &sl, Render &renderer, bool clip) { interpolator_type span_interpolator(mtx); switch (extend) { case ExtendReflect: { agg::gradient_reflect_adaptor grad_refl(linear); typedef agg::span_gradient, color_func_type> span_reflect_type; span_reflect_type span_reflect(span_interpolator, grad_refl, gradient, 0, d2); typedef agg::renderer_scanline_aa renderer_reflect_type; renderer_reflect_type reflect_renderer(renderer, sa, span_reflect); render(ras, ras_clip, sl, reflect_renderer, clip); break; } case ExtendRepeat: { agg::gradient_repeat_adaptor grad_rep(linear); typedef agg::span_gradient, color_func_type> span_repeat_type; span_repeat_type span_repeat(span_interpolator, grad_rep, gradient, 0, d2); typedef agg::renderer_scanline_aa renderer_repeat_type; renderer_repeat_type repeat_renderer(renderer, sa, span_repeat); render(ras, ras_clip, sl, repeat_renderer, clip); break; } case ExtendPad: { typedef agg::span_gradient span_pad_type; span_pad_type span_pad(span_interpolator, linear, gradient, 0, d2); typedef agg::renderer_scanline_aa renderer_pad_type; renderer_pad_type pad_renderer(renderer, sa, span_pad); render(ras, ras_clip, sl, pad_renderer, clip); break; } case ExtendNone: { typedef agg::span_gradient span_pad_type; span_pad_type span_pad(span_interpolator, linear, gradient, 0, d2, false); typedef agg::renderer_scanline_aa renderer_pad_type; renderer_pad_type pad_renderer(renderer, sa, span_pad); render(ras, ras_clip, sl, pad_renderer, clip); break; } } } template void draw_radial(Raster &ras, RasterClip &ras_clip, Scanline &sl, Render &renderer, bool clip) { interpolator_type span_interpolator(mtx); switch (extend) { case ExtendReflect: { agg::gradient_reflect_adaptor grad_refl(radial); typedef agg::span_gradient, color_func_type> span_reflect_type; span_reflect_type span_reflect(span_interpolator, grad_refl, gradient, 0, d2); typedef agg::renderer_scanline_aa renderer_reflect_type; renderer_reflect_type reflect_renderer(renderer, sa, span_reflect); render(ras, ras_clip, sl, reflect_renderer, clip); break; } case ExtendRepeat: { agg::gradient_repeat_adaptor grad_rep(radial); typedef agg::span_gradient, color_func_type> span_repeat_type; span_repeat_type span_repeat(span_interpolator, grad_rep, gradient, 0, d2); typedef agg::renderer_scanline_aa renderer_repeat_type; renderer_repeat_type repeat_renderer(renderer, sa, span_repeat); render(ras, ras_clip, sl, repeat_renderer, clip); break; } case ExtendPad: { typedef agg::span_gradient span_pad_type; span_pad_type span_pad(span_interpolator, radial, gradient, 0, d2); typedef agg::renderer_scanline_aa renderer_pad_type; renderer_pad_type pad_renderer(renderer, sa, span_pad); render(ras, ras_clip, sl, pad_renderer, clip); break; } case ExtendNone: { typedef agg::span_gradient span_pad_type; span_pad_type span_pad(span_interpolator, radial, gradient, 0, d2, false); typedef agg::renderer_scanline_aa renderer_pad_type; renderer_pad_type pad_renderer(renderer, sa, span_pad); render(ras, ras_clip, sl, pad_renderer, clip); break; } } } template void draw_tile(Raster &ras, RasterClip &ras_clip, Scanline &sl, Render &renderer, bool clip) { interpolator_type span_interpolator(mtx); PIXFMT img_pixf(buffer.get_buffer()); agg::span_allocator sa; switch (extend) { case ExtendReflect: { typedef agg::image_accessor_wrap img_source_type; img_source_type img_src(img_pixf); typedef agg::span_image_filter_rgba_bilinear span_reflect_type; span_reflect_type span_reflect(img_src, span_interpolator); agg::renderer_scanline_aa reflect_renderer(renderer, sa, span_reflect); render(ras, ras_clip, sl, reflect_renderer, clip); break; } case ExtendRepeat: { typedef agg::image_accessor_wrap img_source_type; img_source_type img_src(img_pixf); typedef agg::span_image_filter_rgba_bilinear span_repeat_type; span_repeat_type span_repeat(img_src, span_interpolator); agg::renderer_scanline_aa repeat_renderer(renderer, sa, span_repeat); render(ras, ras_clip, sl, repeat_renderer, clip); break; } case ExtendPad: { typedef agg::image_accessor_clone img_source_type; img_source_type img_src(img_pixf); typedef agg::span_image_filter_rgba_bilinear span_pad_type; span_pad_type span_pad(img_src, span_interpolator); agg::renderer_scanline_aa pad_renderer(renderer, sa, span_pad); render(ras, ras_clip, sl, pad_renderer, clip); break; } case ExtendNone: { typedef agg::image_accessor_clip img_source_type; img_source_type img_src(img_pixf, color(0, 0, 0, 0)); typedef agg::span_image_filter_rgba_bilinear span_none_type; span_none_type span_none(img_src, span_interpolator); agg::renderer_scanline_aa none_renderer(renderer, sa, span_none); render(ras, ras_clip, sl, none_renderer, clip); break; } } } }; ragg/src/capture_dev.cpp0000644000176200001440000000104214122043530014755 0ustar liggesusers#include "ragg.h" #include "init_device.h" #include "AggDeviceCapture.h" // [[export]] SEXP agg_capture_c(SEXP name, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling) { int bgCol = RGBpar(bg, 0); BEGIN_CPP AggDeviceCaptureAlpha* device = new AggDeviceCaptureAlpha( "", INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0] ); makeDevice(device, CHAR(STRING_ELT(name, 0))); END_CPP return R_NilValue; } ragg/src/Makevars.ucrt0000644000176200001440000000003714046470414014435 0ustar liggesusersCRT=-ucrt include Makevars.win ragg/src/jpeg_dev.cpp0000644000176200001440000000144114127312027014247 0ustar liggesusers#include "ragg.h" #include "init_device.h" #include "AggDeviceJpeg.h" // [[export]] SEXP agg_jpeg_c(SEXP file, SEXP width, SEXP height, SEXP pointsize, SEXP bg, SEXP res, SEXP scaling, SEXP quality, SEXP smoothing, SEXP method) { int bgCol = RGBpar(bg, 0); if (R_TRANSPARENT(bgCol)) { bgCol = R_TRANWHITE; } BEGIN_CPP AggDeviceJpegNoAlpha* device = new AggDeviceJpegNoAlpha( Rf_translateCharUTF8((STRING_ELT(file, 0))), INTEGER(width)[0], INTEGER(height)[0], REAL(pointsize)[0], bgCol, REAL(res)[0], REAL(scaling)[0], INTEGER(quality)[0], INTEGER(smoothing)[0], INTEGER(method)[0] ); makeDevice(device, "agg_jpeg"); END_CPP return R_NilValue; } ragg/src/Makevars.in0000644000176200001440000000055614004766605014100 0ustar liggesusersPKG_CXXFLAGS = -I./agg/include @cflags@ PKG_LIBS = -Lagg -lstatagg @libs@ AGG_OBJECTS = agg/src/agg_curves.o agg/src/agg_font_freetype.o \ agg/src/agg_image_filters.o agg/src/agg_trans_affine.o \ agg/src/agg_vcgen_dash.o agg/src/agg_vcgen_stroke.o STATLIB = agg/libstatagg.a $(SHLIB): $(STATLIB) $(STATLIB): $(AGG_OBJECTS) $(AR) rcs $(STATLIB) $(AGG_OBJECTS) ragg/configure.win0000644000176200001440000000000013521752411013661 0ustar liggesusersragg/R/0000755000176200001440000000000014147726771011413 5ustar liggesusersragg/R/ragg-package.R0000644000176200001440000000047713722140523014036 0ustar liggesusers#' @keywords internal #' @useDynLib ragg, .registration = TRUE #' @importFrom systemfonts match_font #' @importFrom textshaping text_width "_PACKAGE" # The following block is used by usethis to automatically manage # roxygen namespace tags. Modify with care! ## usethis namespace: start ## usethis namespace: end NULL ragg/R/aaa.R0000644000176200001440000000211614057747415012256 0ustar liggesusersget_dims <- function(width, height, units, res) { dims <- c(width, height) * switch( units, 'in' = res, 'cm' = res / 2.54, 'mm' = res / 25.4, 'px' = 1, stop('Unknown unit. Please use either px, in, cm, or, mm', call. = FALSE) ) max_dim <- getOption('ragg.max_dim', 5e4) if (any(dims > max_dim)) { stop( 'One or both dimensions exceed the maximum (', max_dim, 'px).\n', '- Use `options(ragg.max_dim = ...)` to change the max\n', ' Warning: May cause the R session to crash', call. = FALSE ) } as.integer(dims) } validate_path <- function(path) { dir <- dirname(path) if (!dir.exists(dir)) { dir.create(dir, recursive = TRUE) } dir <- normalizePath(dir) file.path(dir, basename(path)) } #' @importFrom systemfonts register_font #' @export systemfonts::register_font #' @importFrom systemfonts register_variant #' @export systemfonts::register_variant #' @importFrom systemfonts font_feature #' @export systemfonts::font_feature #' @importFrom textshaping get_font_features #' @export textshaping::get_font_features ragg/R/agg_dev.R0000644000176200001440000003347414010207517013122 0ustar liggesusers#' Draw to a PPM file #' #' The PPM (Portable Pixel Map) format defines one of the simplest storage #' formats available for #' image data. It is basically a raw 8bit RGB stream with a few bytes of #' information in the start. It goes without saying, that this file format is #' horribly inefficient and should only be used if you want to play around with #' a simple file format, or need a file-based image stream. #' #' @param filename The name of the file. Follows the same semantics as the file #' naming in [grDevices::png()], meaning that you can provide a [sprintf()] #' compliant string format to name multiple plots (such as the default value) #' @param width,height The dimensions of the device #' @param units The unit `width` and `height` is measured in, in either pixels #' (`'px'`), inches (`'in'`), millimeters (`'mm'`), or centimeter (`'cm'`). #' @param pointsize The default pointsize of the device in pt. This will in #' general not have any effect on grid graphics (including ggplot2) as text #' size is always set explicitly there. #' @param background The background colour of the device #' @param res The resolution of the device. This setting will govern how device #' dimensions given in inches, centimeters, or millimeters will be converted #' to pixels. Further, it will be used to scale text sizes and linewidths #' @param scaling A scaling factor to apply to the rendered line width and text #' size. Useful for getting the right dimensions at the resolution that you #' need. If e.g. you need to render a plot at 4000x3000 pixels for it to fit #' into a layout, but you find that the result appears to small, you can #' increase the `scaling` argument to make everything appear bigger at the #' same resolution. #' @param bg Same as `background` for compatibility with old graphic device APIs #' #' @export #' #' @examples #' file <- tempfile(fileext = '.ppm') #' agg_ppm(file) #' plot(sin, -pi, 2*pi) #' dev.off() #' agg_ppm <- function(filename = 'Rplot%03d.ppm', width = 480, height = 480, units = 'px', pointsize = 12, background = 'white', res = 72, scaling = 1, bg) { if (environmentName(parent.env(parent.frame())) == "knitr" && deparse(sys.call(), nlines = 1, width.cutoff = 500) == 'dev(filename = filename, width = dim[1], height = dim[2], ...)') { units <- 'in' } file <- validate_path(filename) dim <- get_dims(width, height, units, res) background <- if (missing(bg)) background else bg .Call("agg_ppm_c", file, dim[1], dim[2], as.numeric(pointsize), background, as.numeric(res), as.numeric(scaling), PACKAGE = 'ragg') invisible() } #' Draw to a PNG file #' #' The PNG (Portable Network Graphic) format is one of the most ubiquitous #' today, due to its versatiliity #' and widespread support. It supports transparency as well as both 8 and 16 bit #' colour. The device uses default compression and filtering and will not use a #' colour palette as this is less useful for antialiased data. This means that #' it might be possible to compress the resulting image even more if size is of #' concern (though the defaults are often very good). In contrast to #' [grDevices::png()] the date and time will not be written to the file, meaning #' that similar plot code will produce identical files (a good feature if used #' with version control). It will, however, write in the dimensions of the image #' based on the `res` argument. #' #' @inheritParams agg_ppm #' @param bitsize Should the device record colour as 8 or 16bit #' #' @export #' #' @examples #' file <- tempfile(fileext = '.png') #' agg_png(file) #' plot(sin, -pi, 2*pi) #' dev.off() #' agg_png <- function(filename = 'Rplot%03d.png', width = 480, height = 480, units = 'px', pointsize = 12, background = 'white', res = 72, scaling = 1, bitsize = 8, bg) { if (environmentName(parent.env(parent.frame())) == "knitr" && deparse(sys.call(), nlines = 1, width.cutoff = 500) == 'dev(filename = filename, width = dim[1], height = dim[2], ...)') { units <- 'in' } file <- validate_path(filename) if (!bitsize %in% c(8, 16)) { stop('Only 8 and 16 bit is supported', call. = FALSE) } dim <- get_dims(width, height, units, res) background <- if (missing(bg)) background else bg .Call("agg_png_c", file, dim[1], dim[2], as.numeric(pointsize), background, as.numeric(res), as.numeric(scaling), as.integer(bitsize), PACKAGE = 'ragg') invisible() } #' Draw to a TIFF file #' #' The TIFF (Tagged Image File Format) format is a very versatile raster image #' storage format that supports 8 and 16bit colour mode, true transparency, as #' well as a range of other features not relevant to drawing from R (e.g. #' support for different colour spaces). The storage mode of the image data is #' not fixed and different compression modes are possible, in contrast to PNGs #' one-approach-fits-all. The default (uncompressed) will result in much larger #' files than PNG, and in general PNG is a better format for many of the graphic #' types produced in R. Still, TIFF has its purposes and sometimes this file #' format is explicetly requested. #' #' @section Transparency: #' TIFF have support for true transparency, meaning that the pixel colour is #' stored in pre-multiplied form. This is in contrast to pixels being stored in #' plain format, where the alpha values more function as a mask. The utility of #' this is not always that important, but it is one of the benefits of TIFF over #' PNG so it should be noted. #' #' @inheritParams agg_png #' @param compression The compression type to use for the image data. The #' standard options from the [grDevices::tiff()] function are available under #' the same name. #' #' @note `'jpeg'` compression is only available if ragg is compiled with a #' version of `libtiff` where jpeg support has been turned on. #' #' @export #' #' @examples #' file <- tempfile(fileext = '.tiff') #' # Use jpeg compression #' agg_tiff(file, compression = 'lzw+p') #' plot(sin, -pi, 2*pi) #' dev.off() #' agg_tiff <- function(filename = 'Rplot%03d.tiff', width = 480, height = 480, units = 'px', pointsize = 12, background = 'white', res = 72, scaling = 1, compression = 'none', bitsize = 8, bg) { if (environmentName(parent.env(parent.frame())) == "knitr" && deparse(sys.call(), nlines = 1, width.cutoff = 500) == 'dev(filename = filename, width = dim[1], height = dim[2], ...)') { units <- 'in' } file <- validate_path(filename) encoding <- switch(compression, 'lzw+p' = , 'zip+p' = 1L, 0L) compression <- switch( compression, 'none' = 0L, 'rle' = 2L, 'lzw+p' = , 'lzw' = 5L, 'jpeg' = 7L, 'zip+p' = , 'zip' = 8L ) if (!bitsize %in% c(8, 16)) { stop('Only 8 and 16 bit is supported', call. = FALSE) } dim <- get_dims(width, height, units, res) background <- if (missing(bg)) background else bg .Call("agg_tiff_c", file, dim[1], dim[2], as.numeric(pointsize), background, as.numeric(res), as.numeric(scaling), as.integer(bitsize), compression, encoding, PACKAGE = 'ragg') invisible() } #' Draw to a JPEG file #' #' The JPEG file format is a lossy compressed file format developed in #' particular for digital photography. The format is not particularly #' well-suited for line drawings and text of the type normally associated with #' statistical plots as the compression algorithm creates noticable artefacts. #' It is, however, great for saving image data, e.g. heightmaps etc. Thus, for #' standard plots, it would be better to use [agg_png()], but for plots that #' includes a high degree of raster image rendering this device will result in #' smaller plots with very little quality degradation. #' #' @inheritParams agg_png #' @param quality An integer between `0` and `100` defining the quality/size #' tradeoff. Setting this to `100` will result in no compression. #' @param smoothing A smoothing factor to apply before compression, from `0` (no #' smoothing) to `100` (full smoothing). Can also by `FALSE` (no smoothing) or #' `TRUE` (full smoothing). #' @param method The compression algorithm to use. Either `'slow'`, `'fast'`, or #' `'float'`. Default is `'slow'` which works best for most cases. `'fast'` #' should only be used when quality is below `97` as it may result in worse #' performance at high quality settings. `'float'` is a legacy options that #' calculate the compression using floating point precission instead of with #' integers. It offers no quality benefit and is often much slower. #' #' @note Smoothing is only applied if ragg has been compiled against a jpeg #' library that supports smoothing. #' #' @export #' #' @examples #' file <- tempfile(fileext = '.jpeg') #' agg_jpeg(file, quality = 50) #' plot(sin, -pi, 2*pi) #' dev.off() #' agg_jpeg <- function(filename = 'Rplot%03d.jpeg', width = 480, height = 480, units = 'px', pointsize = 12, background = 'white', res = 72, scaling = 1, quality = 75, smoothing = FALSE, method = 'slow', bg) { if (environmentName(parent.env(parent.frame())) == "knitr" && deparse(sys.call(), nlines = 1, width.cutoff = 500) == 'dev(filename = filename, width = dim[1], height = dim[2], ...)') { units <- 'in' } file <- validate_path(filename) quality <- min(100, max(0, quality)) if (is.logical(smoothing)) smoothing <- if (smoothing) 100 else 0 smoothing <- min(100, max(0, smoothing)) method <- match.arg(tolower(method), c('slow', 'fast', 'float')) method <- match(method, c('slow', 'fast', 'float')) - 1L dim <- get_dims(width, height, units, res) background <- if (missing(bg)) background else bg .Call("agg_jpeg_c", file, dim[1], dim[2], as.numeric(pointsize), background, as.numeric(res), as.numeric(scaling), as.integer(quality), as.integer(smoothing), method, PACKAGE = 'ragg') invisible() } #' Draw to a PNG file, modifying transparency on the fly #' #' The graphic engine in R only supports 8bit colours. This is for the most part #' fine, as 8bit gives all the fidelity needed for most graphing needs. However, #' this may become a limitation if you need to plot thousands of very #' translucent shapes on top of each other. 8bit only afford a minimum of 1/255 #' alpha, which may end up accumulating to fully opaque at some point. This #' device allows you to create a 16bit device that modifies the alpha level of #' all incomming colours by a fixed multiplier, thus allowing for much more #' translucent colours. The device will only modify transparent colour, so if #' you pass in an opaque colour it will be left unchanged. #' #' @inheritParams agg_ppm #' @param alpha_mod A numeric between 0 and 1 that will be multiplied to the #' alpha channel of all transparent colours #' #' @export #' @keywords internal #' agg_supertransparent <- function(filename = 'Rplot%03d.png', width = 480, height = 480, units = 'px', pointsize = 12, background = 'white', res = 72, scaling = 1, alpha_mod = 1, bg) { if (environmentName(parent.env(parent.frame())) == "knitr" && deparse(sys.call(), nlines = 1, width.cutoff = 500) == 'dev(filename = filename, width = dim[1], height = dim[2], ...)') { units <- 'in' } file <- validate_path(filename) dim <- get_dims(width, height, units, res) background <- if (missing(bg)) background else bg .Call("agg_supertransparent_c", file, dim[1], dim[2], as.numeric(pointsize), background, as.numeric(res), as.numeric(scaling), as.double(alpha_mod), PACKAGE = 'ragg') invisible() } #' Draw to a buffer that can be accessed directly #' #' Usually the point of using a graphic device is to create a file or show the #' graphic on the screen. A few times we need the image data for further #' processing in R, and instead of writing it to a file and then reading it back #' into R the `agg_capture()` device lets you get the image data directly from #' the buffer. In contrast to the other devices this device returns a function, #' that when called will return the current state of the buffer. #' #' @inheritParams agg_ppm #' #' @return A function that when called returns the current state of the buffer. #' The return value of the function depends on the `native` argument. If `FALSE` #' (default) the return value is a `matrix` of colour values and if `TRUE` the #' return value is a `nativeRaster` object. #' #' @importFrom grDevices dev.list dev.off dev.cur dev.capture dev.set #' @export #' #' @examples #' cap <- agg_capture() #' plot(1:10, 1:10) #' #' # Get the plot as a matrix #' raster <- cap() #' #' # Get the plot as a nativeRaster #' raster_n <- cap(native = TRUE) #' #' dev.off() #' #' # Look at the output #' plot(as.raster(raster)) #' agg_capture <- function(width = 480, height = 480, units = 'px', pointsize = 12, background = 'white', res = 72, scaling = 1, bg) { if (environmentName(parent.env(parent.frame())) == "knitr" && deparse(sys.call(), nlines = 1, width.cutoff = 500) == 'dev(filename = filename, width = dim[1], height = dim[2], ...)') { units <- 'in' } dim <- get_dims(width, height, units, res) background <- if (missing(bg)) background else bg name <- paste0('agg_capture_', sample(.Machine$integer.max, 1)) .Call("agg_capture_c", name, dim[1], dim[2], as.numeric(pointsize), background, as.numeric(res), as.numeric(scaling), PACKAGE = 'ragg') cap <- function(native = FALSE) { current_dev = dev.cur() if (names(current_dev)[1] == name) { return(dev.capture(native = native)) } all_dev <- dev.list() if (!name %in% names(all_dev)) { stop('The device (', name, ') is no longer open', call. = FALSE) } dev.set(all_dev[name]) on.exit(dev.set(current_dev)) dev.capture(native = native) } invisible(cap) } ragg/NEWS.md0000644000176200001440000001027014153422002012261 0ustar liggesusers# ragg 1.2.1 * Fix bug that caused R to crash when writing tiff files with transparent background (#97) # ragg 1.2.0 * Add support for new graphic engine features: - Arbitrary clipping paths - Alpha masks - Linear and radial gradients - Tiling patterns * Use white as background when passing in a fully transparent background colour to devices that doesn't support alpha (notably jpeg) (#91) * ragg now defers symbol font resolving to systemfonts which makes it possible to register alternative symbol fonts using `register_font()` (#90) * Filenames in UTF-8 are now treated correctly on Windows (#87) * Fix size selection of non-scalable fonts when the requested size is bigger than the available # ragg 1.1.3 * Use int32_t instead of int32 in old code * Prepare for UCRT * Better error message when failing to allocate memory for the buffer (#82) * Increase storage size limits for paths (#80) # ragg 1.1.2 * Fix bug in `agg_capture()` that resulted in premultiplied colour values being returned # ragg 1.1.1 * Fix a bug in glyph dimension lookup that could cause system crashes * Fix bug in font caching when multiple ragg devices are used simultaneously # ragg 1.1.0 * Major version release to signify the much improved text support that includes full support for right-to-left scripts and bidirectional text (mix of RtL and LtR scripts). It further adds full support for OpenType features and non-scalable fonts. * Re-exporting `register_font()`, `register_variant()`, and `font_feature()` from systemfonts * Re-exporting `get_font_features()` from textshaping * Use new textshaping API and handle font fallback correctly * Add support for rendering colour fonts (#1) # ragg 0.4.1 * Skip text tests on CRAN as no text is plottet on the CRAN solaris machine * Fixed a bug resulting in system crash on certain systems, as well as clang-ASAN error. (#59) # ragg 0.4.0 * ragg now requires the Harfbuzz and Fribidi libraries to be available when installing from source due to their dependency in the textshaping package. * Move text shaping to the new textshaping package. * Fix `agg_capture()` on big endian systems (#49, @QuLogic) * Fix use of symbol font on Windows by moving to Segoe UI Symbol which has a Unicode charmap (#51) * Better compatibility with knitr and `ggplot2::ggsave()` # ragg 0.3.1 * Roll back support for new clipping options in the graphic engine as it was buggy. # ragg 0.3.0 * Fix a bug when plotting partially transparent raster (#44) * Add a `scaling` argument to all devices allowing you to change relative scaling of output. * Horizontal and vertical text are now snapped to the pixel grid in order to improve rendering quality. * Internal changes to prepare for coming updates to the graphic engine # ragg 0.2.0 * Fix compilation on R <= 3.3 by including Rdynload.h explicitly * Fix a performance regression when plotting text (#33) * Fix erroneous width calculations of strings starting with a space on windows (#32) * Fix a bug in `agg_capture()` where the output became mangled if device height != width * Fix a bug in raster support where raster data did not get premultiplied before rendering (#38, @yixuan) * Fix an integer overflow issue in the AGG source code # ragg 0.1.5 * Fix compilation on macOS # ragg 0.1.4 * Fix a bug in AGG's font manager that ignored the font index when it stored and retrieved cached faces # ragg 0.1.3 * Fix bug preventing ragg from displaying 50% transparent black * Another attempt at fixing compilation on mac build machines # ragg 0.1.2 * Fix compilation on certain Linux systems by preferring dynamic libraries over static ones (#25, @jimhester). # ragg 0.1.1 * Avoid a bug when the call to start a device included too many characters (#16) * Fix integer overflow runtime errors in agg source code (`agg_scanline_storage_aa.h`), by changing storage to `long` * Remove benchmarking vignettes as it was causing too much trouble on stripped down systems... They are still available on * Better build setup to properly build on all macOS systems # ragg 0.1.0 * Basic setup of package. png, tiff, ppm, and buffer capture support * Added a `NEWS.md` file to track changes to the package. ragg/MD50000644000176200001440000003126214153425042011506 0ustar liggesusersb60691d6a9fd7f6a142cbedd568f456c *DESCRIPTION c31ee18d335f7158ed985f5939319c1f *LICENSE c4d2281fabe13eaef0a344d82129875c *LICENSE.note a8964cbb59e44b15f9f801f95fca4957 *NAMESPACE 33e325756ec22a8ca7b7c82c4b91ec07 *NEWS.md fe51628635b95b31fb6015fed21a0bee *R/aaa.R 0911b259ade882d077a21ebce8f67dbe *R/agg_dev.R 6ad67b21797a8729bbe3fd705012d19e *R/ragg-package.R d78430901454ed86efbfd89b14ca8aae *README.md dec917382c9960750df86f1cba0ccbfc *cleanup cafa2e7eaac8c23f28e023084110f4c2 *configure d41d8cd98f00b204e9800998ecf8427e *configure.win 528ba323b310ba9ae080dc00eac99733 *man/agg_capture.Rd b9d8debaa55befc27a87ad6d474e4d05 *man/agg_jpeg.Rd 5c66e5f24a2488f4d2d826d93523a910 *man/agg_png.Rd 7b089561279114337bc0683a72151c22 *man/agg_ppm.Rd af331cd469e89cd969d92b55d85b06e6 *man/agg_supertransparent.Rd 7552d39630c4e100e212fd0ee87ab6f7 *man/agg_tiff.Rd eba6dbf09b3d3b8004a6e2c788e9dd3e *man/figures/README-unnamed-chunk-3-1.png 10ae33788c0e16df595c2596830faf81 *man/figures/README-unnamed-chunk-4-1.png 5d857726ace7419381164b5e1d7e55f6 *man/figures/logo.png 40c6296e015379ff762af986a3ece91a *man/ragg-package.Rd dee794901f050af1cb9cfb9d28d14032 *man/reexports.Rd 66dd704fea65e70fa189ab866b1056ac *src/AggDevice.h 91df3b6ff836dbbad626f19056e5a760 *src/AggDevice16.h 0123a73507e3de76f4e19801d2a696fa *src/AggDeviceCapture.h 1aecb49463e16619bc8df4bcd1d9916c *src/AggDeviceJpeg.h 993f4366af6eb38a38a391b93efcf52c *src/AggDevicePng.h 722d1d1866d2875e62ec271c37f955d5 *src/AggDevicePpm.h 36d8eee3a3ca14b9c5ffdc08c39811e6 *src/AggDeviceTiff.h 998cefe1dc1d224e0c96c482f766ec6e *src/Makevars.in 2cec33791efd347cbcb051402d7cf9c4 *src/Makevars.ucrt 0f4a8a3cda1cbaad9e58f575ae3c22d6 *src/Makevars.win 29cc9bd9024892544f9c08e0e0038bcd *src/RenderBuffer.h 45598580b63ebf0e95ec504405178138 *src/agg/AUTHORS 0a2412244f5b710266589e2d5a5f28f5 *src/agg/copying 0570400627aa774982dbcdca95583990 *src/agg/include/agg_alpha_mask_u8.h 95a94d28a639f203bdc689ad63372222 *src/agg/include/agg_arc.h 9d0cebad9238a69a201b6c98381505d2 *src/agg/include/agg_array.h ba95a66196304605a7af7d205a3f96fe *src/agg/include/agg_arrowhead.h 892f0527ee75bd7cfc765be882c86269 *src/agg/include/agg_basics.h e80e93e581a8786dd3ab43331dde8126 *src/agg/include/agg_bezier_arc.h f40c865098be0a7800a8c06acdfc0a2b *src/agg/include/agg_bitset_iterator.h 972d0c7904a06a43134533282b334155 *src/agg/include/agg_blur.h 51a12206b82ea387b508c4f90777d4c5 *src/agg/include/agg_bounding_rect.h 364262932a0829a49ecf3bd0d4b466ed *src/agg/include/agg_bspline.h aa8d7fcdb5046317ae007bf773b13611 *src/agg/include/agg_clip_liang_barsky.h fe8829b8f0bb42410a1b9febe31cd159 *src/agg/include/agg_color_gray.h 3fcbbb496b85e329991de6bcf5758248 *src/agg/include/agg_color_rgba.h edff8f277ad4f0a89378bf439e039f27 *src/agg/include/agg_config.h 60fce6c9332a4ed6a3c3e92cd632f3b6 *src/agg/include/agg_conv_adaptor_vcgen.h d0e12602db0bf5e49cc4ca422d84975f *src/agg/include/agg_conv_adaptor_vpgen.h 120edf422a1c3d2db87de119fbd86b66 *src/agg/include/agg_conv_bspline.h c65ef77ab20c16dc504494027420b848 *src/agg/include/agg_conv_clip_polygon.h 5b633f00f5ac30a6d791950e9c22f030 *src/agg/include/agg_conv_clip_polyline.h 33000baf6e2db6d87cf2c39850499975 *src/agg/include/agg_conv_close_polygon.h ce365394cb24c51fef550b4fe2886429 *src/agg/include/agg_conv_concat.h 197c5f53b7752e361cdbf6febe538f4c *src/agg/include/agg_conv_contour.h 9478a1f8dce11dbe0a2ece16036b83b1 *src/agg/include/agg_conv_curve.h d17c99d270a85be54452e1d878a8ea47 *src/agg/include/agg_conv_dash.h 0f1f14fb52a9e55faf48e9d399c501ca *src/agg/include/agg_conv_gpc.h 69837d97bb5e1960db17cfee0b9f2616 *src/agg/include/agg_conv_marker.h ba56354d11f5c46e0e999dd8f7ab5f3c *src/agg/include/agg_conv_marker_adaptor.h c1d6b3cb9671e779d34fb0fcd4c0bc31 *src/agg/include/agg_conv_segmentator.h 51be4d941682f01a738ae4494a110d4c *src/agg/include/agg_conv_shorten_path.h 3741e579b4bbecc770be56cca6f851c3 *src/agg/include/agg_conv_smooth_poly1.h 571fad55496bf989a416ae4648ee8d56 *src/agg/include/agg_conv_stroke.h 42c2766c663b823e4d7e56b41ad1a647 *src/agg/include/agg_conv_transform.h 9ae2afaa7095ec879114282c57745583 *src/agg/include/agg_conv_unclose_polygon.h 8bc7a30ca44e0bbd3548a88128362efd *src/agg/include/agg_curves.h 7f9124d068a46e3526e476d6d31ed844 *src/agg/include/agg_dda_line.h 2bf924d76566a09c16b33c8027c5b770 *src/agg/include/agg_ellipse.h 671830085f7a0cfefabd9f2e76eb6478 *src/agg/include/agg_ellipse_bresenham.h 8a96a7cd1b084cd7c3ecfe00836d8b03 *src/agg/include/agg_embedded_raster_fonts.h af804192dde2030a71fade7e88f009ff *src/agg/include/agg_font_cache_manager.h f585358394ae85201694c7a09c0b46f7 *src/agg/include/agg_font_cache_manager2.h 1fabca637a8c25b2eea4b6f36e7657db *src/agg/include/agg_font_freetype.h 3e11e70afa5ae2ca43982d8d3381e24d *src/agg/include/agg_gamma_functions.h 79df8d496dd1a0f08768355d1066d4f1 *src/agg/include/agg_gamma_lut.h aa5f3ff6eb5d4bf1d39fb452d9d6b31f *src/agg/include/agg_glyph_raster_bin.h 3a3cb445bbd567b4cea42f54cf43d3fa *src/agg/include/agg_gradient_lut.h 5fa1f4963042e3f66f998b5758c245a3 *src/agg/include/agg_gsv_text.h 88b5507538f2e34fd7356682bc6d0634 *src/agg/include/agg_image_accessors.h 0166835e3d2957809ecf1fe1ece8f685 *src/agg/include/agg_image_filters.h f5f58953a78115a186403a74395c1db0 *src/agg/include/agg_line_aa_basics.h 9dd47a0fb953fa1efc1ccea760793de7 *src/agg/include/agg_math.h 24553eb6efbcecf3c22159e2061bc6ee *src/agg/include/agg_math_stroke.h e0f4bbbdda917409a1e0d93634cd5532 *src/agg/include/agg_path_length.h 26e0ed3afbe836c8661a408844025721 *src/agg/include/agg_path_storage.h d89adbb72a8a0f12087c1bbaa6887785 *src/agg/include/agg_path_storage_integer.h 040e46915d8d696203ec1ee682f56af9 *src/agg/include/agg_pattern_filters_rgba.h 0b513a67962a7b77628158ec071e63d1 *src/agg/include/agg_pixfmt_amask_adaptor.h 8d8cc2ffb649f50d0e9f012ba4993cea *src/agg/include/agg_pixfmt_base.h 855895d12091b6442363f3c0b5a3dac1 *src/agg/include/agg_pixfmt_gray.h bb7fcafd238146c16e568a1543020a03 *src/agg/include/agg_pixfmt_rgb.h 54aced0c59c4ec4f393c6b9325f474d2 *src/agg/include/agg_pixfmt_rgb_packed.h 82b42f95c2fdfc6daba4f4026bc6674e *src/agg/include/agg_pixfmt_rgba.h a3108d31310efbae2313b0cce38bc540 *src/agg/include/agg_pixfmt_transposer.h 321eb1ccceb079e4084a45d6cc205906 *src/agg/include/agg_rasterizer_cells_aa.h abe7310ce22239112e738ebba8ee502a *src/agg/include/agg_rasterizer_compound_aa.h 2a95fbf723f964641128246e9c0beb24 *src/agg/include/agg_rasterizer_outline.h 62824719e32e73ce6568ca215333199b *src/agg/include/agg_rasterizer_outline_aa.h 512ca079e4422debf7c45dfac61f1a79 *src/agg/include/agg_rasterizer_scanline_aa.h 073f90de5a662f1fafd9702967608060 *src/agg/include/agg_rasterizer_scanline_aa_nogamma.h ad658a8c5c52cdafaea0a9f3e5577756 *src/agg/include/agg_rasterizer_sl_clip.h 15936b9eee0aab2b187a50aa8abd5a43 *src/agg/include/agg_renderer_base.h 600684c2df76936b7e0370b88549a411 *src/agg/include/agg_renderer_markers.h a3fd6998c40dd01499e4837ff2e088fb *src/agg/include/agg_renderer_mclip.h 02db344e31910ebd13d4f64327c49627 *src/agg/include/agg_renderer_outline_aa.h d927181062dbc8084b8b73b77bc923e1 *src/agg/include/agg_renderer_outline_image.h 612735af0829930ba8cb8be39f28e810 *src/agg/include/agg_renderer_primitives.h cd36361c54f91351e12a860848a07509 *src/agg/include/agg_renderer_raster_text.h d0b5903a9478be3a69a6ad102ab1e79a *src/agg/include/agg_renderer_scanline.h 9e35919bdcbb32f83c5a8caeb783c277 *src/agg/include/agg_rendering_buffer.h c0a953b714dd5a119975e6ba4c8de8c1 *src/agg/include/agg_rendering_buffer_dynarow.h 237b63b3b959209a23116593d7b96f6c *src/agg/include/agg_rounded_rect.h e9b99819da18fbfc203b60a56ecbc63e *src/agg/include/agg_scanline_bin.h 722f060a552c160796e757b9d4cdc551 *src/agg/include/agg_scanline_boolean_algebra.h a2bad9dc0b3e801a4206755cf2280c4f *src/agg/include/agg_scanline_p.h ea030e7558f928b0114d07f60c045c6d *src/agg/include/agg_scanline_storage_aa.h 63011d55c04c263e3baec4f467f7b635 *src/agg/include/agg_scanline_storage_bin.h 81a90bd1371c4504bba78133a9f61581 *src/agg/include/agg_scanline_u.h b976e3aed3ecdf35b9dfdcb84f22f883 *src/agg/include/agg_shorten_path.h c9f01039d91431de0035ad707c4f319e *src/agg/include/agg_simul_eq.h 63991fa5ac7ba8069b2b97429a1a0053 *src/agg/include/agg_span_allocator.h 94c585e53f870009c82168779104f7fe *src/agg/include/agg_span_converter.h 2f15697e2478984f29a51346063c1dd9 *src/agg/include/agg_span_gouraud.h 5726d03c1b0f4843d580eeda30f69fc4 *src/agg/include/agg_span_gouraud_gray.h f6415b12d4082d3ed9a5eb4087d5c053 *src/agg/include/agg_span_gouraud_rgba.h 3cb44ea476ef058e3530467b8f289333 *src/agg/include/agg_span_gradient.h 4b5a50bab0d8686dcb2406c2da897027 *src/agg/include/agg_span_gradient_alpha.h 1beab496088ee278c0d931b5b55d3037 *src/agg/include/agg_span_gradient_contour.h 96ed3d55d780ce6c185b4f727ef13a37 *src/agg/include/agg_span_gradient_image.h 20dcf611a1fb33df7354b0a70c247f23 *src/agg/include/agg_span_image_filter.h 6649e6bfe1dbc88af62aadad64c4cebc *src/agg/include/agg_span_image_filter_gray.h 4f892d654a02a21a552a70c7715f7ab3 *src/agg/include/agg_span_image_filter_rgb.h 1b981842e3665f8bb202d9580bdf04c7 *src/agg/include/agg_span_image_filter_rgba.h bff52bb6abfc2aa06e9af2a85235515f *src/agg/include/agg_span_interpolator_adaptor.h 7a192a54a774ec7ac534699bdd30db69 *src/agg/include/agg_span_interpolator_linear.h db3d17b7e9822818d5aa309d9c9fcec6 *src/agg/include/agg_span_interpolator_persp.h 53bc1513b9827974f607ec10d4cc2bc7 *src/agg/include/agg_span_interpolator_trans.h 92ac0b4a05246d150e450c554ee4e272 *src/agg/include/agg_span_pattern_gray.h baa9a875658319def2fd9c18bf708d27 *src/agg/include/agg_span_pattern_rgb.h af0df3d20cfccf49f05084ca40202c87 *src/agg/include/agg_span_pattern_rgba.h 201c676e92bdfa01132a9810d9da0efa *src/agg/include/agg_span_solid.h 3e146f4e835c1b7fee5b58ab83926781 *src/agg/include/agg_span_subdiv_adaptor.h 68aff7733ff1288141a1580087f38667 *src/agg/include/agg_trans_affine.h 7e6dec5ba3c7fa030ceb43178c57813a *src/agg/include/agg_trans_bilinear.h 2505d73023d9297f1df9c9194f4aa557 *src/agg/include/agg_trans_double_path.h f5eb54cf288f112a68adf2f45cb1321a *src/agg/include/agg_trans_perspective.h a3f20e82ed34c39a075a2066ee31f9f0 *src/agg/include/agg_trans_single_path.h a0d9490eb0c7e57a27d8a612d4c7b013 *src/agg/include/agg_trans_viewport.h 6641f0a7aeb0324dca199102633278b6 *src/agg/include/agg_trans_warp_magnifier.h 1e9e63147c32c3fae8ba4ecae40ad8be *src/agg/include/agg_vcgen_bspline.h acbfb6ca3f7de487bfc2f9790dc08bbc *src/agg/include/agg_vcgen_contour.h dd19427a85a98088fcd957a30edb323a *src/agg/include/agg_vcgen_dash.h d8434667ff58ed6160871ba598573e62 *src/agg/include/agg_vcgen_markers_term.h 6916bf1ee4167322b3e84852d8599db0 *src/agg/include/agg_vcgen_smooth_poly1.h e163f76e62e4836e8837301ddddb3882 *src/agg/include/agg_vcgen_stroke.h 719c2585d2225743e7ce9dcbe43755fa *src/agg/include/agg_vcgen_vertex_sequence.h c1de0363d632ea6ec1dc764320b88c1a *src/agg/include/agg_vertex_sequence.h f156302e677f416f2db35fc3fdf461d3 *src/agg/include/agg_vpgen_clip_polygon.h 472904b5e1554a060e839d7069c228e1 *src/agg/include/agg_vpgen_clip_polyline.h 2ea418c867d79494a521d8a1e857e98d *src/agg/include/agg_vpgen_segmentator.h 369f51834747ac293f8d863e6d1dcc83 *src/agg/include/util/agg_color_conv.h 58876ca3d28abd3650acebe8be57c91a *src/agg/src/agg_curves.cpp 462305e0c47f0ebd8c07fc1a2c81b1ba *src/agg/src/agg_font_freetype.cpp de7767170aebc51bf78d6115c0c5d987 *src/agg/src/agg_image_filters.cpp 6715b5433ca26109ce139c7b64f13f57 *src/agg/src/agg_trans_affine.cpp b3a8cf1bd081d8f124035f06f1c18e23 *src/agg/src/agg_vcgen_dash.cpp 5c40f602740a6579e2a5594533da2805 *src/agg/src/agg_vcgen_stroke.cpp 01196f1c3ee9dd743d2cba16cbb3bc32 *src/capture_dev.cpp 67e7e9adb41f4d8547844855074b7bf6 *src/files.h 6d4350aef0ef3c6dd16c7572f38843b6 *src/init.cpp a6be47dd298e888a85390536c20b73b9 *src/init_device.h ed7612a3aa3520cee81e8c1126f39a49 *src/jpeg_dev.cpp 2a9d5309c127bea6a04558c20c39a062 *src/pattern.h 7df59bd5b166cd2d72191fd31d4cc6b9 *src/png_dev.cpp 6a654547d1ee5aed90103c7b0d9df094 *src/ppm_dev.cpp 36fe14b9d9772311874371d10a7806c9 *src/ragg.h f04e9e64c7f9e0f188dbecdef31c88c7 *src/rendering.h caf8751dced36356aa59c5b40fc9f795 *src/text_renderer.h 7a1fa48a2cac0f00568554baa1b7d51f *src/tiff_dev.cpp 969206a560d843a732e9256f8f2f6035 *tests/testthat.R 02b51137d6159f9210b05bb08075c1ad *tests/testthat/test-circle.R 5ab942086191055c8cb0aa8d668b92b1 *tests/testthat/test-jpeg.R 95fd6579dd60691e3d8bcdef1fbb3768 *tests/testthat/test-line.R f53983117e4bff8085c565b286994855 *tests/testthat/test-path.R f170d453afb0f66f9f5efa8aebfc0c00 *tests/testthat/test-png.R 69a9363f4dee561cf4d38d0fc79c40e0 *tests/testthat/test-polygon.R c0fc5a8070541eb777669824aaf826fe *tests/testthat/test-polyline.R 57e8aa9081a528be3657c023318806db *tests/testthat/test-ppm.R ac61c2268cf318ea035e01cae19c05dd *tests/testthat/test-raster.R 05c436c0113022f9394e413ca41657ae *tests/testthat/test-rect.R 33a551b1b5b52c9178ba1d3ae0f8c959 *tests/testthat/test-text.R e1e28ee35d89426433934cfb05cc7a7c *tests/testthat/test-tiff.R 41b1e7cb2851ce354053145b660e0335 *tools/winlibs.R ragg/cleanup0000755000176200001440000000007214153422062012545 0ustar liggesusers#!/bin/sh rm -f src/Makevars configure.log rm -f autobrew ragg/configure0000755000176200001440000000645614153422062013113 0ustar liggesusers# Anticonf (tm) script by Jeroen Ooms, Jim Hester (2020) # This script will query 'pkg-config' for the required cflags and ldflags. # If pkg-config is unavailable or does not find the library, try setting # INCLUDE_DIR and LIB_DIR manually via e.g: # R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib' PLATFORM=`uname` # Library settings PKG_CONFIG_NAME="freetype2 libpng libtiff-4" PKG_DEB_NAME="libfreetype6-dev libpng-dev libtiff5-dev libjpeg-dev" PKG_RPM_NAME="freetype-devel libpng-devel libtiff-devel libjpeg-turbo-devel" PKG_CSW_NAME="libfreetype_dev libpng16_dev libtiff_dev libjpeg_dev" PKG_BREW_NAME="freetype libpng libtiff zlib libjpeg-turbo" PKG_TEST_HEADER="#include \n#include \n#include \n#include \n" PKG_LIBS="-lfreetype -lpng16 -ltiff -lz -ljpeg -lbz2" PKG_CFLAGS="" # Find compiler CC=`${R_HOME}/bin/R CMD config CC` CFLAGS=`${R_HOME}/bin/R CMD config CFLAGS` CPPFLAGS=`${R_HOME}/bin/R CMD config CPPFLAGS` # Use pkg-config if available pkg-config --exists ${PKG_CONFIG_NAME} >/dev/null 2>&1 && R_HAS_PKG_CONFIG=1; # Note that cflags may be empty in case of success if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then echo "Found INCLUDE_DIR and/or LIB_DIR!" PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS" PKG_LIBS="-L$LIB_DIR $PKG_LIBS" elif [ "$PLATFORM" = "Darwin" ]; then test ! "$CI" && brew --version 2>/dev/null if [ $? -eq 0 ]; then BREWDIR=`brew --prefix` PKG_CFLAGS="-I$BREWDIR/include -I$BREWDIR/include/freetype2" PKG_LIBS="-L$BREWDIR/lib ${PKG_LIBS}" else curl -sfL "https://autobrew.github.io/scripts/ragg" > autobrew . autobrew fi elif [ $R_HAS_PKG_CONFIG ]; then echo "Found pkg-config cflags and libs!" PKG_CFLAGS=`pkg-config --cflags ${PKG_CONFIG_NAME}` PKG_LIBS=`pkg-config --libs ${PKG_CONFIG_NAME}` PKG_LIBS="$PKG_LIBS -ljpeg" # Test configuration printf "$PKG_TEST_HEADER" | ${CC} ${CPPFLAGS} ${PKG_CFLAGS} ${CFLAGS} -E -xc - >/dev/null 2>&1 || R_CONFIG_ERROR=1; # if the above errors try using --static if [ $R_CONFIG_ERROR ]; then PKG_LIBS=`pkg-config --libs --static ${PKG_CONFIG_NAME}` fi unset R_CONFIG_ERROR fi # For debugging echo "Using PKG_CFLAGS=$PKG_CFLAGS" echo "Using PKG_LIBS=$PKG_LIBS" # Test configuration printf "$PKG_TEST_HEADER" | ${CC} ${CPPFLAGS} ${PKG_CFLAGS} ${CFLAGS} -E -xc - >/dev/null 2>configure.log # Customize the error if [ $? -ne 0 ]; then echo "-----------------------------[ ANTICONF ]-------------------------------" echo "Configuration failed to find one of $PKG_CONFIG_NAME. Try installing:" echo " * deb: $PKG_DEB_NAME (Debian, Ubuntu, etc)" echo " * rpm: $PKG_RPM_NAME (Fedora, CentOS, RHEL)" echo " * csw: $PKG_CSW_NAME (Solaris)" echo "If $PKG_CONFIG_NAME is already installed, check that 'pkg-config' is in your" echo "PATH and PKG_CONFIG_PATH contains a $PKG_CONFIG_NAME.pc file. If pkg-config" echo "is unavailable you can set INCLUDE_DIR and LIB_DIR manually via:" echo "R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'" echo "-------------------------- [ERROR MESSAGE] ---------------------------" cat configure.log echo "--------------------------------------------------------------------" exit 1 fi # Write to Makevars sed -e "s|@cflags@|$PKG_CFLAGS|" -e "s|@libs@|$PKG_LIBS|" src/Makevars.in > src/Makevars # Success exit 0